]> git.donarmstrong.com Git - lilypond.git/blob - bin/mf-to-table.py
partial: 1.0.1.jcn
[lilypond.git] / bin / mf-to-table.py
1 #!@PYTHON@
2
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
10
11 import getopt
12 from string import *
13 import regex
14 import regsub
15 import os
16 import sys
17 import time
18
19
20
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/'
29
30 lilypath = lilypath + '/bin/'
31 sys.path.append(lilypath)
32  
33 from flower import *
34
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']
41
42 class Feta_file(File):
43     """Read Feta metrics from a metafont log-file."""
44
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))
49
50             line = line[include_pos + 1:]
51             include_pos =  include_re.search (line)
52
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)
61
62         if self.eof():
63            return ''
64
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()
71
72         if self.eof():
73             return '';
74
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();
81
82 #
83 # FIXME: should parse output for {} to do indenting.
84 #
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_)
96
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!'
103
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])
110
111 class Ly_file(Indentable_file):
112     """extra provisions for mozarella quirks"""
113     def print_lit(self, str):
114         self.write('\"%s\"\t' % str)
115
116     def print_f_dimen(self, f):
117         dimstr = '%.2f' % f
118
119         # try to mask rounding errors
120         if (dimstr == '-0.00'):
121                 dimstr = '0.00'
122         self.write( dimstr  +'\\pt\t');
123
124     def print_dimen(self, str):
125         self.print_f_dimen(atof(str))
126     
127     def neg_print_dimen(self, str):
128         self.print_f_dimen(-atof(str));
129         
130     def def_symbol(self, lily_id, tex_id, dims):
131         self.print_lit(lily_id)
132         self.print_lit('\\\\' + tex_id)
133
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')
139         
140         
141 class Log_reader:
142     """Read logs, destill info, and put into output files"""
143     def output_label(self, line):
144
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]
171             
172             ly.def_symbol(id, texstr, tags[3:7])
173             
174             self.texfile.write("\\fetdef\\%s{%s}\n" % (texstr, code))
175         else:
176             raise 'unknown label: ' + label
177
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];
185
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')
191         
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()
200         
201         self.writedeps (feta.dependencies)
202
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')
207
208         headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
209                    (program_id() )
210
211         self.lyfile.write(headerstr)
212         self.texfile.write(headerstr)
213         self.depfile.write ('# automatically generated by %s\n' % program_id ())
214
215     def close(self):
216         self.lyfile.close()
217         self.texfile.close()
218         self.depfile.close ()
219
220     def __del__(self):
221         self.close()
222
223 def today_str():
224     return time.asctime(time.localtime(time.time()))
225         
226 def program_id():
227     return 'mf-to-table.py version ' + version;
228
229 def identify():
230     sys.stdout.write(program_id() + '\n')
231     
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)
242
243
244 def main():
245     identify()
246     (options, files) = getopt.getopt(
247         sys.argv[1:], 'ho:l:t:d:', ['outdir=', 'dep=', 'ly=', 'tex=', 'debug', 'help'])
248
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
270
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()
276
277
278 main()