1"""Filename globbing utility."""
2
3import sys
4import os
5import re
6import fnmatch
7
8try:
9    _unicode = unicode
10except NameError:
11    # If Python is built without Unicode support, the unicode type
12    # will not exist. Fake one.
13    class _unicode(object):
14        pass
15
16__all__ = ["glob", "iglob"]
17
18def glob(pathname):
19    """Return a list of paths matching a pathname pattern.
20
21    The pattern may contain simple shell-style wildcards a la
22    fnmatch. However, unlike fnmatch, filenames starting with a
23    dot are special cases that are not matched by '*' and '?'
24    patterns.
25
26    """
27    return list(iglob(pathname))
28
29def iglob(pathname):
30    """Return an iterator which yields the paths matching a pathname pattern.
31
32    The pattern may contain simple shell-style wildcards a la
33    fnmatch. However, unlike fnmatch, filenames starting with a
34    dot are special cases that are not matched by '*' and '?'
35    patterns.
36
37    """
38    if not has_magic(pathname):
39        if os.path.lexists(pathname):
40            yield pathname
41        return
42    dirname, basename = os.path.split(pathname)
43    if not dirname:
44        for name in glob1(os.curdir, basename):
45            yield name
46        return
47    # `os.path.split()` returns the argument itself as a dirname if it is a
48    # drive or UNC path.  Prevent an infinite recursion if a drive or UNC path
49    # contains magic characters (i.e. r'\\?\C:').
50    if dirname != pathname and has_magic(dirname):
51        dirs = iglob(dirname)
52    else:
53        dirs = [dirname]
54    if has_magic(basename):
55        glob_in_dir = glob1
56    else:
57        glob_in_dir = glob0
58    for dirname in dirs:
59        for name in glob_in_dir(dirname, basename):
60            yield os.path.join(dirname, name)
61
62# These 2 helper functions non-recursively glob inside a literal directory.
63# They return a list of basenames. `glob1` accepts a pattern while `glob0`
64# takes a literal basename (so it only has to check for its existence).
65
66def glob1(dirname, pattern):
67    if not dirname:
68        dirname = os.curdir
69    if isinstance(pattern, _unicode) and not isinstance(dirname, unicode):
70        dirname = unicode(dirname, sys.getfilesystemencoding() or
71                                   sys.getdefaultencoding())
72    try:
73        names = os.listdir(dirname)
74    except os.error:
75        return []
76    if pattern[0] != '.':
77        names = filter(lambda x: x[0] != '.', names)
78    return fnmatch.filter(names, pattern)
79
80def glob0(dirname, basename):
81    if basename == '':
82        # `os.path.split()` returns an empty basename for paths ending with a
83        # directory separator.  'q*x/' should match only directories.
84        if os.path.isdir(dirname):
85            return [basename]
86    else:
87        if os.path.lexists(os.path.join(dirname, basename)):
88            return [basename]
89    return []
90
91
92magic_check = re.compile('[*?[]')
93
94def has_magic(s):
95    return magic_check.search(s) is not None
96