1 # Module 'dospath' -- common operations on DOS pathnames
8 # Normalize the case of a pathname.
9 # On MS-DOS it maps the pathname to lowercase, turns slashes into
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.
18 return string
.lower(string
.replace(s
, "/", "\\"))
21 # Return wheter 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.
29 return s
!= '' and s
[:1] in '/\\'
32 # Join two (or more) paths.
39 elif path
== '' or path
[-1:] in '/\\':
42 path
= path
+ os
.sep
+ b
46 # Split a path in a drive specification (a drive letter followed by a
47 # colon) and the path specification.
48 # It is always true that drivespec + pathspec == p
56 # Split a path in head (everything up to the last '/') and tail (the
57 # 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.
63 # set i to index beyond p's last slash
65 while i
and p
[i
-1] not in '/\\':
67 head
, tail
= p
[:i
], p
[i
:] # now tail has no slashes
68 # remove trailing slashes from head, unless it's all slashes
70 while head2
and head2
[-1] in '/\\':
76 # Split a path in 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.
85 root
, ext
= root
+ ext
+ c
, ''
93 # Return the tail (basename) part of a path.
99 # Return the head (dirname) part of a path.
105 # Return the longest prefix of all list elements.
111 for i
in range(len(prefix
)):
112 if prefix
[:i
+1] <> item
[:i
+1]:
119 # Get size, mtime, atime of files.
121 def getsize(filename
):
122 """Return the size of a file, reported by os.stat()."""
123 st
= os
.stat(filename
)
124 return st
[stat
.ST_SIZE
]
126 def getmtime(filename
):
127 """Return the last modification time of a file, reported by os.stat()."""
128 st
= os
.stat(filename
)
129 return st
[stat
.ST_MTIME
]
131 def getatime(filename
):
132 """Return the last access time of a file, reported by os.stat()."""
133 st
= os
.stat(filename
)
134 return st
[stat
.ST_MTIME
]
137 # Is a path a symbolic link?
138 # This will always return false on systems where posix.lstat doesn't exist.
145 # This is false for dangling symbolic links.
155 # Is a path a dos directory?
156 # This follows symbolic links, so both islink() and isdir() can be true
164 return stat
.S_ISDIR(st
[stat
.ST_MODE
])
167 # Is a path a regular file?
168 # This follows symbolic links, so both islink() and isdir() can be true
176 return stat
.S_ISREG(st
[stat
.ST_MODE
])
179 # Is a path a mount point?
180 # XXX This degenerates in: 'is this the root?' on DOS
183 return isabs(splitdrive(path
)[1])
186 # Directory tree walk.
187 # For each directory under top (including top itself, but excluding
188 # '.' and '..'), func(arg, dirname, filenames) is called, where
189 # dirname is the name of the directory and filenames is the list
190 # files files (and subdirectories etc.) in the directory.
191 # The func may modify the filenames list, to implement a filter,
192 # or to impose a different order of visiting.
194 def walk(top
, func
, arg
):
196 names
= os
.listdir(top
)
199 func(arg
, top
, names
)
200 exceptions
= ('.', '..')
202 if name
not in exceptions
:
203 name
= join(top
, name
)
205 walk(name
, func
, arg
)
208 # Expand paths beginning with '~' or '~user'.
209 # '~' means $HOME; '~user' means that user's home directory.
210 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
211 # the path is returned unchanged (leaving error reporting to whatever
212 # function is called with the expanded path as argument).
213 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
214 # (A function should also be defined to do full *sh-style environment
215 # variable expansion.)
217 def expanduser(path
):
221 while i
< n
and path
[i
] not in '/\\':
224 if not os
.environ
.has_key('HOME'):
226 userhome
= os
.environ
['HOME']
229 return userhome
+ path
[i
:]
232 # Expand paths containing shell variable substitutions.
233 # The following rules apply:
234 # - no expansion within single quotes
235 # - no escape character, except for '$$' which is translated into '$'
236 # - ${varname} is accepted.
237 # - varnames can be made out of letters, digits and the character '_'
238 # XXX With COMMAND.COM you can use any characters in a variable name,
239 # XXX except '^|<>='.
241 varchars
= string
.letters
+ string
.digits
+ '_-'
243 def expandvars(path
):
249 while index
< pathlen
:
251 if c
== '\'': # no expansion within single quotes
252 path
= path
[index
+ 1:]
255 index
= string
.index(path
, '\'')
256 res
= res
+ '\'' + path
[:index
+ 1]
257 except string
.index_error
:
260 elif c
== '$': # variable or '$$'
261 if path
[index
+ 1:index
+ 2] == '$':
264 elif path
[index
+ 1:index
+ 2] == '{':
265 path
= path
[index
+2:]
268 index
= string
.index(path
, '}')
270 if os
.environ
.has_key(var
):
271 res
= res
+ os
.environ
[var
]
272 except string
.index_error
:
278 c
= path
[index
:index
+ 1]
279 while c
!= '' and c
in varchars
:
282 c
= path
[index
:index
+ 1]
283 if os
.environ
.has_key(var
):
284 res
= res
+ os
.environ
[var
]
293 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
294 # Also, components of the path are silently truncated to 8+3 notation.
297 path
= string
.replace(path
, "/", "\\")
298 prefix
, path
= splitdrive(path
)
299 while path
[:1] == os
.sep
:
300 prefix
= prefix
+ os
.sep
302 comps
= string
.splitfields(path
, os
.sep
)
304 while i
< len(comps
):
307 elif comps
[i
] == '..' and i
> 0 and \
308 comps
[i
-1] not in ('', '..'):
311 elif comps
[i
] == '' and i
> 0 and comps
[i
-1] <> '':
313 elif '.' in comps
[i
]:
314 comp
= string
.splitfields(comps
[i
], '.')
315 comps
[i
] = comp
[0][:8] + '.' + comp
[1][:3]
317 elif len(comps
[i
]) > 8:
318 comps
[i
] = comps
[i
][:8]
322 # If the path is now empty, substitute '.'
323 if not prefix
and not comps
:
325 return prefix
+ string
.joinfields(comps
, os
.sep
)
329 # Return an absolute path.
332 path
= join(os
.getcwd(), path
)
333 return normpath(path
)