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