| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 1 | """Pathname and path-related operations for the Macintosh.""" | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 2 |  | 
| Guido van Rossum | 599f2ed | 1992-01-14 18:28:18 +0000 | [diff] [blame] | 3 | import string | 
| Guido van Rossum | 5c1d229 | 1998-03-03 21:49:01 +0000 | [diff] [blame] | 4 | import os | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 5 | from stat import * | 
|  | 6 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 7 |  | 
| Guido van Rossum | 599f2ed | 1992-01-14 18:28:18 +0000 | [diff] [blame] | 8 | # Normalize the case of a pathname.  Dummy in Posix, but string.lower here. | 
|  | 9 |  | 
|  | 10 | normcase = string.lower | 
|  | 11 |  | 
|  | 12 |  | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 13 | def isabs(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 14 | """Return true if a path is absolute. | 
|  | 15 | On the Mac, relative paths begin with a colon, | 
|  | 16 | but as a special case, paths with no colons at all are also relative. | 
|  | 17 | Anything else is absolute (the string up to the first colon is the | 
|  | 18 | volume name).""" | 
|  | 19 |  | 
|  | 20 | return ':' in s and s[0] <> ':' | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 21 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 22 |  | 
| Barry Warsaw | 384d249 | 1997-02-18 21:53:25 +0000 | [diff] [blame] | 23 | def join(s, *p): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 24 | path = s | 
|  | 25 | for t in p: | 
|  | 26 | if (not s) or isabs(t): | 
|  | 27 | path = t | 
|  | 28 | continue | 
|  | 29 | if t[:1] == ':': | 
|  | 30 | t = t[1:] | 
|  | 31 | if ':' not in path: | 
|  | 32 | path = ':' + path | 
|  | 33 | if path[-1:] <> ':': | 
|  | 34 | path = path + ':' | 
|  | 35 | path = path + t | 
|  | 36 | return path | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 37 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 38 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 39 | def split(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 40 | """Split a pathname into two parts: the directory leading up to the final | 
|  | 41 | bit, and the basename (the filename, without colons, in that directory). | 
|  | 42 | The result (s, t) is such that join(s, t) yields the original argument.""" | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 43 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 44 | if ':' not in s: return '', s | 
|  | 45 | colon = 0 | 
|  | 46 | for i in range(len(s)): | 
|  | 47 | if s[i] == ':': colon = i+1 | 
|  | 48 | path, file = s[:colon-1], s[colon:] | 
|  | 49 | if path and not ':' in path: | 
|  | 50 | path = path + ':' | 
|  | 51 | return path, file | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 52 |  | 
| Guido van Rossum | a48bf79 | 1996-07-23 02:28:32 +0000 | [diff] [blame] | 53 |  | 
|  | 54 | def splitext(p): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 55 | """Split a path into root and extension. | 
|  | 56 | The extension is everything starting at the last dot in the last | 
|  | 57 | pathname component; the root is everything before that. | 
|  | 58 | It is always true that root + ext == p.""" | 
| Guido van Rossum | a48bf79 | 1996-07-23 02:28:32 +0000 | [diff] [blame] | 59 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 60 | root, ext = '', '' | 
|  | 61 | for c in p: | 
|  | 62 | if c == ':': | 
|  | 63 | root, ext = root + ext + c, '' | 
|  | 64 | elif c == '.': | 
|  | 65 | if ext: | 
|  | 66 | root, ext = root + ext, c | 
|  | 67 | else: | 
|  | 68 | ext = c | 
|  | 69 | elif ext: | 
|  | 70 | ext = ext + c | 
|  | 71 | else: | 
|  | 72 | root = root + c | 
|  | 73 | return root, ext | 
| Guido van Rossum | a48bf79 | 1996-07-23 02:28:32 +0000 | [diff] [blame] | 74 |  | 
| Guido van Rossum | 0ec3126 | 1995-08-10 18:09:16 +0000 | [diff] [blame] | 75 |  | 
|  | 76 | def splitdrive(p): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 77 | """Split a pathname into a drive specification and the rest of the | 
|  | 78 | path.  Useful on DOS/Windows/NT; on the Mac, the drive is always | 
|  | 79 | empty (don't use the volume name -- it doesn't have the same | 
|  | 80 | syntactic and semantic oddities as DOS drive letters, such as there | 
|  | 81 | being a separate current directory per drive).""" | 
|  | 82 |  | 
|  | 83 | return '', p | 
| Guido van Rossum | 0ec3126 | 1995-08-10 18:09:16 +0000 | [diff] [blame] | 84 |  | 
|  | 85 |  | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 86 | # Short interfaces to split() | 
|  | 87 |  | 
|  | 88 | def dirname(s): return split(s)[0] | 
|  | 89 | def basename(s): return split(s)[1] | 
|  | 90 |  | 
|  | 91 |  | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 92 | def isdir(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 93 | """Return true if the pathname refers to an existing directory.""" | 
|  | 94 |  | 
|  | 95 | try: | 
|  | 96 | st = os.stat(s) | 
|  | 97 | except os.error: | 
|  | 98 | return 0 | 
|  | 99 | return S_ISDIR(st[ST_MODE]) | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 100 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 101 |  | 
| Guido van Rossum | 2bc1f8f | 1998-07-24 20:49:26 +0000 | [diff] [blame] | 102 | # Get size, mtime, atime of files. | 
|  | 103 |  | 
|  | 104 | def getsize(filename): | 
|  | 105 | """Return the size of a file, reported by os.stat().""" | 
|  | 106 | st = os.stat(filename) | 
| Fred Drake | 69f87c5 | 1999-07-23 15:04:05 +0000 | [diff] [blame] | 107 | return st[ST_SIZE] | 
| Guido van Rossum | 2bc1f8f | 1998-07-24 20:49:26 +0000 | [diff] [blame] | 108 |  | 
|  | 109 | def getmtime(filename): | 
|  | 110 | """Return the last modification time of a file, reported by os.stat().""" | 
|  | 111 | st = os.stat(filename) | 
| Fred Drake | 69f87c5 | 1999-07-23 15:04:05 +0000 | [diff] [blame] | 112 | return st[ST_MTIME] | 
| Guido van Rossum | 2bc1f8f | 1998-07-24 20:49:26 +0000 | [diff] [blame] | 113 |  | 
|  | 114 | def getatime(filename): | 
|  | 115 | """Return the last access time of a file, reported by os.stat().""" | 
|  | 116 | st = os.stat(filename) | 
| Fred Drake | 69f87c5 | 1999-07-23 15:04:05 +0000 | [diff] [blame] | 117 | return st[ST_MTIME] | 
| Guido van Rossum | 2bc1f8f | 1998-07-24 20:49:26 +0000 | [diff] [blame] | 118 |  | 
|  | 119 |  | 
| Guido van Rossum | 7e4b2de | 1995-01-27 02:41:45 +0000 | [diff] [blame] | 120 | def islink(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 121 | """Return true if the pathname refers to a symbolic link. | 
|  | 122 | Always false on the Mac, until we understand Aliases.)""" | 
| Guido van Rossum | 7e4b2de | 1995-01-27 02:41:45 +0000 | [diff] [blame] | 123 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 124 | return 0 | 
| Guido van Rossum | 7e4b2de | 1995-01-27 02:41:45 +0000 | [diff] [blame] | 125 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 126 |  | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 127 | def isfile(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 128 | """Return true if the pathname refers to an existing regular file.""" | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 129 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 130 | try: | 
|  | 131 | st = os.stat(s) | 
|  | 132 | except os.error: | 
|  | 133 | return 0 | 
|  | 134 | return S_ISREG(st[ST_MODE]) | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 135 |  | 
| Guido van Rossum | b5e05e9 | 1991-01-01 18:10:40 +0000 | [diff] [blame] | 136 |  | 
| Guido van Rossum | 217a5fa | 1990-12-26 15:40:07 +0000 | [diff] [blame] | 137 | def exists(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 138 | """Return true if the pathname refers to an existing file or directory.""" | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 139 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 140 | try: | 
|  | 141 | st = os.stat(s) | 
|  | 142 | except os.error: | 
|  | 143 | return 0 | 
|  | 144 | return 1 | 
|  | 145 |  | 
|  | 146 |  | 
| Jack Jansen | f4e7d2a | 1995-12-15 13:23:37 +0000 | [diff] [blame] | 147 | def expandvars(path): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 148 | """Dummy to retain interface-compatibility with other operating systems.""" | 
|  | 149 | return path | 
| Jack Jansen | f4e7d2a | 1995-12-15 13:23:37 +0000 | [diff] [blame] | 150 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 151 |  | 
| Jack Jansen | f4e7d2a | 1995-12-15 13:23:37 +0000 | [diff] [blame] | 152 | def expanduser(path): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 153 | """Dummy to retain interface-compatibility with other operating systems.""" | 
|  | 154 | return path | 
| Guido van Rossum | 0ec3126 | 1995-08-10 18:09:16 +0000 | [diff] [blame] | 155 |  | 
|  | 156 | norm_error = 'macpath.norm_error: path cannot be normalized' | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 157 |  | 
|  | 158 | def normpath(s): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 159 | """Normalize a pathname: get rid of '::' sequences by backing up, | 
|  | 160 | e.g., 'foo:bar::bletch' becomes 'foo:bletch'. | 
|  | 161 | Raise the exception norm_error below if backing up is impossible, | 
|  | 162 | e.g., for '::foo'.""" | 
|  | 163 | # XXX The Unix version doesn't raise an exception but simply | 
|  | 164 | # returns an unnormalized path.  Should do so here too. | 
| Jack Jansen | a68bfe2 | 1995-08-07 14:09:27 +0000 | [diff] [blame] | 165 |  | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 166 | import string | 
|  | 167 | if ':' not in s: | 
|  | 168 | return ':' + s | 
|  | 169 | f = string.splitfields(s, ':') | 
|  | 170 | pre = [] | 
|  | 171 | post = [] | 
|  | 172 | if not f[0]: | 
|  | 173 | pre = f[:1] | 
|  | 174 | f = f[1:] | 
|  | 175 | if not f[len(f)-1]: | 
|  | 176 | post = f[-1:] | 
|  | 177 | f = f[:-1] | 
|  | 178 | res = [] | 
|  | 179 | for seg in f: | 
|  | 180 | if seg: | 
|  | 181 | res.append(seg) | 
|  | 182 | else: | 
|  | 183 | if not res: raise norm_error, 'path starts with ::' | 
|  | 184 | del res[len(res)-1] | 
|  | 185 | if not (pre or res): | 
|  | 186 | raise norm_error, 'path starts with volume::' | 
|  | 187 | if pre: res = pre + res | 
|  | 188 | if post: res = res + post | 
|  | 189 | s = res[0] | 
|  | 190 | for seg in res[1:]: | 
|  | 191 | s = s + ':' + seg | 
|  | 192 | return s | 
| Guido van Rossum | 0ec3126 | 1995-08-10 18:09:16 +0000 | [diff] [blame] | 193 |  | 
| Jack Jansen | a68bfe2 | 1995-08-07 14:09:27 +0000 | [diff] [blame] | 194 |  | 
|  | 195 | def walk(top, func, arg): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 196 | """Directory tree walk. | 
|  | 197 | For each directory under top (including top itself), | 
|  | 198 | func(arg, dirname, filenames) is called, where | 
|  | 199 | dirname is the name of the directory and filenames is the list | 
|  | 200 | of files (and subdirectories etc.) in the directory. | 
|  | 201 | The func may modify the filenames list, to implement a filter, | 
|  | 202 | or to impose a different order of visiting.""" | 
|  | 203 |  | 
|  | 204 | try: | 
|  | 205 | names = os.listdir(top) | 
|  | 206 | except os.error: | 
|  | 207 | return | 
|  | 208 | func(arg, top, names) | 
|  | 209 | for name in names: | 
|  | 210 | name = join(top, name) | 
|  | 211 | if isdir(name): | 
|  | 212 | walk(name, func, arg) | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 213 |  | 
|  | 214 |  | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 215 | def abspath(path): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame^] | 216 | """Return an absolute path.""" | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 217 | if not isabs(path): | 
|  | 218 | path = join(os.getcwd(), path) | 
|  | 219 | return normpath(path) |