2 # flp - Module to load fl forms from fd files
4 # Jack Jansen, December 1991
11 SPLITLINE
= '--------------------'
12 FORMLINE
= '=============== FORM ==============='
13 ENDLINE
= '=============================='
15 class error(Exception):
18 ##################################################################
19 # Part 1 - The parsing routines #
20 ##################################################################
23 # Externally visible function. Load form.
25 def parse_form(filename
, formname
):
26 forms
= checkcache(filename
)
28 forms
= parse_forms(filename
)
29 if forms
.has_key(formname
):
30 return forms
[formname
]
32 raise error
, 'No such form in fd file'
35 # Externally visible function. Load all forms.
37 def parse_forms(filename
):
38 forms
= checkcache(filename
)
39 if forms
is not None: return forms
40 fp
= _open_formfile(filename
)
41 nforms
= _parse_fd_header(fp
)
43 for i
in range(nforms
):
44 form
= _parse_fd_form(fp
, None)
45 forms
[form
[0].Name
] = form
46 writecache(filename
, forms
)
50 # Internal: see if a cached version of the file exists
53 _internal_cache
= {} # Used by frozen scripts only
54 def checkcache(filename
):
55 if _internal_cache
.has_key(filename
):
56 altforms
= _internal_cache
[filename
]
57 return _unpack_cache(altforms
)
59 fp
, filename
= _open_formfile2(filename
)
61 cachename
= filename
+ 'c'
63 fp
= open(cachename
, 'r')
65 #print 'flp: no cache file', cachename
68 if fp
.read(4) != MAGIC
:
69 print 'flp: bad magic word in cache file', cachename
71 cache_mtime
= rdlong(fp
)
72 file_mtime
= getmtime(filename
)
73 if cache_mtime
!= file_mtime
:
74 #print 'flp: outdated cache file', cachename
76 #print 'flp: valid cache file', cachename
77 altforms
= marshal
.load(fp
)
78 return _unpack_cache(altforms
)
82 def _unpack_cache(altforms
):
84 for name
in altforms
.keys():
85 altobj
, altlist
= altforms
[name
]
89 for altobj
in altlist
:
93 forms
[name
] = obj
, list
98 if len(s
) != 4: return None
99 a
, b
, c
, d
= s
[0], s
[1], s
[2], s
[3]
100 return ord(a
)<<24 |
ord(b
)<<16 |
ord(c
)<<8 |
ord(d
)
103 a
, b
, c
, d
= (x
>>24)&0xff, (x
>>16)&0xff, (x
>>8)&0xff, x
&0xff
104 fp
.write(chr(a
) + chr(b
) + chr(c
) + chr(d
))
106 def getmtime(filename
):
108 from stat
import ST_MTIME
110 return os
.stat(filename
)[ST_MTIME
]
115 # Internal: write cached version of the form (parsing is too slow!)
117 def writecache(filename
, forms
):
119 fp
, filename
= _open_formfile2(filename
)
121 cachename
= filename
+ 'c'
123 fp
= open(cachename
, 'w')
125 print 'flp: can\'t create cache file', cachename
127 fp
.write('\0\0\0\0') # Seek back and write MAGIC when done
128 wrlong(fp
, getmtime(filename
))
129 altforms
= _pack_cache(forms
)
130 marshal
.dump(altforms
, fp
)
134 #print 'flp: wrote cache file', cachename
137 # External: print some statements that set up the internal cache.
138 # This is for use with the "freeze" script. You should call
139 # flp.freeze(filename) for all forms used by the script, and collect
140 # the output on a file in a module file named "frozenforms.py". Then
141 # in the main program of the script import frozenforms.
142 # (Don't forget to take this out when using the unfrozen version of
145 def freeze(filename
):
146 forms
= parse_forms(filename
)
147 altforms
= _pack_cache(forms
)
149 print 'flp._internal_cache[', `filename`
, '] =', altforms
152 # Internal: create the data structure to be placed in the cache
154 def _pack_cache(forms
):
156 for name
in forms
.keys():
157 obj
, list = forms
[name
]
158 altobj
= obj
.__dict
__
160 for obj
in list: altlist
.append(obj
.__dict
__)
161 altforms
[name
] = altobj
, altlist
165 # Internal: Locate form file (using PYTHONPATH) and open file
167 def _open_formfile(filename
):
168 return _open_formfile2(filename
)[0]
170 def _open_formfile2(filename
):
171 if filename
[-3:] != '.fd':
172 filename
= filename
+ '.fd'
173 if filename
[0] == '/':
175 fp
= open(filename
,'r')
180 pn
= os
.path
.join(pc
, filename
)
188 raise error
, 'Cannot find forms file ' + filename
192 # Internal: parse the fd file header, return number of forms
194 def _parse_fd_header(file):
195 # First read the magic header line
196 datum
= _parse_1_line(file)
197 if datum
!= ('Magic', 12321):
198 raise error
, 'Not a forms definition file'
199 # Now skip until we know number of forms
201 datum
= _parse_1_line(file)
202 if type(datum
) == type(()) and datum
[0] == 'Numberofforms':
206 # Internal: parse fd form, or skip if name doesn't match.
207 # the special value None means 'always parse it'.
209 def _parse_fd_form(file, name
):
210 datum
= _parse_1_line(file)
211 if datum
!= FORMLINE
:
212 raise error
, 'Missing === FORM === line'
213 form
= _parse_object(file)
214 if form
.Name
== name
or name
is None:
216 for j
in range(form
.Numberofobjects
):
217 obj
= _parse_object(file)
221 for j
in range(form
.Numberofobjects
):
226 # Internal class: a convenient place to store object info fields
229 def add(self
, name
, value
):
230 self
.__dict
__[name
] = value
231 def make(self
, dict):
232 for name
in dict.keys():
233 self
.add(name
, dict[name
])
236 # Internal parsing routines.
238 def _parse_string(str):
240 s
= '\'' + str + '\''
250 def _parse_numlist(str):
251 slist
= string
.split(str)
254 nlist
.append(_parse_num(i
))
257 # This dictionary maps item names to parsing routines.
258 # If no routine is given '_parse_num' is default.
260 'Name': _parse_string
, \
261 'Box': _parse_numlist
, \
262 'Colors': _parse_numlist
, \
263 'Label': _parse_string
, \
264 'Name': _parse_string
, \
265 'Callback': _parse_string
, \
266 'Argument': _parse_string
}
268 # This function parses a line, and returns either
269 # a string or a tuple (name,value)
272 prog
= re
.compile('^([^:]*): *(.*)')
274 def _parse_line(line
):
275 match
= prog
.match(line
)
278 name
, value
= match
.group(1, 2)
280 name
= string
.join(string
.split(name
),'')
281 name
= string
.lower(name
)
282 name
= string
.capitalize(name
)
284 pf
= _parse_func
[name
]
291 line
= file.readline()
296 def _parse_1_line(file):
297 line
= _readline(file)
299 line
= _readline(file)
300 return _parse_line(line
)
302 def _skip_object(file):
304 while not line
in (SPLITLINE
, FORMLINE
, ENDLINE
):
306 line
= _readline(file)
310 def _parse_object(file):
314 datum
= _parse_1_line(file)
315 if datum
in (SPLITLINE
, FORMLINE
, ENDLINE
):
316 if datum
== FORMLINE
:
319 if type(datum
) is not type(()) or len(datum
) != 2:
320 raise error
, 'Parse error, illegal line in object: '+datum
321 obj
.add(datum
[0], datum
[1])
323 #################################################################
324 # Part 2 - High-level object/form creation routines #
325 #################################################################
328 # External - Create a form an link to an instance variable.
330 def create_full_form(inst
, (fdata
, odatalist
)):
331 form
= create_form(fdata
)
332 exec 'inst.'+fdata
.Name
+' = form\n'
333 for odata
in odatalist
:
334 create_object_instance(inst
, form
, odata
)
337 # External - Merge a form into an existing form in an instance
340 def merge_full_form(inst
, form
, (fdata
, odatalist
)):
341 exec 'inst.'+fdata
.Name
+' = form\n'
342 if odatalist
[0].Class
!= FL
.BOX
:
343 raise error
, 'merge_full_form() expects FL.BOX as first obj'
344 for odata
in odatalist
[1:]:
345 create_object_instance(inst
, form
, odata
)
348 #################################################################
349 # Part 3 - Low-level object/form creation routines #
350 #################################################################
353 # External Create_form - Create form from parameters
355 def create_form(fdata
):
357 return fl
.make_form(FL
.NO_BOX
, fdata
.Width
, fdata
.Height
)
360 # External create_object - Create an object. Make sure there are
361 # no callbacks. Returns the object created.
363 def create_object(form
, odata
):
364 obj
= _create_object(form
, odata
)
366 raise error
, 'Creating free object with callback'
369 # External create_object_instance - Create object in an instance.
371 def create_object_instance(inst
, form
, odata
):
372 obj
= _create_object(form
, odata
)
374 cbfunc
= eval('inst.'+odata
.Callback
)
375 obj
.set_call_back(cbfunc
, odata
.Argument
)
377 exec 'inst.' + odata
.Name
+ ' = obj\n'
379 # Internal _create_object: Create the object and fill options
381 def _create_object(form
, odata
):
382 crfunc
= _select_crfunc(form
, odata
.Class
)
383 obj
= crfunc(odata
.Type
, odata
.Box
[0], odata
.Box
[1], odata
.Box
[2], \
384 odata
.Box
[3], odata
.Label
)
385 if not odata
.Class
in (FL
.BEGIN_GROUP
, FL
.END_GROUP
):
386 obj
.boxtype
= odata
.Boxtype
387 obj
.col1
= odata
.Colors
[0]
388 obj
.col2
= odata
.Colors
[1]
389 obj
.align
= odata
.Alignment
390 obj
.lstyle
= odata
.Style
391 obj
.lsize
= odata
.Size
392 obj
.lcol
= odata
.Lcol
395 # Internal crfunc: helper function that returns correct create function
397 def _select_crfunc(fm
, cl
):
398 if cl
== FL
.BEGIN_GROUP
: return fm
.bgn_group
399 elif cl
== FL
.END_GROUP
: return fm
.end_group
400 elif cl
== FL
.BITMAP
: return fm
.add_bitmap
401 elif cl
== FL
.BOX
: return fm
.add_box
402 elif cl
== FL
.BROWSER
: return fm
.add_browser
403 elif cl
== FL
.BUTTON
: return fm
.add_button
404 elif cl
== FL
.CHART
: return fm
.add_chart
405 elif cl
== FL
.CHOICE
: return fm
.add_choice
406 elif cl
== FL
.CLOCK
: return fm
.add_clock
407 elif cl
== FL
.COUNTER
: return fm
.add_counter
408 elif cl
== FL
.DIAL
: return fm
.add_dial
409 elif cl
== FL
.FREE
: return fm
.add_free
410 elif cl
== FL
.INPUT
: return fm
.add_input
411 elif cl
== FL
.LIGHTBUTTON
: return fm
.add_lightbutton
412 elif cl
== FL
.MENU
: return fm
.add_menu
413 elif cl
== FL
.POSITIONER
: return fm
.add_positioner
414 elif cl
== FL
.ROUNDBUTTON
: return fm
.add_roundbutton
415 elif cl
== FL
.SLIDER
: return fm
.add_slider
416 elif cl
== FL
.VALSLIDER
: return fm
.add_valslider
417 elif cl
== FL
.TEXT
: return fm
.add_text
418 elif cl
== FL
.TIMER
: return fm
.add_timer
420 raise error
, 'Unknown object type: ' + `cl`
426 if len(sys
.argv
) == 2:
427 forms
= parse_forms(sys
.argv
[1])
429 print 'parse time:', 0.001*(t1
-t0
), 'sec.'
434 elif len(sys
.argv
) == 3:
435 form
= parse_form(sys
.argv
[1], sys
.argv
[2])
437 print 'parse time:', round(t1
-t0
, 3), 'sec.'
440 print 'Usage: test fdfile [form]'
442 def _printform(form
):
445 print 'Form ', f
.Name
, ', size: ', f
.Width
, f
.Height
, ' Nobj ', f
.Numberofobjects
447 print ' Obj ', i
.Name
, ' type ', i
.Class
, i
.Type
448 print ' Box ', i
.Box
, ' btype ', i
.Boxtype
449 print ' Label ', i
.Label
, ' size/style/col/align ', i
.Size
,i
.Style
, i
.Lcol
, i
.Alignment
450 print ' cols ', i
.Colors
451 print ' cback ', i
.Callback
, i
.Argument