lilypond-1.1.33
[lilypond.git] / buildscripts / mf-to-table.py
blobeb45314a1b4c8175ce6880d6a4d62b372244a213
1 #!@PYTHON@
3 # mf-to-table.py -- convert spacing info in MF logs .afm and .tex
4 #
5 # source file of the GNU LilyPond music typesetter
6 #
7 # (c) 1997 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 import os
10 import sys
11 import getopt
12 from string import *
13 import regex
14 import regsub
15 import time
18 (options, files) = getopt.getopt(
19 sys.argv[1:], 'a:d:hl:o:p:t:',
20 ['afm=', 'outdir=', 'dep=', 'tex=', 'debug', 'help', 'package='])
22 for opt in options:
23 o = opt[0]
24 a = opt[1]
25 if o == '-p' or o == '--package':
26 topdir = a
28 sys.path.append (topdir + '/stepmake/bin')
29 from packagepython import *
30 package = Package (topdir)
31 packager = Packager ()
33 from packagepython import *
34 from flower 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('@{\(.*\)@}')
40 version = '0.7'
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):
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)
64 if self.eof():
65 return ''
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()
74 if self.eof():
75 return '';
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();
85 # FIXME: should parse output for {} to do indenting.
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_)
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!'
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])
113 class Afm_file (File):
114 def print_f_dimen(self, f):
115 f = f * 1000 / self.fontsize
117 dimstr = '%.2f' % f
119 # try to mask rounding errors
120 if (dimstr == '-0.00'):
121 dimstr = '0.00'
122 self.write( dimstr +' ');
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))
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])
136 self.write (';\n');
138 def start (self,nm):
139 self.write ('Start%s\n' % nm)
140 def end (self,nm):
141 self.write ('End%s\n' % nm)
144 class Log_reader:
145 """Read logs, destill info, and put into output files"""
146 def output_label(self, line):
148 if not line:
149 return;
150 tags = split(line, '@:')
151 label = tags[0]
152 name = tags[1]
153 afm = self.afmfile
154 if tags[0] == 'font':
155 self.texfile.write("% name\n")
157 afm.write ('FontName %s\n' % name)
158 afm.start ('FontMetrics')
159 afm.start ('CharMetrics')
160 afm.fontsize = atof(tags[2])
161 elif label == "group":
162 self.texfile.write("% " + name + "\n")
163 afm.groupname = name
164 elif label == "puorg":
165 self.texfile.write("\n")
166 elif label == "tnof":
167 afm.end ('CharMetrics')
168 afm.end('FontMetrics');
169 elif label == "char":
170 code = tags[2]
171 id = tags [7]
172 texstr = tags [8]
173 xdim = tags[3:5]
174 ydim = tags[5:7]
176 self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
177 afm.def_symbol (code, id, texstr, xdim, ydim)
178 else:
179 raise 'unknown label: ' + label
181 def writedeps (self, deps):
182 if not len (deps):
183 sys.stderr.write ('Huh, no main target??')
184 return
185 filename = deps[0]
186 split = os.path.splitext(filename)
187 basename=split[0];
189 targets = map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
190 depstring = reduce(lambda x,y: x + ' ' + y, deps)
191 dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
192 for x in dependencies:
193 self.depfile.write (x + '\n')
195 def do_file(self,filenm):
196 self.texfile.write ('\n% input from ' + filenm + '\n')
197 feta = Feta_file(filenm)
198 while not feta.eof():
199 line = feta.readline()
200 self.output_label(line)
201 feta.close()
203 self.writedeps (feta.dependencies)
205 def __init__(self, texfile_nm, depfile_nm, afmfile_nm):
206 self.texfile = Indentable_file(texfile_nm, 'w')
207 self.depfile = File (depfile_nm, 'w')
208 self.afmfile = Afm_file (afmfile_nm, 'w')
209 headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
210 (program_id() )
212 self.texfile.write(headerstr)
213 self.depfile.write ('# automatically generated by %s\n' % program_id ())
215 def close(self):
216 self.texfile.close()
217 self.depfile.close ()
219 def __del__(self):
220 self.close()
222 def today_str():
223 return time.asctime(time.localtime(time.time()))
225 def program_id():
226 return 'mf-to-table.py version ' + version;
228 def identify():
229 sys.stdout.write(program_id() + '\n')
231 def help():
232 sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
233 + "Generate mozarella metrics table from preparated feta log\n\n"
234 + "Options:\n"
235 + " -a, --afm=FILE .afm file\n"
236 + " -d, --dep=FILE print dependency info to FILE\n"
237 + " -h, --help print this help\n"
238 + " -l, --ly=FILE name output table\n"
239 + " -o, --outdir=DIR prefix for dependency info\n"
240 + " -p, --package=DIR specify package\n"
241 + " -t, --tex=FILE name output tex chardefs\n"
243 sys.exit (0)
246 def main():
247 identify()
249 texfile_nm = '';
250 depfile_nm = ''
251 afmfile_nm = ''
252 outdir_prefix = '.'
253 for opt in options:
254 o = opt[0]
255 a = opt[1]
256 if o == '--dep' or o == '-d':
257 depfile_nm = a
258 elif o == '--outdir' or o == '-o':
259 outdir_prefix = a
260 elif o == '--tex' or o == '-t':
261 texfile_nm = a
262 elif o== '--help' or o == '-h':
263 help()
264 elif o=='--afm' or o == '-a':
265 afmfile_nm = a
266 elif o == '--debug':
267 debug_b = 1
268 elif o == '-p' or o == '--package':
269 topdir = a
270 else:
271 print o
272 raise getopt.error
274 log_reader = Log_reader( texfile_nm, depfile_nm, afmfile_nm)
275 log_reader.outdir = outdir_prefix
276 for filenm in files:
277 log_reader.do_file(filenm)
278 log_reader.close()
281 main()