home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / NTPATH.PY < prev    next >
Encoding:
Text File  |  2000-09-28  |  12.8 KB  |  421 lines

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