1b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
2b410d6e4ce58c177569d42b51772f7bb239a24a3darylm"""Common pathname manipulations, WindowsNT/95 version.
3b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
4b410d6e4ce58c177569d42b51772f7bb239a24a3darylmInstead of importing this module directly, import os and refer to this
5b410d6e4ce58c177569d42b51772f7bb239a24a3darylmmodule as os.path.
6b410d6e4ce58c177569d42b51772f7bb239a24a3darylm"""
7b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
8b410d6e4ce58c177569d42b51772f7bb239a24a3darylmimport os
9b410d6e4ce58c177569d42b51772f7bb239a24a3darylmimport sys
10b410d6e4ce58c177569d42b51772f7bb239a24a3darylmimport stat
11b410d6e4ce58c177569d42b51772f7bb239a24a3darylmimport genericpath
12b410d6e4ce58c177569d42b51772f7bb239a24a3darylmimport warnings
13b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
14b410d6e4ce58c177569d42b51772f7bb239a24a3darylmfrom genericpath import *
15b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
16b410d6e4ce58c177569d42b51772f7bb239a24a3darylm__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
17b410d6e4ce58c177569d42b51772f7bb239a24a3darylm           "basename","dirname","commonprefix","getsize","getmtime",
18b410d6e4ce58c177569d42b51772f7bb239a24a3darylm           "getatime","getctime", "islink","exists","lexists","isdir","isfile",
19b410d6e4ce58c177569d42b51772f7bb239a24a3darylm           "ismount","walk","expanduser","expandvars","normpath","abspath",
20b410d6e4ce58c177569d42b51772f7bb239a24a3darylm           "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
21b410d6e4ce58c177569d42b51772f7bb239a24a3darylm           "extsep","devnull","realpath","supports_unicode_filenames","relpath"]
22b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
23b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# strings representing various path-related bits and pieces
24b410d6e4ce58c177569d42b51772f7bb239a24a3darylmcurdir = '.'
25b410d6e4ce58c177569d42b51772f7bb239a24a3darylmpardir = '..'
26b410d6e4ce58c177569d42b51772f7bb239a24a3darylmextsep = '.'
27b410d6e4ce58c177569d42b51772f7bb239a24a3darylmsep = '\\'
28b410d6e4ce58c177569d42b51772f7bb239a24a3darylmpathsep = ';'
29b410d6e4ce58c177569d42b51772f7bb239a24a3darylmaltsep = '/'
30b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdefpath = '.;C:\\bin'
31b410d6e4ce58c177569d42b51772f7bb239a24a3darylmif 'ce' in sys.builtin_module_names:
32b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    defpath = '\\Windows'
33b410d6e4ce58c177569d42b51772f7bb239a24a3darylmelif 'os2' in sys.builtin_module_names:
34b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # OS/2 w/ VACPP
35b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    altsep = '/'
36b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdevnull = 'nul'
37b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
38b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Normalize the case of a pathname and map slashes to backslashes.
39b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Other normalizations (such as optimizing '../' away) are not done
40b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# (this is done by normpath).
41b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
42b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef normcase(s):
43b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Normalize case of pathname.
44b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
45b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Makes all characters lowercase and all slashes into backslashes."""
46b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return s.replace("/", "\\").lower()
47b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
48b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
49b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Return whether a path is absolute.
50b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Trivial in Posix, harder on the Mac or MS-DOS.
51b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# For DOS it is absolute if it starts with a slash or backslash (current
52b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# volume), or if a pathname after the volume letter and colon / UNC resource
53b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# starts with a slash or backslash.
54b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
55b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef isabs(s):
56b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Test whether a path is absolute"""
57b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    s = splitdrive(s)[1]
58b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return s != '' and s[:1] in '/\\'
59b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
60b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
61b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Join two (or more) paths.
62b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
63b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef join(a, *p):
64b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Join two or more pathname components, inserting "\\" as needed.
65b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    If any component is an absolute path, all previous path components
66b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    will be discarded."""
67b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    path = a
68b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    for b in p:
69b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        b_wins = 0  # set to 1 iff b makes path irrelevant
70b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if path == "":
71b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            b_wins = 1
72b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
73b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        elif isabs(b):
74b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            # This probably wipes out path so far.  However, it's more
75b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            # complicated if path begins with a drive letter:
76b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            #     1. join('c:', '/a') == 'c:/a'
77b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            #     2. join('c:/', '/a') == 'c:/a'
78b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            # But
79b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            #     3. join('c:/a', '/b') == '/b'
80b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            #     4. join('c:', 'd:/') = 'd:/'
81b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            #     5. join('c:/', 'd:/') = 'd:/'
82b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if path[1:2] != ":" or b[1:2] == ":":
83b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # Path doesn't start with a drive letter, or cases 4 and 5.
84b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                b_wins = 1
85b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
86b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            # Else path has a drive letter, and b doesn't but is absolute.
87b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            elif len(path) > 3 or (len(path) == 3 and
88b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                                   path[-1] not in "/\\"):
89b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # case 3
90b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                b_wins = 1
91b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
92b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if b_wins:
93b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = b
94b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        else:
95b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            # Join, and ensure there's a separator.
96b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            assert len(path) > 0
97b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if path[-1] in "/\\":
98b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                if b and b[0] in "/\\":
99b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    path += b[1:]
100b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                else:
101b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    path += b
102b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            elif path[-1] == ":":
103b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                path += b
104b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            elif b:
105b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                if b[0] in "/\\":
106b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    path += b
107b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                else:
108b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    path += "\\" + b
109b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            else:
110b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # path is not empty and does not end with a backslash,
111b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # but b is empty; since, e.g., split('a/') produces
112b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # ('a', ''), it's best if join() adds a backslash in
113b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                # this case.
114b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                path += '\\'
115b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
116b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return path
117b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
118b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
119b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Split a path in a drive specification (a drive letter followed by a
120b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# colon) and the path specification.
121b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# It is always true that drivespec + pathspec == p
122b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef splitdrive(p):
123b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Split a pathname into drive and path specifiers. Returns a 2-tuple
124b410d6e4ce58c177569d42b51772f7bb239a24a3darylm"(drive,path)";  either part may be empty"""
125b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    pparts = p.split(':', 2)
126b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    numparts = len(pparts)
127b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if numparts == 2:
128b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return pparts[0] + ':', pparts[1]
129b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    else:
130b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if numparts == 1:
131b410d6e4ce58c177569d42b51772f7bb239a24a3darylm          return '', pparts[0]
132b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return '', p
133b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
134b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
135b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Parse UNC paths
136b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef splitunc(p):
137b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Split a pathname into UNC mount point and relative path specifiers.
138b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
139b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Return a 2-tuple (unc, rest); either part may be empty.
140b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    If unc is not empty, it has the form '//host/mount' (or similar
141b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    using backslashes).  unc+rest is always the input path.
142b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Paths containing drive letters never have an UNC part.
143b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """
144b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if len(p.split(':', 2)) > 1:
145b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return '', p # Drive letter present
146b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    firstTwo = p[0:2]
147b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if firstTwo == '//' or firstTwo == '\\\\':
148b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # is a UNC path:
149b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
150b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # \\machine\mountpoint\directories...
151b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        #           directory ^^^^^^^^^^^^^^^
152b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        normp = normcase(p)
153b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        index = normp.find('\\', 2)
154b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if index == -1:
155b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
156b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            return ("", p)
157b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        index = normp.find('\\', index + 1)
158b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if index == -1:
159b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            index = len(p)
160b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return p[:index], p[index:]
161b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return '', p
162b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
163b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
164b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Split a path in head (everything up to the last '/') and tail (the
165b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# rest).  After the trailing '/' is stripped, the invariant
166b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# join(head, tail) == p holds.
167b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# The resulting head won't end in '/' unless it is the root.
168b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
169b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef split(p):
170b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Split a pathname.
171b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
172b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Return tuple (head, tail) where tail is everything after the final slash.
173b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Either part may be empty."""
174b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
175b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    d, p = splitdrive(p)
176b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # set i to index beyond p's last slash
177b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    i = len(p)
178b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    while i and p[i-1] not in '/\\':
179b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        i = i - 1
180b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    head, tail = p[:i], p[i:]  # now tail has no slashes
181b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # remove trailing slashes from head, unless it's all slashes
182b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    head2 = head
183b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    while head2 and head2[-1] in '/\\':
184b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        head2 = head2[:-1]
185b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    head = head2 or head
186b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return d + head, tail
187b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
188b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
189b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Split a path in root and extension.
190b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# The extension is everything starting at the last dot in the last
191b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# pathname component; the root is everything before that.
192b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# It is always true that root + ext == p.
193b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
194b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef splitext(p):
195b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return genericpath._splitext(p, sep, altsep, extsep)
196b410d6e4ce58c177569d42b51772f7bb239a24a3darylmsplitext.__doc__ = genericpath._splitext.__doc__
197b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
198b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
199b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Return the tail (basename) part of a path.
200b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
201b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef basename(p):
202b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Returns the final component of a pathname"""
203b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return split(p)[1]
204b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
205b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
206b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Return the head (dirname) part of a path.
207b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
208b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef dirname(p):
209b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Returns the directory component of a pathname"""
210b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return split(p)[0]
211b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
212b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Is a path a symbolic link?
213b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# This will always return false on systems where posix.lstat doesn't exist.
214b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
215b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef islink(path):
216b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Test for symbolic link.
217b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    On WindowsNT/95 and OS/2 always returns false
218b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """
219b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return False
220b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
221b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# alias exists to lexists
222b410d6e4ce58c177569d42b51772f7bb239a24a3darylmlexists = exists
223b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
224b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Is a path a mount point?  Either a root (with or without drive letter)
225b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# or an UNC path with at most a / or \ after the mount point.
226b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
227b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef ismount(path):
228b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Test whether a path is a mount point (defined as root of drive)"""
229b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    unc, rest = splitunc(path)
230b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if unc:
231b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return rest in ("", "/", "\\")
232b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    p = splitdrive(path)[1]
233b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return len(p) == 1 and p[0] in '/\\'
234b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
235b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
236b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Directory tree walk.
237b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# For each directory under top (including top itself, but excluding
238b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# '.' and '..'), func(arg, dirname, filenames) is called, where
239b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# dirname is the name of the directory and filenames is the list
240b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# of files (and subdirectories etc.) in the directory.
241b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# The func may modify the filenames list, to implement a filter,
242b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# or to impose a different order of visiting.
243b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
244b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef walk(top, func, arg):
245b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Directory tree walk with callback function.
246b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
247b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    For each directory in the directory tree rooted at top (including top
248b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
249b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    dirname is the name of the directory, and fnames a list of the names of
250b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    the files and subdirectories in dirname (excluding '.' and '..').  func
251b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    may modify the fnames list in-place (e.g. via del or slice assignment),
252b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    and walk will only recurse into the subdirectories whose names remain in
253b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    fnames; this can be used to implement a filter, or to impose a specific
254b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    order of visiting.  No semantics are defined for, or required of, arg,
255b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    beyond that arg is always passed to func.  It can be used, e.g., to pass
256b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    a filename pattern, or a mutable object designed to accumulate
257b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    statistics.  Passing None for arg is common."""
258b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
259b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                      stacklevel=2)
260b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    try:
261b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        names = os.listdir(top)
262b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    except os.error:
263b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return
264b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    func(arg, top, names)
265b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    for name in names:
266b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        name = join(top, name)
267b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if isdir(name):
268b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            walk(name, func, arg)
269b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
270b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
271b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Expand paths beginning with '~' or '~user'.
272b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# '~' means $HOME; '~user' means that user's home directory.
273b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# If the path doesn't begin with '~', or if the user or $HOME is unknown,
274b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# the path is returned unchanged (leaving error reporting to whatever
275b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# function is called with the expanded path as argument).
276b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# See also module 'glob' for expansion of *, ? and [...] in pathnames.
277b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# (A function should also be defined to do full *sh-style environment
278b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# variable expansion.)
279b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
280b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef expanduser(path):
281b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Expand ~ and ~user constructs.
282b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
283b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    If user or $HOME is unknown, do nothing."""
284b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if path[:1] != '~':
285b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return path
286b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    i, n = 1, len(path)
287b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    while i < n and path[i] not in '/\\':
288b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        i = i + 1
289b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
290b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if 'HOME' in os.environ:
291b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        userhome = os.environ['HOME']
292b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    elif 'USERPROFILE' in os.environ:
293b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        userhome = os.environ['USERPROFILE']
294b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    elif not 'HOMEPATH' in os.environ:
295b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return path
296b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    else:
297b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        try:
298b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            drive = os.environ['HOMEDRIVE']
299b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        except KeyError:
300b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            drive = ''
301b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        userhome = join(drive, os.environ['HOMEPATH'])
302b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
303b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if i != 1: #~user
304b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        userhome = join(dirname(userhome), path[1:i])
305b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
306b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return userhome + path[i:]
307b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
308b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
309b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Expand paths containing shell variable substitutions.
310b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# The following rules apply:
311b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - no expansion within single quotes
312b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - '$$' is translated into '$'
313b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
314b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - ${varname} is accepted.
315b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - $varname is accepted.
316b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - %varname% is accepted.
317b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#       - varnames can be made out of letters, digits and the characters '_-'
318b410d6e4ce58c177569d42b51772f7bb239a24a3darylm#         (though is not verified in the ${varname} and %varname% cases)
319b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# XXX With COMMAND.COM you can use any characters in a variable name,
320b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# XXX except '^|<>='.
321b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
322b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef expandvars(path):
323b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Expand shell variables of the forms $var, ${var} and %var%.
324b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
325b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    Unknown variables are left unchanged."""
326b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if '$' not in path and '%' not in path:
327b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return path
328b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    import string
329b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    varchars = string.ascii_letters + string.digits + '_-'
330b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    res = ''
331b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    index = 0
332b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    pathlen = len(path)
333b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    while index < pathlen:
334b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        c = path[index]
335b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if c == '\'':   # no expansion within single quotes
336b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = path[index + 1:]
337b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            pathlen = len(path)
338b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            try:
339b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                index = path.index('\'')
340b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                res = res + '\'' + path[:index + 1]
341b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            except ValueError:
342b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                res = res + path
343b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                index = pathlen - 1
344b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        elif c == '%':  # variable or '%'
345b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if path[index + 1:index + 2] == '%':
346b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                res = res + c
347b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                index = index + 1
348b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            else:
349b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                path = path[index+1:]
350b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                pathlen = len(path)
351b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                try:
352b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = path.index('%')
353b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                except ValueError:
354b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    res = res + '%' + path
355b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = pathlen - 1
356b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                else:
357b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    var = path[:index]
358b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    if var in os.environ:
359b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                        res = res + os.environ[var]
360b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    else:
361b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                        res = res + '%' + var + '%'
362b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        elif c == '$':  # variable or '$$'
363b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if path[index + 1:index + 2] == '$':
364b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                res = res + c
365b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                index = index + 1
366b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            elif path[index + 1:index + 2] == '{':
367b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                path = path[index+2:]
368b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                pathlen = len(path)
369b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                try:
370b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = path.index('}')
371b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    var = path[:index]
372b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    if var in os.environ:
373b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                        res = res + os.environ[var]
374b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    else:
375b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                        res = res + '${' + var + '}'
376b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                except ValueError:
377b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    res = res + '${' + path
378b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = pathlen - 1
379b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            else:
380b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                var = ''
381b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                index = index + 1
382b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                c = path[index:index + 1]
383b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                while c != '' and c in varchars:
384b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    var = var + c
385b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = index + 1
386b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    c = path[index:index + 1]
387b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                if var in os.environ:
388b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    res = res + os.environ[var]
389b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                else:
390b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    res = res + '$' + var
391b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                if c != '':
392b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                    index = index - 1
393b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        else:
394b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            res = res + c
395b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        index = index + 1
396b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return res
397b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
398b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
399b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
400b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Previously, this function also truncated pathnames to 8+3 format,
401b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# but as this module is called "ntpath", that's obviously wrong!
402b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
403b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef normpath(path):
404b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Normalize path, eliminating double slashes, etc."""
405b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # Preserve unicode (if path is unicode)
406b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
407b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if path.startswith(('\\\\.\\', '\\\\?\\')):
408b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # in the case of paths with these prefixes:
409b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # \\.\ -> device names
410b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # \\?\ -> literal paths
411b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # do not do any normalization, but return the path unchanged
412b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return path
413b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    path = path.replace("/", "\\")
414b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    prefix, path = splitdrive(path)
415b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # We need to be careful here. If the prefix is empty, and the path starts
416b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # with a backslash, it could either be an absolute path on the current
417b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
418b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # is therefore imperative NOT to collapse multiple backslashes blindly in
419b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # that case.
420b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # The code below preserves multiple backslashes when there is no drive
421b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # letter. This means that the invalid filename \\\a\b is preserved
422b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # unchanged, where a\\\b is normalised to a\b. It's not clear that there
423b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # is any better behaviour for such edge cases.
424b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if prefix == '':
425b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # No drive letter - preserve initial backslashes
426b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        while path[:1] == "\\":
427b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            prefix = prefix + backslash
428b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = path[1:]
429b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    else:
430b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        # We have a drive letter - collapse initial backslashes
431b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if path.startswith("\\"):
432b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            prefix = prefix + backslash
433b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = path.lstrip("\\")
434b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    comps = path.split("\\")
435b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    i = 0
436b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    while i < len(comps):
437b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if comps[i] in ('.', ''):
438b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            del comps[i]
439b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        elif comps[i] == '..':
440b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if i > 0 and comps[i-1] != '..':
441b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                del comps[i-1:i+1]
442b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                i -= 1
443b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            elif i == 0 and prefix.endswith("\\"):
444b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                del comps[i]
445b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            else:
446b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                i += 1
447b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        else:
448b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            i += 1
449b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # If the path is now empty, substitute '.'
450b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if not prefix and not comps:
451b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        comps.append(dot)
452b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return prefix + backslash.join(comps)
453b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
454b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
455b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Return an absolute path.
456b410d6e4ce58c177569d42b51772f7bb239a24a3darylmtry:
457b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    from nt import _getfullpathname
458b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
459b410d6e4ce58c177569d42b51772f7bb239a24a3darylmexcept ImportError: # not running on Windows - mock up something sensible
460b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    def abspath(path):
461b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        """Return the absolute version of a path."""
462b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if not isabs(path):
463b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            if isinstance(path, unicode):
464b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                cwd = os.getcwdu()
465b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            else:
466b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                cwd = os.getcwd()
467b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = join(cwd, path)
468b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return normpath(path)
469b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
470b410d6e4ce58c177569d42b51772f7bb239a24a3darylmelse:  # use native Windows method on Windows
471b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    def abspath(path):
472b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        """Return the absolute version of a path."""
473b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
474b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if path: # Empty path must return current working directory.
475b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            try:
476b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                path = _getfullpathname(path)
477b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            except WindowsError:
478b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                pass # Bad path - return unchanged.
479b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        elif isinstance(path, unicode):
480b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = os.getcwdu()
481b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        else:
482b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            path = os.getcwd()
483b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return normpath(path)
484b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
485b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# realpath is a no-op on systems without islink support
486b410d6e4ce58c177569d42b51772f7bb239a24a3darylmrealpath = abspath
487b410d6e4ce58c177569d42b51772f7bb239a24a3darylm# Win9x family and earlier have no Unicode filename support.
488b410d6e4ce58c177569d42b51772f7bb239a24a3darylmsupports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
489b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                              sys.getwindowsversion()[3] >= 2)
490b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
491b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef _abspath_split(path):
492b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    abs = abspath(normpath(path))
493b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    prefix, rest = splitunc(abs)
494b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    is_unc = bool(prefix)
495b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if not is_unc:
496b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        prefix, rest = splitdrive(abs)
497b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return is_unc, prefix, [x for x in rest.split(sep) if x]
498b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
499b410d6e4ce58c177569d42b51772f7bb239a24a3darylmdef relpath(path, start=curdir):
500b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    """Return a relative version of a path"""
501b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
502b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if not path:
503b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        raise ValueError("no path specified")
504b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
505b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    start_is_unc, start_prefix, start_list = _abspath_split(start)
506b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    path_is_unc, path_prefix, path_list = _abspath_split(path)
507b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
508b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if path_is_unc ^ start_is_unc:
509b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
510b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                                                            % (path, start))
511b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if path_prefix.lower() != start_prefix.lower():
512b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if path_is_unc:
513b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            raise ValueError("path is on UNC root %s, start on UNC root %s"
514b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                                                % (path_prefix, start_prefix))
515b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        else:
516b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            raise ValueError("path is on drive %s, start on drive %s"
517b410d6e4ce58c177569d42b51772f7bb239a24a3darylm                                                % (path_prefix, start_prefix))
518b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    # Work out how much of the filepath is shared by start and path.
519b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    i = 0
520b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    for e1, e2 in zip(start_list, path_list):
521b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        if e1.lower() != e2.lower():
522b410d6e4ce58c177569d42b51772f7bb239a24a3darylm            break
523b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        i += 1
524b410d6e4ce58c177569d42b51772f7bb239a24a3darylm
525b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
526b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    if not rel_list:
527b410d6e4ce58c177569d42b51772f7bb239a24a3darylm        return curdir
528b410d6e4ce58c177569d42b51772f7bb239a24a3darylm    return join(*rel_list)
529