blob: 345b940e4357c5eb466114225e9a500f99aac45f [file] [log] [blame]
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +00001"""Common operations on DOS pathnames."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +00002
3import os
4import stat
Guido van Rossum3ed23cc1994-02-15 15:57:15 +00005
Skip Montanaroeccd02a2001-01-20 23:34:12 +00006__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
7 "basename","dirname","commonprefix","getsize","getmtime",
8 "getatime","islink","exists","isdir","isfile","ismount",
Mark Hammond8696ebc2002-10-08 02:44:31 +00009 "walk","expanduser","expandvars","normpath","abspath",
10 "supports_unicode_filenames"]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000011
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000012def normcase(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000013 """Normalize the case of a pathname.
14 On MS-DOS it maps the pathname to lowercase, turns slashes into
15 backslashes.
16 Other normalizations (such as optimizing '../' away) are not allowed
17 (this is done by normpath).
Tim Peters88869f92001-01-14 23:36:06 +000018 Previously, this version mapped invalid consecutive characters to a
19 single '_', but this has been removed. This functionality should
Guido van Rossum54f22ed2000-02-04 15:10:34 +000020 possibly be added as a new function."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000021
Fred Drakeb4e460a2000-09-28 16:25:20 +000022 return s.replace("/", "\\").lower()
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000023
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000024
25def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000026 """Return whether a path is absolute.
27 Trivial in Posix, harder on the Mac or MS-DOS.
28 For DOS it is absolute if it starts with a slash or backslash (current
29 volume), or if a pathname after the volume letter and colon starts with
30 a slash or backslash."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000031
Guido van Rossum54f22ed2000-02-04 15:10:34 +000032 s = splitdrive(s)[1]
33 return s != '' and s[:1] in '/\\'
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000034
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000035
Guido van Rossumae590db1997-10-07 14:48:23 +000036def join(a, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000037 """Join two (or more) paths."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000038
Guido van Rossum54f22ed2000-02-04 15:10:34 +000039 path = a
40 for b in p:
41 if isabs(b):
42 path = b
Tim Petersceeda0e2000-09-19 23:46:56 +000043 elif path == '' or path[-1:] in '/\\:':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000044 path = path + b
45 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +000046 path = path + "\\" + b
Guido van Rossum54f22ed2000-02-04 15:10:34 +000047 return path
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000048
Guido van Rossumfda5c1a1995-08-10 19:27:42 +000049
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000050def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000051 """Split a path into a drive specification (a drive letter followed
52 by a colon) and path specification.
53 It is always true that drivespec + pathspec == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000054
Guido van Rossum54f22ed2000-02-04 15:10:34 +000055 if p[1:2] == ':':
56 return p[0:2], p[2:]
57 return '', p
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000058
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000059
60def split(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000061 """Split a path into head (everything up to the last '/') and tail
62 (the rest). After the trailing '/' is stripped, the invariant
63 join(head, tail) == p holds.
64 The resulting head won't end in '/' unless it is the root."""
65
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +000066 d, p = splitdrive(p)
67 # set i to index beyond p's last slash
68 i = len(p)
69 while i and p[i-1] not in '/\\':
70 i = i - 1
71 head, tail = p[:i], p[i:] # now tail has no slashes
72 # remove trailing slashes from head, unless it's all slashes
73 head2 = head
74 while head2 and head2[-1] in '/\\':
75 head2 = head2[:-1]
76 head = head2 or head
77 return d + head, tail
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000078
79
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000080def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000081 """Split a path into root and extension.
82 The extension is everything starting at the first dot in the last
83 pathname component; the root is everything before that.
84 It is always true that root + ext == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000085
Guido van Rossum54f22ed2000-02-04 15:10:34 +000086 root, ext = '', ''
87 for c in p:
88 if c in '/\\':
89 root, ext = root + ext + c, ''
90 elif c == '.' or ext:
91 ext = ext + c
92 else:
93 root = root + c
94 return root, ext
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000095
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000096
97def basename(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000098 """Return the tail (basename) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000099
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000100 return split(p)[1]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000101
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000102
103def dirname(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000104 """Return the head (dirname) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000105
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000106 return split(p)[0]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000107
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000108
Skip Montanaro97bc98a2000-07-12 16:55:57 +0000109def commonprefix(m):
Skip Montanaro62358312000-08-22 13:01:53 +0000110 """Return the longest prefix of all list elements."""
111
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000112 if not m: return ''
Skip Montanaro62358312000-08-22 13:01:53 +0000113 prefix = m[0]
114 for item in m:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000115 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000116 if prefix[:i+1] != item[:i+1]:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000117 prefix = prefix[:i]
118 if i == 0: return ''
119 break
Skip Montanaro62358312000-08-22 13:01:53 +0000120 return prefix
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000121
122
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000123# Get size, mtime, atime of files.
124
125def getsize(filename):
126 """Return the size of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000127 return os.stat(filename).st_size
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000128
129def getmtime(filename):
130 """Return the last modification time of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000131 return os.stat(filename).st_mtime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000132
133def getatime(filename):
134 """Return the last access time of a file, reported by os.stat()."""
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000135
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000136 return os.stat(filename).st_atime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000137
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000138def islink(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000139 """Is a path a symbolic link?
140 This will always return false on systems where posix.lstat doesn't exist."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000141
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000142 return False
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000143
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000144
145def exists(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000146 """Does a path exist?
147 This is false for dangling symbolic links."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000148
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000149 try:
150 st = os.stat(path)
151 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000152 return False
153 return True
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000154
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000155
156def isdir(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000157 """Is a path a dos directory?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000158
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000159 try:
160 st = os.stat(path)
161 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000162 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000163 return stat.S_ISDIR(st.st_mode)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000164
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000165
166def isfile(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000167 """Is a path a regular file?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000168
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000169 try:
170 st = os.stat(path)
171 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000172 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000173 return stat.S_ISREG(st.st_mode)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000174
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000175
176def ismount(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000177 """Is a path a mount point?"""
178 # XXX This degenerates in: 'is this the root?' on DOS
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000179
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000180 return isabs(splitdrive(path)[1])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000181
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000182
183def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000184 """Directory tree walk with callback function.
185
186 For each directory in the directory tree rooted at top (including top
187 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
188 dirname is the name of the directory, and fnames a list of the names of
189 the files and subdirectories in dirname (excluding '.' and '..'). func
190 may modify the fnames list in-place (e.g. via del or slice assignment),
191 and walk will only recurse into the subdirectories whose names remain in
192 fnames; this can be used to implement a filter, or to impose a specific
193 order of visiting. No semantics are defined for, or required of, arg,
194 beyond that arg is always passed to func. It can be used, e.g., to pass
195 a filename pattern, or a mutable object designed to accumulate
196 statistics. Passing None for arg is common."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000197
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000198 try:
199 names = os.listdir(top)
200 except os.error:
201 return
202 func(arg, top, names)
203 exceptions = ('.', '..')
204 for name in names:
205 if name not in exceptions:
206 name = join(top, name)
207 if isdir(name):
208 walk(name, func, arg)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000209
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000210
211def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000212 """Expand paths beginning with '~' or '~user'.
213 '~' means $HOME; '~user' means that user's home directory.
214 If the path doesn't begin with '~', or if the user or $HOME is unknown,
215 the path is returned unchanged (leaving error reporting to whatever
216 function is called with the expanded path as argument).
217 See also module 'glob' for expansion of *, ? and [...] in pathnames.
218 (A function should also be defined to do full *sh-style environment
219 variable expansion.)"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000220
Fred Drake8152d322000-12-12 23:20:45 +0000221 if path[:1] != '~':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000222 return path
223 i, n = 1, len(path)
224 while i < n and path[i] not in '/\\':
225 i = i+1
226 if i == 1:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000227 if not 'HOME' in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000228 return path
229 userhome = os.environ['HOME']
230 else:
231 return path
232 return userhome + path[i:]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000233
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000234
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000235def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000236 """Expand paths containing shell variable substitutions.
237 The following rules apply:
238 - no expansion within single quotes
239 - no escape character, except for '$$' which is translated into '$'
240 - ${varname} is accepted.
241 - varnames can be made out of letters, digits and the character '_'"""
242 # XXX With COMMAND.COM you can use any characters in a variable name,
243 # XXX except '^|<>='.
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000244
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000245 if '$' not in path:
246 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000247 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000248 varchars = string.ascii_letters + string.digits + "_-"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000249 res = ''
250 index = 0
251 pathlen = len(path)
252 while index < pathlen:
253 c = path[index]
254 if c == '\'': # no expansion within single quotes
255 path = path[index + 1:]
256 pathlen = len(path)
257 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000258 index = path.index('\'')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000259 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000260 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000261 res = res + path
262 index = pathlen -1
263 elif c == '$': # variable or '$$'
264 if path[index + 1:index + 2] == '$':
265 res = res + c
266 index = index + 1
267 elif path[index + 1:index + 2] == '{':
268 path = path[index+2:]
269 pathlen = len(path)
270 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000271 index = path.index('}')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000272 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000273 if var in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000274 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000275 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000276 res = res + path
277 index = pathlen - 1
278 else:
279 var = ''
280 index = index + 1
281 c = path[index:index + 1]
282 while c != '' and c in varchars:
283 var = var + c
284 index = index + 1
285 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000286 if var in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000287 res = res + os.environ[var]
288 if c != '':
289 res = res + c
290 else:
291 res = res + c
292 index = index + 1
293 return res
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000294
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000295
296def normpath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000297 """Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
298 Also, components of the path are silently truncated to 8+3 notation."""
299
Fred Drakeb4e460a2000-09-28 16:25:20 +0000300 path = path.replace("/", "\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000301 prefix, path = splitdrive(path)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000302 while path[:1] == "\\":
303 prefix = prefix + "\\"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000304 path = path[1:]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000305 comps = path.split("\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000306 i = 0
307 while i < len(comps):
308 if comps[i] == '.':
309 del comps[i]
310 elif comps[i] == '..' and i > 0 and \
311 comps[i-1] not in ('', '..'):
312 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000313 i = i - 1
Fred Drake8152d322000-12-12 23:20:45 +0000314 elif comps[i] == '' and i > 0 and comps[i-1] != '':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000315 del comps[i]
316 elif '.' in comps[i]:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000317 comp = comps[i].split('.')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000318 comps[i] = comp[0][:8] + '.' + comp[1][:3]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000319 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000320 elif len(comps[i]) > 8:
321 comps[i] = comps[i][:8]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000322 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000323 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000324 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000325 # If the path is now empty, substitute '.'
326 if not prefix and not comps:
327 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000328 return prefix + "\\".join(comps)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000329
Guido van Rossume294cf61999-01-29 18:05:18 +0000330
331
Guido van Rossume294cf61999-01-29 18:05:18 +0000332def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000333 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000334 if not isabs(path):
335 path = join(os.getcwd(), path)
336 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000337
338# realpath is a no-op on systems without islink support
339realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000340supports_unicode_filenames = False