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). If the original path ends in '/' but is not the root, this
58 # '/' is stripped. After the trailing '/' is stripped, the invariant
59 # join(head, tail) == p holds.
60 # The resulting head won't end in '/' unless it is the root.
65 while p
and p
[-1:] in '/\\':
66 slashes
= slashes
+ p
[-1]
74 head
, tail
= head
+ tail
, ''
76 while head
and head
[-1:] in '/\\':
77 slashes
= slashes
+ head
[-1]
84 # Split a path in root and extension.
85 # The extension is everything starting at the first dot in the last
86 # pathname component; the root is everything before that.
87 # It is always true that root + ext == p.
93 root
, ext
= root
+ ext
+ c
, ''
101 # Return the tail (basename) part of a path.
107 # Return the head (dirname) part of a path.
113 # Return the longest prefix of all list elements.
119 for i
in range(len(prefix
)):
120 if prefix
[:i
+1] <> item
[:i
+1]:
127 # Get size, mtime, atime of files.
129 def getsize(filename
):
130 """Return the size of a file, reported by os.stat()."""
131 st
= os
.stat(filename
)
132 return st
[stat
.ST_SIZE
]
134 def getmtime(filename
):
135 """Return the last modification time of a file, reported by os.stat()."""
136 st
= os
.stat(filename
)
137 return st
[stat
.ST_MTIME
]
139 def getatime(filename
):
140 """Return the last access time of a file, reported by os.stat()."""
141 st
= os
.stat(filename
)
142 return st
[stat
.ST_MTIME
]
145 # Is a path a symbolic link?
146 # This will always return false on systems where posix.lstat doesn't exist.
153 # This is false for dangling symbolic links.
163 # Is a path a dos directory?
164 # This follows symbolic links, so both islink() and isdir() can be true
172 return stat
.S_ISDIR(st
[stat
.ST_MODE
])
175 # Is a path a regular file?
176 # This follows symbolic links, so both islink() and isdir() can be true
184 return stat
.S_ISREG(st
[stat
.ST_MODE
])
187 # Is a path a mount point?
188 # XXX This degenerates in: 'is this the root?' on DOS
191 return isabs(splitdrive(path
)[1])
194 # Directory tree walk.
195 # For each directory under top (including top itself, but excluding
196 # '.' and '..'), func(arg, dirname, filenames) is called, where
197 # dirname is the name of the directory and filenames is the list
198 # files files (and subdirectories etc.) in the directory.
199 # The func may modify the filenames list, to implement a filter,
200 # or to impose a different order of visiting.
202 def walk(top
, func
, arg
):
204 names
= os
.listdir(top
)
207 func(arg
, top
, names
)
208 exceptions
= ('.', '..')
210 if name
not in exceptions
:
211 name
= join(top
, name
)
213 walk(name
, func
, arg
)
216 # Expand paths beginning with '~' or '~user'.
217 # '~' means $HOME; '~user' means that user's home directory.
218 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
219 # the path is returned unchanged (leaving error reporting to whatever
220 # function is called with the expanded path as argument).
221 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
222 # (A function should also be defined to do full *sh-style environment
223 # variable expansion.)
225 def expanduser(path
):
229 while i
< n
and path
[i
] not in '/\\':
232 if not os
.environ
.has_key('HOME'):
234 userhome
= os
.environ
['HOME']
237 return userhome
+ path
[i
:]
240 # Expand paths containing shell variable substitutions.
241 # The following rules apply:
242 # - no expansion within single quotes
243 # - no escape character, except for '$$' which is translated into '$'
244 # - ${varname} is accepted.
245 # - varnames can be made out of letters, digits and the character '_'
246 # XXX With COMMAND.COM you can use any characters in a variable name,
247 # XXX except '^|<>='.
249 varchars
= string
.letters
+ string
.digits
+ '_-'
251 def expandvars(path
):
257 while index
< pathlen
:
259 if c
== '\'': # no expansion within single quotes
260 path
= path
[index
+ 1:]
263 index
= string
.index(path
, '\'')
264 res
= res
+ '\'' + path
[:index
+ 1]
265 except string
.index_error
:
268 elif c
== '$': # variable or '$$'
269 if path
[index
+ 1:index
+ 2] == '$':
272 elif path
[index
+ 1:index
+ 2] == '{':
273 path
= path
[index
+2:]
276 index
= string
.index(path
, '}')
278 if os
.environ
.has_key(var
):
279 res
= res
+ os
.environ
[var
]
280 except string
.index_error
:
286 c
= path
[index
:index
+ 1]
287 while c
!= '' and c
in varchars
:
290 c
= path
[index
:index
+ 1]
291 if os
.environ
.has_key(var
):
292 res
= res
+ os
.environ
[var
]
301 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
302 # Also, components of the path are silently truncated to 8+3 notation.
305 path
= string
.replace(path
, "/", "\\")
306 prefix
, path
= splitdrive(path
)
307 while path
[:1] == os
.sep
:
308 prefix
= prefix
+ os
.sep
310 comps
= string
.splitfields(path
, os
.sep
)
312 while i
< len(comps
):
315 elif comps
[i
] == '..' and i
> 0 and \
316 comps
[i
-1] not in ('', '..'):
319 elif comps
[i
] == '' and i
> 0 and comps
[i
-1] <> '':
321 elif '.' in comps
[i
]:
322 comp
= string
.splitfields(comps
[i
], '.')
323 comps
[i
] = comp
[0][:8] + '.' + comp
[1][:3]
325 elif len(comps
[i
]) > 8:
326 comps
[i
] = comps
[i
][:8]
330 # If the path is now empty, substitute '.'
331 if not prefix
and not comps
:
333 return prefix
+ string
.joinfields(comps
, os
.sep
)
337 # Return an absolute path.
340 path
= join(os
.getcwd(), path
)
341 return normpath(path
)