home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Lib / sgi / flp.py < prev    next >
Text File  |  1994-02-18  |  13KB  |  466 lines

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