]> git.donarmstrong.com Git - lilypond.git/blob - buildscripts/mf-to-table.py
release: 1.1.24
[lilypond.git] / buildscripts / mf-to-table.py
1 #!@PYTHON@
2
3 # mf-to-table.py -- convert spacing info in  MF logs .ly and .tex
4
5 # source file of the GNU LilyPond music typesetter
6
7 # (c) 1997 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8
9 import os
10 import sys
11 import getopt
12 from string import *
13 import regex
14 import regsub
15 import time
16
17
18 (options, files) = getopt.getopt(
19     sys.argv[1:], 'a:d:hl:o:p:t:', 
20     ['afm=', 'outdir=', 'dep=', 'ly=', 'tex=', 'debug', 'help', 'package='])
21
22 for opt in options:
23     o = opt[0]
24     a = opt[1]
25     if o == '-p' or o == '--package':
26         topdir = a
27
28 sys.path.append (topdir + '/stepmake/bin')
29 from packagepython import *
30 package = Package (topdir)
31 packager = Packager ()
32
33 from packagepython import *
34 from flower import *
35
36 begin_autometric_re = regex.compile('@{')
37 end_autometric_re = regex.compile('@}')
38 include_re = regex.compile ('(\([a-zA-Z_0-9-]+\.mf\)')
39 autometric_re = regex.compile('@{\(.*\)@}')
40 version = '0.7'
41 postfixes = ['log', 'dvi', '2602gf', 'tfm']
42
43 class Feta_file(File):
44     """Read Feta metrics from a metafont log-file."""
45
46     def include_scan (self, line):
47         include_pos =  include_re.search (line)
48         while include_pos <> -1:
49             self.dependencies.append (include_re.group (1))
50
51             line = line[include_pos + 1:]
52             include_pos =  include_re.search (line)
53
54     def read_autometricline(self):
55         line = ''
56         while end_autometric_re.search(line) == -1 and not self.eof():
57             suf = File.readline(self)
58             self.include_scan (suf)
59             if begin_autometric_re.search(line) == -1:
60                 line = ''
61             line = line + regsub.sub('\n','', suf)
62             line = regsub.sub('\r','', line)
63
64         if self.eof():
65            return ''
66
67         return line;
68     def readline(self):
69         """return what is enclosed in one @{ @} pair"""
70         line = '';
71         while autometric_re.search(line) == -1 and not self.eof():
72             line = self.read_autometricline()
73
74         if self.eof():
75             return '';
76
77         return autometric_re.group(1);
78     def __init__(self, nm):
79         File.__init__(self, nm)
80         self.dependencies = []
81     def do_file(infile_nm):
82         infile = readline();
83
84 #
85 # FIXME: should parse output for {} to do indenting.
86 #
87 class Indentable_file(File):
88     """Output file with support for indentation"""
89     def __init__(self,nm, mode):
90         File.__init__(self,nm,mode)
91         self.current_indent_ = 0
92         self.delta_indent_ = 4
93     def writeline (self, str):
94         File.write(self, str)
95     def writeeol(self):
96         File.write(self, '\n')
97         File.write(self, ' '* self.current_indent_)
98
99     def indent(self):
100         self.current_indent_ = self.delta_indent_ + self.current_indent_;
101     def dedent(self):
102         self.current_indent_ = self.current_indent_ - self.delta_indent_;
103         if self.current_indent_ < 0:
104             raise 'Nesting!'
105
106     def write(self, str):
107         lines = split(str, '\n')
108         for l in lines[:-1]:
109             self.writeline(l)
110             self.writeeol()
111         self.writeline (lines[-1])
112
113 class Afm_file (File):
114     def print_f_dimen(self, f):
115         f = f * 1000
116     
117         dimstr = '%.2f' % f
118
119         # try to mask rounding errors
120         if (dimstr == '-0.00'):
121                 dimstr = '0.00'
122         self.write( dimstr  +' ');
123
124     def neg_print_dimen(self, str):
125         self.print_f_dimen(-atof(str))
126     def print_dimen(self, str):
127         self.print_f_dimen(atof(str))
128     def def_symbol (self, code, lily_id, tex_id, xdim, ydim):
129         self.write ('C %s; N %s-%s; B ' % (code, self.groupname, lily_id))
130
131         self.neg_print_dimen(xdim [0])
132         self.neg_print_dimen(ydim [0])
133         self.print_dimen(xdim [1])
134         self.print_dimen(ydim [1])
135
136         self.write (';\n');
137         
138     def start (self,nm):
139         self.write ('Start%s\n' % nm)
140     def end (self,nm):
141         self.write ('End%s\n' % nm)
142
143 class Ly_file(Indentable_file):
144     """extra provisions for mozarella quirks"""
145     def print_lit(self, str):
146         self.write('\"%s\"\t' % str)
147
148     def print_f_dimen(self, f):
149         dimstr = '%.2f' % f
150
151         # try to mask rounding errors
152         if (dimstr == '-0.00'):
153                 dimstr = '0.00'
154         self.write( dimstr  +'\\pt\t');
155
156     def print_dimen(self, str):
157         self.print_f_dimen(atof(str))
158     
159     def neg_print_dimen(self, str):
160         self.print_f_dimen(-atof(str));
161         
162     def def_symbol(self, code, lily_id, tex_id, xdim, ydim):
163         self.print_lit(lily_id)
164         self.print_lit('\\\\' + tex_id)
165
166         self.neg_print_dimen(xdim [0])
167         self.print_dimen(xdim [1])
168         self.neg_print_dimen(ydim [0])
169         self.print_dimen(ydim [1])
170         self.write('\n')
171         
172         
173 class Log_reader:
174     """Read logs, destill info, and put into output files"""
175     def output_label(self, line):
176
177         if not line:
178             return;
179         tags = split(line, '@:')
180         label = tags[0]
181         name = tags[1]
182         ly = self.lyfile
183         afm = self.afmfile
184         if tags[0] == 'font':
185             ly.indent()
186             ly.write("% name=\\symboltables {\n")
187             self.texfile.write("% name\n")
188
189             afm.write ('FontName %s\n' % name)
190             afm.start ('FontMetrics')
191             afm.start ('CharMetrics')       
192             
193         elif label == "group":
194             ly.indent()
195             ly.print_lit(name)
196             ly.write(' = \\table {\n')
197             self.texfile.write("% " + name + "\n")
198             afm.groupname = name
199         elif label == "puorg":
200             ly.dedent()
201             ly.write("}\n")
202             self.texfile.write("\n")
203         elif label == "tnof":
204             ly.dedent()
205             ly.write("%  } % $name\n")
206             afm.end ('CharMetrics')
207             afm.end('FontMetrics');
208         elif label == "char":
209             code = tags[2]
210             id = tags [7]
211             texstr = tags [8]
212             xdim = tags[3:5]
213             ydim = tags[5:7]
214             ly.def_symbol(code, id, texstr, xdim, ydim)
215             
216             self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
217             afm.def_symbol (code, id, texstr, xdim, ydim)
218         else:
219             raise 'unknown label: ' + label
220
221     def writedeps (self, deps):
222         if not len (deps):
223             sys.stderr.write  ('Huh, no main target??')
224             return
225         filename = deps[0]
226         split = os.path.splitext(filename)      
227         basename=split[0];
228
229         targets =  map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
230         depstring = reduce(lambda x,y: x + ' ' + y, deps) 
231         dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
232         for x in dependencies: 
233             self.depfile.write (x + '\n')
234         
235     def do_file(self,filenm):
236         self.lyfile.write ('\n% input from ' + filenm + '\n')
237         self.texfile.write ('\n% input from ' + filenm + '\n')
238         feta = Feta_file(filenm)
239         while not feta.eof():
240             line = feta.readline()
241             self.output_label(line)
242         feta.close()
243         
244         self.writedeps (feta.dependencies)
245
246     def __init__(self, lyfile_nm, texfile_nm, depfile_nm, afmfile_nm):      
247         self.lyfile = Ly_file(lyfile_nm, 'w')
248         self.texfile = Indentable_file(texfile_nm, 'w')
249         self.depfile = File (depfile_nm, 'w')
250         self.afmfile = Afm_file (afmfile_nm, 'w')
251         headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
252                    (program_id() )
253
254         self.lyfile.write(headerstr)
255         self.texfile.write(headerstr)
256         self.depfile.write ('# automatically generated by %s\n' % program_id ())
257
258     def close(self):
259         self.lyfile.close()
260         self.texfile.close()
261         self.depfile.close ()
262
263     def __del__(self):
264         self.close()
265
266 def today_str():
267     return time.asctime(time.localtime(time.time()))
268         
269 def program_id():
270     return 'mf-to-table.py version ' + version;
271
272 def identify():
273     sys.stdout.write(program_id() + '\n')
274     
275 def help():
276     sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
277                  + "Generate mozarella metrics table from preparated feta log\n\n"
278                  + "Options:\n"
279                  + "  -a, --afm=FILE         .afm file\n"
280                  + "  -d, --dep=FILE         print dependency info to FILE\n"
281                  + "  -h, --help             print this help\n"
282                  + "  -l, --ly=FILE          name output table\n"
283                  + "  -o, --outdir=DIR       prefix for dependency info\n"
284                  + "  -p, --package=DIR      specify package\n"
285                  + "  -t, --tex=FILE         name output tex chardefs\n"
286                      )
287     sys.exit (0)
288
289
290 def main():
291     identify()
292
293     lyfile_nm = texfile_nm = '';
294     depfile_nm = ''
295     afmfile_nm = ''
296     outdir_prefix = '.'
297     for opt in options:
298         o = opt[0]
299         a = opt[1]
300         if o == '--dep' or o == '-d':
301             depfile_nm = a
302         elif o == '--outdir' or o == '-o':
303             outdir_prefix = a
304         elif o == '--ly' or o == '-l':
305             lyfile_nm = a
306         elif o == '--tex' or o == '-t':
307             texfile_nm = a
308         elif o== '--help' or o == '-h':
309             help()
310         elif o=='--afm' or o == '-a':
311             afmfile_nm = a
312         elif o == '--debug':
313             debug_b = 1
314         elif o == '-p' or o == '--package':
315             topdir = a
316         else:
317             print o
318             raise getopt.error
319
320     log_reader = Log_reader(lyfile_nm, texfile_nm, depfile_nm, afmfile_nm)
321     log_reader.outdir = outdir_prefix
322     for filenm in files:
323         log_reader.do_file(filenm)
324     log_reader.close()
325
326
327 main()