lilypond-1.3.140
[lilypond.git] / bin / mf-to-table.py
blob0db3593dcdd8986791a8aa11a7c11e9c890caf23
1 #!@PYTHON@
3 #
4 # mf-to-table.py -- convert spacing info in MF logs .ly and .tex
5 #
6 # source file of the GNU LilyPond music typesetter
7 #
8 # (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
9 #
11 import getopt
12 from string import *
13 import regex
14 import regsub
15 import os
16 import sys
17 import time
21 lilypath =''
22 try:
23 lilypath = os.environ['LILYPOND_SOURCEDIR'] + '/'
24 except KeyError:
25 try:
26 lilypath = os.environ['top_srcdir'] + '/'
27 except KeyError:
28 print 'Please set LILYPOND_SOURCEDIR to the toplevel source, eg LILYPOND_SOURCEDIR=/home/foobar/lilypond-1.2.3/'
30 lilypath = lilypath + '/bin/'
31 sys.path.append(lilypath)
33 from flower import *
35 begin_autometric_re = regex.compile('@{')
36 end_autometric_re = regex.compile('@}')
37 include_re = regex.compile ('(\([a-zA-Z_0-9-]+\.mf\)')
38 autometric_re = regex.compile('@{\(.*\)@}')
39 version = '0.6'
40 postfixes = ['log', 'dvi', '2602gf', 'tfm']
42 class Feta_file(File):
43 """Read Feta metrics from a metafont log-file."""
45 def include_scan (self, line):
46 include_pos = include_re.search (line)
47 while include_pos <> -1:
48 self.dependencies.append (include_re.group (1))
50 line = line[include_pos + 1:]
51 include_pos = include_re.search (line)
53 def read_autometricline(self):
54 line = ''
55 while end_autometric_re.search(line) == -1 and not self.eof():
56 suf = File.readline(self)
57 self.include_scan (suf)
58 if begin_autometric_re.search(line) == -1:
59 line = ''
60 line = line + regsub.sub('\n','', suf)
62 if self.eof():
63 return ''
65 return line;
66 def readline(self):
67 """return what is enclosed in one @{ @} pair"""
68 line = '';
69 while autometric_re.search(line) == -1 and not self.eof():
70 line = self.read_autometricline()
72 if self.eof():
73 return '';
75 return autometric_re.group(1);
76 def __init__(self, nm):
77 File.__init__(self, nm)
78 self.dependencies = []
79 def do_file(infile_nm):
80 infile = readline();
83 # FIXME: should parse output for {} to do indenting.
85 class Indentable_file(File):
86 """Output file with support for indentation"""
87 def __init__(self,nm, mode):
88 File.__init__(self,nm,mode)
89 self.current_indent_ = 0
90 self.delta_indent_ = 4
91 def writeline (self, str):
92 File.write(self, str)
93 def writeeol(self):
94 File.write(self, '\n')
95 File.write(self, ' '* self.current_indent_)
97 def indent(self):
98 self.current_indent_ = self.delta_indent_ + self.current_indent_;
99 def dedent(self):
100 self.current_indent_ = self.current_indent_ - self.delta_indent_;
101 if self.current_indent_ < 0:
102 raise 'Nesting!'
104 def write(self, str):
105 lines = split(str, '\n')
106 for l in lines[:-1]:
107 self.writeline(l)
108 self.writeeol()
109 self.writeline (lines[-1])
111 class Ly_file(Indentable_file):
112 """extra provisions for mozarella quirks"""
113 def print_lit(self, str):
114 self.write('\"%s\"\t' % str)
116 def print_f_dimen(self, f):
117 dimstr = '%.2f' % f
119 # try to mask rounding errors
120 if (dimstr == '-0.00'):
121 dimstr = '0.00'
122 self.write( dimstr +'\\pt\t');
124 def print_dimen(self, str):
125 self.print_f_dimen(atof(str))
127 def neg_print_dimen(self, str):
128 self.print_f_dimen(-atof(str));
130 def def_symbol(self, lily_id, tex_id, dims):
131 self.print_lit(lily_id)
132 self.print_lit('\\\\' + tex_id)
134 self.neg_print_dimen(dims [0])
135 self.print_dimen(dims [1])
136 self.neg_print_dimen(dims [2])
137 self.print_dimen(dims [3])
138 self.write('\n')
141 class Log_reader:
142 """Read logs, destill info, and put into output files"""
143 def output_label(self, line):
145 if not line:
146 return;
147 tags = split(line, '@:')
148 label = tags[0]
149 name = tags[1]
150 ly = self.lyfile
151 if tags[0] == 'font':
152 ly.indent()
153 ly.write("% name=\\symboltables {\n")
154 self.texfile.write("% name\n")
155 elif label == "group":
156 ly.indent()
157 ly.print_lit(name)
158 ly.write(' = \\table {\n')
159 self.texfile.write("% " + name + "\n")
160 elif label == "puorg":
161 ly.dedent()
162 ly.write("}\n")
163 self.texfile.write("\n")
164 elif label == "tnof":
165 ly.dedent()
166 ly.write("% } % $name\n")
167 elif label == "char":
168 code = tags[2]
169 id = tags [7]
170 texstr = tags [8]
172 ly.def_symbol(id, texstr, tags[3:7])
174 self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
175 else:
176 raise 'unknown label: ' + label
178 def writedeps (self, deps):
179 if not len (deps):
180 sys.stderr.write ('Huh, no main target??')
181 return
182 filename = deps[0]
183 split = os.path.splitext(filename)
184 basename=split[0];
186 targets = map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
187 depstring = reduce(lambda x,y: x + ' ' + y, deps)
188 dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
189 for x in dependencies:
190 self.depfile.write (x + '\n')
192 def do_file(self,filenm):
193 self.lyfile.write ('\n% input from ' + filenm + '\n')
194 self.texfile.write ('\n% input from ' + filenm + '\n')
195 feta = Feta_file(filenm)
196 while not feta.eof():
197 line = feta.readline()
198 self.output_label(line)
199 feta.close()
201 self.writedeps (feta.dependencies)
203 def __init__(self, lyfile_nm, texfile_nm, depfile_nm):
204 self.lyfile = Ly_file(lyfile_nm, 'w')
205 self.texfile = Indentable_file(texfile_nm, 'w')
206 self.depfile = File (depfile_nm, 'w')
208 headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
209 (program_id() )
211 self.lyfile.write(headerstr)
212 self.texfile.write(headerstr)
213 self.depfile.write ('# automatically generated by %s\n' % program_id ())
215 def close(self):
216 self.lyfile.close()
217 self.texfile.close()
218 self.depfile.close ()
220 def __del__(self):
221 self.close()
223 def today_str():
224 return time.asctime(time.localtime(time.time()))
226 def program_id():
227 return 'mf-to-table.py version ' + version;
229 def identify():
230 sys.stdout.write(program_id() + '\n')
232 def help():
233 sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
234 + "Generate mozarella metrics table from preparated feta log\n\n"
235 + "Options:\n"
236 + " -h, --help print this help\n"
237 + " -l, --ly=FILE name output table\n"
238 + " -d, --dep=FILE print dependency info to FILE\n"
239 + " -o, --outdir=DIR prefix for dependency info\n"
240 + " -t, --tex=FILE name output tex chardefs\n")
241 sys.exit (0)
244 def main():
245 identify()
246 (options, files) = getopt.getopt(
247 sys.argv[1:], 'ho:l:t:d:', ['outdir=', 'dep=', 'ly=', 'tex=', 'debug', 'help'])
249 lyfile_nm = texfile_nm = '';
250 depfile_nm = ''
251 outdir_prefix = '.'
252 for opt in options:
253 o = opt[0]
254 a = opt[1]
255 if o == '--dep' or o == '-d':
256 depfile_nm = a
257 elif o == '--outdir' or o == '-o':
258 outdir_prefix = a
259 elif o == '--ly' or o == '-l':
260 lyfile_nm = a
261 elif o == '--tex' or o == '-t':
262 texfile_nm = a
263 elif o== '--help' or o == '-h':
264 help()
265 elif o == '--debug':
266 debug_b = 1
267 else:
268 print o
269 raise getopt.error
271 log_reader = Log_reader(lyfile_nm, texfile_nm, depfile_nm)
272 log_reader.outdir = outdir_prefix
273 for filenm in files:
274 log_reader.do_file(filenm)
275 log_reader.close()
278 main()