| 1 | #
|
|---|
| 2 | # flp - Module to load fl forms from fd files
|
|---|
| 3 | #
|
|---|
| 4 | # Jack Jansen, December 1991
|
|---|
| 5 | #
|
|---|
| 6 | import os
|
|---|
| 7 | import sys
|
|---|
| 8 | import FL
|
|---|
| 9 |
|
|---|
| 10 | SPLITLINE = '--------------------'
|
|---|
| 11 | FORMLINE = '=============== FORM ==============='
|
|---|
| 12 | ENDLINE = '=============================='
|
|---|
| 13 |
|
|---|
| 14 | class error(Exception):
|
|---|
| 15 | pass
|
|---|
| 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 is not 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[', repr(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 is 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 'always parse it'.
|
|---|
| 207 | #
|
|---|
|
|---|