blob: 4b78d8d223b6158059be27312ac8e03bc169fbe8 [file] [log] [blame]
Guido van Rossum15e22e11997-12-05 19:03:01 +00001# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
Tim Peters2344fae2001-01-15 00:50:52 +00002"""Common pathname manipulations, WindowsNT/95 version.
Guido van Rossum534972b1999-02-03 17:20:50 +00003
4Instead of importing this module directly, import os and refer to this
5module as os.path.
Guido van Rossum15e22e11997-12-05 19:03:01 +00006"""
Guido van Rossum555915a1994-02-24 11:32:59 +00007
8import os
Mark Hammond8696ebc2002-10-08 02:44:31 +00009import sys
Christian Heimes05e8be12008-02-23 18:30:17 +000010import stat
Guido van Rossumd8faa362007-04-27 19:54:29 +000011import genericpath
Thomas Wouters89f507f2006-12-13 04:49:30 +000012from genericpath import *
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000013
Skip Montanaro269b83b2001-02-06 01:07:02 +000014__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
15 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000016 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
Benjamin Petersond71ca412008-05-08 23:44:58 +000017 "ismount", "expanduser","expandvars","normpath","abspath",
Georg Brandlf0de6a12005-08-22 18:02:59 +000018 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
Guido van Rossumd8faa362007-04-27 19:54:29 +000019 "extsep","devnull","realpath","supports_unicode_filenames","relpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000020
Skip Montanaro117910d2003-02-14 19:35:31 +000021# strings representing various path-related bits and pieces
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000022# These are primarily for export; internally, they are hardcoded.
Skip Montanaro117910d2003-02-14 19:35:31 +000023curdir = '.'
24pardir = '..'
25extsep = '.'
26sep = '\\'
27pathsep = ';'
Skip Montanaro9ddac3e2003-03-28 22:23:24 +000028altsep = '/'
Andrew MacIntyre437966c2003-02-17 09:17:50 +000029defpath = '.;C:\\bin'
Skip Montanaro117910d2003-02-14 19:35:31 +000030if 'ce' in sys.builtin_module_names:
31 defpath = '\\Windows'
32elif 'os2' in sys.builtin_module_names:
Andrew MacIntyre437966c2003-02-17 09:17:50 +000033 # OS/2 w/ VACPP
Skip Montanaro117910d2003-02-14 19:35:31 +000034 altsep = '/'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000035devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000036
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000037def _get_sep(path):
38 if isinstance(path, bytes):
39 return b'\\'
40 else:
41 return '\\'
42
43def _get_altsep(path):
44 if isinstance(path, bytes):
45 return b'/'
46 else:
47 return '/'
48
49def _get_bothseps(path):
50 if isinstance(path, bytes):
51 return b'\\/'
52 else:
53 return '\\/'
54
55def _get_dot(path):
56 if isinstance(path, bytes):
57 return b'.'
58 else:
59 return '.'
60
61def _get_colon(path):
62 if isinstance(path, bytes):
63 return b':'
64 else:
65 return ':'
66
Guido van Rossume2ad88c1997-08-12 14:46:58 +000067# Normalize the case of a pathname and map slashes to backslashes.
68# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000069# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000070
Guido van Rossum555915a1994-02-24 11:32:59 +000071def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000072 """Normalize case of pathname.
73
Guido van Rossum534972b1999-02-03 17:20:50 +000074 Makes all characters lowercase and all slashes into backslashes."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000075 return s.replace(_get_altsep(s), _get_sep(s)).lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000076
Guido van Rossum77e1db31997-06-02 23:11:57 +000077
Fred Drakeef0b5dd2000-02-17 17:30:40 +000078# Return whether a path is absolute.
Guido van Rossum555915a1994-02-24 11:32:59 +000079# Trivial in Posix, harder on the Mac or MS-DOS.
80# For DOS it is absolute if it starts with a slash or backslash (current
Guido van Rossum534972b1999-02-03 17:20:50 +000081# volume), or if a pathname after the volume letter and colon / UNC resource
82# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000083
84def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000085 """Test whether a path is absolute"""
86 s = splitdrive(s)[1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000087 return len(s) > 0 and s[:1] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000088
89
Guido van Rossum77e1db31997-06-02 23:11:57 +000090# Join two (or more) paths.
91
Barry Warsaw384d2491997-02-18 21:53:25 +000092def join(a, *p):
Guido van Rossum04110fb2007-08-24 16:32:05 +000093 """Join two or more pathname components, inserting "\\" as needed.
94 If any component is an absolute path, all previous path components
95 will be discarded."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000096 sep = _get_sep(a)
97 seps = _get_bothseps(a)
98 colon = _get_colon(a)
Guido van Rossum15e22e11997-12-05 19:03:01 +000099 path = a
100 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +0000101 b_wins = 0 # set to 1 iff b makes path irrelevant
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000102 if not path:
Tim Peters33dc0a12001-07-27 08:09:54 +0000103 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +0000104
Tim Peters33dc0a12001-07-27 08:09:54 +0000105 elif isabs(b):
106 # This probably wipes out path so far. However, it's more
107 # complicated if path begins with a drive letter:
108 # 1. join('c:', '/a') == 'c:/a'
109 # 2. join('c:/', '/a') == 'c:/a'
110 # But
111 # 3. join('c:/a', '/b') == '/b'
112 # 4. join('c:', 'd:/') = 'd:/'
113 # 5. join('c:/', 'd:/') = 'd:/'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000114 if path[1:2] != colon or b[1:2] == colon:
Tim Peters33dc0a12001-07-27 08:09:54 +0000115 # Path doesn't start with a drive letter, or cases 4 and 5.
116 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +0000117
Tim Peters33dc0a12001-07-27 08:09:54 +0000118 # Else path has a drive letter, and b doesn't but is absolute.
119 elif len(path) > 3 or (len(path) == 3 and
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000120 path[-1:] not in seps):
Tim Peters33dc0a12001-07-27 08:09:54 +0000121 # case 3
122 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +0000123
Tim Peters33dc0a12001-07-27 08:09:54 +0000124 if b_wins:
125 path = b
126 else:
127 # Join, and ensure there's a separator.
128 assert len(path) > 0
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000129 if path[-1:] in seps:
130 if b and b[:1] in seps:
Tim Peters33dc0a12001-07-27 08:09:54 +0000131 path += b[1:]
132 else:
133 path += b
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000134 elif path[-1:] == colon:
Tim Peters33dc0a12001-07-27 08:09:54 +0000135 path += b
136 elif b:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000137 if b[:1] in seps:
Tim Peters33dc0a12001-07-27 08:09:54 +0000138 path += b
139 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000140 path += sep + b
Tim Peters6a3e5f12001-11-05 21:25:02 +0000141 else:
142 # path is not empty and does not end with a backslash,
143 # but b is empty; since, e.g., split('a/') produces
144 # ('a', ''), it's best if join() adds a backslash in
145 # this case.
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000146 path += sep
Tim Peters1bdd0f22001-07-19 17:18:18 +0000147
Guido van Rossum15e22e11997-12-05 19:03:01 +0000148 return path
Guido van Rossum555915a1994-02-24 11:32:59 +0000149
150
151# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000152# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000153# It is always true that drivespec + pathspec == p
154def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000155 """Split a pathname into drive and path specifiers. Returns a 2-tuple
156"(drive,path)"; either part may be empty"""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000157 if p[1:2] == _get_colon(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000158 return p[0:2], p[2:]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000159 return p[:0], p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000160
161
162# Parse UNC paths
163def splitunc(p):
164 """Split a pathname into UNC mount point and relative path specifiers.
165
166 Return a 2-tuple (unc, rest); either part may be empty.
167 If unc is not empty, it has the form '//host/mount' (or similar
168 using backslashes). unc+rest is always the input path.
169 Paths containing drive letters never have an UNC part.
170 """
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000171 sep = _get_sep(p)
172 if not p[1:2]:
173 return p[:0], p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000174 firstTwo = p[0:2]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000175 if normcase(firstTwo) == sep + sep:
Guido van Rossum534972b1999-02-03 17:20:50 +0000176 # is a UNC path:
177 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
178 # \\machine\mountpoint\directories...
179 # directory ^^^^^^^^^^^^^^^
180 normp = normcase(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000181 index = normp.find(sep, 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000182 if index == -1:
183 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000184 return (p[:0], p)
185 index = normp.find(sep, index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000186 if index == -1:
187 index = len(p)
188 return p[:index], p[index:]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000189 return p[:0], p
Guido van Rossum555915a1994-02-24 11:32:59 +0000190
191
192# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000193# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000194# join(head, tail) == p holds.
195# The resulting head won't end in '/' unless it is the root.
196
197def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000198 """Split a pathname.
199
200 Return tuple (head, tail) where tail is everything after the final slash.
201 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000202
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000203 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000204 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000205 # set i to index beyond p's last slash
206 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000207 while i and p[i-1] not in seps:
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000208 i = i - 1
209 head, tail = p[:i], p[i:] # now tail has no slashes
210 # remove trailing slashes from head, unless it's all slashes
211 head2 = head
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000212 while head2 and head2[-1:] in seps:
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000213 head2 = head2[:-1]
214 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000215 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000216
217
218# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000219# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000220# pathname component; the root is everything before that.
221# It is always true that root + ext == p.
222
223def splitext(p):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000224 return genericpath._splitext(p, _get_sep(p), _get_altsep(p),
225 _get_dot(p))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000226splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000227
228
229# Return the tail (basename) part of a path.
230
231def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000232 """Returns the final component of a pathname"""
233 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000234
235
236# Return the head (dirname) part of a path.
237
238def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000239 """Returns the directory component of a pathname"""
240 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000241
Guido van Rossum555915a1994-02-24 11:32:59 +0000242# Is a path a symbolic link?
243# This will always return false on systems where posix.lstat doesn't exist.
244
245def islink(path):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000246 """Test for symbolic link.
247 On WindowsNT/95 and OS/2 always returns false
248 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000249 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000250
Thomas Wouters89f507f2006-12-13 04:49:30 +0000251# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000252lexists = exists
253
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000254# Is a path a mount point? Either a root (with or without drive letter)
255# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000256
257def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000258 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000259 unc, rest = splitunc(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000260 seps = _get_bothseps(p)
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000261 if unc:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000262 return rest in p[:0] + seps
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000263 p = splitdrive(path)[1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000264 return len(p) == 1 and p[0] in seps
Guido van Rossum555915a1994-02-24 11:32:59 +0000265
266
Guido van Rossum555915a1994-02-24 11:32:59 +0000267# Expand paths beginning with '~' or '~user'.
268# '~' means $HOME; '~user' means that user's home directory.
269# If the path doesn't begin with '~', or if the user or $HOME is unknown,
270# the path is returned unchanged (leaving error reporting to whatever
271# function is called with the expanded path as argument).
272# See also module 'glob' for expansion of *, ? and [...] in pathnames.
273# (A function should also be defined to do full *sh-style environment
274# variable expansion.)
275
276def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000277 """Expand ~ and ~user constructs.
278
279 If user or $HOME is unknown, do nothing."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000280 if isinstance(path, bytes):
281 tilde = b'~'
282 else:
283 tilde = '~'
284 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000285 return path
286 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000287 while i < n and path[i] not in _get_bothseps(path):
Fred Drakeb4e460a2000-09-28 16:25:20 +0000288 i = i + 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289
290 if 'HOME' in os.environ:
291 userhome = os.environ['HOME']
292 elif 'USERPROFILE' in os.environ:
293 userhome = os.environ['USERPROFILE']
294 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000295 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000296 else:
297 try:
298 drive = os.environ['HOMEDRIVE']
299 except KeyError:
300 drive = ''
301 userhome = join(drive, os.environ['HOMEPATH'])
302
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000303 if isinstance(path, bytes):
304 userhome = userhome.encode(sys.getfilesystemencoding())
305
Guido van Rossumd8faa362007-04-27 19:54:29 +0000306 if i != 1: #~user
307 userhome = join(dirname(userhome), path[1:i])
308
Guido van Rossum15e22e11997-12-05 19:03:01 +0000309 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000310
311
312# Expand paths containing shell variable substitutions.
313# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000314# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000315# - '$$' is translated into '$'
316# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000317# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000318# - $varname is accepted.
319# - %varname% is accepted.
320# - varnames can be made out of letters, digits and the characters '_-'
321# (though is not verifed in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000322# XXX With COMMAND.COM you can use any characters in a variable name,
323# XXX except '^|<>='.
324
Tim Peters2344fae2001-01-15 00:50:52 +0000325def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000326 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000327
328 Unknown variables are left unchanged."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000329 if isinstance(path, bytes):
330 if ord('$') not in path and ord('%') not in path:
331 return path
332 import string
333 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000334 quote = b'\''
335 percent = b'%'
336 brace = b'{'
337 dollar = b'$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000338 else:
339 if '$' not in path and '%' not in path:
340 return path
341 import string
342 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000343 quote = '\''
344 percent = '%'
345 brace = '{'
346 dollar = '$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000347 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000348 index = 0
349 pathlen = len(path)
350 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000351 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000352 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000353 path = path[index + 1:]
354 pathlen = len(path)
355 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000356 index = path.index(c)
357 res = res + c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000358 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000359 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000360 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000361 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000362 if path[index + 1:index + 2] == percent:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000363 res = res + c
364 index = index + 1
365 else:
366 path = path[index+1:]
367 pathlen = len(path)
368 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000369 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000370 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000371 res = res + percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000372 index = pathlen - 1
373 else:
374 var = path[:index]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000375 if isinstance(path, bytes):
376 var = var.decode('ascii')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000377 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000378 value = os.environ[var]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000379 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000380 value = '%' + var + '%'
381 if isinstance(path, bytes):
382 value = value.encode('ascii')
383 res = res + value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000384 elif c == dollar: # variable or '$$'
385 if path[index + 1:index + 2] == dollar:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000386 res = res + c
387 index = index + 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000388 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000389 path = path[index+2:]
390 pathlen = len(path)
391 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000392 if isinstance(path, bytes):
393 index = path.index(b'}')
Thomas Woutersb2137042007-02-01 18:02:27 +0000394 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000395 index = path.index('}')
396 var = path[:index]
397 if isinstance(path, bytes):
398 var = var.decode('ascii')
399 if var in os.environ:
400 value = os.environ[var]
401 else:
402 value = '${' + var + '}'
403 if isinstance(path, bytes):
404 value = value.encode('ascii')
405 res = res + value
Fred Drakeb4e460a2000-09-28 16:25:20 +0000406 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000407 if isinstance(path, bytes):
408 res = res + b'${' + path
409 else:
410 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000411 index = pathlen - 1
412 else:
413 var = ''
414 index = index + 1
415 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000416 while c and c in varchars:
417 if isinstance(path, bytes):
418 var = var + c.decode('ascii')
419 else:
420 var = var + c
Guido van Rossum15e22e11997-12-05 19:03:01 +0000421 index = index + 1
422 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000423 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000424 value = os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000425 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000426 value = '$' + var
427 if isinstance(path, bytes):
428 value = value.encode('ascii')
429 res = res + value
430 if c:
Thomas Woutersb2137042007-02-01 18:02:27 +0000431 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000432 else:
433 res = res + c
434 index = index + 1
435 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000436
437
Tim Peters54a14a32001-08-30 22:05:26 +0000438# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
Guido van Rossum3df7b5a1996-08-26 16:35:26 +0000439# Previously, this function also truncated pathnames to 8+3 format,
440# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000441
442def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000443 """Normalize path, eliminating double slashes, etc."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000444 sep = _get_sep(path)
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000445 dotdot = _get_dot(path) * 2
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000446 path = path.replace(_get_altsep(path), sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000447 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000448 # We need to be careful here. If the prefix is empty, and the path starts
449 # with a backslash, it could either be an absolute path on the current
450 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
451 # is therefore imperative NOT to collapse multiple backslashes blindly in
452 # that case.
453 # The code below preserves multiple backslashes when there is no drive
454 # letter. This means that the invalid filename \\\a\b is preserved
455 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
456 # is any better behaviour for such edge cases.
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000457 if not prefix:
Brett Cannonbdc36272004-07-10 20:42:22 +0000458 # No drive letter - preserve initial backslashes
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000459 while path[:1] == sep:
460 prefix = prefix + sep
Brett Cannonbdc36272004-07-10 20:42:22 +0000461 path = path[1:]
462 else:
463 # We have a drive letter - collapse initial backslashes
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000464 if path.startswith(sep):
465 prefix = prefix + sep
466 path = path.lstrip(sep)
467 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000468 i = 0
469 while i < len(comps):
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000470 if not comps[i] or comps[i] == _get_dot(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000471 del comps[i]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000472 elif comps[i] == dotdot:
473 if i > 0 and comps[i-1] != dotdot:
Tim Peters54a14a32001-08-30 22:05:26 +0000474 del comps[i-1:i+1]
475 i -= 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000476 elif i == 0 and prefix.endswith(_get_sep(path)):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000477 del comps[i]
478 else:
479 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000480 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000481 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000482 # If the path is now empty, substitute '.'
483 if not prefix and not comps:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000484 comps.append(_get_dot(path))
485 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000486
487
488# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000489try:
490 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000491
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492except ImportError: # not running on Windows - mock up something sensible
493 def abspath(path):
494 """Return the absolute version of a path."""
495 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000496 if isinstance(path, bytes):
497 cwd = os.getcwdb()
498 else:
499 cwd = os.getcwd()
500 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501 return normpath(path)
502
503else: # use native Windows method on Windows
504 def abspath(path):
505 """Return the absolute version of a path."""
506
507 if path: # Empty path must return current working directory.
508 try:
509 path = _getfullpathname(path)
510 except WindowsError:
511 pass # Bad path - return unchanged.
512 else:
513 path = os.getcwd()
514 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000515
516# realpath is a no-op on systems without islink support
517realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000518# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000519supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
520 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000521
522def relpath(path, start=curdir):
523 """Return a relative version of a path"""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000524 sep = _get_sep(path)
525
526 if start is curdir:
527 start = _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000528
529 if not path:
530 raise ValueError("no path specified")
531 start_list = abspath(start).split(sep)
532 path_list = abspath(path).split(sep)
533 if start_list[0].lower() != path_list[0].lower():
534 unc_path, rest = splitunc(path)
535 unc_start, rest = splitunc(start)
536 if bool(unc_path) ^ bool(unc_start):
537 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
538 % (path, start))
539 else:
540 raise ValueError("path is on drive %s, start on drive %s"
541 % (path_list[0], start_list[0]))
542 # Work out how much of the filepath is shared by start and path.
543 for i in range(min(len(start_list), len(path_list))):
544 if start_list[i].lower() != path_list[i].lower():
545 break
546 else:
547 i += 1
548
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000549 if isinstance(path, bytes):
550 pardir = b'..'
551 else:
552 pardir = '..'
Guido van Rossumd8faa362007-04-27 19:54:29 +0000553 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000554 if not rel_list:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000555 return _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000556 return join(*rel_list)