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):
203 # since geometry sometimes ignores 'includemp', this is
204 # more complicated than it should be
206 if self.m_geo_includemp:
207 if self.m_geo_x_marginparsep is not None:
208 mp = mp + self.m_geo_x_marginparsep
210 mp = mp + self.m_geo_marginparsep[self.m_fontsize]
211 if self.m_geo_x_marginparwidth is not None:
212 mp = mp + self.m_geo_x_marginparwidth
214 mp = mp + self.m_geo_marginparwidth[self.m_fontsize]
215 if self.__body:#ugh test if this is necessary
218 return a == None, b == None, c == None
219 if not self.m_use_geometry:
220 return latex_linewidths[self.m_papersize][self.m_fontsize]
222 if tNone(self.m_geo_lmargin, self.m_geo_width,
223 self.m_geo_rmargin) == (1, 1, 1):
224 if self.m_geo_textwidth:
225 return self.m_geo_textwidth
226 w = self.get_paperwidth() * 0.8
228 elif tNone(self.m_geo_lmargin, self.m_geo_width,
229 self.m_geo_rmargin) == (0, 1, 1):
230 if self.m_geo_textwidth:
231 return self.m_geo_textwidth
232 return self.f1(self.m_geo_lmargin, mp)
233 elif tNone(self.m_geo_lmargin, self.m_geo_width,
234 self.m_geo_rmargin) == (1, 1, 0):
235 if self.m_geo_textwidth:
236 return self.m_geo_textwidth
237 return self.f1(self.m_geo_rmargin, mp)
238 elif tNone(self.m_geo_lmargin, self.m_geo_width,
239 self.m_geo_rmargin) \
240 in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
241 if self.m_geo_textwidth:
242 return self.m_geo_textwidth
243 return self.m_geo_width - mp
244 elif tNone(self.m_geo_lmargin, self.m_geo_width,
245 self.m_geo_rmargin) in ((0, 1, 0), (0, 0, 0)):
246 w = self.get_paperwidth() - self.m_geo_lmargin - self.m_geo_rmargin - mp
250 raise "Never do this!"
252 tmp = self.get_paperwidth() - m * 2 - mp
257 tmp = self.get_paperwidth() - self.m_geo_lmargin \
265 self.m_papersize = 'a4'
267 def get_linewidth(self):
268 return texi_linewidths[self.m_papersize][self.m_fontsize]
274 def em2pt(x, fontsize):
275 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
276 def ex2pt(x, fontsize):
277 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
280 # indices are no. of columns, papersize, fontsize
281 # Why can't this be calculated?
283 'a4paper':{10: 345, 11: 360, 12: 390},
284 'a4paper-landscape': {10: 598, 11: 596, 12:592},
285 'a5paper':{10: 276, 11: 276, 12: 276},
286 'b5paper':{10: 345, 11: 356, 12: 356},
287 'letterpaper':{10: 345, 11: 360, 12: 390},
288 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
289 'legalpaper': {10: 345, 11: 360, 12: 390},
290 'executivepaper':{10: 345, 11: 360, 12: 379}}
295 'smallbook': {12: 361},
296 'texidefault': {12: 433}}
298 option_definitions = [
299 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
300 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
301 ('DIM', '', 'default-mudela-fontsize', 'deprecated, use --default-music-fontsize'),
302 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline mudela. DIM is assumed be to in points'),
303 ('DIM', '', 'force-mudela-fontsize', 'deprecated, use --force-music-fontsize'),
304 ('DIR', 'I', 'include', 'include path'),
305 ('', 'M', 'dependencies', 'write dependencies'),
306 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
307 ('', 'n', 'no-lily', 'don\'t run lilypond'),
308 ('', '', 'no-pictures', "don\'t generate pictures"),
309 ('', '', 'read-lys', "don't write ly files."),
310 ('FILE', 'o', 'outname', 'filename main output file'),
311 ('FILE', '', 'outdir', "where to place generated files"),
312 ('', 'v', 'version', 'print version information' ),
313 ('', 'h', 'help', 'print help'),
316 # format specific strings, ie. regex-es for input, and % strings for output
319 'output-mudela-fragment' : r"""\begin[eps,singleline,%s]{mudela}
326 'output-mudela':r"""\begin[%s]{mudela}
329 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
330 'output-default-post': r"""\def\postMudelaExample{}""",
331 'output-default-pre': r"""\def\preMudelaExample{}""",
332 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
333 'output-tex': '\\preMudelaExample \\input %(fn)s.tex \\postMudelaExample\n',
334 'pagebreak': r'\pagebreak',
336 'texi' : {'output-mudela': """@mudela[%s]
340 'output-mudela-fragment': """@mudela[%s]
341 \context Staff\context Voice{ %s }
344 'output-verbatim': r"""@example
349 # do some tweaking: @ is needed in some ps stuff.
350 # override EndLilyPondOutput, since @tex is done
351 # in a sandbox, you can't do \input lilyponddefs at the
352 # top of the document.
354 # should also support fragment in
356 'output-all': r"""@tex
359 \def\EndLilyPondOutput{}
371 def output_verbatim (body):#ugh .format
372 if __main__.format == 'texi':
373 body = re.sub ('([@{}])', '@\\1', body)
374 return get_output ('output-verbatim') % body
376 def output_mbverbatim (body):#ugh .format
377 if __main__.format == 'texi':
378 body = re.sub ('([@{}])', '@\\1', body)
379 return get_output ('output-verbatim') % body
382 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
383 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
384 'option-sep' : ', *',
385 'header': r"\\documentclass\s*(\[.*?\])?",
386 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
387 'preamble-end': r'(?P<code>\\begin{document})',
388 'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
389 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
390 'mudela-file': r'(?m)^[^%\n]*?(?P<match>\\mudelafile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
391 'mudela' : r'(?m)^[^%\n]*?(?P<match>\\mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
392 'mudela-block': r"(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{mudela}(?P<code>.*?)\\end{mudela})",
393 'def-post-re': r"\\def\\postMudelaExample",
394 'def-pre-re': r"\\def\\preMudelaExample",
395 'intertext': r',?\s*intertext=\".*?\"',
396 'multiline-comment': no_match,
397 'singleline-comment': r"(?m)(?P<code>^%.*$\n+)",
398 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
402 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
405 'preamble-end': no_match,
406 'landscape': no_match,
407 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
408 'verb': r"""(?P<code>@code{.*?})""",
409 'mudela-file': '(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
410 'mudela' : '(?m)^(?!@c)(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
411 #ugh add check for @c
412 'mudela-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end mudela\s))""",
413 'option-sep' : ', *',
414 'intertext': r',?\s*intertext=\".*?\"',
416 'multiline-comment': r"(?s)(?P<code>@ignore\s.*?@end ignore)\s",
417 'singleline-comment': r"(?m)(?P<code>^@c.*$\n+)",
423 for r in re_dict.keys ():
426 for k in olddict.keys ():
427 newdict[k] = re.compile (olddict[k])
441 def get_output (name):
442 return output_dict[format][name]
445 return re_dict[format][name]
447 def bounding_box_dimensions(fname):
451 error ("Error opening `%s'" % fname)
453 s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
455 return (int(s.group(3))-int(s.group(1)),
456 int(s.group(4))-int(s.group(2)))
462 sys.stderr.write (str + "\n Exiting ... \n\n")
466 def compose_full_body (body, opts):
467 """Construct the mudela code to send to Lilypond.
468 Add stuff to BODY using OPTS as options."""
469 music_size = default_music_fontsize
470 latex_size = default_text_fontsize
472 if g_force_mudela_fontsize:
473 music_size = g_force_mudela_fontsize
475 m = re.match ('([0-9]+)pt', o)
477 music_size = string.atoi(m.group (1))
479 m = re.match ('latexfontsize=([0-9]+)pt', o)
481 latex_size = string.atoi (m.group (1))
483 if re.search ('\\\\score', body):
487 if 'fragment' in opts:
489 if 'nonfragment' in opts:
492 if is_fragment and not 'multiline' in opts:
493 opts.append('singleline')
494 if 'singleline' in opts:
497 l = paperguru.get_linewidth()
499 if 'relative' in opts:#ugh only when is_fragment
500 body = '\\relative c { %s }' % body
509 optstring = string.join (opts, ' ')
510 optstring = re.sub ('\n', ' ', optstring)
512 %% Generated by mudela-book.py; options are %s %%ughUGH not original options
513 \include "paper%d.ly"
514 \paper { linewidth = %f \pt; }
515 """ % (optstring, music_size, l) + body
518 def parse_options_string(s):
520 r1 = re.compile("((\w+)={(.*?)})((,\s*)|$)")
521 r2 = re.compile("((\w+)=(.*?))((,\s*)|$)")
522 r3 = re.compile("(\w+?)((,\s*)|$)")
527 d[m.group(2)] = re.split(",\s*", m.group(3))
532 d[m.group(2)] = m.group(3)
539 print "trøbbel:%s:" % s
542 def scan_latex_preamble(chunks):
543 # first we want to scan the \documentclass line
544 # it should be the first non-comment line
547 if chunks[idx][0] == 'ignore':
550 m = get_re ('header').match(chunks[idx][1])
551 options = re.split (',[\n \t]*', m.group(1)[1:-1])
554 paperguru.m_landscape = 1
555 m = re.match("(.*?)paper", o)
557 paperguru.m_papersize = m.group()
559 m = re.match("(\d\d)pt", o)
561 paperguru.m_fontsize = int(m.group(1))
564 while chunks[idx][0] != 'preamble-end':
565 if chunks[idx] == 'ignore':
568 m = get_re ('geometry').search(chunks[idx][1])
570 paperguru.m_use_geometry = 1
571 o = parse_options_string(m.group('options'))
573 paperguru.set_geo_option(k, o[k])
576 def scan_preamble (chunks):
577 if __main__.format == 'texi':
578 #ugh has to be fixed when @c comments are implemented
579 # also the searching here is far from bullet proof.
580 if string.find(chunks[0][1], "@afourpaper") != -1:
581 paperguru.m_papersize = 'a4'
582 elif string.find(chunks[0][1], "@afourwide") != -1:
583 paperguru.m_papersize = 'a4wide'
584 elif string.find(chunks[0][1], "@smallbook") != -1:
585 paperguru.m_papersize = 'smallbook'
587 assert __main__.format == 'latex'
588 scan_latex_preamble(chunks)
591 def completize_preamble (str):
592 m = get_re ('preamble-end').search( str)
596 preamble = str [:m.start (0)]
597 str = str [m.start(0):]
599 if not get_re('def-post-re').search (preamble):
600 preamble = preamble + get_output('output-default-post')
601 if not get_re ('def-pre-re').search( preamble):
602 preamble = preamble + get_output ('output-default-pre')
605 #if re.search ('\\\\includegraphics', str) and not re.search ('usepackage{graphics}',str):
607 preamble = preamble + '\\usepackage{graphics}\n'
609 return preamble + str
613 def find_file (name):
615 for a in include_path:
617 nm = os.path.join (a, name)
619 __main__.read_files.append (nm)
626 error ("File not found `%s'\n" % name)
629 def do_ignore(match_object):
630 return [('ignore', match_object.group('code'))]
631 def do_preamble_end(match_object):
632 return [('preamble-end', match_object.group('code'))]
634 def make_verbatim(match_object):
635 return [('verbatim', match_object.group('code'))]
637 def make_verb(match_object):
638 return [('verb', match_object.group('code'))]
640 def do_include_file(m):
642 return [('input', get_output ('pagebreak'))] \
643 + read_doc_file(m.group('filename')) \
644 + [('input', get_output ('pagebreak'))]
646 def do_input_file(m):
647 return read_doc_file(m.group('filename'))
650 if m.group('options'):
651 options = m.group('options')
654 return [('input', get_output('output-mudela-fragment') %
655 (options, m.group('code')))]
657 def make_mudela_file(m):
658 if m.group('options'):
659 options = m.group('options')
662 return [('input', get_output('output-mudela') %
663 (options, find_file(m.group('filename'))))]
665 def make_mudela_block(m):
666 if m.group('options'):
667 options = get_re('option-sep').split (m.group('options'))
670 options = filter(lambda s: s != '', options)
671 if 'mbverbatim' in options:#ugh this is ugly and only for texi format
673 im = get_re('intertext').search(s)
675 s = s[:im.start()] + s[im.end():]
676 im = re.search('mbverbatim', s)
678 s = s[:im.start()] + s[im.end():]
679 if s[:9] == "@mudela[]":
680 s = "@mudela" + s[9:]
681 return [('mudela', m.group('code'), options, s)]
682 return [('mudela', m.group('code'), options)]
685 if __main__.format != 'latex':
687 if m.group('num') == 'one':
688 return [('numcols', m.group('code'), 1)]
689 if m.group('num') == 'two':
690 return [('numcols', m.group('code'), 2)]
692 def new_chop_chunks(chunks, re_name, func):
698 m = get_re (re_name).search (str)
700 newchunks.append (('input', str))
703 newchunks.append (('input', str[:m.start ('match')]))
704 #newchunks.extend(func(m))
705 # python 1.5 compatible:
706 newchunks = newchunks + func(m)
707 str = str [m.end(0):]
712 def chop_chunks(chunks, re_name, func):
718 m = get_re (re_name).search (str)
720 newchunks.append (('input', str))
723 newchunks.append (('input', str[:m.start (0)]))
724 #newchunks.extend(func(m))
725 # python 1.5 compatible:
726 newchunks = newchunks + func(m)
727 str = str [m.end(0):]
732 def read_doc_file (filename):
733 """Read the input file, find verbatim chunks and do \input and \include
736 str = find_file(filename)
738 if __main__.format == '':
739 latex = re.search ('\\\\document', str[:200])
740 texinfo = re.search ('@node|@setfilename', str[:200])
741 if (texinfo and latex) or not (texinfo or latex):
742 error("error: can't determine format, please specify")
744 __main__.format = 'texi'
745 __main__.paperguru = TexiPaper()
747 __main__.format = 'latex'
748 __main__.paperguru = LatexPaper()
749 chunks = [('input', str)]
750 # we have to check for verbatim before doing include,
751 # because we don't want to include files that are mentioned
752 # inside a verbatim environment
753 chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
754 chunks = chop_chunks(chunks, 'verb', make_verb)
755 chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
757 chunks = new_chop_chunks(chunks, 'include', do_include_file)
758 chunks = new_chop_chunks(chunks, 'input', do_input_file)
762 taken_file_names = {}
763 def schedule_mudela_block (chunk):
764 """Take the body and options from CHUNK, figure out how the
765 real .ly should look, and what should be left MAIN_STR (meant
766 for the main file). The .ly is written, and scheduled in
769 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
771 TODO has format [basename, extension, extension, ... ]
775 (type, body, opts) = chunk
778 (type, body, opts, complete_body) = chunk
779 assert type == 'mudela'
780 file_body = compose_full_body (body, opts)
781 basename = `abs(hash (file_body))`
783 m = re.search ('filename="(.*?)"', o)
785 basename = m.group (1)
786 if not taken_file_names.has_key(basename):
787 taken_file_names[basename] = 0
789 taken_file_names[basename] = taken_file_names[basename] + 1
790 basename = basename + "-%i" % taken_file_names[basename]
791 # writes the file if necessary, returns true if it was written
793 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
794 needed_filetypes = ['tex']
797 needed_filetypes.append('eps')
798 needed_filetypes.append('png')
799 if 'eps' in opts and not ('eps' in needed_filetypes):
800 needed_filetypes.append('eps')
801 outname = os.path.join(g_outdir, basename)
802 if not os.path.isfile(outname + '.tex') \
803 or os.stat(outname+'.ly')[stat.ST_MTIME] > \
804 os.stat(outname+'.tex')[stat.ST_MTIME]:
805 todo = needed_filetypes
810 if 'verbatim' in opts:
811 newbody = output_verbatim (body)
812 elif 'mbverbatim' in opts:
813 newbody = output_mbverbatim (complete_body)
816 m = re.search ('intertext="(.*?)"', o)
818 newbody = newbody + m.group (1) + "\n\n"
819 if format == 'latex':
824 else: # format == 'texi'
826 newbody = newbody + get_output(s) % {'fn': basename }
827 return ('mudela', newbody, opts, todo, basename)
829 def process_mudela_blocks(outname, chunks):#ugh rename
831 # Count sections/chapters.
834 c = schedule_mudela_block (c)
835 elif c[0] == 'numcols':
836 paperguru.m_num_cols = c[2]
841 def find_eps_dims (match):
842 "Fill in dimensions of EPS files."
845 dims = bounding_box_dimensions (fn)
847 return '%ipt' % dims[0]
851 sys.stderr.write ("invoking `%s'\n" % cmd)
854 error ('Error command exited with value %d\n' % st)
857 def compile_all_files (chunks):
872 if base + '.ly' not in tex:
873 tex.append (base + '.ly')
874 elif e == 'png' and g_do_pictures:
880 lilyopts = map (lambda x: '-I ' + x, include_path)
881 lilyopts = string.join (lilyopts, ' ' )
882 texfiles = string.join (tex, ' ')
883 system ('lilypond %s %s' % (lilyopts, texfiles))
885 system(r"tex '\nonstopmode \input %s'" % e)
886 system(r"dvips -E -o %s %s" % (e + '.eps', e))
888 cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
889 cmd = cmd % (g + '.eps', g + '.png')
895 def update_file (body, name):
897 write the body if it has changed
908 f = open (name , 'w')
915 def getopt_args (opts):
916 "Construct arguments (LONG, SHORT) for getopt from list of options."
931 def option_help_str (o):
932 "Transform one option description (4-tuple ) into neatly formatted string"
950 return ' ' + sh + sep + long + arg
953 def options_help_str (opts):
954 "Convert a list of options into a neatly formatted string"
960 s = option_help_str (o)
961 strs.append ((s, o[3]))
967 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
971 sys.stdout.write("""Usage: mudela-book [options] FILE\n
972 Generate hybrid LaTeX input from Latex + mudela
975 sys.stdout.write (options_help_str (option_definitions))
976 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
980 Report bugs to bug-gnu-music@gnu.org.
982 Written by Tom Cato Amundsen <tca@gnu.org> and
983 Han-Wen Nienhuys <hanwen@cs.uu.nl>
989 def write_deps (fn, target):
990 sys.stdout.write('writing `%s\'\n' % os.path.join(g_outdir, fn))
991 f = open (os.path.join(g_outdir, fn), 'w')
992 f.write ('%s%s: ' % (g_dep_prefix, target))
993 for d in __main__.read_files:
997 __main__.read_files = []
1000 sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
1002 def print_version ():
1004 sys.stdout.write (r"""Copyright 1998--1999
1005 Distributed under terms of the GNU General Public License. It comes with
1009 def do_file(input_filename):
1012 my_outname = outname
1014 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
1015 my_depname = my_outname + '.dep'
1017 chunks = read_doc_file(input_filename)
1018 chunks = new_chop_chunks(chunks, 'mudela', make_mudela)
1019 chunks = new_chop_chunks(chunks, 'mudela-file', make_mudela_file)
1020 chunks = new_chop_chunks(chunks, 'mudela-block', make_mudela_block)
1021 chunks = chop_chunks(chunks, 'singleline-comment', do_ignore)
1022 chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
1023 chunks = chop_chunks(chunks, 'numcols', do_columns)
1025 #for c in chunks: print "c:", c;
1027 scan_preamble(chunks)
1028 chunks = process_mudela_blocks(my_outname, chunks)
1030 if __main__.g_run_lilypond:
1031 compile_all_files (chunks)
1035 if c[0] == 'mudela' and 'eps' in c[2]:
1036 body = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, c[1])
1037 newchunks.append (('mudela', body))
1039 newchunks.append (c)
1042 if chunks and chunks[0][0] == 'input':
1043 chunks[0] = ('input', completize_preamble (chunks[0][1]))
1045 foutn = os.path.join(g_outdir, my_outname + '.' + format)
1046 sys.stderr.write ("Writing `%s'\n" % foutn)
1047 fout = open (foutn, 'w')
1053 write_deps (my_depname, foutn)
1058 (sh, long) = getopt_args (__main__.option_definitions)
1059 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1060 except getopt.error, msg:
1061 sys.stderr.write("error: %s" % msg)
1069 if o == '--include' or o == '-I':
1070 include_path.append (a)
1071 elif o == '--version' or o == '-v':
1074 elif o == '--format' or o == '-f':
1076 elif o == '--outname' or o == '-o':
1079 sys.stderr.write("Mudela-book is confused by --outname on multiple files")
1082 elif o == '--help' or o == '-h':
1084 elif o == '--no-lily' or o == '-n':
1085 __main__.g_run_lilypond = 0
1086 elif o == '--dependencies' or o == '-M':
1088 elif o == '--default-music-fontsize':
1089 default_music_fontsize = string.atoi (a)
1090 elif o == '--default-mudela-fontsize':
1091 print "--default-mudela-fontsize is deprecated, use --default-music-fontsize"
1092 default_music_fontsize = string.atoi (a)
1093 elif o == '--force-music-fontsize':
1094 g_force_mudela_fontsize = string.atoi(a)
1095 elif o == '--force-mudela-fontsize':
1096 print "--force-mudela-fontsize is deprecated, use --default-mudela-fontsize"
1097 g_force_mudela_fontsize = string.atoi(a)
1098 elif o == '--dep-prefix':
1100 elif o == '--no-pictures':
1102 elif o == '--read-lys':
1104 elif o == '--outdir':
1109 if os.path.isfile(g_outdir):
1110 error ("outdir is a file: %s" % g_outdir)
1111 if not os.path.exists(g_outdir):
1113 for input_filename in files:
1114 do_file(input_filename)
1117 # Petr, ik zou willen dat ik iets zinvoller deed,
1118 # maar wat ik kan ik doen, het verandert toch niets?