diff options
-rw-r--r-- | Mac/Lib/preferences.py | 219 | ||||
-rw-r--r-- | Mac/Lib/pythonprefs.py | 122 |
2 files changed, 341 insertions, 0 deletions
diff --git a/Mac/Lib/preferences.py b/Mac/Lib/preferences.py new file mode 100644 index 0000000..810d9cc --- /dev/null +++ b/Mac/Lib/preferences.py @@ -0,0 +1,219 @@ +# +# General parser/loaders for preferences files and such +# +import Res +import macfs +import struct +import MACFS + +READ=1 +READWRITE=3 +Error = "Preferences.Error" + +debug = 0 + +class NullLoader: + def __init__(self, data=None): + self.data = data + + def load(self): + if self.data is None: + raise Error, "No default given" + return self.data + + def save(self, data): + raise Error, "Cannot save to default value" + + def delete(self, deep=0): + if debug: + print 'Attempt to delete default value' + raise Error, "Cannot delete default value" + +_defaultdefault = NullLoader() + +class ResLoader: + def __init__(self, filename, resid, resnum=None, resname=None, default=_defaultdefault): + self.filename = filename + self.fss = macfs.FSSpec(self.filename) + self.resid = resid + self.resnum = resnum + self.resname = resname + self.default = default + self.data = None + + def load(self): + oldrh = Res.CurResFile() + try: + rh = Res.FSpOpenResFile(self.fss, READ) + except Res.Error: + self.data = self.default.load() + return self.data + try: + if self.resname: + handle = Res.Get1NamedResource(self.resid, self.resname) + else: + handle = Res.Get1Resource(self.resid, self.resnum) + except Res.Error: + self.data = self.default.load() + else: + if debug: + print 'Loaded', (self.resid, self.resnum, self.resname), 'from', self.fss.as_pathname() + self.data = handle.data + Res.CloseResFile(rh) + Res.UseResFile(oldrh) + return self.data + + def save(self, data): + if self.data is None or self.data != data: + oldrh = Res.CurResFile() + rh = Res.FSpOpenResFile(self.fss, READWRITE) + try: + handle = Res.Get1Resource(self.resid, self.resnum) + except Res.Error: + handle = Res.Resource(data) + handle.AddResource(self.resid, self.resnum, '') + if debug: + print 'Added', (self.resid, self.resnum), 'to', self.fss.as_pathname() + else: + handle.data = data + handle.ChangedResource() + if debug: + print 'Changed', (self.resid, self.resnum), 'in', self.fss.as_pathname() + Res.CloseResFile(rh) + Res.UseResFile(oldrh) + + def delete(self, deep=0): + if debug: + print 'Deleting in', self.fss.as_pathname(), `self.data`, deep + oldrh = Res.CurResFile() + rh = Res.FSpOpenResFile(self.fss, READWRITE) + try: + handle = Res.Get1Resource(self.resid, self.resnum) + except Res.Error: + if deep: + if debug: print 'deep in', self.default + self.default.delete(1) + else: + handle.RemoveResource() + if debug: + print 'Deleted', (self.resid, self.resnum), 'from', self.fss.as_pathname() + self.data = None + Res.CloseResFile(rh) + Res.UseResFile(oldrh) + +class AnyResLoader: + def __init__(self, resid, resnum=None, resname=None, default=_defaultdefault): + self.resid = resid + self.resnum = resnum + self.resname = resname + self.default = default + self.data = None + + def load(self): + try: + if self.resname: + handle = Res.GetNamedResource(self.resid, self.resname) + else: + handle = Res.GetResource(self.resid, self.resnum) + except Res.Error: + self.data = self.default.load() + else: + self.data = handle.data + return self.data + + def save(self, data): + raise Error, "Cannot save AnyResLoader preferences" + + def delete(self, deep=0): + raise Error, "Cannot delete AnyResLoader preferences" + +class StructLoader: + def __init__(self, format, loader): + self.format = format + self.loader = loader + + def load(self): + data = self.loader.load() + return struct.unpack(self.format, data) + + def save(self, data): + data = apply(struct.pack, (self.format,)+data) + self.loader.save(data) + + def delete(self, deep=0): + self.loader.delete(deep) + +class PstringLoader: + def __init__(self, loader): + self.loader = loader + + def load(self): + data = self.loader.load() + len = ord(data[0]) + return data[1:1+len] + + def save(self, data): + if len(data) > 255: + raise Error, "String too big for pascal-style" + self.loader.save(chr(len(data))+data) + + def delete(self, deep=0): + self.loader.delete(deep) + +class VersionLoader(StructLoader): + def load(self): + while 1: + data = self.loader.load() + if debug: + print 'Versionloader:', `data` + try: + rv = struct.unpack(self.format, data) + rv = self.versioncheck(rv) + return rv + except (struct.error, Error): + self.delete(1) + + def versioncheck(self, data): + return data + +class StrListLoader: + def __init__(self, loader): + self.loader = loader + + def load(self): + data = self.loader.load() + num, = struct.unpack('h', data[:2]) + data = data[2:] + rv = [] + for i in range(num): + strlen = ord(data[0]) + if strlen < 0: strlen = strlen + 256 + str = data[1:strlen+1] + data = data[strlen+1:] + rv.append(str) + return rv + + def save(self, list): + rv = struct.pack('h', len(list)) + for str in list: + rv = rv + chr(len(str)) + str + self.loader.save(rv) + + def delete(self, deep=0): + self.loader.delete(deep) + +def preferencefile(filename, creator=None, type=None): + create = creator != None and type != None + vrefnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk, 'pref', create) + fss = macfs.FSSpec((vrefnum, dirid, filename)) + oldrf = Res.CurResFile() + if create: + try: + rh = Res.FSpOpenResFile(fss, READ) + except Res.Error: + Res.FSpCreateResFile(fss, creator, type, MACFS.smAllScripts) + else: + Res.CloseResFile(rh) + Res.UseResFile(oldrf) + return fss + diff --git a/Mac/Lib/pythonprefs.py b/Mac/Lib/pythonprefs.py new file mode 100644 index 0000000..1f9fd98 --- /dev/null +++ b/Mac/Lib/pythonprefs.py @@ -0,0 +1,122 @@ +from preferences import * + +# Names of Python resources +PREFNAME_NAME="PythonPreferenceFileName" + +# Resource IDs in the preferences file +PATH_ID = 128 +DIR_ID = 128 +POPT_ID = 128 +GUSI_ID = 10240 + +# Override IDs (in the applet) +OVERRIDE_PATH_ID = 129 +OVERRIDE_DIR_ID = 129 +OVERRIDE_POPT_ID = 129 +OVERRIDE_GUSI_ID = 10241 + +# version +CUR_VERSION=3 + +preffilename = PstringLoader(AnyResLoader('STR ', resname=PREFNAME_NAME)).load() +pref_fss = preferencefile(preffilename, 'Pyth', 'pref') + +class PoptLoader(VersionLoader): + def __init__(self, loader): + VersionLoader.__init__(self, "bbbbbbbbbb", loader) + + def versioncheck(self, data): + if data[0] == CUR_VERSION: + return data + print 'old resource' + raise Error, "old resource" + +class GusiLoader: + def __init__(self, loader): + self.loader = loader + self.data = None + + def load(self): + self.data = self.loader.load() + while self.data[10:14] != '0181': + self.loader.delete(1) + self.loader.load() + tp = self.data[0:4] + cr = self.data[4:8] + flags = ord(self.data[9]) + delay = ((flags & 0x20) == 0x20) + return cr, tp, delay + + def save(self, (cr, tp, delay)): + flags = ord(self.data[9]) + if delay: + flags = flags | 0x20 + else: + flags = flags & ~0x20 + newdata = tp + cr + self.data[8] + chr(flags) + self.data[10:] + self.loader.save(newdata) + +popt_default_default = NullLoader(chr(CUR_VERSION) + 8*'\0') +popt_default = AnyResLoader('Popt', POPT_ID, default=popt_default_default) +popt_loader = ResLoader(pref_fss, 'Popt', POPT_ID, default=popt_default) +popt = PoptLoader(popt_loader) + +dir_default = AnyResLoader('alis', DIR_ID) +dir = ResLoader(pref_fss, 'alis', DIR_ID, default=dir_default) + +gusi_default = AnyResLoader('GU\267I', GUSI_ID) +gusi_loader = ResLoader(pref_fss, 'GU\267I', GUSI_ID, default=gusi_default) +gusi = GusiLoader(gusi_loader) + +path_default = AnyResLoader('STR#', PATH_ID) +path_loader = ResLoader(pref_fss, 'STR#', PATH_ID, default=path_default) +path = StrListLoader(path_loader) + +class PythonOptions: + def __init__(self, popt=popt, dir=dir, gusi=gusi, path=path): + self.popt = popt + self.dir = dir + self.gusi = gusi + self.path = path + + def load(self): + dict = {} + dict['path'] = self.path.load() + diralias = self.dir.load() + dirfss, dummy = macfs.RawAlias(diralias).Resolve() + dict['dir'] = dirfss + dict['creator'], dict['type'], dict['delayconsole'] = self.gusi.load() + flags = self.popt.load() + dict['version'], dict['inspect'], dict['verbose'], dict['optimize'], \ + dict['unbuffered'], dict['debugging'], dict['keepopen'], dict['keeperror'], \ + dict['nointopt'], dict['noargs'] = flags + return dict + + def save(self, dict): + self.path.save(dict['path']) + diralias = macfs.FSSpec(dict['dir']).NewAlias().data + self.dir.save(diralias) + self.gusi.save((dict['creator'], dict['type'], dict['delayconsole'])) + flags = dict['version'], dict['inspect'], dict['verbose'], dict['optimize'], \ + dict['unbuffered'], dict['debugging'], dict['keepopen'], dict['keeperror'], \ + dict['nointopt'], dict['noargs'] + self.popt.save(flags) + +def AppletOptions(file): + fss = macfs.FSSpec(file) + a_popt = PoptLoader(ResLoader(fss, 'Popt', OVERRIDE_POPT_ID, default=popt_loader)) + a_dir = ResLoader(fss, 'alis', OVERRIDE_DIR_ID, default=dir) + a_gusi = ResLoader(fss, 'GU\267I', OVERRIDE_GUSI_ID, default=gusi_loader) + a_path = StrListLoader(fss, 'STR#', OVERRIDE_PATH_ID, default=path_loader) + return PythonOptions(a_popt, a_dir, a_gusi, a_path) + +def _test(): + import preferences + preferences.debug = 1 + dict = PythonOptions().load() + for k in dict.keys(): + print k, '\t', dict[k] + +if __name__ == '__main__': + _test() + |