3 # mf-to-table.py -- convert spacing info in MF logs .ly and .tex
5 # source file of the GNU LilyPond music typesetter
7 # (c) 1997 Han-Wen Nienhuys <hanwen@cs.uu.nl>
18 (options, files) = getopt.getopt(
19 sys.argv[1:], 'a:d:hl:o:p:t:',
20 ['afm=', 'outdir=', 'dep=', 'ly=', 'tex=', 'debug', 'help', 'package='])
25 if o == '-p' or o == '--package':
28 sys.path.append (topdir + '/stepmake/bin')
29 from packagepython import *
30 package = Package (topdir)
31 packager = Packager ()
33 from packagepython import *
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('@{\(.*\)@}')
41 postfixes = ['log', 'dvi', '2602gf', 'tfm']
43 class Feta_file(File):
44 """Read Feta metrics from a metafont log-file."""
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))
51 line = line[include_pos + 1:]
52 include_pos = include_re.search (line)
54 def read_autometricline(self):
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:
61 line = line + regsub.sub('\n','', suf)
68 """return what is enclosed in one @{ @} pair"""
70 while autometric_re.search(line) == -1 and not self.eof():
71 line = self.read_autometricline()
76 return autometric_re.group(1);
77 def __init__(self, nm):
78 File.__init__(self, nm)
79 self.dependencies = []
80 def do_file(infile_nm):
84 # FIXME: should parse output for {} to do indenting.
86 class Indentable_file(File):
87 """Output file with support for indentation"""
88 def __init__(self,nm, mode):
89 File.__init__(self,nm,mode)
90 self.current_indent_ = 0
91 self.delta_indent_ = 4
92 def writeline (self, str):
95 File.write(self, '\n')
96 File.write(self, ' '* self.current_indent_)
99 self.current_indent_ = self.delta_indent_ + self.current_indent_;
101 self.current_indent_ = self.current_indent_ - self.delta_indent_;
102 if self.current_indent_ < 0:
105 def write(self, str):
106 lines = split(str, '\n')
110 self.writeline (lines[-1])
112 class Afm_file (File):
113 def print_f_dimen(self, f):
118 # try to mask rounding errors
119 if (dimstr == '-0.00'):
121 self.write( dimstr +' ');
123 def neg_print_dimen(self, str):
124 self.print_f_dimen(-atof(str))
125 def print_dimen(self, str):
126 self.print_f_dimen(atof(str))
127 def def_symbol (self, code, lily_id, tex_id, xdim, ydim):
128 self.write ('C %s; N %s-%s; B ' % (code, self.groupname, lily_id))
130 self.neg_print_dimen(xdim [0])
131 self.neg_print_dimen(ydim [0])
132 self.print_dimen(xdim [1])
133 self.print_dimen(ydim [1])
138 self.write ('Start%s\n' % nm)
140 self.write ('End%s\n' % nm)
142 class Ly_file(Indentable_file):
143 """extra provisions for mozarella quirks"""
144 def print_lit(self, str):
145 self.write('\"%s\"\t' % str)
147 def print_f_dimen(self, f):
150 # try to mask rounding errors
151 if (dimstr == '-0.00'):
153 self.write( dimstr +'\\pt\t');
155 def print_dimen(self, str):
156 self.print_f_dimen(atof(str))
158 def neg_print_dimen(self, str):
159 self.print_f_dimen(-atof(str));
161 def def_symbol(self, code, lily_id, tex_id, xdim, ydim):
162 self.print_lit(lily_id)
163 self.print_lit('\\\\' + tex_id)
165 self.neg_print_dimen(xdim [0])
166 self.print_dimen(xdim [1])
167 self.neg_print_dimen(ydim [0])
168 self.print_dimen(ydim [1])
173 """Read logs, destill info, and put into output files"""
174 def output_label(self, line):
178 tags = split(line, '@:')
183 if tags[0] == 'font':
185 ly.write("% name=\\symboltables {\n")
186 self.texfile.write("% name\n")
188 afm.write ('FontName %s\n' % name)
189 afm.start ('FontMetrics')
190 afm.start ('CharMetrics')
192 elif label == "group":
195 ly.write(' = \\table {\n')
196 self.texfile.write("% " + name + "\n")
198 elif label == "puorg":
201 self.texfile.write("\n")
202 elif label == "tnof":
204 ly.write("% } % $name\n")
205 afm.end ('CharMetrics')
206 afm.end('FontMetrics');
207 elif label == "char":
213 ly.def_symbol(code, id, texstr, xdim, ydim)
215 self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
216 afm.def_symbol (code, id, texstr, xdim, ydim)
218 raise 'unknown label: ' + label
220 def writedeps (self, deps):
222 sys.stderr.write ('Huh, no main target??')
225 split = os.path.splitext(filename)
228 targets = map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
229 depstring = reduce(lambda x,y: x + ' ' + y, deps)
230 dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
231 for x in dependencies:
232 self.depfile.write (x + '\n')
234 def do_file(self,filenm):
235 self.lyfile.write ('\n% input from ' + filenm + '\n')
236 self.texfile.write ('\n% input from ' + filenm + '\n')
237 feta = Feta_file(filenm)
238 while not feta.eof():
239 line = feta.readline()
240 self.output_label(line)
243 self.writedeps (feta.dependencies)
245 def __init__(self, lyfile_nm, texfile_nm, depfile_nm, afmfile_nm):
246 self.lyfile = Ly_file(lyfile_nm, 'w')
247 self.texfile = Indentable_file(texfile_nm, 'w')
248 self.depfile = File (depfile_nm, 'w')
249 self.afmfile = Afm_file (afmfile_nm, 'w')
250 headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
253 self.lyfile.write(headerstr)
254 self.texfile.write(headerstr)
255 self.depfile.write ('# automatically generated by %s\n' % program_id ())
260 self.depfile.close ()
266 return time.asctime(time.localtime(time.time()))
269 return 'mf-to-table.py version ' + version;
272 sys.stdout.write(program_id() + '\n')
275 sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
276 + "Generate mozarella metrics table from preparated feta log\n\n"
278 + " -a, --afm=FILE .afm file\n"
279 + " -d, --dep=FILE print dependency info to FILE\n"
280 + " -h, --help print this help\n"
281 + " -l, --ly=FILE name output table\n"
282 + " -o, --outdir=DIR prefix for dependency info\n"
283 + " -p, --package=DIR specify package\n"
284 + " -t, --tex=FILE name output tex chardefs\n"
292 lyfile_nm = texfile_nm = '';
299 if o == '--dep' or o == '-d':
301 elif o == '--outdir' or o == '-o':
303 elif o == '--ly' or o == '-l':
305 elif o == '--tex' or o == '-t':
307 elif o== '--help' or o == '-h':
309 elif o=='--afm' or o == '-a':
313 elif o == '-p' or o == '--package':
319 log_reader = Log_reader(lyfile_nm, texfile_nm, depfile_nm, afmfile_nm)
320 log_reader.outdir = outdir_prefix
322 log_reader.do_file(filenm)