blob: 2fd26b1f3d502e92694225a98838fc4a6b7371e1 [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
Mark Hammond5a607a32009-05-06 08:04:54 +000037def _get_empty(path):
38 if isinstance(path, bytes):
39 return b''
40 else:
41 return ''
42
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000043def _get_sep(path):
44 if isinstance(path, bytes):
45 return b'\\'
46 else:
47 return '\\'
48
49def _get_altsep(path):
50 if isinstance(path, bytes):
51 return b'/'
52 else:
53 return '/'
54
55def _get_bothseps(path):
56 if isinstance(path, bytes):
57 return b'\\/'
58 else:
59 return '\\/'
60
61def _get_dot(path):
62 if isinstance(path, bytes):
63 return b'.'
64 else:
65 return '.'
66
67def _get_colon(path):
68 if isinstance(path, bytes):
69 return b':'
70 else:
71 return ':'
72
Guido van Rossume2ad88c1997-08-12 14:46:58 +000073# Normalize the case of a pathname and map slashes to backslashes.
74# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000075# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000076
Guido van Rossum555915a1994-02-24 11:32:59 +000077def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000078 """Normalize case of pathname.
79
Guido van Rossum534972b1999-02-03 17:20:50 +000080 Makes all characters lowercase and all slashes into backslashes."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000081 return s.replace(_get_altsep(s), _get_sep(s)).lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000082
Guido van Rossum77e1db31997-06-02 23:11:57 +000083
Fred Drakeef0b5dd2000-02-17 17:30:40 +000084# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000085# Trivial in Posix, harder on Windows.
86# For Windows it is absolute if it starts with a slash or backslash (current
87# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000088# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000089
90def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000091 """Test whether a path is absolute"""
92 s = splitdrive(s)[1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000093 return len(s) > 0 and s[:1] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000094
95
Guido van Rossum77e1db31997-06-02 23:11:57 +000096# Join two (or more) paths.
97
Barry Warsaw384d2491997-02-18 21:53:25 +000098def join(a, *p):
Guido van Rossum04110fb2007-08-24 16:32:05 +000099 """Join two or more pathname components, inserting "\\" as needed.
100 If any component is an absolute path, all previous path components
101 will be discarded."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000102 sep = _get_sep(a)
103 seps = _get_bothseps(a)
104 colon = _get_colon(a)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000105 path = a
106 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +0000107 b_wins = 0 # set to 1 iff b makes path irrelevant
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000108 if not path:
Tim Peters33dc0a12001-07-27 08:09:54 +0000109 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +0000110
Tim Peters33dc0a12001-07-27 08:09:54 +0000111 elif isabs(b):
112 # This probably wipes out path so far. However, it's more
Mark Hammond5a607a32009-05-06 08:04:54 +0000113 # complicated if path begins with a drive letter. You get a+b
114 # (minus redundant slashes) in these four cases:
Tim Peters33dc0a12001-07-27 08:09:54 +0000115 # 1. join('c:', '/a') == 'c:/a'
Mark Hammond5a607a32009-05-06 08:04:54 +0000116 # 2. join('//computer/share', '/a') == '//computer/share/a'
117 # 3. join('c:/', '/a') == 'c:/a'
118 # 4. join('//computer/share/', '/a') == '//computer/share/a'
119 # But b wins in all of these cases:
120 # 5. join('c:/a', '/b') == '/b'
121 # 6. join('//computer/share/a', '/b') == '/b'
122 # 7. join('c:', 'd:/') == 'd:/'
123 # 8. join('c:', '//computer/share/') == '//computer/share/'
124 # 9. join('//computer/share', 'd:/') == 'd:/'
125 # 10. join('//computer/share', '//computer/share/') == '//computer/share/'
126 # 11. join('c:/', 'd:/') == 'd:/'
127 # 12. join('c:/', '//computer/share/') == '//computer/share/'
128 # 13. join('//computer/share/', 'd:/') == 'd:/'
129 # 14. join('//computer/share/', '//computer/share/') == '//computer/share/'
130 b_prefix, b_rest = splitdrive(b)
Tim Peters1bdd0f22001-07-19 17:18:18 +0000131
Mark Hammond5a607a32009-05-06 08:04:54 +0000132 # if b has a prefix, it always wins.
133 if b_prefix:
Tim Peters33dc0a12001-07-27 08:09:54 +0000134 b_wins = 1
Mark Hammond5a607a32009-05-06 08:04:54 +0000135 else:
136 # b doesn't have a prefix.
137 # but isabs(b) returned true.
138 # and therefore b_rest[0] must be a slash.
139 # (but let's check that.)
140 assert(b_rest and b_rest[0] in seps)
141
142 # so, b still wins if path has a rest that's more than a sep.
143 # you get a+b if path_rest is empty or only has a sep.
144 # (see cases 1-4 for times when b loses.)
145 path_rest = splitdrive(path)[1]
146 b_wins = path_rest and path_rest not in seps
Tim Peters1bdd0f22001-07-19 17:18:18 +0000147
Tim Peters33dc0a12001-07-27 08:09:54 +0000148 if b_wins:
149 path = b
150 else:
151 # Join, and ensure there's a separator.
152 assert len(path) > 0
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000153 if path[-1:] in seps:
154 if b and b[:1] in seps:
Tim Peters33dc0a12001-07-27 08:09:54 +0000155 path += b[1:]
156 else:
157 path += b
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000158 elif path[-1:] == colon:
Tim Peters33dc0a12001-07-27 08:09:54 +0000159 path += b
160 elif b:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000161 if b[:1] in seps:
Tim Peters33dc0a12001-07-27 08:09:54 +0000162 path += b
163 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000164 path += sep + b
Tim Peters6a3e5f12001-11-05 21:25:02 +0000165 else:
166 # path is not empty and does not end with a backslash,
167 # but b is empty; since, e.g., split('a/') produces
168 # ('a', ''), it's best if join() adds a backslash in
169 # this case.
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000170 path += sep
Tim Peters1bdd0f22001-07-19 17:18:18 +0000171
Guido van Rossum15e22e11997-12-05 19:03:01 +0000172 return path
Guido van Rossum555915a1994-02-24 11:32:59 +0000173
174
175# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000176# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000177# It is always true that drivespec + pathspec == p
178def splitdrive(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000179 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
180 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
181
182 If you assign
183 result = splitdrive(p)
184 It is always true that:
185 result[0] + result[1] == p
186
187 If the path contained a drive letter, drive_or_unc will contain everything
188 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
189
190 If the path contained a UNC path, the drive_or_unc will contain the host name
191 and share up to but not including the fourth directory separator character.
192 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
193
194 Paths cannot contain both a drive letter and a UNC path.
195
196 """
197 empty = _get_empty(p)
198 if len(p) > 1:
199 sep = _get_sep(p)
200 normp = normcase(p)
201 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
202 # is a UNC path:
203 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
204 # \\machine\mountpoint\directory\etc\...
205 # directory ^^^^^^^^^^^^^^^
206 index = normp.find(sep, 2)
207 if index == -1:
208 return empty, p
209 index2 = normp.find(sep, index + 1)
210 # a UNC path can't have two slashes in a row
211 # (after the initial two)
212 if index2 == index + 1:
213 return empty, p
214 if index2 == -1:
215 index2 = len(p)
216 return p[:index2], p[index2:]
217 if normp[1:2] == _get_colon(p):
218 return p[:2], p[2:]
219 return empty, p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000220
221
222# Parse UNC paths
223def splitunc(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000224 """Deprecated since Python 3.1. Please use splitdrive() instead;
225 it now handles UNC paths.
226
227 Split a pathname into UNC mount point and relative path specifiers.
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000228
229 Return a 2-tuple (unc, rest); either part may be empty.
230 If unc is not empty, it has the form '//host/mount' (or similar
231 using backslashes). unc+rest is always the input path.
232 Paths containing drive letters never have an UNC part.
233 """
Mark Hammond5a607a32009-05-06 08:04:54 +0000234 import warnings
235 warnings.warn("ntpath.splitunc is deprecated, use ntpath.splitdrive instead",
236 PendingDeprecationWarning)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000237 sep = _get_sep(p)
238 if not p[1:2]:
239 return p[:0], p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000240 firstTwo = p[0:2]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000241 if normcase(firstTwo) == sep + sep:
Guido van Rossum534972b1999-02-03 17:20:50 +0000242 # is a UNC path:
243 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
244 # \\machine\mountpoint\directories...
245 # directory ^^^^^^^^^^^^^^^
246 normp = normcase(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000247 index = normp.find(sep, 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000248 if index == -1:
249 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000250 return (p[:0], p)
251 index = normp.find(sep, index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000252 if index == -1:
253 index = len(p)
254 return p[:index], p[index:]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000255 return p[:0], p
Guido van Rossum555915a1994-02-24 11:32:59 +0000256
257
258# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000259# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000260# join(head, tail) == p holds.
261# The resulting head won't end in '/' unless it is the root.
262
263def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000264 """Split a pathname.
265
266 Return tuple (head, tail) where tail is everything after the final slash.
267 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000268
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000269 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000270 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000271 # set i to index beyond p's last slash
272 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000273 while i and p[i-1] not in seps:
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000274 i = i - 1
275 head, tail = p[:i], p[i:] # now tail has no slashes
276 # remove trailing slashes from head, unless it's all slashes
277 head2 = head
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000278 while head2 and head2[-1:] in seps:
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000279 head2 = head2[:-1]
280 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000281 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000282
283
284# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000285# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000286# pathname component; the root is everything before that.
287# It is always true that root + ext == p.
288
289def splitext(p):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000290 return genericpath._splitext(p, _get_sep(p), _get_altsep(p),
291 _get_dot(p))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000292splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000293
294
295# Return the tail (basename) part of a path.
296
297def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000298 """Returns the final component of a pathname"""
299 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000300
301
302# Return the head (dirname) part of a path.
303
304def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000305 """Returns the directory component of a pathname"""
306 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000307
Guido van Rossum555915a1994-02-24 11:32:59 +0000308# Is a path a symbolic link?
309# This will always return false on systems where posix.lstat doesn't exist.
310
311def islink(path):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000312 """Test for symbolic link.
313 On WindowsNT/95 and OS/2 always returns false
314 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000315 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000316
Thomas Wouters89f507f2006-12-13 04:49:30 +0000317# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000318lexists = exists
319
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000320# Is a path a mount point? Either a root (with or without drive letter)
321# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000322
323def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000324 """Test whether a path is a mount point (defined as root of drive)"""
Benjamin Peterson48e24782009-03-29 13:02:52 +0000325 seps = _get_bothseps(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000326 root, rest = splitdrive(path)
327 if root and root[0] in seps:
328 return (not rest) or (rest in seps)
329 return rest in seps
Guido van Rossum555915a1994-02-24 11:32:59 +0000330
331
Guido van Rossum555915a1994-02-24 11:32:59 +0000332# Expand paths beginning with '~' or '~user'.
333# '~' means $HOME; '~user' means that user's home directory.
334# If the path doesn't begin with '~', or if the user or $HOME is unknown,
335# the path is returned unchanged (leaving error reporting to whatever
336# function is called with the expanded path as argument).
337# See also module 'glob' for expansion of *, ? and [...] in pathnames.
338# (A function should also be defined to do full *sh-style environment
339# variable expansion.)
340
341def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000342 """Expand ~ and ~user constructs.
343
344 If user or $HOME is unknown, do nothing."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000345 if isinstance(path, bytes):
346 tilde = b'~'
347 else:
348 tilde = '~'
349 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000350 return path
351 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000352 while i < n and path[i] not in _get_bothseps(path):
Fred Drakeb4e460a2000-09-28 16:25:20 +0000353 i = i + 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000354
355 if 'HOME' in os.environ:
356 userhome = os.environ['HOME']
357 elif 'USERPROFILE' in os.environ:
358 userhome = os.environ['USERPROFILE']
359 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000360 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000361 else:
362 try:
363 drive = os.environ['HOMEDRIVE']
364 except KeyError:
365 drive = ''
366 userhome = join(drive, os.environ['HOMEPATH'])
367
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000368 if isinstance(path, bytes):
369 userhome = userhome.encode(sys.getfilesystemencoding())
370
Guido van Rossumd8faa362007-04-27 19:54:29 +0000371 if i != 1: #~user
372 userhome = join(dirname(userhome), path[1:i])
373
Guido van Rossum15e22e11997-12-05 19:03:01 +0000374 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000375
376
377# Expand paths containing shell variable substitutions.
378# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000379# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000380# - '$$' is translated into '$'
381# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000382# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000383# - $varname is accepted.
384# - %varname% is accepted.
385# - varnames can be made out of letters, digits and the characters '_-'
386# (though is not verifed in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000387# XXX With COMMAND.COM you can use any characters in a variable name,
388# XXX except '^|<>='.
389
Tim Peters2344fae2001-01-15 00:50:52 +0000390def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000391 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000392
393 Unknown variables are left unchanged."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000394 if isinstance(path, bytes):
395 if ord('$') not in path and ord('%') not in path:
396 return path
397 import string
398 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000399 quote = b'\''
400 percent = b'%'
401 brace = b'{'
402 dollar = b'$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000403 else:
404 if '$' not in path and '%' not in path:
405 return path
406 import string
407 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000408 quote = '\''
409 percent = '%'
410 brace = '{'
411 dollar = '$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000412 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000413 index = 0
414 pathlen = len(path)
415 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000416 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000417 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000418 path = path[index + 1:]
419 pathlen = len(path)
420 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000421 index = path.index(c)
422 res = res + c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000423 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000424 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000425 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000426 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000427 if path[index + 1:index + 2] == percent:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000428 res = res + c
429 index = index + 1
430 else:
431 path = path[index+1:]
432 pathlen = len(path)
433 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000434 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000435 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000436 res = res + percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000437 index = pathlen - 1
438 else:
439 var = path[:index]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000440 if isinstance(path, bytes):
441 var = var.decode('ascii')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000442 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000443 value = os.environ[var]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000444 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000445 value = '%' + var + '%'
446 if isinstance(path, bytes):
447 value = value.encode('ascii')
448 res = res + value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000449 elif c == dollar: # variable or '$$'
450 if path[index + 1:index + 2] == dollar:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000451 res = res + c
452 index = index + 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000453 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000454 path = path[index+2:]
455 pathlen = len(path)
456 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000457 if isinstance(path, bytes):
458 index = path.index(b'}')
Thomas Woutersb2137042007-02-01 18:02:27 +0000459 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000460 index = path.index('}')
461 var = path[:index]
462 if isinstance(path, bytes):
463 var = var.decode('ascii')
464 if var in os.environ:
465 value = os.environ[var]
466 else:
467 value = '${' + var + '}'
468 if isinstance(path, bytes):
469 value = value.encode('ascii')
470 res = res + value
Fred Drakeb4e460a2000-09-28 16:25:20 +0000471 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000472 if isinstance(path, bytes):
473 res = res + b'${' + path
474 else:
475 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000476 index = pathlen - 1
477 else:
478 var = ''
479 index = index + 1
480 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000481 while c and c in varchars:
482 if isinstance(path, bytes):
483 var = var + c.decode('ascii')
484 else:
485 var = var + c
Guido van Rossum15e22e11997-12-05 19:03:01 +0000486 index = index + 1
487 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000488 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000489 value = os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000490 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000491 value = '$' + var
492 if isinstance(path, bytes):
493 value = value.encode('ascii')
494 res = res + value
495 if c:
Thomas Woutersb2137042007-02-01 18:02:27 +0000496 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000497 else:
498 res = res + c
499 index = index + 1
500 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000501
502
Tim Peters54a14a32001-08-30 22:05:26 +0000503# 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 +0000504# Previously, this function also truncated pathnames to 8+3 format,
505# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000506
507def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000508 """Normalize path, eliminating double slashes, etc."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000509 sep = _get_sep(path)
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000510 dotdot = _get_dot(path) * 2
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000511 path = path.replace(_get_altsep(path), sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000512 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000513
514 # collapse initial backslashes
515 if path.startswith(sep):
516 prefix = prefix + sep
517 path = path.lstrip(sep)
518
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000519 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000520 i = 0
521 while i < len(comps):
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000522 if not comps[i] or comps[i] == _get_dot(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000523 del comps[i]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000524 elif comps[i] == dotdot:
525 if i > 0 and comps[i-1] != dotdot:
Tim Peters54a14a32001-08-30 22:05:26 +0000526 del comps[i-1:i+1]
527 i -= 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000528 elif i == 0 and prefix.endswith(_get_sep(path)):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000529 del comps[i]
530 else:
531 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000532 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000533 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000534 # If the path is now empty, substitute '.'
535 if not prefix and not comps:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000536 comps.append(_get_dot(path))
537 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000538
539
540# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000541try:
542 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000543
Thomas Wouters477c8d52006-05-27 19:21:47 +0000544except ImportError: # not running on Windows - mock up something sensible
545 def abspath(path):
546 """Return the absolute version of a path."""
547 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000548 if isinstance(path, bytes):
549 cwd = os.getcwdb()
550 else:
551 cwd = os.getcwd()
552 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000553 return normpath(path)
554
555else: # use native Windows method on Windows
556 def abspath(path):
557 """Return the absolute version of a path."""
558
559 if path: # Empty path must return current working directory.
560 try:
561 path = _getfullpathname(path)
562 except WindowsError:
563 pass # Bad path - return unchanged.
564 else:
565 path = os.getcwd()
566 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000567
568# realpath is a no-op on systems without islink support
569realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000570# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000571supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
572 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000573
574def relpath(path, start=curdir):
575 """Return a relative version of a path"""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000576 sep = _get_sep(path)
577
578 if start is curdir:
579 start = _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000580
581 if not path:
582 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000583
584 start_abs = abspath(normpath(start))
585 path_abs = abspath(normpath(path))
586 start_drive, start_rest = splitdrive(start_abs)
587 path_drive, path_rest = splitdrive(path_abs)
588 if start_drive != path_drive:
589 error = "path is on mount '{0}', start on mount '{1}'".format(
590 path_drive, start_drive)
591 raise ValueError(error)
592
593 start_list = [x for x in start_rest.split(sep) if x]
594 path_list = [x for x in path_rest.split(sep) if x]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595 # Work out how much of the filepath is shared by start and path.
Mark Hammond5a607a32009-05-06 08:04:54 +0000596 i = 0
597 for e1, e2 in zip(start_list, path_list):
598 if e1 != e2:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000599 break
Guido van Rossumd8faa362007-04-27 19:54:29 +0000600 i += 1
601
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000602 if isinstance(path, bytes):
603 pardir = b'..'
604 else:
605 pardir = '..'
Guido van Rossumd8faa362007-04-27 19:54:29 +0000606 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000607 if not rel_list:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000608 return _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000609 return join(*rel_list)