12 program_version = '@TOPLEVEL_VERSION@'
17 # TODO: use splitting iso. \mudelagraphic.
20 default_music_fontsize = 16
21 default_text_fontsize = 12
24 # indices are no. of columns, papersize, fontsize
25 # Why can't this be calculated?
27 1: {'a4':{10: 345, 11: 360, 12: 390},
28 'a5':{10: 276, 11: 276, 12: 276},
29 'b5':{10: 345, 11: 356, 12: 356},
30 'letter':{10: 345, 11: 360, 12: 390},
31 'legal': {10: 345, 11: 360, 12: 390},
32 'executive':{10: 345, 11: 360, 12: 379}},
33 2: {'a4':{10: 167, 11: 175, 12: 190},
34 'a5':{10: 133, 11: 133, 12: 133},
35 'b5':{10: 167, 11: 173, 12: 173},
36 'letter':{10: 167, 11: 175, 12: 190},
37 'legal':{10: 167, 11: 175, 12: 190},
38 'executive':{10: 167, 11: 175, 12: 184}}}
42 ('', 'h', 'help', 'print help'),
43 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
44 ('', 'v', 'version', 'print version information' ),
45 ('FILE', 'o', 'outname', 'prefix for filenames'),
46 ('DIM', '', 'default-mudela-fontsize', 'default fontsize for music. DIM is assumed to in points'),
47 # ('DIM', '', 'force-mudela-fontsize', 'force fontsize for all inline mudela. DIM is assumed to in points'),
48 ('', '', 'force-verbatim', 'make all mudela verbatim'),
49 ('', 'M', 'dependencies', 'write dependencies'),
50 ('DIR', 'I', 'include', 'include path'),
51 ('', '', 'init', 'mudela-book initfile')
57 # format specific strings, ie. regex-es for input, and % strings for output
59 'latex': {'input': '\\\\input{?([^}\t \n}]*)',
60 'include': '\\\\include{([^}]+)}',
61 'include-mudela':r"""\begin%s{mudela}
64 'header': r"""\\documentclass(\[.*?\])?""",
65 'preamble-end': '\\\\begin{document}',
66 'verbatim': r"""(?s)\\begin{verbatim}(.*?)\\end{verbatim}""",
67 'verb': r"""\\verb(.)(.*?)\1""",
68 'mudela-file': '\\\\mudelafile(\[[^\\]]+\])?{([^}]+)}',
69 'mudela' : '\\\\mudela(\[.*?\])?{(.*?)}',
70 'mudela-block': r"""(?s)\\begin(\[.*?\])?{mudela}(.*?)\\end{mudela}""",
71 'interesting-cs': '\\\\(chapter|section|mudelagraphic|twocolumn|onecolumn)',
72 'quote-verbatim': r"""\begin{verbatim}%s\end{verbatim}""",
73 'def-post-re': r"""\\def\\postMudelaExample""",
74 'def-pre-re': r"""\\def\\preMudelaExample""",
75 'default-post': r"""\def\postMudelaExample{}""",
76 'default-pre': r"""\def\preMudelaExample{}""",
77 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%s.eps}}{\includegraphics{%s.eps}}',
78 'output-tex': '\\preMudelaExample \\input %s.tex \\postMudelaExample\n'
80 'texi': {'input': '@include[ \n\t]+([^\t \n]*)',
82 'include-mudela': """@mudela[%s]
87 'preamble-end': no_match,
88 'verbatim': r"""(?s)@example(.*?)@end example$""",
89 'verb': r"""@code{(.*?)}""",
90 'mudela-file': '@mudelafile(\[[^\\]]+\])?{([^}]+)}',
91 'mudela' : '@mudela(\[.*?\])?{(.*?)}',
92 'mudela-block': r"""(?s)@mudela(\[.*?\])?(.*?)@end mudela""",
93 'interesting-cs': r"""[\\@](node|mudelagraphic)""",
94 'quote-verbatim': r"""@example
97 'output-all': r"""@tex
111 return re_dict[format][name]
114 def bounding_box_dimensions(fname):
118 error ("Error opening `%s'" % fname)
120 s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
122 return (int(s.group(3))-int(s.group(1)),
123 int(s.group(4))-int(s.group(2)))
128 def find_file (name):
129 for a in include_path:
131 nm = os.path.join (a, name)
139 sys.stderr.write (str + "\n Exiting ... \n\n")
143 def compose_full_body (body, opts):
144 "Construct the text of an input file: add stuff to BODY using OPTS as options."
146 music_size = default_music_fontsize
147 latex_size = default_text_fontsize
151 m = re.search ('^(.*)paper$', o)
156 m = re.match ('([0-9]+)pt', o)
158 music_size = string.atoi(m.group (1))
160 m = re.match ('latexfontsize=([0-9]+)pt', o)
162 latex_size = string.atoi (m.group (1))
165 if 'twocolumn' in opts:
168 if 'fragment' or 'singleline' in opts:
171 l = latex_linewidths[cols][paper][latex_size]
173 if not 'nofly' in opts and not re.search ('\\\\score', body):
187 %% Generated by mudela-book.py
188 \include "paper%d.ly"
189 \paper { linewidth = %f \pt; }
190 """ % (music_size, l) + body
196 # Petr, ik zou willen dat ik iets zinvoller deed,
197 # maar wat ik kan ik doen, het verandert toch niets?
202 def read_tex_file (filename):
203 """Read the input file, substituting for \input, \include, \mudela{} and \mudelafile"""
205 for fn in [filename, filename+'.tex', filename+'.doc']:
218 def inclusion_func (match, surround):
219 insert = match.group (0)
221 (insert, d) = read_tex_file (match.group(1))
223 insert = surround + insert + surround
225 sys.stderr.write("warning: can't find %s, let's hope latex will\n" % m.group(1))
227 return (insert, deps)
229 def include_func (match, d = retdeps):
230 (s,d) = inclusion_func (match, '\\newpage ', retdeps)
231 retdeps = retdeps + d
234 str = re.sub (get_re ('input'), include_func, str)
236 def input_func (match, d = retdeps):
237 (s,d) = inclusion_func (match, '', retdeps)
238 retdeps = retdeps + d
241 str = re.sub (get_re ('include'), input_func, str)
243 return (str, retdeps)
245 def scan_preamble (str):
247 m = re.search (get_re ('header'), str)
249 # should extract paper & fontsz.
250 if m and m.group (1):
251 options = options + re.split (',[\n \t]*', m.group(1)[1:-1])
253 def verbose_fontsize ( x):
254 if o.match('[0-9]+pt'):
255 return 'latexfontsize=' + x
259 options = map (verbose_fontsize, options)
264 def completize_preamble (str):
265 m = re.search (get_re ('preamble-end'), str)
269 preamble = str [:m.start (0)]
270 str = str [m.start(0):]
272 if not re.search (get_re('def-post-re'), preamble):
273 preamble = preamble + get_re('default-post')
274 if not re.search (get_re ('def-pre-re'), preamble):
275 preamble = preamble + get_re ('default-pre')
277 if re.search ('\\\\includegraphics', str) and not re.search ('usepackage{graphics}',str):
278 preamble = preamble + '\\usepackage{graphics}\n'
280 return preamble + str
282 def find_mudela_sections (str):
283 """Find mudela blocks, while watching for verbatim. Returns
284 (STR,MUDS) with \mudelagraphic substituted for the blocks in STR,
285 and the blocks themselves MUDS"""
292 m = re.search (get_re ('verbatim'), str)
293 m2 = re.search (get_re ("verb"), str)
295 if m == None and m2 == None:
296 noverbblocks.append (str)
303 if m2 and m2.start (0) < m.start (0):
306 noverbblocks.append (str[:m.start (0)])
307 verbblocks.append (m.group (0))
308 str = str [m.end(0):]
310 def mudela_short (match):
311 "Find \mudela{}, and substitute appropriate \begin / \end blocks."
312 opts = match.group (1)
314 opts = ',' + opts[1:-1]
317 return r"""\begin[eps,fragment%s]{mudela}
323 \end{mudela}""" % (opts, match.group (2))
325 def mudela_file (match):
326 "Find \mudelafile, and substitute appropriate \begin / \end blocks."
327 d = [] #, d = retdeps
328 full_path = find_file (match.group (2))
330 error("error: can't find file `%s'\n" % match.group(2))
335 opts = match.group (1)
337 opts = re.split (',[ \n\t]*', opts[1:-1])
341 if re.search ('.fly$', full_path):
343 elif re.search ('.sly$', full_path):
344 opts = opts + [ 'fly','fragment']
345 elif re.search ('.ly$', full_path):
346 opts .append ('nofly')
348 str_opts = string.join (opts, ',')
349 if str_opts: str_opts = '[' + str_opts + ']'
352 str = "%% copied from %s" % full_path + str
353 return get_re ('include-mudela') % (str_opts, str)
356 def find_one_mudela_block (match,muds =mudelas):
357 "extract body and options from a mudela block, and append into MUDELAS"
358 opts = match.group (1)
364 body = match.group (2)
365 optlist = re.split (', *', opts)
366 muds.append ((body, optlist))
368 return '\\mudelagraphic\n'# UGH.
371 for b in noverbblocks:
372 b = re.sub (get_re('mudela-file'), mudela_file, b)
373 b = re.sub (get_re('mudela'), mudela_short, b)
374 b = re.sub (get_re ("mudela-block"), find_one_mudela_block, b)
375 doneblocks.append (b)
378 verbblocks.append ('')
380 allblocks = allblocks + doneblocks[0:1] + verbblocks[0:1]
381 verbblocks = verbblocks[1:]
382 doneblocks =doneblocks[1:]
384 str = string.join (allblocks,'')
386 return (str, mudelas)
389 def eps_file_cs (base):
390 if format == 'latex':
394 def tex_file_cs (base):
400 def make_files (str, mudelas, filename):
401 (chapter, section, count) = (0,0,0)
409 m = re.search (get_re ('interesting-cs'), str)
415 done = done + str[:m.end (0)]
420 current_opts.append ('twocolumn')
421 elif g == 'onecolumn':
423 current_opts.remove ('twocolumn')
426 if g == 'mudelagraphic':
427 numbering.append ((chapter, section, count, current_opts[:]))
430 (chapter, section, count) = (chapter + 1, 0, 0)
431 elif g == 'section' or g == 'node':
432 (section, count) = (section + 1, 0)
441 m = re.search ('\\\\mudelagraphic', str)
447 done = done + str[:m.start(0)]
450 (c1,c2,c3, file_opts) = numbering[0]
451 (body, opts) = mudelas[0]
452 numbering = numbering[1:]
453 mudelas = mudelas[1:]
455 opts = opts + file_opts
457 base = '%s-%d.%d.%d' % (filename, c1, c2,c3)
458 if 'verbatim' in opts:
459 done = done + get_re ('quote-verbatim') % body
462 body = compose_full_body (body, opts)
463 updated = update_file (body, base + '.ly')
464 def is_updated (extension, t = todo):
466 if t[0] == extension:
470 if not os.path.isfile (base + '.tex') or updated:
471 todo.append (('tex', base, opts))
475 m = re.search ('intertext="(.*?)"', o)
477 done = done + m.group (1)
485 if 'eps' in opts and (is_updated ('tex') or
486 not os.path.isfile (base + '.eps')):
487 todo.append (('eps', base, opts))
489 if 'png' in opts and (is_updated ('eps') or
490 not os.path.isfile (base + '.png')):
491 todo.append (('png', base, opts))
493 if format == 'latex':
495 done = done + get_re ('output-eps') % (base, base )
497 done = done + get_re ('output-tex') % base
498 elif format == 'texi':
499 done = done + get_re ('output-all') % (base, base)
502 compile_all_files (todo)
504 def find_eps_dims (match):
505 "Fill in dimensions of EPS files."
507 dims = bounding_box_dimensions (fn)
509 return '%ipt' % dims[0]
511 done = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, done)
516 sys.stderr.write ("invoking `%s'\n" % cmd)
519 sys.stderr.write ('Error command exited with value %d\n' % st)
522 def compile_all_files ( list):
530 tex.append (l[1] + '.ly')
535 lilyopts = map (lambda x: '-I ' + x, include_path)
536 texfiles = string.join (tex, ' ')
537 lilyopts = string.join (lilyopts, ' ' )
538 system ('lilypond %s %s' % (lilyopts, texfiles))
542 cmd = r"""tex %s; dvips -E -o %s %s""" % \
547 cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
549 cmd = cmd % (g + '.eps', g + '.png')
553 def update_file (body, name):
563 f = open (name , 'w')
572 def getopt_args (opts):
573 "Construct arguments (LONG, SHORT) for getopt from list of options."
588 def option_help_str (o):
589 "Transform one option description (4-tuple ) into neatly formatted string"
607 return ' ' + sh + sep + long + arg
610 def options_help_str (opts):
611 "Transform a list of options into a neatly formatted string"
616 s = option_help_str (o)
617 strs.append ((s, o[3]))
623 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
627 sys.stdout.write("""Usage: mudela-book [options] FILE\n
628 Generate hybrid LaTeX input from Latex + mudela
631 sys.stdout.write (options_help_str (options))
632 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
636 Report bugs to bug-gnu-music@gnu.org.
638 Written by Tom Cato Amundsen <tomcato@xoommail.com> and
639 Han-Wen Nienhuys <hanwen@cs.uu.nl>
645 def write_deps (fn, target, deps):
646 sys.stdout.write('writing `%s\'\n' % fn)
650 target = target + '.latex'
651 f.write ('%s: %s\n'% (target, string.join (deps, ' ')))
656 sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
658 def print_version ():
660 sys.stdout.write (r"""Copyright 1998--1999
661 Distributed under terms of the GNU General Public License. It comes with
667 global outdir, initfile, defined_mudela_cmd, defined_mudela_cmd_re
670 (sh, long) = getopt_args (__main__.options)
671 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
672 except getopt.error, msg:
673 sys.stderr.write("error: %s" % msg)
681 if o == '--include' or o == '-I':
682 include_path.append (a)
683 elif o == '--version':
687 elif o == '--format' or o == '-o':
689 elif o == '--outname' or o == '-o':
692 sys.stderr.write("Mudela-book is confused by --outname on multiple files")
695 elif o == '--outdir' or o == '-d':
697 elif o == '--help' or o == '-h':
699 elif o == '--dependencies':
701 elif o == '--default-mudela-fontsize':
702 default_music_fontsize = string.atoi (a)
708 for input_filename in files:
713 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
714 my_depname = my_outname + '.dep'
716 (input, deps) = read_tex_file (input_filename)
717 (input, muds) = find_mudela_sections (input)
718 output = make_files (input, muds, my_outname)
719 output = completize_preamble (output)
721 foutn = my_outname + '.' + format
722 sys.stderr.write ("Writing `%s'\n" % foutn)
723 fout = open (foutn, 'w')
729 write_deps (my_depname, my_outname, deps)