blob: 17db624e835f9bc980d179d07979bb3e5aca318d [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
6
Guido van Rossum3ed23cc1994-02-15 15:57:15 +00007def normcase(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +00008 """Normalize the case of a pathname.
9 On MS-DOS it maps the pathname to lowercase, turns slashes into
10 backslashes.
11 Other normalizations (such as optimizing '../' away) are not allowed
12 (this is done by normpath).
13 Previously, this version mapped invalid consecutive characters to a
14 single '_', but this has been removed. This functionality should
15 possibly be added as a new function."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000016
Fred Drakeb4e460a2000-09-28 16:25:20 +000017 return s.replace("/", "\\").lower()
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000018
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000019
20def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000021 """Return whether a path is absolute.
22 Trivial in Posix, harder on the Mac or MS-DOS.
23 For DOS it is absolute if it starts with a slash or backslash (current
24 volume), or if a pathname after the volume letter and colon starts with
25 a slash or backslash."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000026
Guido van Rossum54f22ed2000-02-04 15:10:34 +000027 s = splitdrive(s)[1]
28 return s != '' and s[:1] in '/\\'
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000029
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000030
Guido van Rossumae590db1997-10-07 14:48:23 +000031def join(a, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000032 """Join two (or more) paths."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000033
Guido van Rossum54f22ed2000-02-04 15:10:34 +000034 path = a
35 for b in p:
36 if isabs(b):
37 path = b
Tim Petersceeda0e2000-09-19 23:46:56 +000038 elif path == '' or path[-1:] in '/\\:':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000039 path = path + b
40 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +000041 path = path + "\\" + b
Guido van Rossum54f22ed2000-02-04 15:10:34 +000042 return path
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000043
Guido van Rossumfda5c1a1995-08-10 19:27:42 +000044
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000045def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000046 """Split a path into a drive specification (a drive letter followed
47 by a colon) and path specification.
48 It is always true that drivespec + pathspec == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000049
Guido van Rossum54f22ed2000-02-04 15:10:34 +000050 if p[1:2] == ':':
51 return p[0:2], p[2:]
52 return '', p
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000053
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000054
55def split(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000056 """Split a path into head (everything up to the last '/') and tail
57 (the rest). After the trailing '/' is stripped, the invariant
58 join(head, tail) == p holds.
59 The resulting head won't end in '/' unless it is the root."""
60
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +000061 d, p = splitdrive(p)
62 # set i to index beyond p's last slash
63 i = len(p)
64 while i and p[i-1] not in '/\\':
65 i = i - 1
66 head, tail = p[:i], p[i:] # now tail has no slashes
67 # remove trailing slashes from head, unless it's all slashes
68 head2 = head
69 while head2 and head2[-1] in '/\\':
70 head2 = head2[:-1]
71 head = head2 or head
72 return d + head, tail
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000073
74
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000075def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000076 """Split a path into root and extension.
77 The extension is everything starting at the first dot in the last
78 pathname component; the root is everything before that.
79 It is always true that root + ext == p."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000080
Guido van Rossum54f22ed2000-02-04 15:10:34 +000081 root, ext = '', ''
82 for c in p:
83 if c in '/\\':
84 root, ext = root + ext + c, ''
85 elif c == '.' or ext:
86 ext = ext + c
87 else:
88 root = root + c
89 return root, ext
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000090
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000091
92def basename(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000093 """Return the tail (basename) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000094
Guido van Rossum54f22ed2000-02-04 15:10:34 +000095 return split(p)[1]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000096
Guido van Rossum3ed23cc1994-02-15 15:57:15 +000097
98def dirname(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000099 """Return the head (dirname) part of a path."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000100
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000101 return split(p)[0]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000102
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000103
Skip Montanaro97bc98a2000-07-12 16:55:57 +0000104def commonprefix(m):
Skip Montanaro62358312000-08-22 13:01:53 +0000105 """Return the longest prefix of all list elements."""
106
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000107 if not m: return ''
Skip Montanaro62358312000-08-22 13:01:53 +0000108 prefix = m[0]
109 for item in m:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000110 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000111 if prefix[:i+1] != item[:i+1]:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000112 prefix = prefix[:i]
113 if i == 0: return ''
114 break
Skip Montanaro62358312000-08-22 13:01:53 +0000115 return prefix
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000116
117
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000118# Get size, mtime, atime of files.
119
120def getsize(filename):
121 """Return the size of a file, reported by os.stat()."""
122 st = os.stat(filename)
123 return st[stat.ST_SIZE]
124
125def getmtime(filename):
126 """Return the last modification time of a file, reported by os.stat()."""
127 st = os.stat(filename)
128 return st[stat.ST_MTIME]
129
130def getatime(filename):
131 """Return the last access time of a file, reported by os.stat()."""
132 st = os.stat(filename)
Guido van Rossum46d56512000-07-01 10:52:49 +0000133 return st[stat.ST_ATIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000134
135
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000136def islink(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000137 """Is a path a symbolic link?
138 This will always return false on systems where posix.lstat doesn't exist."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000139
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000140 return 0
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000141
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000142
143def exists(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000144 """Does a path exist?
145 This is false for dangling symbolic links."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000146
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000147 try:
148 st = os.stat(path)
149 except os.error:
150 return 0
151 return 1
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000152
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000153
154def isdir(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000155 """Is a path a dos directory?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000156
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000157 try:
158 st = os.stat(path)
159 except os.error:
160 return 0
161 return stat.S_ISDIR(st[stat.ST_MODE])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000162
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000163
164def isfile(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000165 """Is a path a regular file?"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000166
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000167 try:
168 st = os.stat(path)
169 except os.error:
170 return 0
171 return stat.S_ISREG(st[stat.ST_MODE])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000172
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000173
174def ismount(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000175 """Is a path a mount point?"""
176 # XXX This degenerates in: 'is this the root?' on DOS
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000177
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000178 return isabs(splitdrive(path)[1])
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000179
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000180
181def walk(top, func, arg):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000182 """Directory tree walk.
183 For each directory under top (including top itself, but excluding
184 '.' and '..'), func(arg, dirname, filenames) is called, where
185 dirname is the name of the directory and filenames is the list
186 files files (and subdirectories etc.) in the directory.
187 The func may modify the filenames list, to implement a filter,
188 or to impose a different order of visiting."""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000189
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000190 try:
191 names = os.listdir(top)
192 except os.error:
193 return
194 func(arg, top, names)
195 exceptions = ('.', '..')
196 for name in names:
197 if name not in exceptions:
198 name = join(top, name)
199 if isdir(name):
200 walk(name, func, arg)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000201
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000202
203def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000204 """Expand paths beginning with '~' or '~user'.
205 '~' means $HOME; '~user' means that user's home directory.
206 If the path doesn't begin with '~', or if the user or $HOME is unknown,
207 the path is returned unchanged (leaving error reporting to whatever
208 function is called with the expanded path as argument).
209 See also module 'glob' for expansion of *, ? and [...] in pathnames.
210 (A function should also be defined to do full *sh-style environment
211 variable expansion.)"""
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000212
Fred Drake8152d322000-12-12 23:20:45 +0000213 if path[:1] != '~':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000214 return path
215 i, n = 1, len(path)
216 while i < n and path[i] not in '/\\':
217 i = i+1
218 if i == 1:
219 if not os.environ.has_key('HOME'):
220 return path
221 userhome = os.environ['HOME']
222 else:
223 return path
224 return userhome + path[i:]
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000225
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000226
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000227def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000228 """Expand paths containing shell variable substitutions.
229 The following rules apply:
230 - no expansion within single quotes
231 - no escape character, except for '$$' which is translated into '$'
232 - ${varname} is accepted.
233 - varnames can be made out of letters, digits and the character '_'"""
234 # XXX With COMMAND.COM you can use any characters in a variable name,
235 # XXX except '^|<>='.
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000236
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000237 if '$' not in path:
238 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000239 import string
240 varchars = string.letters + string.digits + '_-'
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000241 res = ''
242 index = 0
243 pathlen = len(path)
244 while index < pathlen:
245 c = path[index]
246 if c == '\'': # no expansion within single quotes
247 path = path[index + 1:]
248 pathlen = len(path)
249 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000250 index = path.index('\'')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000251 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000252 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000253 res = res + path
254 index = pathlen -1
255 elif c == '$': # variable or '$$'
256 if path[index + 1:index + 2] == '$':
257 res = res + c
258 index = index + 1
259 elif path[index + 1:index + 2] == '{':
260 path = path[index+2:]
261 pathlen = len(path)
262 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000263 index = path.index('}')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000264 var = path[:index]
265 if os.environ.has_key(var):
266 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000267 except ValueError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000268 res = res + path
269 index = pathlen - 1
270 else:
271 var = ''
272 index = index + 1
273 c = path[index:index + 1]
274 while c != '' and c in varchars:
275 var = var + c
276 index = index + 1
277 c = path[index:index + 1]
278 if os.environ.has_key(var):
279 res = res + os.environ[var]
280 if c != '':
281 res = res + c
282 else:
283 res = res + c
284 index = index + 1
285 return res
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000286
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000287
288def normpath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000289 """Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
290 Also, components of the path are silently truncated to 8+3 notation."""
291
Fred Drakeb4e460a2000-09-28 16:25:20 +0000292 path = path.replace("/", "\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000293 prefix, path = splitdrive(path)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000294 while path[:1] == "\\":
295 prefix = prefix + "\\"
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000296 path = path[1:]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000297 comps = path.split("\\")
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000298 i = 0
299 while i < len(comps):
300 if comps[i] == '.':
301 del comps[i]
302 elif comps[i] == '..' and i > 0 and \
303 comps[i-1] not in ('', '..'):
304 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000305 i = i - 1
Fred Drake8152d322000-12-12 23:20:45 +0000306 elif comps[i] == '' and i > 0 and comps[i-1] != '':
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000307 del comps[i]
308 elif '.' in comps[i]:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000309 comp = comps[i].split('.')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000310 comps[i] = comp[0][:8] + '.' + comp[1][:3]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000311 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000312 elif len(comps[i]) > 8:
313 comps[i] = comps[i][:8]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000314 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000315 else:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000316 i = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000317 # If the path is now empty, substitute '.'
318 if not prefix and not comps:
319 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000320 return prefix + "\\".join(comps)
Guido van Rossum3ed23cc1994-02-15 15:57:15 +0000321
Guido van Rossume294cf61999-01-29 18:05:18 +0000322
323
Guido van Rossume294cf61999-01-29 18:05:18 +0000324def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000325 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000326 if not isabs(path):
327 path = join(os.getcwd(), path)
328 return normpath(path)