home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Python 1.1 / Lib / irix5 / flp.py < prev    next >
Encoding:
Python Source  |  1994-08-23  |  12.0 KB  |  456 lines  |  [TEXT/R*ch]

  1. #
  2. # flp - Module to load fl forms from fd files
  3. #
  4. # Jack Jansen, December 1991
  5. #
  6. import string
  7. import os
  8. import sys
  9. import FL
  10.  
  11. SPLITLINE = '--------------------'
  12. FORMLINE = '=============== FORM ==============='
  13. ENDLINE = '=============================='
  14.  
  15. error = 'flp.error'
  16.  
  17. ##################################################################
  18. #    Part 1 - The parsing routines                               #
  19. ##################################################################
  20.  
  21. #
  22. # Externally visible function. Load form.
  23. #
  24. def parse_form(filename, formname):
  25.     forms = checkcache(filename)
  26.     if forms is None:
  27.     forms = parse_forms(filename)
  28.     if forms.has_key(formname):
  29.     return forms[formname]
  30.     else:
  31.     raise error, 'No such form in fd file'
  32.  
  33. #
  34. # Externally visible function. Load all forms.
  35. #
  36. def parse_forms(filename):
  37.     forms = checkcache(filename)
  38.     if forms != None: return forms
  39.     fp = _open_formfile(filename)
  40.     nforms = _parse_fd_header(fp)
  41.     forms = {}
  42.     for i in range(nforms):
  43.     form = _parse_fd_form(fp, None)
  44.     forms[form[0].Name] = form
  45.     writecache(filename, forms)
  46.     return forms
  47.  
  48. #
  49. # Internal: see if a cached version of the file exists
  50. #
  51. MAGIC = '.fdc'
  52. _internal_cache = {}            # Used by frozen scripts only
  53. def checkcache(filename):
  54.     if _internal_cache.has_key(filename):
  55.     altforms = _internal_cache[filename]
  56.     return _unpack_cache(altforms)
  57.     import marshal
  58.     fp, filename = _open_formfile2(filename)
  59.     fp.close()
  60.     cachename = filename + 'c'
  61.     try:
  62.     fp = open(cachename, 'r')
  63.     except IOError:
  64.     #print 'flp: no cache file', cachename
  65.     return None
  66.     try:
  67.     if fp.read(4) != MAGIC:
  68.         print 'flp: bad magic word in cache file', cachename
  69.         return None
  70.     cache_mtime = rdlong(fp)
  71.     file_mtime = getmtime(filename)
  72.     if cache_mtime != file_mtime:
  73.         #print 'flp: outdated cache file', cachename
  74.         return None
  75.     #print 'flp: valid cache file', cachename
  76.     altforms = marshal.load(fp)
  77.     return _unpack_cache(altforms)
  78.     finally:
  79.     fp.close()
  80.  
  81. def _unpack_cache(altforms):
  82.     forms = {}
  83.     for name in altforms.keys():
  84.         altobj, altlist = altforms[name]
  85.         obj = _newobj()
  86.         obj.make(altobj)
  87.         list = []
  88.         for altobj in altlist:
  89.         nobj = _newobj()
  90.         nobj.make(altobj)
  91.         list.append(nobj)
  92.         forms[name] = obj, list
  93.     return forms
  94.  
  95. def rdlong(fp):
  96.     s = fp.read(4)
  97.     if len(s) != 4: return None
  98.     a, b, c, d = s[0], s[1], s[2], s[3]
  99.     return ord(a)<<24 | ord(b)<<16 | ord(c)<<8 | ord(d)
  100.  
  101. def wrlong(fp, x):
  102.     a, b, c, d = (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff
  103.     fp.write(chr(a) + chr(b) + chr(c) + chr(d))
  104.  
  105. def getmtime(filename):
  106.     import os
  107.     from stat import ST_MTIME
  108.     try:
  109.     return os.stat(filename)[ST_MTIME]
  110.     except os.error:
  111.     return None
  112.  
  113. #
  114. # Internal: write cached version of the form (parsing is too slow!)
  115. #
  116. def writecache(filename, forms):
  117.     import marshal
  118.     fp, filename = _open_formfile2(filename)
  119.     fp.close()
  120.     cachename = filename + 'c'
  121.     try:
  122.     fp = open(cachename, 'w')
  123.     except IOError:
  124.     print 'flp: can\'t create cache file', cachename
  125.     return # Never mind
  126.     fp.write('\0\0\0\0') # Seek back and write MAGIC when done
  127.     wrlong(fp, getmtime(filename))
  128.     altforms = _pack_cache(forms)
  129.     marshal.dump(altforms, fp)
  130.     fp.seek(0)
  131.     fp.write(MAGIC)
  132.     fp.close()
  133.     #print 'flp: wrote cache file', cachename
  134.  
  135. #
  136. # External: print some statements that set up the internal cache.
  137. # This is for use with the "freeze" script.  You should call
  138. # flp.freeze(filename) for all forms used by the script, and collect
  139. # the output on a file in a module file named "frozenforms.py".  Then
  140. # in the main program of the script import frozenforms.
  141. # (Don't forget to take this out when using the unfrozen version of
  142. # the script!)
  143. #
  144. def freeze(filename):
  145.     forms = parse_forms(filename)
  146.     altforms = _pack_cache(forms)
  147.     print 'import flp'
  148.     print 'flp._internal_cache[', `filename`, '] =', altforms
  149.  
  150. #
  151. # Internal: create the data structure to be placed in the cache
  152. #
  153. def _pack_cache(forms):
  154.     altforms = {}
  155.     for name in forms.keys():
  156.     obj, list = forms[name]
  157.     altobj = obj.__dict__
  158.     altlist = []
  159.     for obj in list: altlist.append(obj.__dict__)
  160.     altforms[name] = altobj, altlist
  161.     return altforms
  162.  
  163. #
  164. # Internal: Locate form file (using PYTHONPATH) and open file
  165. #
  166. def _open_formfile(filename):
  167.     return _open_formfile2(filename)[0]
  168.  
  169. def _open_formfile2(filename):
  170.     if filename[-3:] <> '.fd':
  171.     filename = filename + '.fd'
  172.     if filename[0] == '/':
  173.     try:
  174.         fp = open(filename,'r')
  175.     except IOError:
  176.         fp = None
  177.     else:
  178.     for pc in sys.path:
  179.         pn = os.path.join(pc, filename)
  180.         try:
  181.         fp = open(pn, 'r')
  182.         filename = pn
  183.         break
  184.         except IOError:
  185.         fp = None
  186.     if fp == None:
  187.     raise error, 'Cannot find forms file ' + filename
  188.     return fp, filename
  189.  
  190. #
  191. # Internal: parse the fd file header, return number of forms
  192. #
  193. def _parse_fd_header(file):
  194.     # First read the magic header line
  195.     datum = _parse_1_line(file)
  196.     if datum <> ('Magic', 12321):
  197.     raise error, 'Not a forms definition file'
  198.     # Now skip until we know number of forms
  199.     while 1:
  200.     datum = _parse_1_line(file)
  201.     if type(datum) == type(()) and datum[0] == 'Numberofforms':
  202.         break
  203.     return datum[1]
  204. #
  205. # Internal: parse fd form, or skip if name doesn't match.
  206. # the special value None means 'allways parse it'.
  207. #
  208. def _parse_fd_form(file, name):
  209.     datum = _parse_1_line(file)
  210.     if datum <> FORMLINE:
  211.     raise error, 'Missing === FORM === line'
  212.     form = _parse_object(file)
  213.     if form.Name == name or name == None:
  214.     objs = []
  215.     for j in range(form.Numberofobjects):
  216.         obj = _parse_object(file)
  217.         objs.append(obj)
  218.     return (form, objs)
  219.     else:
  220.     for j in range(form.Numberofobjects):
  221.         _skip_object(file)
  222.     return None
  223.  
  224. #
  225. # Internal class: a convient place to store object info fields
  226. #
  227. class _newobj:
  228.     def add(self, name, value):
  229.     self.__dict__[name] = value
  230.     def make(self, dict):
  231.     for name in dict.keys():
  232.         self.add(name, dict[name])
  233.  
  234. #
  235. # Internal parsing routines.
  236. #
  237. def _parse_string(str):
  238.     if '\\' in str:
  239.     s = '\'' + str + '\''
  240.     try:
  241.         return eval(s)
  242.     except:
  243.         pass
  244.     return str
  245.  
  246. def _parse_num(str):
  247.     return eval(str)
  248.  
  249. def _parse_numlist(str):
  250.     slist = string.split(str)
  251.     nlist = []
  252.     for i in slist:
  253.     nlist.append(_parse_num(i))
  254.     return nlist
  255.  
  256. # This dictionary maps item names to parsing routines.
  257. # If no routine is given '_parse_num' is default.
  258. _parse_func = { \
  259.     'Name':        _parse_string, \
  260.     'Box':        _parse_numlist, \
  261.     'Colors':    _parse_numlist, \
  262.     'Label':    _parse_string, \
  263.     'Name':        _parse_string, \
  264.     'Callback':    _parse_string, \
  265.     'Argument':    _parse_string }
  266.  
  267. # This function parses a line, and returns either
  268. # a string or a tuple (name,value)
  269.  
  270. import regex
  271. prog = regex.compile('^\([^:]*\): *\(.*\)')
  272.  
  273. def _parse_line(line):
  274.     if prog.match(line) < 0:
  275.     return line
  276.     a = prog.regs
  277.     name = line[:a[1][1]]
  278.     if name[0] == 'N':
  279.         name = string.joinfields(string.split(name),'')
  280.         name = string.lower(name)
  281.     name = string.upper(name[0]) + name[1:]
  282.     value = line[a[2][0]:]
  283.     try:
  284.     pf = _parse_func[name]
  285.     except KeyError:
  286.     pf = _parse_num
  287.     value = pf(value)
  288.     return (name, value)
  289.  
  290. def _readline(file):
  291.     line = file.readline()
  292.     if not line:
  293.         raise EOFError
  294.     return line[:-1]
  295.     
  296. def _parse_1_line(file):
  297.     line = _readline(file)
  298.     while line == '':
  299.     line = _readline(file)
  300.     return _parse_line(line)
  301.  
  302. def _skip_object(file):
  303.     line = ''
  304.     while not line in (SPLITLINE, FORMLINE, ENDLINE):
  305.     pos = file.tell()
  306.     line = _readline(file)
  307.     if line == FORMLINE:
  308.     file.seek(pos)
  309.  
  310. def _parse_object(file):
  311.     obj = _newobj()
  312.     while 1:
  313.     pos = file.tell()
  314.     datum = _parse_1_line(file)
  315.     if datum in (SPLITLINE, FORMLINE, ENDLINE):
  316.         if datum == FORMLINE:
  317.         file.seek(pos)
  318.         return obj
  319.     if type(datum) <> type(()) or len(datum) <> 2:
  320.         raise error, 'Parse error, illegal line in object: '+datum
  321.     obj.add(datum[0], datum[1])
  322.  
  323. #################################################################
  324. #   Part 2 - High-level object/form creation routines            #
  325. #################################################################
  326.  
  327. #
  328. # External - Create a form an link to an instance variable.
  329. #
  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)
  335.  
  336. #
  337. # External - Merge a form into an existing form in an instance
  338. # variable.
  339. #
  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)
  346.  
  347.  
  348. #################################################################
  349. #   Part 3 - Low-level object/form creation routines            #
  350. #################################################################
  351.  
  352. #
  353. # External Create_form - Create form from parameters
  354. #
  355. def create_form(fdata):
  356.     import fl
  357.     return fl.make_form(FL.NO_BOX, fdata.Width, fdata.Height)
  358.  
  359. #
  360. # External create_object - Create an object. Make sure there are
  361. # no callbacks. Returns the object created.
  362. #
  363. def create_object(form, odata):
  364.     obj = _create_object(form, odata)
  365.     if odata.Callback:
  366.     raise error, 'Creating free object with callback'
  367.     return obj
  368. #
  369. # External create_object_instance - Create object in an instance.
  370. #
  371. def create_object_instance(inst, form, odata):
  372.     obj = _create_object(form, odata)
  373.     if odata.Callback:
  374.     cbfunc = eval('inst.'+odata.Callback)
  375.     obj.set_call_back(cbfunc, odata.Argument)
  376.     if odata.Name:
  377.     exec('inst.' + odata.Name + ' = obj\n')
  378. #
  379. # Internal _create_object: Create the object and fill options
  380. #
  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
  393.     return obj
  394. #
  395. # Internal crfunc: helper function that returns correct create function
  396. #
  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
  419.     else:
  420.     raise error, 'Unknown object type: ' + `cl`
  421.  
  422.  
  423. def test():
  424.     import time
  425.     t0 = time.time()
  426.     if len(sys.argv) == 2:
  427.     forms = parse_forms(sys.argv[1])
  428.     t1 = time.time()
  429.     print 'parse time:', 0.001*(t1-t0), 'sec.'
  430.     keys = forms.keys()
  431.     keys.sort()
  432.     for i in keys:
  433.         _printform(forms[i])
  434.     elif len(sys.argv) == 3:
  435.     form = parse_form(sys.argv[1], sys.argv[2])
  436.     t1 = time.time()
  437.     print 'parse time:', round(t1-t0, 3), 'sec.'
  438.     _printform(form)
  439.     else:
  440.     print 'Usage: test fdfile [form]'
  441.  
  442. def _printform(form):
  443.     f = form[0]
  444.     objs = form[1]
  445.     print 'Form ', f.Name, ', size: ', f.Width, f.Height, ' Nobj ', f.Numberofobjects
  446.     for i in objs:
  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
  452.  
  453. # Local variables:
  454. # py-indent-offset: 4
  455. # end:
  456.