blob: 79c3d4d6371fdb5724717c40b9d975fcc7d86b37 [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')
334 else:
335 if '$' not in path and '%' not in path:
336 return path
337 import string
338 varchars = string.ascii_letters + string.digits + '_-'
339 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000340 index = 0
341 pathlen = len(path)
342 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000343 c = path[index:index+1]
344 if c in ('\'', b'\''): # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000345 path = path[index + 1:]
346 pathlen = len(path)
347 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000348 index = path.index(c)
349 res = res + c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000350 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000351 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000352 index = pathlen - 1
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000353 elif c in ('%', b'%'): # variable or '%'
354 if isinstance(path, bytes):
355 percent = b'%'
356 else:
357 percent = '%'
358 if path[index + 1:index + 2] == percent:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000359 res = res + c
360 index = index + 1
361 else:
362 path = path[index+1:]
363 pathlen = len(path)
364 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000365 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000366 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000367 res = res + percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000368 index = pathlen - 1
369 else:
370 var = path[:index]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000371 if isinstance(path, bytes):
372 var = var.decode('ascii')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000373 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000374 value = os.environ[var]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000375 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000376 value = '%' + var + '%'
377 if isinstance(path, bytes):
378 value = value.encode('ascii')
379 res = res + value
380 elif c in ('$', b'$'): # variable or '$$'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000381 if path[index + 1:index + 2] == '$':
382 res = res + c
383 index = index + 1
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000384 elif path[index + 1:index + 2] in ('{', b'{'):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 path = path[index+2:]
386 pathlen = len(path)
387 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000388 if isinstance(path, bytes):
389 index = path.index(b'}')
Thomas Woutersb2137042007-02-01 18:02:27 +0000390 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000391 index = path.index('}')
392 var = path[:index]
393 if isinstance(path, bytes):
394 var = var.decode('ascii')
395 if var in os.environ:
396 value = os.environ[var]
397 else:
398 value = '${' + var + '}'
399 if isinstance(path, bytes):
400 value = value.encode('ascii')
401 res = res + value
Fred Drakeb4e460a2000-09-28 16:25:20 +0000402 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000403 if isinstance(path, bytes):
404 res = res + b'${' + path
405 else:
406 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000407 index = pathlen - 1
408 else:
409 var = ''
410 index = index + 1
411 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000412 while c and c in varchars:
413 if isinstance(path, bytes):
414 var = var + c.decode('ascii')
415 else:
416 var = var + c
Guido van Rossum15e22e11997-12-05 19:03:01 +0000417 index = index + 1
418 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000419 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000420 value = os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000421 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000422 value = '$' + var
423 if isinstance(path, bytes):
424 value = value.encode('ascii')
425 res = res + value
426 if c:
Thomas Woutersb2137042007-02-01 18:02:27 +0000427 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000428 else:
429 res = res + c
430 index = index + 1
431 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000432
433
Tim Peters54a14a32001-08-30 22:05:26 +0000434# 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 +0000435# Previously, this function also truncated pathnames to 8+3 format,
436# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000437
438def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000439 """Normalize path, eliminating double slashes, etc."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000440 sep = _get_sep(path)
441 path = path.replace(_get_altsep(path), sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000442 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000443 # We need to be careful here. If the prefix is empty, and the path starts
444 # with a backslash, it could either be an absolute path on the current
445 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
446 # is therefore imperative NOT to collapse multiple backslashes blindly in
447 # that case.
448 # The code below preserves multiple backslashes when there is no drive
449 # letter. This means that the invalid filename \\\a\b is preserved
450 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
451 # is any better behaviour for such edge cases.
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000452 if not prefix:
Brett Cannonbdc36272004-07-10 20:42:22 +0000453 # No drive letter - preserve initial backslashes
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000454 while path[:1] == sep:
455 prefix = prefix + sep
Brett Cannonbdc36272004-07-10 20:42:22 +0000456 path = path[1:]
457 else:
458 # We have a drive letter - collapse initial backslashes
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000459 if path.startswith(sep):
460 prefix = prefix + sep
461 path = path.lstrip(sep)
462 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000463 i = 0
464 while i < len(comps):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000465 if comps[i] in ('.', '', b'.', b''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000466 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000467 elif comps[i] == '..':
468 if i > 0 and comps[i-1] != '..':
469 del comps[i-1:i+1]
470 i -= 1
471 elif i == 0 and prefix.endswith("\\"):
472 del comps[i]
473 else:
474 i += 1
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000475 elif comps[i] == b'..':
476 if i > 0 and comps[i-1] != b'..':
477 del comps[i-1:i+1]
478 i -= 1
479 elif i == 0 and prefix.endswith(b"\\"):
480 del comps[i]
481 else:
482 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000483 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000484 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000485 # If the path is now empty, substitute '.'
486 if not prefix and not comps:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000487 comps.append(_get_dot(path))
488 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000489
490
491# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492try:
493 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000494
Thomas Wouters477c8d52006-05-27 19:21:47 +0000495except ImportError: # not running on Windows - mock up something sensible
496 def abspath(path):
497 """Return the absolute version of a path."""
498 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000499 if isinstance(path, bytes):
500 cwd = os.getcwdb()
501 else:
502 cwd = os.getcwd()
503 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504 return normpath(path)
505
506else: # use native Windows method on Windows
507 def abspath(path):
508 """Return the absolute version of a path."""
509
510 if path: # Empty path must return current working directory.
511 try:
512 path = _getfullpathname(path)
513 except WindowsError:
514 pass # Bad path - return unchanged.
515 else:
516 path = os.getcwd()
517 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000518
519# realpath is a no-op on systems without islink support
520realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000521# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000522supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
523 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000524
525def relpath(path, start=curdir):
526 """Return a relative version of a path"""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000527 sep = _get_sep(path)
528
529 if start is curdir:
530 start = _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000531
532 if not path:
533 raise ValueError("no path specified")
534 start_list = abspath(start).split(sep)
535 path_list = abspath(path).split(sep)
536 if start_list[0].lower() != path_list[0].lower():
537 unc_path, rest = splitunc(path)
538 unc_start, rest = splitunc(start)
539 if bool(unc_path) ^ bool(unc_start):
540 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
541 % (path, start))
542 else:
543 raise ValueError("path is on drive %s, start on drive %s"
544 % (path_list[0], start_list[0]))
545 # Work out how much of the filepath is shared by start and path.
546 for i in range(min(len(start_list), len(path_list))):
547 if start_list[i].lower() != path_list[i].lower():
548 break
549 else:
550 i += 1
551
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000552 if isinstance(path, bytes):
553 pardir = b'..'
554 else:
555 pardir = '..'
Guido van Rossumd8faa362007-04-27 19:54:29 +0000556 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000557 if not rel_list:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000558 return _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000559 return join(*rel_list)