]> git.donarmstrong.com Git - lilypond.git/blob - buildscripts/mf-to-table.py
release: 1.1.49
[lilypond.git] / buildscripts / mf-to-table.py
1 #!@PYTHON@
2
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>
8
9
10 #
11 # TODO: Should use RE.
12 #
13
14 import os
15 import sys
16 import getopt
17 from string import *
18 import regex
19 import regsub
20 import time
21
22
23 (options, files) = getopt.getopt(
24     sys.argv[1:], 'a:d:hl:o:p:t:', 
25     ['afm=', 'outdir=', 'dep=',  'tex=', 'debug', 'help', 'package='])
26
27 for opt in options:
28     o = opt[0]
29     a = opt[1]
30     if o == '-p' or o == '--package':
31         topdir = a
32
33 sys.path.append (topdir + '/stepmake/bin')
34 from packagepython import *
35 package = Package (topdir)
36 packager = Packager ()
37
38 from packagepython import *
39 from flower import *
40
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('@{\(.*\)@}')
45 version = '0.8'
46 postfixes = ['log', 'dvi', '2602gf', 'tfm']
47
48 class Feta_file(File):
49     """Read Feta metrics from a metafont log-file."""
50
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))
55
56             line = line[include_pos + 1:]
57             include_pos =  include_re.search (line)
58
59     def read_autometricline(self):
60         line = ''
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:
65                 line = ''
66             line = line + regsub.sub('\n','', suf)
67             line = regsub.sub('\r','', line)
68
69         if self.eof():
70            return ''
71
72         return line;
73     def readline(self):
74         """return what is enclosed in one @{ @} pair"""
75         line = '';
76         while autometric_re.search(line) == -1 and not self.eof():
77             line = self.read_autometricline()
78
79         if self.eof():
80             return '';
81
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):
87         infile = readline();
88
89 #
90 # FIXME: should parse output for {} to do indenting.
91 #
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):
99         File.write(self, str)
100     def writeeol(self):
101         File.write(self, '\n')
102         File.write(self, ' '* self.current_indent_)
103
104     def indent(self):
105         self.current_indent_ = self.delta_indent_ + self.current_indent_;
106     def dedent(self):
107         self.current_indent_ = self.current_indent_ - self.delta_indent_;
108         if self.current_indent_ < 0:
109             raise 'Nesting!'
110
111     def write(self, str):
112         lines = split(str, '\n')
113         for l in lines[:-1]:
114             self.writeline(l)
115             self.writeeol()
116         self.writeline (lines[-1])
117
118 class Afm_file (File):
119     def print_dimen(self, f):
120         f = f * 1000 / self.fontsize
121     
122         dimstr = '%.2f' % f
123
124         # try to mask rounding errors
125         if (dimstr == '-0.00'):
126                 dimstr = '0.00'
127         self.write( dimstr  +' ');
128
129     def def_symbol (self, code, lily_id, tex_id, xdim, ydim):
130         xdim = map (atof, xdim)
131         ydim = map (atof, ydim)
132         
133         wid = xdim[0] + xdim[1]
134         self.write ('C %s ; ' % code)
135         self.write ('WX ')
136         self.print_dimen (wid)
137
138         self.write (' ; N %s-%s ; B ' % (self.groupname, lily_id))
139
140         self.print_dimen(-xdim [0])
141         self.print_dimen(-ydim [0])
142         self.print_dimen(xdim [1])
143         self.print_dimen(ydim [1])
144
145         self.write (' ;\n');
146         
147     def start (self,nm):
148         self.write ('Start%s\n' % nm)
149     def end (self,nm):
150         self.write ('End%s\n' % nm)
151
152         
153 class Log_reader:
154     """Read logs, destill info, and put into output files"""
155     def output_label(self, line):
156
157         if not line:
158             return;
159         tags = split(line, '@:')
160         label = tags[0]
161         name = tags[1]
162         afm = self.afmfile
163         if tags[0] == 'font':
164             self.texfile.write("% name\n")
165
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")
172             afm.groupname = name
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":
179             code = tags[2]
180             id = tags [7]
181             texstr = tags [8]
182             xdim = tags[3:5]
183             ydim = tags[5:7]
184             
185             self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
186             afm.def_symbol (code, id, texstr, xdim, ydim)
187         else:
188             raise 'unknown label: ' + label
189
190     def writedeps (self, deps):
191         if not len (deps):
192             sys.stderr.write  ('Huh, no main target??')
193             return
194         filename = deps[0]
195         split = os.path.splitext(filename)      
196         basename=split[0];
197
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')
203         
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)
210         feta.close()
211         
212         self.writedeps (feta.dependencies)
213
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' % \
219                    (program_id() )
220
221         self.texfile.write(headerstr)
222         self.depfile.write ('# automatically generated by %s\n' % program_id ())
223
224     def close(self):
225         self.texfile.close()
226         self.depfile.close ()
227
228     def __del__(self):
229         self.close()
230
231 def today_str():
232     return time.asctime(time.localtime(time.time()))
233         
234 def program_id():
235     return 'mf-to-table.py version ' + version;
236
237 def identify():
238     sys.stdout.write(program_id() + '\n')
239     
240 def help():
241     sys.stdout.write("Usage: mf-to-table [options] LOGFILEs\n"
242                  + "Generate mozarella metrics table from preparated feta log\n\n"
243                  + "Options:\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"
251                      )
252     sys.exit (0)
253
254
255 def main():
256     identify()
257
258     texfile_nm = '';
259     depfile_nm = ''
260     afmfile_nm = ''
261     outdir_prefix = '.'
262     for opt in options:
263         o = opt[0]
264         a = opt[1]
265         if o == '--dep' or o == '-d':
266             depfile_nm = a
267         elif o == '--outdir' or o == '-o':
268             outdir_prefix = a
269         elif o == '--tex' or o == '-t':
270             texfile_nm = a
271         elif o== '--help' or o == '-h':
272             help()
273         elif o=='--afm' or o == '-a':
274             afmfile_nm = a
275         elif o == '--debug':
276             debug_b = 1
277         elif o == '-p' or o == '--package':
278             topdir = a
279         else:
280             print o
281             raise getopt.error
282
283     log_reader = Log_reader( texfile_nm, depfile_nm, afmfile_nm)
284     log_reader.outdir = outdir_prefix
285     for filenm in files:
286         log_reader.do_file(filenm)
287     log_reader.close()
288
289
290 main()