blob: 5dd5f1a17768e9ea782300cc43126e637afa9ae7 [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",
Georg Brandlf0de6a12005-08-22 18:02:59 +000014 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
15 "ismount","walk","expanduser","expandvars","normpath","abspath",
16 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
17 "extsep","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 ''
Georg Brandl649f8e72005-08-03 07:30:12 +0000215 s1 = min(m)
216 s2 = max(m)
217 n = min(len(s1), len(s2))
218 for i in xrange(n):
219 if s1[i] != s2[i]:
220 return s1[:i]
221 return s1[:n]
Guido van Rossum555915a1994-02-24 11:32:59 +0000222
223
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000224# Get size, mtime, atime of files.
225
226def getsize(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000227 """Return the size of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000228 return os.stat(filename).st_size
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000229
230def getmtime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000231 """Return the last modification time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000232 return os.stat(filename).st_mtime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000233
234def getatime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000235 """Return the last access time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000236 return os.stat(filename).st_atime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000237
Martin v. Löwis96a60e42002-12-31 13:11:54 +0000238def getctime(filename):
239 """Return the creation time of a file, reported by os.stat()."""
240 return os.stat(filename).st_ctime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +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):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000246 """Test for symbolic link. On WindowsNT/95 always returns false"""
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000247 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000248
249
250# Does a path exist?
Guido van Rossum555915a1994-02-24 11:32:59 +0000251
252def exists(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000253 """Test whether a path exists"""
254 try:
255 st = os.stat(path)
256 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000257 return False
258 return True
Guido van Rossum555915a1994-02-24 11:32:59 +0000259
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000260lexists = exists
261
Guido van Rossum555915a1994-02-24 11:32:59 +0000262
263# Is a path a dos directory?
264# This follows symbolic links, so both islink() and isdir() can be true
265# for the same path.
266
267def isdir(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000268 """Test whether a path is a directory"""
269 try:
270 st = os.stat(path)
271 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000272 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000273 return stat.S_ISDIR(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000274
275
276# Is a path a regular file?
277# This follows symbolic links, so both islink() and isdir() can be true
278# for the same path.
279
280def isfile(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000281 """Test whether a path is a regular file"""
282 try:
283 st = os.stat(path)
284 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000285 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000286 return stat.S_ISREG(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000287
288
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000289# Is a path a mount point? Either a root (with or without drive letter)
290# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000291
292def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000293 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000294 unc, rest = splitunc(path)
295 if unc:
296 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000297 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000298 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000299
300
301# Directory tree walk.
302# For each directory under top (including top itself, but excluding
303# '.' and '..'), func(arg, dirname, filenames) is called, where
304# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000305# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000306# The func may modify the filenames list, to implement a filter,
307# or to impose a different order of visiting.
308
309def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000310 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000311
Tim Peterscf5e6a42001-10-10 04:16:20 +0000312 For each directory in the directory tree rooted at top (including top
313 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
314 dirname is the name of the directory, and fnames a list of the names of
315 the files and subdirectories in dirname (excluding '.' and '..'). func
316 may modify the fnames list in-place (e.g. via del or slice assignment),
317 and walk will only recurse into the subdirectories whose names remain in
318 fnames; this can be used to implement a filter, or to impose a specific
319 order of visiting. No semantics are defined for, or required of, arg,
320 beyond that arg is always passed to func. It can be used, e.g., to pass
321 a filename pattern, or a mutable object designed to accumulate
322 statistics. Passing None for arg is common."""
323
Guido van Rossum15e22e11997-12-05 19:03:01 +0000324 try:
325 names = os.listdir(top)
326 except os.error:
327 return
328 func(arg, top, names)
329 exceptions = ('.', '..')
330 for name in names:
331 if name not in exceptions:
332 name = join(top, name)
333 if isdir(name):
334 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000335
336
337# Expand paths beginning with '~' or '~user'.
338# '~' means $HOME; '~user' means that user's home directory.
339# If the path doesn't begin with '~', or if the user or $HOME is unknown,
340# the path is returned unchanged (leaving error reporting to whatever
341# function is called with the expanded path as argument).
342# See also module 'glob' for expansion of *, ? and [...] in pathnames.
343# (A function should also be defined to do full *sh-style environment
344# variable expansion.)
345
346def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000347 """Expand ~ and ~user constructs.
348
349 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000350 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000351 return path
352 i, n = 1, len(path)
353 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000354 i = i + 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000355 if i == 1:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000356 if 'HOME' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000357 userhome = os.environ['HOME']
Raymond Hettinger54f02222002-06-01 14:18:47 +0000358 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000359 return path
360 else:
361 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000362 drive = os.environ['HOMEDRIVE']
Guido van Rossum15e22e11997-12-05 19:03:01 +0000363 except KeyError:
364 drive = ''
365 userhome = join(drive, os.environ['HOMEPATH'])
366 else:
367 return path
368 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000369
370
371# Expand paths containing shell variable substitutions.
372# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000373# - no expansion within single quotes
374# - no escape character, except for '$$' which is translated into '$'
375# - ${varname} is accepted.
376# - varnames can be made out of letters, digits and the character '_'
Guido van Rossum555915a1994-02-24 11:32:59 +0000377# XXX With COMMAND.COM you can use any characters in a variable name,
378# XXX except '^|<>='.
379
Tim Peters2344fae2001-01-15 00:50:52 +0000380def expandvars(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000381 """Expand shell variables of form $var and ${var}.
382
383 Unknown variables are left unchanged."""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000384 if '$' not in path:
385 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000386 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000387 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 res = ''
389 index = 0
390 pathlen = len(path)
391 while index < pathlen:
392 c = path[index]
393 if c == '\'': # no expansion within single quotes
394 path = path[index + 1:]
395 pathlen = len(path)
396 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000397 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000398 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000399 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000400 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000401 index = pathlen - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000402 elif c == '$': # variable or '$$'
403 if path[index + 1:index + 2] == '$':
404 res = res + c
405 index = index + 1
406 elif path[index + 1:index + 2] == '{':
407 path = path[index+2:]
408 pathlen = len(path)
409 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000410 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000411 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000412 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000413 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000414 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000415 res = res + path
416 index = pathlen - 1
417 else:
418 var = ''
419 index = index + 1
420 c = path[index:index + 1]
421 while c != '' and c in varchars:
422 var = var + c
423 index = index + 1
424 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000425 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000426 res = res + os.environ[var]
427 if c != '':
428 res = res + c
429 else:
430 res = res + c
431 index = index + 1
432 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000433
434
Tim Peters54a14a32001-08-30 22:05:26 +0000435# 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 +0000436# Previously, this function also truncated pathnames to 8+3 format,
437# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000438
439def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000440 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000441 path = path.replace("/", "\\")
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.
452 if prefix == '':
453 # No drive letter - preserve initial backslashes
454 while path[:1] == "\\":
455 prefix = prefix + "\\"
456 path = path[1:]
457 else:
458 # We have a drive letter - collapse initial backslashes
459 if path.startswith("\\"):
460 prefix = prefix + "\\"
461 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000462 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000463 i = 0
464 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000465 if comps[i] in ('.', ''):
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
Guido van Rossum15e22e11997-12-05 19:03:01 +0000475 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000476 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000477 # If the path is now empty, substitute '.'
478 if not prefix and not comps:
479 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000480 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000481
482
483# Return an absolute path.
484def abspath(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000485 """Return the absolute version of a path"""
Mark Hammondf717f052002-01-17 00:44:26 +0000486 try:
Mark Hammondef8b6542001-05-13 08:04:26 +0000487 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000488 except ImportError: # Not running on Windows - mock up something sensible.
489 global abspath
490 def _abspath(path):
491 if not isabs(path):
492 path = join(os.getcwd(), path)
493 return normpath(path)
494 abspath = _abspath
495 return _abspath(path)
496
497 if path: # Empty path must return current working directory.
Mark Hammond647d2fe2000-08-14 06:20:32 +0000498 try:
Mark Hammondef8b6542001-05-13 08:04:26 +0000499 path = _getfullpathname(path)
500 except WindowsError:
Fred Drakeda05e972001-05-15 15:23:01 +0000501 pass # Bad path - return unchanged.
Mark Hammond647d2fe2000-08-14 06:20:32 +0000502 else:
503 path = os.getcwd()
Guido van Rossum6dfc7921999-11-30 15:00:00 +0000504 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000505
506# realpath is a no-op on systems without islink support
507realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000508# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000509supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
510 sys.getwindowsversion()[3] >= 2)