diff options
Diffstat (limited to 'Lib/plat-riscos/riscospath.py')
-rw-r--r-- | Lib/plat-riscos/riscospath.py | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/Lib/plat-riscos/riscospath.py b/Lib/plat-riscos/riscospath.py new file mode 100644 index 0000000..b83c632 --- /dev/null +++ b/Lib/plat-riscos/riscospath.py @@ -0,0 +1,354 @@ +# Module 'riscospath' -- common operations on RISC OS pathnames. + +# contributed by Andrew Clover ( andrew@oaktree.co.uk ) + +# The "os.path" name is an alias for this module on RISC OS systems; +# on other systems (e.g. Mac, Windows), os.path provides the same +# operations in a manner specific to that platform, and is an alias +# to another module (e.g. macpath, ntpath). + +""" +Instead of importing this module directly, import os and refer to this module +as os.path. +""" + + +# Imports - make an error-generating swi object if the swi module is not +# available (ie. we are not running on RISC OS Python) + +import os, stat, string + +try: + import swi +except ImportError: + class _swi: + def swi(*a): + raise AttributeError, 'This function only available under RISC OS' + block= swi + swi= _swi() + +[_false, _true]= range(2) + +_roots= ['$', '&', '%', '@', '\\'] + + +# _allowMOSFSNames +# After importing riscospath, set _allowMOSFSNames true if you want the module +# to understand the "-SomeFS-" notation left over from the old BBC Master MOS, +# as well as the standard "SomeFS:" notation. Set this to be fully backwards +# compatible but remember that "-SomeFS-" can also be a perfectly valid file +# name so care must be taken when splitting and joining paths. + +_allowMOSFSNames= _false + + +## Path manipulation, RISC OS stylee. + +def _split(p): + """ +split filing system name (including special field) and drive specifier from rest +of path. This is needed by many riscospath functions. +""" + dash= _allowMOSFSNames and p[:1]=='-' + if dash: + q= string.find(p, '-', 1)+1 + else: + if p[:1]==':': + q= 0 + else: + q= string.find(p, ':')+1 # q= index of start of non-FS portion of path + s= string.find(p, '#') + if s==-1 or s>q: + s= q # find end of main FS name, not including special field + else: + for c in p[dash:s]: + if c not in string.letters: + q= 0 + break # disallow invalid non-special-field characters in FS name + r= q + if p[q:q+1]==':': + r= string.find(p, '.', q+1)+1 + if r==0: + r= len(p) # find end of drive name (if any) following FS name (if any) + return (p[:q], p[q:r], p[r:]) + + +def normcase(p): + """ +Normalize the case of a pathname. This converts to lowercase as the native RISC +OS filesystems are case-insensitive. However, not all filesystems have to be, +and there's no simple way to find out what type an FS is argh. +""" + return string.lower(p) + + +def isabs(p): + """ +Return whether a path is absolute. Under RISC OS, a file system specifier does +not make a path absolute, but a drive name or number does, and so does using the +symbol for root, URD, library, CSD or PSD. This means it is perfectly possible +to have an "absolute" URL dependent on the current working directory, and +equally you can have a "relative" URL that's on a completely different device to +the current one argh. +""" + (fs, drive, path)= _split(p) + return drive!='' or path[:1] in _roots + + +def join(a, *p): + """ +Join path elements with the directory separator, replacing the entire path when +an absolute or FS-changing path part is found. +""" + j= a + for b in p: + (fs, drive, path)= _split(b) + if fs!='' or drive!='' or path[:1] in _roots: + j= b + else: + j= j+'.'+b + return j + + +def split(p): + """ +Split a path in head (everything up to the last '.') and tail (the rest). FS +name must still be dealt with separately since special field may contain '.'. +""" + (fs, drive, path)= _split(p) + q= string.rfind(path, '.') + if q!=-1: + return (fs+drive+path[:q], path[q+1:]) + return ('', p) + + +def splitext(p): + """ +Split a path in root and extension. This assumes the 'using slash for dot and +dot for slash with foreign files' convention common in RISC OS is in force. +""" + (tail, head)= split(p) + if '/' in head: + q= len(head)-string.rfind(head, '/') + return (p[:-q], p[-q:]) + return (p, '') + + +def splitdrive(p): + """ +Split a pathname into a drive specification (including FS name) and the rest of +the path. The terminating dot of the drive name is included in the drive +specification. +""" + (fs, drive, path)= _split(p) + return (fs+drive, p) + + +def basename(p): + """ +Return the tail (basename) part of a path. +""" + return split(p)[1] + + +def dirname(p): + """ +Return the head (dirname) part of a path. +""" + return split(p)[0] + + +def commonprefix(ps): + """ +Return the longest prefix of all list elements. Purely string-based; does not +separate any path parts. Why am I in os.path? +""" + if len(ps)==0: + return '' + prefix= ps[0] + for p in ps[1:]: + prefix= prefix[:len(p)] + for i in range(len(prefix)): + if prefix[i] <> p[i]: + prefix= prefix[:i] + if i==0: + return '' + break + return prefix + + +## File access functions. Why are we in os.path? + +def getsize(p): + """ +Return the size of a file, reported by os.stat(). +""" + st= os.stat(p) + return st[stat.ST_SIZE] + + +def getmtime(p): + """ +Return the last modification time of a file, reported by os.stat(). +""" + st = os.stat(p) + return st[stat.ST_MTIME] + +getatime= getmtime + + +# RISC OS-specific file access functions + +def exists(p): + """ +Test whether a path exists. +""" + return swi.swi('OS_File', '5s;i', p)!=0 + + +def isdir(p): + """ +Is a path a directory? Includes image files. +""" + return swi.swi('OS_File', '5s;i', p) in [2, 3] + + +def isfile(p): + """ +Test whether a path is a file, including image files. +""" + return swi.swi('OS_File', '5s;i', p) in [1, 3] + + +def islink(p): + """ +RISC OS has no links or mounts. +""" + return _false + +ismount= islink + + +# Same-file testing. + +# samefile works on filename comparison since there is no ST_DEV and ST_INO is +# not reliably unique (esp. directories). First it has to normalise the +# pathnames, which it can do 'properly' using OS_FSControl since samefile can +# assume it's running on RISC OS (unlike normpath). + +def samefile(fa, fb): + """ +Test whether two pathnames reference the same actual file. +""" + l= 512 + b= swi.block(l) + swi.swi('OS_FSControl', 'isb..i', 37, fa, b, l) + fa= b.ctrlstring() + swi.swi('OS_FSControl', 'isb..i', 37, fb, b, l) + fb= b.ctrlstring() + return fa==fb + + +def sameopenfile(a, b): + """ +Test whether two open file objects reference the same file. +""" + return os.fstat(a)[stat.ST_INO]==os.fstat(b)[stat.ST_INO] + + +## Path canonicalisation + +# 'user directory' is taken as meaning the User Root Directory, which is in +# practice never used, for anything. + +def expanduser(p): + (fs, drive, path)= _split(p) + l= 512 + b= swi.block(l) + + if path[:1]!='@': + return p + if fs=='': + fsno= swi.swi('OS_Args', '00;i') + swi.swi('OS_FSControl', 'iibi', 33, fsno, b, l) + fsname= b.ctrlstring() + else: + if fs[:1]=='-': + fsname= fs[1:-1] + else: + fsname= fs[:-1] + fsname= string.split(fsname, '#', 1)[0] # remove special field from fs + x= swi.swi('OS_FSControl', 'ib2s.i;.....i', 54, b, fsname, l) + if x<l: + urd= b.tostring(0, l-x-1) + else: # no URD! try CSD + x= swi.swi('OS_FSControl', 'ib0s.i;.....i', 54, b, fsname, l) + if x<l: + urd= b.tostring(0, l-x-1) + else: # no CSD! use root + urd= '$' + return fsname+':'+urd+path[1:] + +# Environment variables are in angle brackets. + +def expandvars(p): + """ +Expand environment variables using OS_GSTrans. +""" + l= 512 + b= swi.block(l) + return b.tostring(0, swi.swi('OS_GSTrans', 'sbi;..i', p, b, l)) + + +# Return an absolute path. + +def abspath(p): + return normpath(join(os.getcwd(), p)) + + +# Normalize a path. Only special path element under RISC OS is "^" for "..". + +def normpath(p): + """ +Normalize path, eliminating up-directory ^s. +""" + (fs, drive, path)= _split(p) + rhs= '' + ups= 0 + while path!='': + (path, el)= split(path) + if el=='^': + ups= ups+1 + else: + if ups>0: + ups= ups-1 + else: + if rhs=='': + rhs= el + else: + rhs= el+'.'+rhs + while ups>0: + ups= ups-1 + rhs= '^.'+rhs + return fs+drive+rhs + + +# Directory tree walk. +# Independent of host system. Why am I in os.path? + +def walk(top, func, arg): + """ +walk(top,func,args) calls func(arg, d, files) for each directory "d" in the tree +rooted at "top" (including "top" itself). "files" is a list of all the files and +subdirs in directory "d". +""" + try: + names= os.listdir(top) + except os.error: + return + func(arg, top, names) + for name in names: + name= join(top, name) + if isdir(name) and not islink(name): + walk(name, func, arg) + |