blob: 899577cb0b54a74ce1bfaf7e124aebc68d3e59b5 [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Pathname and path-related operations for the Macintosh."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +00002
Guido van Rossum599f2ed1992-01-14 18:28:18 +00003import string
Guido van Rossum5c1d2291998-03-03 21:49:01 +00004import os
Guido van Rossum217a5fa1990-12-26 15:40:07 +00005from stat import *
6
Guido van Rossumb5e05e91991-01-01 18:10:40 +00007
Guido van Rossum599f2ed1992-01-14 18:28:18 +00008# Normalize the case of a pathname. Dummy in Posix, but string.lower here.
9
10normcase = string.lower
11
12
Guido van Rossum217a5fa1990-12-26 15:40:07 +000013def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000014 """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 Rossum217a5fa1990-12-26 15:40:07 +000021
Guido van Rossumb5e05e91991-01-01 18:10:40 +000022
Barry Warsaw384d2491997-02-18 21:53:25 +000023def join(s, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000024 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 Rossum217a5fa1990-12-26 15:40:07 +000037
Guido van Rossumb5e05e91991-01-01 18:10:40 +000038
Guido van Rossumb5e05e91991-01-01 18:10:40 +000039def split(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000040 """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 Rossumb5e05e91991-01-01 18:10:40 +000043
Guido van Rossum54f22ed2000-02-04 15:10:34 +000044 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 Rossumb5e05e91991-01-01 18:10:40 +000052
Guido van Rossuma48bf791996-07-23 02:28:32 +000053
54def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000055 """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 Rossuma48bf791996-07-23 02:28:32 +000059
Guido van Rossum54f22ed2000-02-04 15:10:34 +000060 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 Rossuma48bf791996-07-23 02:28:32 +000074
Guido van Rossum0ec31261995-08-10 18:09:16 +000075
76def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000077 """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 Rossum0ec31261995-08-10 18:09:16 +000084
85
Guido van Rossumc629d341992-11-05 10:43:02 +000086# Short interfaces to split()
87
88def dirname(s): return split(s)[0]
89def basename(s): return split(s)[1]
90
91
Skip Montanaro97bc98a2000-07-12 16:55:57 +000092# Return the longest prefix of all list elements.
93# XXX completely untested on Mac!!!
94
95def commonprefix(m):
96 "Given a list of pathnames, returns the longest common leading component"
97 if not m: return ''
98 n = m[:]
99 for i in range(len(n)):
100 n[i] = n[i].split(os.sep)
101 # if os.sep didn't have any effect, try os.altsep
102 if os.altsep and len(n[i]) == 1:
103 n[i] = n[i].split(os.altsep)
104
105 prefix = n[0]
106 for item in n:
107 for i in range(len(prefix)):
108 if prefix[:i+1] <> item[:i+1]:
109 prefix = prefix[:i]
110 if i == 0: return ''
111 break
112 return os.sep.join(prefix)
113
114
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000115def isdir(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000116 """Return true if the pathname refers to an existing directory."""
117
118 try:
119 st = os.stat(s)
120 except os.error:
121 return 0
122 return S_ISDIR(st[ST_MODE])
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000123
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000124
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000125# Get size, mtime, atime of files.
126
127def getsize(filename):
128 """Return the size of a file, reported by os.stat()."""
129 st = os.stat(filename)
Fred Drake69f87c51999-07-23 15:04:05 +0000130 return st[ST_SIZE]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000131
132def getmtime(filename):
133 """Return the last modification time of a file, reported by os.stat()."""
134 st = os.stat(filename)
Fred Drake69f87c51999-07-23 15:04:05 +0000135 return st[ST_MTIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000136
137def getatime(filename):
138 """Return the last access time of a file, reported by os.stat()."""
139 st = os.stat(filename)
Guido van Rossum46d56512000-07-01 10:52:49 +0000140 return st[ST_ATIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000141
142
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000143def islink(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000144 """Return true if the pathname refers to a symbolic link.
145 Always false on the Mac, until we understand Aliases.)"""
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000146
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000147 return 0
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000148
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000149
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000150def isfile(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000151 """Return true if the pathname refers to an existing regular file."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000152
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000153 try:
154 st = os.stat(s)
155 except os.error:
156 return 0
157 return S_ISREG(st[ST_MODE])
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000158
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000159
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000160def exists(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000161 """Return true if the pathname refers to an existing file or directory."""
Guido van Rossumc629d341992-11-05 10:43:02 +0000162
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000163 try:
164 st = os.stat(s)
165 except os.error:
166 return 0
167 return 1
168
169
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000170def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000171 """Dummy to retain interface-compatibility with other operating systems."""
172 return path
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000173
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000174
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000175def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000176 """Dummy to retain interface-compatibility with other operating systems."""
177 return path
Guido van Rossum0ec31261995-08-10 18:09:16 +0000178
179norm_error = 'macpath.norm_error: path cannot be normalized'
Guido van Rossumc629d341992-11-05 10:43:02 +0000180
181def normpath(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000182 """Normalize a pathname: get rid of '::' sequences by backing up,
183 e.g., 'foo:bar::bletch' becomes 'foo:bletch'.
184 Raise the exception norm_error below if backing up is impossible,
185 e.g., for '::foo'."""
186 # XXX The Unix version doesn't raise an exception but simply
187 # returns an unnormalized path. Should do so here too.
Jack Jansena68bfe21995-08-07 14:09:27 +0000188
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000189 import string
190 if ':' not in s:
191 return ':' + s
192 f = string.splitfields(s, ':')
193 pre = []
194 post = []
195 if not f[0]:
196 pre = f[:1]
197 f = f[1:]
198 if not f[len(f)-1]:
199 post = f[-1:]
200 f = f[:-1]
201 res = []
202 for seg in f:
203 if seg:
204 res.append(seg)
205 else:
206 if not res: raise norm_error, 'path starts with ::'
207 del res[len(res)-1]
208 if not (pre or res):
209 raise norm_error, 'path starts with volume::'
210 if pre: res = pre + res
211 if post: res = res + post
212 s = res[0]
213 for seg in res[1:]:
214 s = s + ':' + seg
215 return s
Guido van Rossum0ec31261995-08-10 18:09:16 +0000216
Jack Jansena68bfe21995-08-07 14:09:27 +0000217
218def walk(top, func, arg):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000219 """Directory tree walk.
220 For each directory under top (including top itself),
221 func(arg, dirname, filenames) is called, where
222 dirname is the name of the directory and filenames is the list
223 of files (and subdirectories etc.) in the directory.
224 The func may modify the filenames list, to implement a filter,
225 or to impose a different order of visiting."""
226
227 try:
228 names = os.listdir(top)
229 except os.error:
230 return
231 func(arg, top, names)
232 for name in names:
233 name = join(top, name)
234 if isdir(name):
235 walk(name, func, arg)
Guido van Rossume294cf61999-01-29 18:05:18 +0000236
237
Guido van Rossume294cf61999-01-29 18:05:18 +0000238def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000239 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000240 if not isabs(path):
241 path = join(os.getcwd(), path)
242 return normpath(path)