2 # vim: set noexpandtab:
4 # * Figure out clean set of options.
5 # * add support for .lilyrc
6 # * %\def\preMudelaExample should be ignored by mudela-book because
8 # * if you run mudela-book once with --no-pictures, and then again
9 # without the option, then the pngs will not be created. You have
10 # to delete the generated .ly files and rerun mudela-book.
11 # * kontroller hvordan det skannes etter preMudelaExample i preamble
12 # det ser ut til at \usepackage{graphics} legges til bare hvis
13 # preMudelaExample ikke finnes.
14 # * add suppoert for @c comments. Check that preamble scanning works after this.
16 # * in LaTeX, commenting out blocks like this
19 # %\end{mudela} works as expected.
20 # * \usepackage{landscape} is gone. Convince me it is really neede to get it back.
21 # * We are calculating more of the linewidths, for example 2 col from 1 col.
25 # This is was the idea for handling of comments:
26 # Multiline comments, @ignore .. @end ignore is scanned for
27 # in read_doc_file, and the chunks are marked as 'ignore', so
28 # mudela-book will not touch them any more. The content of the
29 # chunks are written to the output file. Also 'include' and 'input'
30 # regex has to check if they are commented out.
32 # Then it is scanned for 'mudela', 'mudela-file' and 'mudela-block'.
33 # These three regex's has to check if they are on a commented line,
34 # % for latex, @c for texinfo.
36 # Then lines that are commented out with % (latex) and @c (Texinfo)
37 # are put into chunks marked 'ignore'. This cannot be done before
38 # searching for the mudela-blocks because % is also the comment character
41 # The the rest of the rexeces are searched for. They don't have to test
42 # if they are on a commented out line.
54 program_version = '@TOPLEVEL_VERSION@'
55 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
56 program_version = '1.3.85'
58 include_path = [os.getcwd()]
62 g_force_mudela_fontsize = 0
70 default_music_fontsize = 16
71 default_text_fontsize = 12
77 # the dimentions are from geometry.sty
78 'a0paper': (mm2pt(841), mm2pt(1189)),
79 'a1paper': (mm2pt(595), mm2pt(841)),
80 'a2paper': (mm2pt(420), mm2pt(595)),
81 'a3paper': (mm2pt(297), mm2pt(420)),
82 'a4paper': (mm2pt(210), mm2pt(297)),
83 'a5paper': (mm2pt(149), mm2pt(210)),
84 'b0paper': (mm2pt(1000), mm2pt(1414)),
85 'b1paper': (mm2pt(707), mm2pt(1000)),
86 'b2paper': (mm2pt(500), mm2pt(707)),
87 'b3paper': (mm2pt(353), mm2pt(500)),
88 'b4paper': (mm2pt(250), mm2pt(353)),
89 'b5paper': (mm2pt(176), mm2pt(250)),
90 'letterpaper': (in2pt(8.5), in2pt(11)),
91 'legalpaper': (in2pt(8.5), in2pt(14)),
92 'executivepaper': (in2pt(7.25), in2pt(10.5))}
93 self.m_use_geometry = None
94 self.m_papersize = 'letterpaper'
98 self.m_geo_landscape = 0
99 self.m_geo_width = None
100 self.m_geo_textwidth = None
101 self.m_geo_lmargin = None
102 self.m_geo_rmargin = None
103 self.m_geo_includemp = None
104 self.m_geo_marginparwidth = {10: 57, 11: 50, 12: 35}
105 self.m_geo_marginparsep = {10: 11, 11: 10, 12: 10}
106 self.m_geo_x_marginparwidth = None
107 self.m_geo_x_marginparsep = None
109 def set_geo_option(self, name, value):
110 if name == 'body' or name == 'text':
111 if type(value) == type(""):
112 self._set_dimen('m_geo_textwidth', value)
114 self._set_dimen('m_geo_textwidth', value[0])
116 elif name == 'portrait':
117 self.m_geo_landscape = 0
118 elif name == 'reversemp' or name == 'reversemarginpar':
119 if self.m_geo_includemp == None:
120 self.m_geo_includemp = 1
121 elif name == 'marginparwidth' or name == 'marginpar':
122 self._set_dimen('m_geo_x_marginparwidth', value)
123 self.m_geo_includemp = 1
124 elif name == 'marginparsep':
125 self._set_dimen('m_geo_x_marginparsep', value)
126 self.m_geo_includemp = 1
127 elif name == 'scale':
128 if type(value) == type(""):
129 self.m_geo_width = self.get_paperwidth() * float(value)
131 self.m_geo_width = self.get_paperwidth() * float(value[0])
132 elif name == 'hscale':
133 self.m_geo_width = self.get_paperwidth() * float(value)
134 elif name == 'left' or name == 'lmargin':
135 self._set_dimen('m_geo_lmargin', value)
136 elif name == 'right' or name == 'rmargin':
137 self._set_dimen('m_geo_rmargin', value)
138 elif name == 'hdivide' or name == 'divide':
139 if value[0] not in ('*', ''):
140 self._set_dimen('m_geo_lmargin', value[0])
141 if value[1] not in ('*', ''):
142 self._set_dimen('m_geo_width', value[1])
143 if value[2] not in ('*', ''):
144 self._set_dimen('m_geo_rmargin', value[2])
145 elif name == 'hmargin':
146 if type(value) == type(""):
147 self._set_dimen('m_geo_lmargin', value)
148 self._set_dimen('m_geo_rmargin', value)
150 self._set_dimen('m_geo_lmargin', value[0])
151 self._set_dimen('m_geo_rmargin', value[1])
152 elif name == 'margin':#ugh there is a bug about this option in
153 # the geometry documentation
154 if type(value) == type(""):
155 self._set_dimen('m_geo_lmargin', value)
156 self._set_dimen('m_geo_rmargin', value)
158 self._set_dimen('m_geo_lmargin', value[0])
159 self._set_dimen('m_geo_rmargin', value[0])
160 elif name == 'total':
161 if type(value) == type(""):
162 self._set_dimen('m_geo_width', value)
164 self._set_dimen('m_geo_width', value[0])
165 elif name == 'width' or name == 'totalwidth':
166 self._set_dimen('m_geo_width', value)
167 elif name == 'paper' or name == 'papername':
168 self.m_papersize = value
169 elif name[-5:] == 'paper':
170 self.m_papersize = name
172 self._set_dimen('m_geo_'+name, value)
173 def _set_dimen(self, name, value):
174 if type(value) == type("") and value[-2:] == 'pt':
175 self.__dict__[name] = float(value[:-2])
176 elif type(value) == type("") and value[-2:] == 'mm':
177 self.__dict__[name] = mm2pt(float(value[:-2]))
178 elif type(value) == type("") and value[-2:] == 'cm':
179 self.__dict__[name] = 10 * mm2pt(float(value[:-2]))
180 elif type(value) == type("") and value[-2:] == 'in':
181 self.__dict__[name] = in2pt(float(value[:-2]))
183 self.__dict__[name] = value
185 print "LatexPaper:\n-----------"
186 for v in self.__dict__.keys():
188 print v, self.__dict__[v]
190 def get_linewidth(self):
191 w = self._calc_linewidth()
192 if self.m_num_cols == 2:
196 def get_paperwidth(self):
197 #if self.m_use_geometry:
198 return self.m_paperdef[self.m_papersize][self.m_landscape or self.m_geo_landscape]
199 #return self.m_paperdef[self.m_papersize][self.m_landscape]
201 def _calc_linewidth(self):
202 # since geometry sometimes ignores 'includemp', this is
203 # more complicated than it should be
205 if self.m_geo_includemp:
206 if self.m_geo_x_marginparsep is not None:
207 mp = mp + self.m_geo_x_marginparsep
209 mp = mp + self.m_geo_marginparsep[self.m_fontsize]
210 if self.m_geo_x_marginparwidth is not None:
211 mp = mp + self.m_geo_x_marginparwidth
213 mp = mp + self.m_geo_marginparwidth[self.m_fontsize]
214 if self.__body:#ugh test if this is necessary
217 return a == None, b == None, c == None
218 if not self.m_use_geometry:
219 return latex_linewidths[self.m_papersize][self.m_fontsize]
221 if tNone(self.m_geo_lmargin, self.m_geo_width,
222 self.m_geo_rmargin) == (1, 1, 1):
223 if self.m_geo_textwidth:
224 return self.m_geo_textwidth
225 w = self.get_paperwidth() * 0.8
227 elif tNone(self.m_geo_lmargin, self.m_geo_width,
228 self.m_geo_rmargin) == (0, 1, 1):
229 if self.m_geo_textwidth:
230 return self.m_geo_textwidth
231 return self.f1(self.m_geo_lmargin, mp)
232 elif tNone(self.m_geo_lmargin, self.m_geo_width,
233 self.m_geo_rmargin) == (1, 1, 0):
234 if self.m_geo_textwidth:
235 return self.m_geo_textwidth
236 return self.f1(self.m_geo_rmargin, mp)
237 elif tNone(self.m_geo_lmargin, self.m_geo_width,
238 self.m_geo_rmargin) \
239 in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
240 if self.m_geo_textwidth:
241 return self.m_geo_textwidth
242 return self.m_geo_width - mp
243 elif tNone(self.m_geo_lmargin, self.m_geo_width,
244 self.m_geo_rmargin) in ((0, 1, 0), (0, 0, 0)):
245 w = self.get_paperwidth() - self.m_geo_lmargin - self.m_geo_rmargin - mp
249 raise "Never do this!"
251 tmp = self.get_paperwidth() - m * 2 - mp
256 tmp = self.get_paperwidth() - self.m_geo_lmargin \
264 self.m_papersize = 'a4'
266 def get_linewidth(self):
267 return texi_linewidths[self.m_papersize][self.m_fontsize]
273 def em2pt(x, fontsize):
274 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
275 def ex2pt(x, fontsize):
276 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
279 # indices are no. of columns, papersize, fontsize
280 # Why can't this be calculated?
282 'a4paper':{10: 345, 11: 360, 12: 390},
283 'a4paper-landscape': {10: 598, 11: 596, 12:592},
284 'a5paper':{10: 276, 11: 276, 12: 276},
285 'b5paper':{10: 345, 11: 356, 12: 356},
286 'letterpaper':{10: 345, 11: 360, 12: 390},
287 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
288 'legalpaper': {10: 345, 11: 360, 12: 390},
289 'executivepaper':{10: 345, 11: 360, 12: 379}}
294 'smallbook': {12: 361},
295 'texidefault': {12: 433}}
297 option_definitions = [
298 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
299 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
300 ('DIM', '', 'default-mudela-fontsize', 'deprecated, use --default-music-fontsize'),
301 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline mudela. DIM is assumed be to in points'),
302 ('DIM', '', 'force-mudela-fontsize', 'deprecated, use --force-music-fontsize'),
303 ('DIR', 'I', 'include', 'include path'),
304 ('', 'M', 'dependencies', 'write dependencies'),
305 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
306 ('', 'n', 'no-lily', 'don\'t run lilypond'),
307 ('', '', 'no-pictures', "don\'t generate pictures"),
308 ('', '', 'read-lys', "don't write ly files."),
309 ('FILE', 'o', 'outname', 'filename main output file'),
310 ('FILE', '', 'outdir', "where to place generated files"),
311 ('', 'v', 'version', 'print version information' ),
312 ('', 'h', 'help', 'print help'),
315 # format specific strings, ie. regex-es for input, and % strings for output
318 'output-mudela-fragment' : r"""\begin[eps,singleline,%s]{mudela}
325 'output-mudela':r"""\begin[%s]{mudela}
328 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
329 'output-default-post': r"""\def\postMudelaExample{}""",
330 'output-default-pre': r"""\def\preMudelaExample{}""",
331 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
332 'output-tex': '\\preMudelaExample \\input %(fn)s.tex \\postMudelaExample\n',
333 'pagebreak': r'\pagebreak',
335 'texi' : {'output-mudela': """@mudela[%s]
339 'output-mudela-fragment': """@mudela[%s]
340 \context Staff\context Voice{ %s }
343 'output-verbatim': r"""@example
348 # do some tweaking: @ is needed in some ps stuff.
349 # override EndLilyPondOutput, since @tex is done
350 # in a sandbox, you can't do \input lilyponddefs at the
351 # top of the document.
353 # should also support fragment in
355 'output-all': r"""@tex
358 \def\EndLilyPondOutput{}
370 def output_verbatim (body):#ugh .format
371 if __main__.format == 'texi':
372 body = re.sub ('([@{}])', '@\\1', body)
373 return get_output ('output-verbatim') % body
375 def output_mbverbatim (body):#ugh .format
376 if __main__.format == 'texi':
377 body = re.sub ('([@{}])', '@\\1', body)
378 return get_output ('output-verbatim') % body
381 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
382 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
383 'option-sep' : ', *',
384 'header': r"\\documentclass\s*(\[.*?\])?",
385 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
386 'preamble-end': r'(?P<code>\\begin{document})',
387 'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
388 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
389 'mudela-file': r'(?m)^[^%\n]*?(?P<match>\\mudelafile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
390 'mudela' : r'(?m)^[^%\n]*?(?P<match>\\mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
391 'mudela-block': r"(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{mudela}(?P<code>.*?)\\end{mudela})",
392 'def-post-re': r"\\def\\postMudelaExample",
393 'def-pre-re': r"\\def\\preMudelaExample",
394 'intertext': r',?\s*intertext=\".*?\"',
395 'multiline-comment': no_match,
396 'singleline-comment': r"(?m)(?P<code>^%.*$\n+)",
397 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
401 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
404 'preamble-end': no_match,
405 'landscape': no_match,
406 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
407 'verb': r"""(?P<code>@code{.*?})""",
408 'mudela-file': '(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
409 'mudela' : '(?m)^(?!@c)(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
410 #ugh add check for @c
411 'mudela-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end mudela\s))""",
412 'option-sep' : ', *',
413 'intertext': r',?\s*intertext=\".*?\"',
415 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
416 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
422 for r in re_dict.keys ():
425 for k in olddict.keys ():
426 newdict[k] = re.compile (olddict[k])
440 def get_output (name):
441 return output_dict[format][name]
444 return re_dict[format][name]
446 def bounding_box_dimensions(fname):
450 error ("Error opening `%s'" % fname)
452 s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
454 return (int(s.group(3))-int(s.group(1)),
455 int(s.group(4))-int(s.group(2)))
461 sys.stderr.write (str + "\n Exiting ... \n\n")
465 def compose_full_body (body, opts):
466 """Construct the mudela code to send to Lilypond.
467 Add stuff to BODY using OPTS as options."""
468 music_size = default_music_fontsize
469 latex_size = default_text_fontsize
471 if g_force_mudela_fontsize:
472 music_size = g_force_mudela_fontsize
474 m = re.match ('([0-9]+)pt', o)
476 music_size = string.atoi(m.group (1))
478 m = re.match ('latexfontsize=([0-9]+)pt', o)
480 latex_size = string.atoi (m.group (1))
482 if re.search ('\\\\score', body):
486 if 'fragment' in opts:
488 if 'nonfragment' in opts:
491 if is_fragment and not 'multiline' in opts:
492 opts.append('singleline')
493 if 'singleline' in opts:
496 l = paperguru.get_linewidth()
498 if 'relative' in opts:#ugh only when is_fragment
499 body = '\\relative c { %s }' % body
508 optstring = string.join (opts, ' ')
509 optstring = re.sub ('\n', ' ', optstring)
511 %% Generated by mudela-book.py; options are %s %%ughUGH not original options
512 \include "paper%d.ly"
513 \paper { linewidth = %f \pt; }
514 """ % (optstring, music_size, l) + body
517 def parse_options_string(s):
519 r1 = re.compile("((\w+)={(.*?)})((,\s*)|$)")
520 r2 = re.compile("((\w+)=(.*?))((,\s*)|$)")
521 r3 = re.compile("(\w+?)((,\s*)|$)")
526 d[m.group(2)] = re.split(",\s*", m.group(3))
531 d[m.group(2)] = m.group(3)
538 print "trøbbel:%s:" % s
541 def scan_latex_preamble(chunks):
542 # first we want to scan the \documentclass line
543 # it should be the first non-comment line
546 if chunks[idx][0] == 'ignore':
549 m = get_re ('header').match(chunks[idx][1])
550 options = re.split (',[\n \t]*', m.group(1)[1:-1])
553 paperguru.m_landscape = 1
554 m = re.match("(.*?)paper", o)
556 paperguru.m_papersize = m.group()
558 m = re.match("(\d\d)pt", o)
560 paperguru.m_fontsize = int(m.group(1))
563 while chunks[idx][0] != 'preamble-end':
564 if chunks[idx] == 'ignore':
567 m = get_re ('geometry').search(chunks[idx][1])
569 paperguru.m_use_geometry = 1
570 o = parse_options_string(m.group('options'))
572 paperguru.set_geo_option(k, o[k])
575 def scan_preamble (chunks):
576 if __main__.format == 'texi':
577 #ugh has to be fixed when @c comments are implemented
578 # also the searching here is far from bullet proof.
579 if string.find(chunks[0][1], "@afourpaper") != -1:
580 paperguru.m_papersize = 'a4'
581 elif string.find(chunks[0][1], "@afourwide") != -1:
582 paperguru.m_papersize = 'a4wide'
583 elif string.find(chunks[0][1], "@smallbook") != -1:
584 paperguru.m_papersize = 'smallbook'
586 assert __main__.format == 'latex'
587 scan_latex_preamble(chunks)
590 def completize_preamble (str):
591 m = get_re ('preamble-end').search( str)
595 preamble = str [:m.start (0)]
596 str = str [m.start(0):]
598 if not get_re('def-post-re').search (preamble):
599 preamble = preamble + get_output('output-default-post')
600 if not get_re ('def-pre-re').search( preamble):
601 preamble = preamble + get_output ('output-default-pre')
604 #if re.search ('\\\\includegraphics', str) and not re.search ('usepackage{graphics}',str):
606 preamble = preamble + '\\usepackage{graphics}\n'
608 return preamble + str
612 def find_file (name):
614 for a in include_path:
616 nm = os.path.join (a, name)
618 __main__.read_files.append (nm)
625 error ("File not found `%s'\n" % name)
628 def do_ignore(match_object):
629 return [('ignore', match_object.group('code'))]
630 def do_preamble_end(match_object):
631 return [('preamble-end', match_object.group('code'))]
633 def make_verbatim(match_object):
634 return [('verbatim', match_object.group('code'))]
636 def make_verb(match_object):
637 return [('verb', match_object.group('code'))]
639 def do_include_file(m):
641 return [('input', get_output ('pagebreak'))] \
642 + read_doc_file(m.group('filename')) \
643 + [('input', get_output ('pagebreak'))]
645 def do_input_file(m):
646 return read_doc_file(m.group('filename'))
649 if m.group('options'):
650 options = m.group('options')
653 return [('input', get_output('output-mudela-fragment') %
654 (options, m.group('code')))]
656 def make_mudela_file(m):
657 if m.group('options'):
658 options = m.group('options')
661 return [('input', get_output('output-mudela') %
662 (options, find_file(m.group('filename'))))]
664 def make_mudela_block(m):
665 if m.group('options'):
666 options = get_re('option-sep').split (m.group('options'))
669 options = filter(lambda s: s != '', options)
670 if 'mbverbatim' in options:#ugh this is ugly and only for texi format
672 im = get_re('intertext').search(s)
674 s = s[:im.start()] + s[im.end():]
675 im = re.search('mbverbatim', s)
677 s = s[:im.start()] + s[im.end():]
678 if s[:9] == "@mudela[]":
679 s = "@mudela" + s[9:]
680 return [('mudela', m.group('code'), options, s)]
681 return [('mudela', m.group('code'), options)]
684 if __main__.format != 'latex':
686 if m.group('num') == 'one':
687 return [('numcols', m.group('code'), 1)]
688 if m.group('num') == 'two':
689 return [('numcols', m.group('code'), 2)]
691 def chop_chunks(chunks, re_name, func, use_match=0):
697 m = get_re (re_name).search (str)
699 newchunks.append (('input', str))
703 newchunks.append (('input', str[:m.start ('match')]))
705 newchunks.append (('input', str[:m.start (0)]))
706 #newchunks.extend(func(m))
707 # python 1.5 compatible:
708 newchunks = newchunks + func(m)
709 str = str [m.end(0):]
714 def read_doc_file (filename):
715 """Read the input file, find verbatim chunks and do \input and \include
718 str = find_file(filename)
720 if __main__.format == '':
721 latex = re.search ('\\\\document', str[:200])
722 texinfo = re.search ('@node|@setfilename', str[:200])
723 if (texinfo and latex) or not (texinfo or latex):
724 error("error: can't determine format, please specify")
726 __main__.format = 'texi'
728 __main__.format = 'latex'
729 if __main__.format == 'texi':
730 __main__.paperguru = TexiPaper()
732 __main__.paperguru = LatexPaper()
733 chunks = [('input', str)]
734 # we have to check for verbatim before doing include,
735 # because we don't want to include files that are mentioned
736 # inside a verbatim environment
737 chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
738 chunks = chop_chunks(chunks, 'verb', make_verb)
739 chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
741 chunks = chop_chunks(chunks, 'include', do_include_file, 1)
742 chunks = chop_chunks(chunks, 'input', do_input_file, 1)
746 taken_file_names = {}
747 def schedule_mudela_block (chunk):
748 """Take the body and options from CHUNK, figure out how the
749 real .ly should look, and what should be left MAIN_STR (meant
750 for the main file). The .ly is written, and scheduled in
753 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
755 TODO has format [basename, extension, extension, ... ]
759 (type, body, opts) = chunk
762 (type, body, opts, complete_body) = chunk
763 assert type == 'mudela'
764 file_body = compose_full_body (body, opts)
765 basename = `abs(hash (file_body))`
767 m = re.search ('filename="(.*?)"', o)
769 basename = m.group (1)
770 if not taken_file_names.has_key(basename):
771 taken_file_names[basename] = 0
773 taken_file_names[basename] = taken_file_names[basename] + 1
774 basename = basename + "-%i" % taken_file_names[basename]
775 # writes the file if necessary, returns true if it was written
777 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
778 needed_filetypes = ['tex']
781 needed_filetypes.append('eps')
782 needed_filetypes.append('png')
783 if 'eps' in opts and not ('eps' in needed_filetypes):
784 needed_filetypes.append('eps')
785 outname = os.path.join(g_outdir, basename)
786 if not os.path.isfile(outname + '.tex') \
787 or os.stat(outname+'.ly')[stat.ST_MTIME] > \
788 os.stat(outname+'.tex')[stat.ST_MTIME]:
789 todo = needed_filetypes
794 if 'verbatim' in opts:
795 newbody = output_verbatim (body)
796 elif 'mbverbatim' in opts:
797 newbody = output_mbverbatim (complete_body)
800 m = re.search ('intertext="(.*?)"', o)
802 newbody = newbody + m.group (1) + "\n\n"
803 if format == 'latex':
808 else: # format == 'texi'
810 newbody = newbody + get_output(s) % {'fn': basename }
811 return ('mudela', newbody, opts, todo, basename)
813 def process_mudela_blocks(outname, chunks):#ugh rename
815 # Count sections/chapters.
818 c = schedule_mudela_block (c)
819 elif c[0] == 'numcols':
820 paperguru.m_num_cols = c[2]
825 def find_eps_dims (match):
826 "Fill in dimensions of EPS files."
829 dims = bounding_box_dimensions (fn)
831 return '%ipt' % dims[0]
835 sys.stderr.write ("invoking `%s'\n" % cmd)
838 error ('Error command exited with value %d\n' % st)
841 def compile_all_files (chunks):
856 if base + '.ly' not in tex:
857 tex.append (base + '.ly')
858 elif e == 'png' and g_do_pictures:
864 lilyopts = map (lambda x: '-I ' + x, include_path)
865 lilyopts = string.join (lilyopts, ' ' )
866 texfiles = string.join (tex, ' ')
867 system ('lilypond %s %s' % (lilyopts, texfiles))
869 system(r"tex '\nonstopmode \input %s'" % e)
870 system(r"dvips -E -o %s %s" % (e + '.eps', e))
872 cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
873 cmd = cmd % (g + '.eps', g + '.png')
879 def update_file (body, name):
881 write the body if it has changed
892 f = open (name , 'w')
899 def getopt_args (opts):
900 "Construct arguments (LONG, SHORT) for getopt from list of options."
915 def option_help_str (o):
916 "Transform one option description (4-tuple ) into neatly formatted string"
934 return ' ' + sh + sep + long + arg
937 def options_help_str (opts):
938 "Convert a list of options into a neatly formatted string"
944 s = option_help_str (o)
945 strs.append ((s, o[3]))
951 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
955 sys.stdout.write("""Usage: mudela-book [options] FILE\n
956 Generate hybrid LaTeX input from Latex + mudela
959 sys.stdout.write (options_help_str (option_definitions))
960 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
964 Report bugs to bug-gnu-music@gnu.org.
966 Written by Tom Cato Amundsen <tca@gnu.org> and
967 Han-Wen Nienhuys <hanwen@cs.uu.nl>
973 def write_deps (fn, target):
974 sys.stdout.write('writing `%s\'\n' % os.path.join(g_outdir, fn))
975 f = open (os.path.join(g_outdir, fn), 'w')
976 f.write ('%s%s: ' % (g_dep_prefix, target))
977 for d in __main__.read_files:
981 __main__.read_files = []
984 sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
986 def print_version ():
988 sys.stdout.write (r"""Copyright 1998--1999
989 Distributed under terms of the GNU General Public License. It comes with
993 def do_file(input_filename):
998 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
999 my_depname = my_outname + '.dep'
1001 chunks = read_doc_file(input_filename)
1002 chunks = chop_chunks(chunks, 'mudela', make_mudela, 1)
1003 chunks = chop_chunks(chunks, 'mudela-file', make_mudela_file, 1)
1004 chunks = chop_chunks(chunks, 'mudela-block', make_mudela_block, 1)
1005 chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
1006 chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
1007 chunks = chop_chunks(chunks, 'numcols', do_columns)
1009 #for c in chunks: print "c:", c;
1011 scan_preamble(chunks)
1012 chunks = process_mudela_blocks(my_outname, chunks)
1014 if __main__.g_run_lilypond:
1015 compile_all_files (chunks)
1019 if c[0] == 'mudela' and 'eps' in c[2]:
1020 body = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, c[1])
1021 newchunks.append (('mudela', body))
1023 newchunks.append (c)
1026 if chunks and chunks[0][0] == 'input':
1027 chunks[0] = ('input', completize_preamble (chunks[0][1]))
1029 foutn = os.path.join(g_outdir, my_outname + '.' + format)
1030 sys.stderr.write ("Writing `%s'\n" % foutn)
1031 fout = open (foutn, 'w')
1037 write_deps (my_depname, foutn)
1042 (sh, long) = getopt_args (__main__.option_definitions)
1043 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1044 except getopt.error, msg:
1045 sys.stderr.write("error: %s" % msg)
1053 if o == '--include' or o == '-I':
1054 include_path.append (a)
1055 elif o == '--version' or o == '-v':
1058 elif o == '--format' or o == '-f':
1060 elif o == '--outname' or o == '-o':
1063 sys.stderr.write("Mudela-book is confused by --outname on multiple files")
1066 elif o == '--help' or o == '-h':
1068 elif o == '--no-lily' or o == '-n':
1069 __main__.g_run_lilypond = 0
1070 elif o == '--dependencies' or o == '-M':
1072 elif o == '--default-music-fontsize':
1073 default_music_fontsize = string.atoi (a)
1074 elif o == '--default-mudela-fontsize':
1075 print "--default-mudela-fontsize is deprecated, use --default-music-fontsize"
1076 default_music_fontsize = string.atoi (a)
1077 elif o == '--force-music-fontsize':
1078 g_force_mudela_fontsize = string.atoi(a)
1079 elif o == '--force-mudela-fontsize':
1080 print "--force-mudela-fontsize is deprecated, use --default-mudela-fontsize"
1081 g_force_mudela_fontsize = string.atoi(a)
1082 elif o == '--dep-prefix':
1084 elif o == '--no-pictures':
1086 elif o == '--read-lys':
1088 elif o == '--outdir':
1093 if os.path.isfile(g_outdir):
1094 error ("outdir is a file: %s" % g_outdir)
1095 if not os.path.exists(g_outdir):
1097 for input_filename in files:
1098 do_file(input_filename)
1101 # Petr, ik zou willen dat ik iets zinvoller deed,
1102 # maar wat ik kan ik doen, het verandert toch niets?