The 0.5 release happened on 2/15, not on 2/14. :-)
[python/dscho.git] / Mac / Lib / preferences.py
blobb1e094818e1e738dbbe9a947618123aaeba009c1
2 # General parser/loaders for preferences files and such
4 import Res
5 import macfs
6 import struct
7 import MACFS
9 READ=1
10 READWRITE=3
11 Error = "Preferences.Error"
13 debug = 0
15 class NullLoader:
16 def __init__(self, data=None):
17 self.data = data
19 def load(self):
20 if self.data is None:
21 raise Error, "No default given"
22 return self.data
24 def save(self, data):
25 raise Error, "Cannot save to default value"
27 def delete(self, deep=0):
28 if debug:
29 print 'Attempt to delete default value'
30 raise Error, "Cannot delete default value"
32 _defaultdefault = NullLoader()
34 class ResLoader:
35 def __init__(self, filename, resid, resnum=None, resname=None, default=_defaultdefault):
36 self.filename = filename
37 self.fss = macfs.FSSpec(self.filename)
38 self.resid = resid
39 self.resnum = resnum
40 self.resname = resname
41 self.default = default
42 self.data = None
44 def load(self):
45 oldrh = Res.CurResFile()
46 try:
47 rh = Res.FSpOpenResFile(self.fss, READ)
48 except Res.Error:
49 self.data = self.default.load()
50 return self.data
51 try:
52 if self.resname:
53 handle = Res.Get1NamedResource(self.resid, self.resname)
54 else:
55 handle = Res.Get1Resource(self.resid, self.resnum)
56 except Res.Error:
57 self.data = self.default.load()
58 else:
59 if debug:
60 print 'Loaded', (self.resid, self.resnum, self.resname), 'from', self.fss.as_pathname()
61 self.data = handle.data
62 Res.CloseResFile(rh)
63 Res.UseResFile(oldrh)
64 return self.data
66 def save(self, data):
67 if self.data is None or self.data != data:
68 oldrh = Res.CurResFile()
69 rh = Res.FSpOpenResFile(self.fss, READWRITE)
70 try:
71 handle = Res.Get1Resource(self.resid, self.resnum)
72 except Res.Error:
73 handle = Res.Resource(data)
74 handle.AddResource(self.resid, self.resnum, '')
75 if debug:
76 print 'Added', (self.resid, self.resnum), 'to', self.fss.as_pathname()
77 else:
78 handle.data = data
79 handle.ChangedResource()
80 if debug:
81 print 'Changed', (self.resid, self.resnum), 'in', self.fss.as_pathname()
82 Res.CloseResFile(rh)
83 Res.UseResFile(oldrh)
85 def delete(self, deep=0):
86 if debug:
87 print 'Deleting in', self.fss.as_pathname(), `self.data`, deep
88 oldrh = Res.CurResFile()
89 rh = Res.FSpOpenResFile(self.fss, READWRITE)
90 try:
91 handle = Res.Get1Resource(self.resid, self.resnum)
92 except Res.Error:
93 if deep:
94 if debug: print 'deep in', self.default
95 self.default.delete(1)
96 else:
97 handle.RemoveResource()
98 if debug:
99 print 'Deleted', (self.resid, self.resnum), 'from', self.fss.as_pathname()
100 self.data = None
101 Res.CloseResFile(rh)
102 Res.UseResFile(oldrh)
104 class AnyResLoader:
105 def __init__(self, resid, resnum=None, resname=None, default=_defaultdefault):
106 self.resid = resid
107 self.resnum = resnum
108 self.resname = resname
109 self.default = default
110 self.data = None
112 def load(self):
113 try:
114 if self.resname:
115 handle = Res.GetNamedResource(self.resid, self.resname)
116 else:
117 handle = Res.GetResource(self.resid, self.resnum)
118 except Res.Error:
119 self.data = self.default.load()
120 else:
121 self.data = handle.data
122 return self.data
124 def save(self, data):
125 raise Error, "Cannot save AnyResLoader preferences"
127 def delete(self, deep=0):
128 raise Error, "Cannot delete AnyResLoader preferences"
130 class StructLoader:
131 def __init__(self, format, loader):
132 self.format = format
133 self.loader = loader
135 def load(self):
136 data = self.loader.load()
137 return struct.unpack(self.format, data)
139 def save(self, data):
140 data = apply(struct.pack, (self.format,)+data)
141 self.loader.save(data)
143 def delete(self, deep=0):
144 self.loader.delete(deep)
146 class PstringLoader:
147 def __init__(self, loader):
148 self.loader = loader
150 def load(self):
151 data = self.loader.load()
152 len = ord(data[0])
153 return data[1:1+len]
155 def save(self, data):
156 if len(data) > 255:
157 raise Error, "String too big for pascal-style"
158 self.loader.save(chr(len(data))+data)
160 def delete(self, deep=0):
161 self.loader.delete(deep)
163 class VersionLoader(StructLoader):
164 def load(self):
165 while 1:
166 data = self.loader.load()
167 if debug:
168 print 'Versionloader:', `data`
169 try:
170 rv = struct.unpack(self.format, data)
171 rv = self.versioncheck(rv)
172 return rv
173 except (struct.error, Error):
174 self.delete(1)
176 def versioncheck(self, data):
177 return data
179 class StrListLoader:
180 def __init__(self, loader):
181 self.loader = loader
183 def load(self):
184 data = self.loader.load()
185 num, = struct.unpack('h', data[:2])
186 data = data[2:]
187 rv = []
188 for i in range(num):
189 strlen = ord(data[0])
190 if strlen < 0: strlen = strlen + 256
191 str = data[1:strlen+1]
192 data = data[strlen+1:]
193 rv.append(str)
194 return rv
196 def save(self, list):
197 rv = struct.pack('h', len(list))
198 for str in list:
199 rv = rv + chr(len(str)) + str
200 self.loader.save(rv)
202 def delete(self, deep=0):
203 self.loader.delete(deep)
205 def preferencefile(filename, creator=None, type=None):
206 create = creator != None and type != None
207 vrefnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk, 'pref', create)
208 fss = macfs.FSSpec((vrefnum, dirid, ":Python:" + filename))
209 oldrf = Res.CurResFile()
210 if create:
211 try:
212 rh = Res.FSpOpenResFile(fss, READ)
213 except Res.Error:
214 Res.FSpCreateResFile(fss, creator, type, MACFS.smAllScripts)
215 else:
216 Res.CloseResFile(rh)
217 Res.UseResFile(oldrf)
218 return fss