blob: a539a826092fbe9ceb5fd959bf1b1bc24a3d80db [file] [log] [blame]
Andrew MacIntyre5cef5712002-02-24 05:32:32 +00001# Module 'os2emxpath' -- common operations on OS/2 pathnames
Tim Peters863ac442002-04-16 01:38:40 +00002"""Common pathname manipulations, OS/2 EMX version.
Andrew MacIntyre5cef5712002-02-24 05:32:32 +00003
4Instead of importing this module directly, import os and refer to this
5module as os.path.
6"""
7
8import os
9import stat
10
11__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
12 "basename","dirname","commonprefix","getsize","getmtime",
13 "getatime","islink","exists","isdir","isfile","ismount",
14 "walk","expanduser","expandvars","normpath","abspath","splitunc"]
15
16# Normalize the case of a pathname and map slashes to backslashes.
17# Other normalizations (such as optimizing '../' away) are not done
18# (this is done by normpath).
19
20def normcase(s):
21 """Normalize case of pathname.
22
23 Makes all characters lowercase and all altseps into seps."""
24 return s.replace('\\', '/').lower()
25
26
27# Return whether a path is absolute.
28# Trivial in Posix, harder on the Mac or MS-DOS.
29# For DOS it is absolute if it starts with a slash or backslash (current
30# volume), or if a pathname after the volume letter and colon / UNC resource
31# starts with a slash or backslash.
32
33def isabs(s):
34 """Test whether a path is absolute"""
35 s = splitdrive(s)[1]
36 return s != '' and s[:1] in '/\\'
37
38
39# Join two (or more) paths.
40
41def join(a, *p):
42 """Join two or more pathname components, inserting sep as needed"""
43 path = a
44 for b in p:
45 if isabs(b):
46 path = b
47 elif path == '' or path[-1:] in '/\\:':
48 path = path + b
49 else:
50 path = path + '/' + b
51 return path
52
53
54# Split a path in a drive specification (a drive letter followed by a
55# colon) and the path specification.
56# It is always true that drivespec + pathspec == p
57def splitdrive(p):
58 """Split a pathname into drive and path specifiers. Returns a 2-tuple
59"(drive,path)"; either part may be empty"""
60 if p[1:2] == ':':
61 return p[0:2], p[2:]
62 return '', p
63
64
65# Parse UNC paths
66def splitunc(p):
67 """Split a pathname into UNC mount point and relative path specifiers.
68
69 Return a 2-tuple (unc, rest); either part may be empty.
70 If unc is not empty, it has the form '//host/mount' (or similar
71 using backslashes). unc+rest is always the input path.
72 Paths containing drive letters never have an UNC part.
73 """
74 if p[1:2] == ':':
75 return '', p # Drive letter present
76 firstTwo = p[0:2]
77 if firstTwo == '/' * 2 or firstTwo == '\\' * 2:
78 # is a UNC path:
79 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
80 # \\machine\mountpoint\directories...
81 # directory ^^^^^^^^^^^^^^^
82 normp = normcase(p)
83 index = normp.find('/', 2)
84 if index == -1:
85 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
86 return ("", p)
87 index = normp.find('/', index + 1)
88 if index == -1:
89 index = len(p)
90 return p[:index], p[index:]
91 return '', p
92
93
94# Split a path in head (everything up to the last '/') and tail (the
95# rest). After the trailing '/' is stripped, the invariant
96# join(head, tail) == p holds.
97# The resulting head won't end in '/' unless it is the root.
98
99def split(p):
100 """Split a pathname.
101
102 Return tuple (head, tail) where tail is everything after the final slash.
103 Either part may be empty."""
104
105 d, p = splitdrive(p)
106 # set i to index beyond p's last slash
107 i = len(p)
108 while i and p[i-1] not in '/\\':
109 i = i - 1
110 head, tail = p[:i], p[i:] # now tail has no slashes
111 # remove trailing slashes from head, unless it's all slashes
112 head2 = head
113 while head2 and head2[-1] in '/\\':
114 head2 = head2[:-1]
115 head = head2 or head
116 return d + head, tail
117
118
119# Split a path in root and extension.
120# The extension is everything starting at the last dot in the last
121# pathname component; the root is everything before that.
122# It is always true that root + ext == p.
123
124def splitext(p):
125 """Split the extension from a pathname.
126
127 Extension is everything from the last dot to the end.
128 Return (root, ext), either part may be empty."""
129 root, ext = '', ''
130 for c in p:
131 if c in ['/','\\']:
132 root, ext = root + ext + c, ''
133 elif c == '.':
134 if ext:
135 root, ext = root + ext, c
136 else:
137 ext = c
138 elif ext:
139 ext = ext + c
140 else:
141 root = root + c
142 return root, ext
143
144
145# Return the tail (basename) part of a path.
146
147def basename(p):
148 """Returns the final component of a pathname"""
149 return split(p)[1]
150
151
152# Return the head (dirname) part of a path.
153
154def dirname(p):
155 """Returns the directory component of a pathname"""
156 return split(p)[0]
157
158
159# Return the longest prefix of all list elements.
160
161def commonprefix(m):
162 "Given a list of pathnames, returns the longest common leading component"
163 if not m: return ''
164 prefix = m[0]
165 for item in m:
166 for i in range(len(prefix)):
167 if prefix[:i+1] != item[:i+1]:
168 prefix = prefix[:i]
169 if i == 0: return ''
170 break
171 return prefix
172
173
174# Get size, mtime, atime of files.
175
176def getsize(filename):
177 """Return the size of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000178 return os.stat(filename).st_size
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000179
180def getmtime(filename):
181 """Return the last modification time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000182 return os.stat(filename).st_mtime
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000183
184def getatime(filename):
185 """Return the last access time of a file, reported by os.stat()"""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000186 return os.stat(filename).st_atime
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000187
188
189# Is a path a symbolic link?
190# This will always return false on systems where posix.lstat doesn't exist.
191
192def islink(path):
193 """Test for symbolic link. On OS/2 always returns false"""
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000194 return False
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000195
196
197# Does a path exist?
198# This is false for dangling symbolic links.
199
200def exists(path):
201 """Test whether a path exists"""
202 try:
203 st = os.stat(path)
204 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000205 return False
206 return True
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000207
208
209# Is a path a directory?
210
211def isdir(path):
212 """Test whether a path is a directory"""
213 try:
214 st = os.stat(path)
215 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000216 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000217 return stat.S_ISDIR(st.st_mode)
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000218
219
220# Is a path a regular file?
221# This follows symbolic links, so both islink() and isdir() can be true
222# for the same path.
223
224def isfile(path):
225 """Test whether a path is a regular file"""
226 try:
227 st = os.stat(path)
228 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000229 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000230 return stat.S_ISREG(st.st_mode)
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000231
232
233# Is a path a mount point? Either a root (with or without drive letter)
234# or an UNC path with at most a / or \ after the mount point.
235
236def ismount(path):
237 """Test whether a path is a mount point (defined as root of drive)"""
238 unc, rest = splitunc(path)
239 if unc:
240 return rest in ("", "/", "\\")
241 p = splitdrive(path)[1]
242 return len(p) == 1 and p[0] in '/\\'
243
244
245# Directory tree walk.
246# For each directory under top (including top itself, but excluding
247# '.' and '..'), func(arg, dirname, filenames) is called, where
248# dirname is the name of the directory and filenames is the list
249# files files (and subdirectories etc.) in the directory.
250# The func may modify the filenames list, to implement a filter,
251# or to impose a different order of visiting.
252
253def walk(top, func, arg):
254 """Directory tree walk whth callback function.
255
256 walk(top, func, arg) calls func(arg, d, files) for each directory d
257 in the tree rooted at top (including top itself); files is a list
258 of all the files and subdirs in directory d."""
259 try:
260 names = os.listdir(top)
261 except os.error:
262 return
263 func(arg, top, names)
264 exceptions = ('.', '..')
265 for name in names:
266 if name not in exceptions:
267 name = join(top, name)
268 if isdir(name):
269 walk(name, func, arg)
270
271
272# Expand paths beginning with '~' or '~user'.
273# '~' means $HOME; '~user' means that user's home directory.
274# If the path doesn't begin with '~', or if the user or $HOME is unknown,
275# the path is returned unchanged (leaving error reporting to whatever
276# function is called with the expanded path as argument).
277# See also module 'glob' for expansion of *, ? and [...] in pathnames.
278# (A function should also be defined to do full *sh-style environment
279# variable expansion.)
280
281def expanduser(path):
282 """Expand ~ and ~user constructs.
283
284 If user or $HOME is unknown, do nothing."""
285 if path[:1] != '~':
286 return path
287 i, n = 1, len(path)
288 while i < n and path[i] not in '/\\':
289 i = i + 1
290 if i == 1:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000291 if 'HOME' in os.environ:
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000292 userhome = os.environ['HOME']
Raymond Hettinger54f02222002-06-01 14:18:47 +0000293 elif not 'HOMEPATH' in os.environ:
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000294 return path
295 else:
296 try:
297 drive = os.environ['HOMEDRIVE']
298 except KeyError:
299 drive = ''
300 userhome = join(drive, os.environ['HOMEPATH'])
301 else:
302 return path
303 return userhome + path[i:]
304
305
306# Expand paths containing shell variable substitutions.
307# The following rules apply:
308# - no expansion within single quotes
309# - no escape character, except for '$$' which is translated into '$'
310# - ${varname} is accepted.
311# - varnames can be made out of letters, digits and the character '_'
312# XXX With COMMAND.COM you can use any characters in a variable name,
313# XXX except '^|<>='.
314
315def expandvars(path):
316 """Expand shell variables of form $var and ${var}.
317
318 Unknown variables are left unchanged."""
319 if '$' not in path:
320 return path
321 import string
322 varchars = string.letters + string.digits + '_-'
323 res = ''
324 index = 0
325 pathlen = len(path)
326 while index < pathlen:
327 c = path[index]
328 if c == '\'': # no expansion within single quotes
329 path = path[index + 1:]
330 pathlen = len(path)
331 try:
332 index = path.index('\'')
333 res = res + '\'' + path[:index + 1]
334 except ValueError:
335 res = res + path
336 index = pathlen - 1
337 elif c == '$': # variable or '$$'
338 if path[index + 1:index + 2] == '$':
339 res = res + c
340 index = index + 1
341 elif path[index + 1:index + 2] == '{':
342 path = path[index+2:]
343 pathlen = len(path)
344 try:
345 index = path.index('}')
346 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000347 if var in os.environ:
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000348 res = res + os.environ[var]
349 except ValueError:
350 res = res + path
351 index = pathlen - 1
352 else:
353 var = ''
354 index = index + 1
355 c = path[index:index + 1]
356 while c != '' and c in varchars:
357 var = var + c
358 index = index + 1
359 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000360 if var in os.environ:
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000361 res = res + os.environ[var]
362 if c != '':
363 res = res + c
364 else:
365 res = res + c
366 index = index + 1
367 return res
368
369
370# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
371
372def normpath(path):
373 """Normalize path, eliminating double slashes, etc."""
374 path = path.replace('\\', '/')
375 prefix, path = splitdrive(path)
376 while path[:1] == '/':
377 prefix = prefix + '/'
378 path = path[1:]
379 comps = path.split('/')
380 i = 0
381 while i < len(comps):
382 if comps[i] == '.':
383 del comps[i]
384 elif comps[i] == '..' and i > 0 and comps[i-1] not in ('', '..'):
385 del comps[i-1:i+1]
386 i = i - 1
387 elif comps[i] == '' and i > 0 and comps[i-1] != '':
388 del comps[i]
389 else:
390 i = i + 1
391 # If the path is now empty, substitute '.'
392 if not prefix and not comps:
393 comps.append('.')
394 return prefix + '/'.join(comps)
395
396
397# Return an absolute path.
398def abspath(path):
399 """Return the absolute version of a path"""
400 if not isabs(path):
401 path = join(os.getcwd(), path)
402 return normpath(path)