blob: f613a633f7d249ed6648e4f735ec75af4a3c2f4e [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",
9 "walk","expanduser","expandvars","normpath","abspath"]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000010
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000011def normcase(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000012 """Normalize the case of a pathname.
13 On MS-DOS it maps the pathname to lowercase, turns slashes into
14 backslashes.
15 Other normalizations (such as optimizing '../' away) are not allowed
16 (this is done by normpath).
Tim Peters88869f92001-01-14 23:36:06 +000017 Previously, this version mapped invalid consecutive characters to a
18 single '_', but this has been removed. This functionality should
Guido van Rossum54f22ed2000-02-04 15:10:34 +000019 possibly be added as a new function."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000020
Fred Drakeb4e460a2000-09-28 16:25:20 +000021 return s.replace("/", "\\").lower()
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000022
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000023
24def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000025 """Return whether a path is absolute.
26 Trivial in Posix, harder on the Mac or MS-DOS.
27 For DOS it is absolute if it starts with a slash or backslash (current
28 volume), or if a pathname after the volume letter and colon starts with
29 a slash or backslash."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000030
Guido van Rossum54f22ed2000-02-04 15:10:34 +000031 s = splitdrive(s)[1]
32 return s != '' and s[:1] in '/\\'
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000033
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000034
Guido van Rossumae590db1997-10-07 14:48:23 +000035def join(a, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000036 """Join two (or more) paths."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000037
Guido van Rossum54f22ed2000-02-04 15:10:34 +000038 path = a
39 for b in p:
40 if isabs(b):
41 path = b
Tim Petersceeda0e2000-09-19 23:46:56 +000042 elif path == '' or path[-1:] in '/\\:':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000043 path = path + b
44 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +000045 path = path + "\\" + b
Guido van Rossum54f22ed2000-02-04 15:10:34 +000046 return path
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000047
Guido van Rossumfda5c1a1995-08-10 19:27:42 +000048
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000049def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000050 """Split a path into a drive specification (a drive letter followed
51 by a colon) and path specification.
52 It is always true that drivespec + pathspec == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000053
Guido van Rossum54f22ed2000-02-04 15:10:34 +000054 if p[1:2] == ':':
55 return p[0:2], p[2:]
56 return '', p
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000057
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000058
59def split(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000060 """Split a path into head (everything up to the last '/') and tail
61 (the rest). After the trailing '/' is stripped, the invariant
62 join(head, tail) == p holds.
63 The resulting head won't end in '/' unless it is the root."""
64
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +000065 d, p = splitdrive(p)
66 # set i to index beyond p's last slash
67 i = len(p)
68 while i and p[i-1] not in '/\\':
69 i = i - 1
70 head, tail = p[:i], p[i:] # now tail has no slashes
71 # remove trailing slashes from head, unless it's all slashes
72 head2 = head
73 while head2 and head2[-1] in '/\\':
74 head2 = head2[:-1]
75 head = head2 or head
76 return d + head, tail
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000077
78
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000079def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000080 """Split a path into root and extension.
81 The extension is everything starting at the first dot in the last
82 pathname component; the root is everything before that.
83 It is always true that root + ext == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000084
Guido van Rossum54f22ed2000-02-04 15:10:34 +000085 root, ext = '', ''
86 for c in p:
87 if c in '/\\':
88 root, ext = root + ext + c, ''
89 elif c == '.' or ext:
90 ext = ext + c
91 else:
92 root = root + c
93 return root, ext
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000094
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000095
96def basename(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000097 """Return the tail (basename) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000098
Guido van Rossum54f22ed2000-02-04 15:10:34 +000099 return split(p)[1]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000100
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000101
102def dirname(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000103 """Return the head (dirname) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000104
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000105 return split(p)[0]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000106
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000107
Skip Montanaro97bc98a2000-07-12 16:55:57 +0000108def commonprefix(m):
Skip Montanaro62358312000-08-22 13:01:53 +0000109 """Return the longest prefix of all list elements."""
110
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000111 if not m: return ''
Skip Montanaro62358312000-08-22 13:01:53 +0000112 prefix = m[0]
113 for item in m:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000114 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000115 if prefix[:i+1] != item[:i+1]:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000116 prefix = prefix[:i]
117 if i == 0: return ''
118 break
Skip Montanaro62358312000-08-22 13:01:53 +0000119 return prefix
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000120
121
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000122# Get size, mtime, atime of files.
123
124def getsize(filename):
125 """Return the size of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000126 return os.stat(filename).st_size
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000127
128def getmtime(filename):
129 """Return the last modification time of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000130 return os.stat(filename).st_mtime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000131
132def getatime(filename):
133 """Return the last access time of a file, reported by os.stat()."""
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000134
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000135 return os.stat(filename).st_atime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000136
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000137def islink(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000138 """Is a path a symbolic link?
139 This will always return false on systems where posix.lstat doesn't exist."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000140
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000141 return False
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000142
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000143
144def exists(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000145 """Does a path exist?
146 This is false for dangling symbolic links."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000147
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000148 try:
149 st = os.stat(path)
150 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000151 return False
152 return True
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000153
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000154
155def isdir(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000156 """Is a path a dos directory?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000157
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000158 try:
159 st = os.stat(path)
160 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000161 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000162 return stat.S_ISDIR(st.st_mode)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000163
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000164
165def isfile(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000166 """Is a path a regular file?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000167
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000168 try:
169 st = os.stat(path)
170 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000171 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000172 return stat.S_ISREG(st.st_mode)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000173
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000174
175def ismount(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000176 """Is a path a mount point?"""
177 # XXX This degenerates in: 'is this the root?' on DOS
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000178
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000179 return isabs(splitdrive(path)[1])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000180
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000181
182def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000183 """Directory tree walk with callback function.
184
185 For each directory in the directory tree rooted at top (including top
186 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
187 dirname is the name of the directory, and fnames a list of the names of
188 the files and subdirectories in dirname (excluding '.' and '..'). func
189 may modify the fnames list in-place (e.g. via del or slice assignment),
190 and walk will only recurse into the subdirectories whose names remain in
191 fnames; this can be used to implement a filter, or to impose a specific
192 order of visiting. No semantics are defined for, or required of, arg,
193 beyond that arg is always passed to func. It can be used, e.g., to pass
194 a filename pattern, or a mutable object designed to accumulate
195 statistics. Passing None for arg is common."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000196
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000197 try:
198 names = os.listdir(top)
199 except os.error:
200 return
201 func(arg, top, names)
202 exceptions = ('.', '..')
203 for name in names:
204 if name not in exceptions:
205 name = join(top, name)
206 if isdir(name):
207 walk(name, func, arg)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000208
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000209
210def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000211 """Expand paths beginning with '~' or '~user'.
212 '~' means $HOME; '~user' means that user's home directory.
213 If the path doesn't begin with '~', or if the user or $HOME is unknown,
214 the path is returned unchanged (leaving error reporting to whatever
215 function is called with the expanded path as argument).
216 See also module 'glob' for expansion of *, ? and [...] in pathnames.
217 (A function should also be defined to do full *sh-style environment
218 variable expansion.)"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000219
Fred Drake8152d322000-12-12 23:20:45 +0000220 if path[:1] != '~':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000221 return path
222 i, n = 1, len(path)
223 while i < n and path[i] not in '/\\':
224 i = i+1
225 if i == 1:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000226 if not 'HOME' in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000227 return path
228 userhome = os.environ['HOME']
229 else:
230 return path
231 return userhome + path[i:]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000232
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000233
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000234def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000235 """Expand paths containing shell variable substitutions.
236 The following rules apply:
237 - no expansion within single quotes
238 - no escape character, except for '$$' which is translated into '$'
239 - ${varname} is accepted.
240 - varnames can be made out of letters, digits and the character '_'"""
241 # XXX With COMMAND.COM you can use any characters in a variable name,
242 # XXX except '^|<>='.
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000243
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000244 if '$' not in path:
245 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000246 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000247 varchars = string.ascii_letters + string.digits + "_-"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000248 res = ''
249 index = 0
250 pathlen = len(path)
251 while index < pathlen:
252 c = path[index]
253 if c == '\'': # no expansion within single quotes
254 path = path[index + 1:]
255 pathlen = len(path)
256 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000257 index = path.index('\'')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000258 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000259 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000260 res = res + path
261 index = pathlen -1
262 elif c == '$': # variable or '$$'
263 if path[index + 1:index + 2] == '$':
264 res = res + c
265 index = index + 1
266 elif path[index + 1:index + 2] == '{':
267 path = path[index+2:]
268 pathlen = len(path)
269 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000270 index = path.index('}')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000271 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000272 if var in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000273 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000274 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000275 res = res + path
276 index = pathlen - 1
277 else:
278 var = ''
279 index = index + 1
280 c = path[index:index + 1]
281 while c != '' and c in varchars:
282 var = var + c
283 index = index + 1
284 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000285 if var in os.environ:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000286 res = res + os.environ[var]
287 if c != '':
288 res = res + c
289 else:
290 res = res + c
291 index = index + 1
292 return res
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000293
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000294
295def normpath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000296 """Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
297 Also, components of the path are silently truncated to 8+3 notation."""
298
Fred Drakeb4e460a2000-09-28 16:25:20 +0000299 path = path.replace("/", "\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000300 prefix, path = splitdrive(path)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000301 while path[:1] == "\\":
302 prefix = prefix + "\\"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000303 path = path[1:]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000304 comps = path.split("\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000305 i = 0
306 while i < len(comps):
307 if comps[i] == '.':
308 del comps[i]
309 elif comps[i] == '..' and i > 0 and \
310 comps[i-1] not in ('', '..'):
311 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000312 i = i - 1
Fred Drake8152d322000-12-12 23:20:45 +0000313 elif comps[i] == '' and i > 0 and comps[i-1] != '':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000314 del comps[i]
315 elif '.' in comps[i]:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000316 comp = comps[i].split('.')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000317 comps[i] = comp[0][:8] + '.' + comp[1][:3]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000318 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000319 elif len(comps[i]) > 8:
320 comps[i] = comps[i][:8]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000321 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000322 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000323 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000324 # If the path is now empty, substitute '.'
325 if not prefix and not comps:
326 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000327 return prefix + "\\".join(comps)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000328
Guido van Rossume294cf61999-01-29 18:05:18 +0000329
330
Guido van Rossume294cf61999-01-29 18:05:18 +0000331def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000332 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000333 if not isabs(path):
334 path = join(os.getcwd(), path)
335 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000336
337# realpath is a no-op on systems without islink support
338realpath = abspath