blob: 652b35f51f92c6672ef0c04ff7940d5f6683c766 [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()."""
126 st = os.stat(filename)
127 return st[stat.ST_SIZE]
128
129def getmtime(filename):
130 """Return the last modification time of a file, reported by os.stat()."""
131 st = os.stat(filename)
132 return st[stat.ST_MTIME]
133
134def getatime(filename):
135 """Return the last access time of a file, reported by os.stat()."""
136 st = os.stat(filename)
Guido van Rossum46d56512000-07-01 10:52:49 +0000137 return st[stat.ST_ATIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000138
139
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000140def islink(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000141 """Is a path a symbolic link?
142 This will always return false on systems where posix.lstat doesn't exist."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000143
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000144 return 0
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000145
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000146
147def exists(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000148 """Does a path exist?
149 This is false for dangling symbolic links."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000150
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000151 try:
152 st = os.stat(path)
153 except os.error:
154 return 0
155 return 1
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000156
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000157
158def isdir(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000159 """Is a path a dos directory?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000160
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000161 try:
162 st = os.stat(path)
163 except os.error:
164 return 0
165 return stat.S_ISDIR(st[stat.ST_MODE])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000166
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000167
168def isfile(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000169 """Is a path a regular file?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000170
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000171 try:
172 st = os.stat(path)
173 except os.error:
174 return 0
175 return stat.S_ISREG(st[stat.ST_MODE])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000176
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000177
178def ismount(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000179 """Is a path a mount point?"""
180 # XXX This degenerates in: 'is this the root?' on DOS
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000181
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000182 return isabs(splitdrive(path)[1])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000183
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000184
185def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000186 """Directory tree walk with callback function.
187
188 For each directory in the directory tree rooted at top (including top
189 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
190 dirname is the name of the directory, and fnames a list of the names of
191 the files and subdirectories in dirname (excluding '.' and '..'). func
192 may modify the fnames list in-place (e.g. via del or slice assignment),
193 and walk will only recurse into the subdirectories whose names remain in
194 fnames; this can be used to implement a filter, or to impose a specific
195 order of visiting. No semantics are defined for, or required of, arg,
196 beyond that arg is always passed to func. It can be used, e.g., to pass
197 a filename pattern, or a mutable object designed to accumulate
198 statistics. Passing None for arg is common."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000199
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000200 try:
201 names = os.listdir(top)
202 except os.error:
203 return
204 func(arg, top, names)
205 exceptions = ('.', '..')
206 for name in names:
207 if name not in exceptions:
208 name = join(top, name)
209 if isdir(name):
210 walk(name, func, arg)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000211
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000212
213def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000214 """Expand paths beginning with '~' or '~user'.
215 '~' means $HOME; '~user' means that user's home directory.
216 If the path doesn't begin with '~', or if the user or $HOME is unknown,
217 the path is returned unchanged (leaving error reporting to whatever
218 function is called with the expanded path as argument).
219 See also module 'glob' for expansion of *, ? and [...] in pathnames.
220 (A function should also be defined to do full *sh-style environment
221 variable expansion.)"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000222
Fred Drake8152d322000-12-12 23:20:45 +0000223 if path[:1] != '~':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000224 return path
225 i, n = 1, len(path)
226 while i < n and path[i] not in '/\\':
227 i = i+1
228 if i == 1:
229 if not os.environ.has_key('HOME'):
230 return path
231 userhome = os.environ['HOME']
232 else:
233 return path
234 return userhome + path[i:]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000235
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000236
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000237def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000238 """Expand paths containing shell variable substitutions.
239 The following rules apply:
240 - no expansion within single quotes
241 - no escape character, except for '$$' which is translated into '$'
242 - ${varname} is accepted.
243 - varnames can be made out of letters, digits and the character '_'"""
244 # XXX With COMMAND.COM you can use any characters in a variable name,
245 # XXX except '^|<>='.
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000246
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000247 if '$' not in path:
248 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000249 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000250 varchars = string.ascii_letters + string.digits + "_-"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000251 res = ''
252 index = 0
253 pathlen = len(path)
254 while index < pathlen:
255 c = path[index]
256 if c == '\'': # no expansion within single quotes
257 path = path[index + 1:]
258 pathlen = len(path)
259 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000260 index = path.index('\'')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000261 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000262 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000263 res = res + path
264 index = pathlen -1
265 elif c == '$': # variable or '$$'
266 if path[index + 1:index + 2] == '$':
267 res = res + c
268 index = index + 1
269 elif path[index + 1:index + 2] == '{':
270 path = path[index+2:]
271 pathlen = len(path)
272 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000273 index = path.index('}')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000274 var = path[:index]
275 if os.environ.has_key(var):
276 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000277 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000278 res = res + path
279 index = pathlen - 1
280 else:
281 var = ''
282 index = index + 1
283 c = path[index:index + 1]
284 while c != '' and c in varchars:
285 var = var + c
286 index = index + 1
287 c = path[index:index + 1]
288 if os.environ.has_key(var):
289 res = res + os.environ[var]
290 if c != '':
291 res = res + c
292 else:
293 res = res + c
294 index = index + 1
295 return res
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000296
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000297
298def normpath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000299 """Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
300 Also, components of the path are silently truncated to 8+3 notation."""
301
Fred Drakeb4e460a2000-09-28 16:25:20 +0000302 path = path.replace("/", "\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000303 prefix, path = splitdrive(path)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000304 while path[:1] == "\\":
305 prefix = prefix + "\\"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000306 path = path[1:]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000307 comps = path.split("\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000308 i = 0
309 while i < len(comps):
310 if comps[i] == '.':
311 del comps[i]
312 elif comps[i] == '..' and i > 0 and \
313 comps[i-1] not in ('', '..'):
314 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000315 i = i - 1
Fred Drake8152d322000-12-12 23:20:45 +0000316 elif comps[i] == '' and i > 0 and comps[i-1] != '':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000317 del comps[i]
318 elif '.' in comps[i]:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000319 comp = comps[i].split('.')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000320 comps[i] = comp[0][:8] + '.' + comp[1][:3]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000321 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000322 elif len(comps[i]) > 8:
323 comps[i] = comps[i][:8]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000324 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000325 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000326 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000327 # If the path is now empty, substitute '.'
328 if not prefix and not comps:
329 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000330 return prefix + "\\".join(comps)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000331
Guido van Rossume294cf61999-01-29 18:05:18 +0000332
333
Guido van Rossume294cf61999-01-29 18:05:18 +0000334def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000335 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000336 if not isabs(path):
337 path = join(os.getcwd(), path)
338 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000339
340# realpath is a no-op on systems without islink support
341realpath = abspath