blob: 649e424f26443e38632901ae54213d3a0932525b [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
9import stat
Mark Hammond8696ebc2002-10-08 02:44:31 +000010import sys
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000011
Skip Montanaro269b83b2001-02-06 01:07:02 +000012__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
13 "basename","dirname","commonprefix","getsize","getmtime",
Martin v. Löwis96a60e42002-12-31 13:11:54 +000014 "getatime","getctime", "islink","exists","isdir","isfile","ismount",
Mark Hammond8696ebc2002-10-08 02:44:31 +000015 "walk","expanduser","expandvars","normpath","abspath","splitunc",
Skip Montanaro117910d2003-02-14 19:35:31 +000016 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000017 "devnull","realpath","supports_unicode_filenames"]
Guido van Rossum555915a1994-02-24 11:32:59 +000018
Skip Montanaro117910d2003-02-14 19:35:31 +000019# strings representing various path-related bits and pieces
20curdir = '.'
21pardir = '..'
22extsep = '.'
23sep = '\\'
24pathsep = ';'
Skip Montanaro9ddac3e2003-03-28 22:23:24 +000025altsep = '/'
Andrew MacIntyre437966c2003-02-17 09:17:50 +000026defpath = '.;C:\\bin'
Skip Montanaro117910d2003-02-14 19:35:31 +000027if 'ce' in sys.builtin_module_names:
28 defpath = '\\Windows'
29elif 'os2' in sys.builtin_module_names:
Andrew MacIntyre437966c2003-02-17 09:17:50 +000030 # OS/2 w/ VACPP
Skip Montanaro117910d2003-02-14 19:35:31 +000031 altsep = '/'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000032devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000033
Guido van Rossume2ad88c1997-08-12 14:46:58 +000034# Normalize the case of a pathname and map slashes to backslashes.
35# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000036# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000037
Guido van Rossum555915a1994-02-24 11:32:59 +000038def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000039 """Normalize case of pathname.
40
Guido van Rossum534972b1999-02-03 17:20:50 +000041 Makes all characters lowercase and all slashes into backslashes."""
Fred Drakeb4e460a2000-09-28 16:25:20 +000042 return s.replace("/", "\\").lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000043
Guido van Rossum77e1db31997-06-02 23:11:57 +000044
Fred Drakeef0b5dd2000-02-17 17:30:40 +000045# Return whether a path is absolute.
Guido van Rossum555915a1994-02-24 11:32:59 +000046# Trivial in Posix, harder on the Mac or MS-DOS.
47# For DOS it is absolute if it starts with a slash or backslash (current
Guido van Rossum534972b1999-02-03 17:20:50 +000048# volume), or if a pathname after the volume letter and colon / UNC resource
49# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000050
51def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000052 """Test whether a path is absolute"""
53 s = splitdrive(s)[1]
54 return s != '' and s[:1] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +000055
56
Guido van Rossum77e1db31997-06-02 23:11:57 +000057# Join two (or more) paths.
58
Barry Warsaw384d2491997-02-18 21:53:25 +000059def join(a, *p):
Guido van Rossum15e22e11997-12-05 19:03:01 +000060 """Join two or more pathname components, inserting "\\" as needed"""
61 path = a
62 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +000063 b_wins = 0 # set to 1 iff b makes path irrelevant
64 if path == "":
65 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000066
Tim Peters33dc0a12001-07-27 08:09:54 +000067 elif isabs(b):
68 # This probably wipes out path so far. However, it's more
69 # complicated if path begins with a drive letter:
70 # 1. join('c:', '/a') == 'c:/a'
71 # 2. join('c:/', '/a') == 'c:/a'
72 # But
73 # 3. join('c:/a', '/b') == '/b'
74 # 4. join('c:', 'd:/') = 'd:/'
75 # 5. join('c:/', 'd:/') = 'd:/'
76 if path[1:2] != ":" or b[1:2] == ":":
77 # Path doesn't start with a drive letter, or cases 4 and 5.
78 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000079
Tim Peters33dc0a12001-07-27 08:09:54 +000080 # Else path has a drive letter, and b doesn't but is absolute.
81 elif len(path) > 3 or (len(path) == 3 and
82 path[-1] not in "/\\"):
83 # case 3
84 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000085
Tim Peters33dc0a12001-07-27 08:09:54 +000086 if b_wins:
87 path = b
88 else:
89 # Join, and ensure there's a separator.
90 assert len(path) > 0
91 if path[-1] in "/\\":
92 if b and b[0] in "/\\":
93 path += b[1:]
94 else:
95 path += b
96 elif path[-1] == ":":
97 path += b
98 elif b:
99 if b[0] in "/\\":
100 path += b
101 else:
102 path += "\\" + b
Tim Peters6a3e5f12001-11-05 21:25:02 +0000103 else:
104 # path is not empty and does not end with a backslash,
105 # but b is empty; since, e.g., split('a/') produces
106 # ('a', ''), it's best if join() adds a backslash in
107 # this case.
108 path += '\\'
Tim Peters1bdd0f22001-07-19 17:18:18 +0000109
Guido van Rossum15e22e11997-12-05 19:03:01 +0000110 return path
Guido van Rossum555915a1994-02-24 11:32:59 +0000111
112
113# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000114# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000115# It is always true that drivespec + pathspec == p
116def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000117 """Split a pathname into drive and path specifiers. Returns a 2-tuple
118"(drive,path)"; either part may be empty"""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000119 if p[1:2] == ':':
120 return p[0:2], p[2:]
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000121 return '', p
122
123
124# Parse UNC paths
125def splitunc(p):
126 """Split a pathname into UNC mount point and relative path specifiers.
127
128 Return a 2-tuple (unc, rest); either part may be empty.
129 If unc is not empty, it has the form '//host/mount' (or similar
130 using backslashes). unc+rest is always the input path.
131 Paths containing drive letters never have an UNC part.
132 """
133 if p[1:2] == ':':
134 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000135 firstTwo = p[0:2]
136 if firstTwo == '//' or firstTwo == '\\\\':
137 # is a UNC path:
138 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
139 # \\machine\mountpoint\directories...
140 # directory ^^^^^^^^^^^^^^^
141 normp = normcase(p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000142 index = normp.find('\\', 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000143 if index == -1:
144 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
145 return ("", p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000146 index = normp.find('\\', index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000147 if index == -1:
148 index = len(p)
149 return p[:index], p[index:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000150 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000151
152
153# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000154# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000155# join(head, tail) == p holds.
156# The resulting head won't end in '/' unless it is the root.
157
158def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000159 """Split a pathname.
160
161 Return tuple (head, tail) where tail is everything after the final slash.
162 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000163
Guido van Rossum15e22e11997-12-05 19:03:01 +0000164 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000165 # set i to index beyond p's last slash
166 i = len(p)
167 while i and p[i-1] not in '/\\':
168 i = i - 1
169 head, tail = p[:i], p[i:] # now tail has no slashes
170 # remove trailing slashes from head, unless it's all slashes
171 head2 = head
172 while head2 and head2[-1] in '/\\':
173 head2 = head2[:-1]
174 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000175 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000176
177
178# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000179# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000180# pathname component; the root is everything before that.
181# It is always true that root + ext == p.
182
183def splitext(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000184 """Split the extension from a pathname.
185
186 Extension is everything from the last dot to the end.
187 Return (root, ext), either part may be empty."""
Martin v. Löwisde333792002-12-12 20:30:20 +0000188
189 i = p.rfind('.')
190 if i<=max(p.rfind('/'), p.rfind('\\')):
191 return p, ''
192 else:
193 return p[:i], p[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000194
195
196# Return the tail (basename) part of a path.
197
198def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000199 """Returns the final component of a pathname"""
200 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000201
202
203# Return the head (dirname) part of a path.
204
205def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000206 """Returns the directory component of a pathname"""
207 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000208
209
210# Return the longest prefix of all list elements.
211
212def commonprefix(m):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000213 "Given a list of pathnames, returns the longest common leading component"
214 if not m: return ''
Skip Montanaro62358312000-08-22 13:01:53 +0000215 prefix = m[0]
216 for item in m:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000217 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000218 if prefix[:i+1] != item[:i+1]:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000219 prefix = prefix[:i]
220 if i == 0: return ''
221 break
Skip Montanaro62358312000-08-22 13:01:53 +0000222 return prefix
Guido van Rossum555915a1994-02-24 11:32:59 +0000223
224
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000225# Get size, mtime, atime of files.
226
227def getsize(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000228 """Return the size of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000229 return os.stat(filename).st_size
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000230
231def getmtime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000232 """Return the last modification time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000233 return os.stat(filename).st_mtime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000234
235def getatime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000236 """Return the last access time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000237 return os.stat(filename).st_atime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000238
Martin v. Löwis96a60e42002-12-31 13:11:54 +0000239def getctime(filename):
240 """Return the creation time of a file, reported by os.stat()."""
241 return os.stat(filename).st_ctime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000242
Guido van Rossum555915a1994-02-24 11:32:59 +0000243# Is a path a symbolic link?
244# This will always return false on systems where posix.lstat doesn't exist.
245
246def islink(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000247 """Test for symbolic link. On WindowsNT/95 always returns false"""
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000248 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000249
250
251# Does a path exist?
Guido van Rossum555915a1994-02-24 11:32:59 +0000252
253def exists(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000254 """Test whether a path exists"""
255 try:
256 st = os.stat(path)
257 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000258 return False
259 return True
Guido van Rossum555915a1994-02-24 11:32:59 +0000260
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000261lexists = exists
262
Guido van Rossum555915a1994-02-24 11:32:59 +0000263
264# Is a path a dos directory?
265# This follows symbolic links, so both islink() and isdir() can be true
266# for the same path.
267
268def isdir(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000269 """Test whether a path is a directory"""
270 try:
271 st = os.stat(path)
272 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000273 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000274 return stat.S_ISDIR(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000275
276
277# Is a path a regular file?
278# This follows symbolic links, so both islink() and isdir() can be true
279# for the same path.
280
281def isfile(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000282 """Test whether a path is a regular file"""
283 try:
284 st = os.stat(path)
285 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000286 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000287 return stat.S_ISREG(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000288
289
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000290# Is a path a mount point? Either a root (with or without drive letter)
291# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000292
293def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000294 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000295 unc, rest = splitunc(path)
296 if unc:
297 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000298 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000299 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000300
301
302# Directory tree walk.
303# For each directory under top (including top itself, but excluding
304# '.' and '..'), func(arg, dirname, filenames) is called, where
305# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000306# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000307# The func may modify the filenames list, to implement a filter,
308# or to impose a different order of visiting.
309
310def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000311 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000312
Tim Peterscf5e6a42001-10-10 04:16:20 +0000313 For each directory in the directory tree rooted at top (including top
314 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
315 dirname is the name of the directory, and fnames a list of the names of
316 the files and subdirectories in dirname (excluding '.' and '..'). func
317 may modify the fnames list in-place (e.g. via del or slice assignment),
318 and walk will only recurse into the subdirectories whose names remain in
319 fnames; this can be used to implement a filter, or to impose a specific
320 order of visiting. No semantics are defined for, or required of, arg,
321 beyond that arg is always passed to func. It can be used, e.g., to pass
322 a filename pattern, or a mutable object designed to accumulate
323 statistics. Passing None for arg is common."""
324
Guido van Rossum15e22e11997-12-05 19:03:01 +0000325 try:
326 names = os.listdir(top)
327 except os.error:
328 return
329 func(arg, top, names)
330 exceptions = ('.', '..')
331 for name in names:
332 if name not in exceptions:
333 name = join(top, name)
334 if isdir(name):
335 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000336
337
338# Expand paths beginning with '~' or '~user'.
339# '~' means $HOME; '~user' means that user's home directory.
340# If the path doesn't begin with '~', or if the user or $HOME is unknown,
341# the path is returned unchanged (leaving error reporting to whatever
342# function is called with the expanded path as argument).
343# See also module 'glob' for expansion of *, ? and [...] in pathnames.
344# (A function should also be defined to do full *sh-style environment
345# variable expansion.)
346
347def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000348 """Expand ~ and ~user constructs.
349
350 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000351 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000352 return path
353 i, n = 1, len(path)
354 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000355 i = i + 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000356 if i == 1:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000357 if 'HOME' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000358 userhome = os.environ['HOME']
Raymond Hettinger54f02222002-06-01 14:18:47 +0000359 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000360 return path
361 else:
362 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000363 drive = os.environ['HOMEDRIVE']
Guido van Rossum15e22e11997-12-05 19:03:01 +0000364 except KeyError:
365 drive = ''
366 userhome = join(drive, os.environ['HOMEPATH'])
367 else:
368 return path
369 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000370
371
372# Expand paths containing shell variable substitutions.
373# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000374# - no expansion within single quotes
375# - no escape character, except for '$$' which is translated into '$'
376# - ${varname} is accepted.
377# - varnames can be made out of letters, digits and the character '_'
Guido van Rossum555915a1994-02-24 11:32:59 +0000378# XXX With COMMAND.COM you can use any characters in a variable name,
379# XXX except '^|<>='.
380
Tim Peters2344fae2001-01-15 00:50:52 +0000381def expandvars(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000382 """Expand shell variables of form $var and ${var}.
383
384 Unknown variables are left unchanged."""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 if '$' not in path:
386 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000387 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000388 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000389 res = ''
390 index = 0
391 pathlen = len(path)
392 while index < pathlen:
393 c = path[index]
394 if c == '\'': # no expansion within single quotes
395 path = path[index + 1:]
396 pathlen = len(path)
397 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000398 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000399 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000400 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000401 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000402 index = pathlen - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000403 elif c == '$': # variable or '$$'
404 if path[index + 1:index + 2] == '$':
405 res = res + c
406 index = index + 1
407 elif path[index + 1:index + 2] == '{':
408 path = path[index+2:]
409 pathlen = len(path)
410 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000411 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000412 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000413 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000414 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000415 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000416 res = res + path
417 index = pathlen - 1
418 else:
419 var = ''
420 index = index + 1
421 c = path[index:index + 1]
422 while c != '' and c in varchars:
423 var = var + c
424 index = index + 1
425 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000426 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000427 res = res + os.environ[var]
428 if c != '':
429 res = res + c
430 else:
431 res = res + c
432 index = index + 1
433 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000434
435
Tim Peters54a14a32001-08-30 22:05:26 +0000436# 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 +0000437# Previously, this function also truncated pathnames to 8+3 format,
438# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000439
440def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000441 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000442 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000443 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000444 # We need to be careful here. If the prefix is empty, and the path starts
445 # with a backslash, it could either be an absolute path on the current
446 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
447 # is therefore imperative NOT to collapse multiple backslashes blindly in
448 # that case.
449 # The code below preserves multiple backslashes when there is no drive
450 # letter. This means that the invalid filename \\\a\b is preserved
451 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
452 # is any better behaviour for such edge cases.
453 if prefix == '':
454 # No drive letter - preserve initial backslashes
455 while path[:1] == "\\":
456 prefix = prefix + "\\"
457 path = path[1:]
458 else:
459 # We have a drive letter - collapse initial backslashes
460 if path.startswith("\\"):
461 prefix = prefix + "\\"
462 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000463 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000464 i = 0
465 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000466 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000467 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000468 elif comps[i] == '..':
469 if i > 0 and comps[i-1] != '..':
470 del comps[i-1:i+1]
471 i -= 1
472 elif i == 0 and prefix.endswith("\\"):
473 del comps[i]
474 else:
475 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000476 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000477 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000478 # If the path is now empty, substitute '.'
479 if not prefix and not comps:
480 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000481 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000482
483
484# Return an absolute path.
485def abspath(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000486 """Return the absolute version of a path"""
Mark Hammondf717f052002-01-17 00:44:26 +0000487 try:
Mark Hammondef8b6542001-05-13 08:04:26 +0000488 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000489 except ImportError: # Not running on Windows - mock up something sensible.
490 global abspath
491 def _abspath(path):
492 if not isabs(path):
493 path = join(os.getcwd(), path)
494 return normpath(path)
495 abspath = _abspath
496 return _abspath(path)
497
498 if path: # Empty path must return current working directory.
Mark Hammond647d2fe2000-08-14 06:20:32 +0000499 try:
Mark Hammondef8b6542001-05-13 08:04:26 +0000500 path = _getfullpathname(path)
501 except WindowsError:
Fred Drakeda05e972001-05-15 15:23:01 +0000502 pass # Bad path - return unchanged.
Mark Hammond647d2fe2000-08-14 06:20:32 +0000503 else:
504 path = os.getcwd()
Guido van Rossum6dfc7921999-11-30 15:00:00 +0000505 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000506
507# realpath is a no-op on systems without islink support
508realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000509# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000510supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
511 sys.getwindowsversion()[3] >= 2)