summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Mac/Lib/preferences.py219
-rw-r--r--Mac/Lib/pythonprefs.py122
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()
+