3 # mf-to-table.py -- convert spacing info in MF logs .afm and .tex
5 # source file of the GNU LilyPond music typesetter
7 # (c) 1997 Han-Wen Nienhuys <hanwen@cs.uu.nl>
11 # TODO: Should use RE.
23 (options, files) = getopt.getopt(
24 sys.argv[1:], 'a:d:hl:o:p:t:',
25 ['afm=', 'outdir=', 'dep=', 'tex=', 'debug', 'help', 'package='])
30 if o == '-p' or o == '--package':
33 sys.path.append (topdir + '/stepmake/bin')
34 from packagepython import *
35 package = Package (topdir)
36 packager = Packager ()
38 from packagepython import *
41 begin_autometric_re = regex.compile('@{')
42 end_autometric_re = regex.compile('@}')
43 include_re = regex.compile ('(\([a-zA-Z_0-9-]+\.mf\)')
44 autometric_re = regex.compile('@{\(.*\)@}')
46 postfixes = ['log', 'dvi', '2602gf', 'tfm']
48 class Feta_file(File):
49 """Read Feta metrics from a metafont log-file."""
51 def include_scan (self, line):
52 include_pos = include_re.search (line)
53 while include_pos <> -1:
54 self.dependencies.append (include_re.group (1))
56 line = line[include_pos + 1:]
57 include_pos = include_re.search (line)
59 def read_autometricline(self):
61 while end_autometric_re.search(line) == -1 and not self.eof():
62 suf = File.readline(self)
63 self.include_scan (suf)
64 if begin_autometric_re.search(line) == -1:
66 line = line + regsub.sub('\n','', suf)
67 line = regsub.sub('\r','', line)
74 """return what is enclosed in one @{ @} pair"""
76 while autometric_re.search(line) == -1 and not self.eof():
77 line = self.read_autometricline()
82 return autometric_re.group(1);
83 def __init__(self, nm):
84 File.__init__(self, nm)
85 self.dependencies = []
86 def do_file(infile_nm):
90 # FIXME: should parse output for {} to do indenting.
92 class Indentable_file(File):
93 """Output file with support for indentation"""
94 def __init__(self,nm, mode):
95 File.__init__(self,nm,mode)
96 self.current_indent_ = 0
97 self.delta_indent_ = 4
98 def writeline (self, str):
101 File.write(self, '\n')
102 File.write(self, ' '* self.current_indent_)
105 self.current_indent_ = self.delta_indent_ + self.current_indent_;
107 self.current_indent_ = self.current_indent_ - self.delta_indent_;
108 if self.current_indent_ < 0:
111 def write(self, str):
112 lines = split(str, '\n')
116 self.writeline (lines[-1])
118 class Afm_file (File):
119 def print_dimen(self, f):
120 f = f * 1000 / self.fontsize
124 # try to mask rounding errors
125 if (dimstr == '-0.00'):
127 self.write( dimstr +' ');
129 def def_symbol (self, code, lily_id, tex_id, xdim, ydim):
130 xdim = map (atof, xdim)
131 ydim = map (atof, ydim)
133 wid = xdim[0] + xdim[1]
134 self.write ('C %s ; ' % code)
136 self.print_dimen (wid)
138 self.write (' ; N %s-%s ; B ' % (self.groupname, lily_id))
140 self.print_dimen(-xdim [0])
141 self.print_dimen(-ydim [0])
142 self.print_dimen(xdim [1])
143 self.print_dimen(ydim [1])
148 self.write ('Start%s\n' % nm)
150 self.write ('End%s\n' % nm)
154 """Read logs, destill info, and put into output files"""
155 def output_label(self, line):
159 tags = split(line, '@:')
163 if tags[0] == 'font':
164 self.texfile.write("% name\n")
166 afm.write ('FontName %s\n' % name)
167 afm.start ('FontMetrics')
168 afm.start ('CharMetrics')
169 afm.fontsize = atof(tags[2])
170 elif label == "group":
171 self.texfile.write("% " + name + "\n")
173 elif label == "puorg":
174 self.texfile.write("\n")
175 elif label == "tnof":
176 afm.end ('CharMetrics')
177 afm.end('FontMetrics');
178 elif label == "char":
185 self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
186 afm.def_symbol (code, id, texstr, xdim, ydim)
188 raise 'unknown label: ' + label
190 def writedeps (self, deps):
192 sys.stderr.write ('Huh, no main target??')
195 split = os.path.splitext(filename)
198 targets = map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
199 depstring = reduce(lambda x,y: x + ' ' + y, deps)
200 dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
201 for x in dependencies:
202 self.depfile.write (x + '\n')
204 def do_file(self,filenm):
205 self.texfile.write ('\n% input from ' + filenm + '\n')
206 feta = Feta_file(filenm)
207 while not feta.eof():
208 line = feta.readline()
209 self.output_label(line)
212 self.writedeps (feta.dependencies)
214 def __init__(self, texfile_nm, depfile_nm, afmfile_nm):
215 self.texfile = Indentable_file(texfile_nm, 'w')
216 self.depfile = File (depfile_nm, 'w')
217 self.afmfile = Afm_file (afmfile_nm, 'w')
218 headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
221 self.texfile.write(headerstr)
222 self.depfile.write ('# automatically generated by %s\n' % program_id ())
226 self.depfile.close ()
232 return time.asctime(time.localtime(time.time()))
235 return 'mf-to-table.py version ' + version;
238 sys.stdout.write(program_id() + '\n')
241 sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
242 + "Generate mozarella metrics table from preparated feta log\n\n"
244 + " -a, --afm=FILE .afm file\n"
245 + " -d, --dep=FILE print dependency info to FILE\n"
246 + " -h, --help print this help\n"
247 + " -l, --ly=FILE name output table\n"
248 + " -o, --outdir=DIR prefix for dependency info\n"
249 + " -p, --package=DIR specify package\n"
250 + " -t, --tex=FILE name output tex chardefs\n"
265 if o == '--dep' or o == '-d':
267 elif o == '--outdir' or o == '-o':
269 elif o == '--tex' or o == '-t':
271 elif o== '--help' or o == '-h':
273 elif o=='--afm' or o == '-a':
277 elif o == '-p' or o == '--package':
283 log_reader = Log_reader( texfile_nm, depfile_nm, afmfile_nm)
284 log_reader.outdir = outdir_prefix
286 log_reader.do_file(filenm)