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"(?s)(?P<code>@ignore\s.*?@end ignore)\s",
416 'singleline-comment': r"(?m)(?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 new_chop_chunks(chunks, re_name, func):
697 m = get_re (re_name).search (str)
699 newchunks.append (('input', str))
702 newchunks.append (('input', str[:m.start ('match')]))
703 #newchunks.extend(func(m))
704 # python 1.5 compatible:
705 newchunks = newchunks + func(m)
706 str = str [m.end(0):]
711 def chop_chunks(chunks, re_name, func):
717 m = get_re (re_name).search (str)
719 newchunks.append (('input', str))
722 newchunks.append (('input', str[:m.start (0)]))
723 #newchunks.extend(func(m))
724 # python 1.5 compatible:
725 newchunks = newchunks + func(m)
726 str = str [m.end(0):]
731 def read_doc_file (filename):
732 """Read the input file, find verbatim chunks and do \input and \include
735 str = find_file(filename)
737 if __main__.format == '':
738 latex = re.search ('\\\\document', str[:200])
739 texinfo = re.search ('@node|@setfilename', str[:200])
740 if (texinfo and latex) or not (texinfo or latex):
741 error("error: can't determine format, please specify")
743 __main__.format = 'texi'
745 __main__.format = 'latex'
746 if __main__.format == 'texi':
747 __main__.paperguru = TexiPaper()
749 __main__.paperguru = LatexPaper()
750 chunks = [('input', str)]
751 # we have to check for verbatim before doing include,
752 # because we don't want to include files that are mentioned
753 # inside a verbatim environment
754 chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
755 chunks = chop_chunks(chunks, 'verb', make_verb)
756 chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
758 chunks = new_chop_chunks(chunks, 'include', do_include_file)
759 chunks = new_chop_chunks(chunks, 'input', do_input_file)
763 taken_file_names = {}
764 def schedule_mudela_block (chunk):
765 """Take the body and options from CHUNK, figure out how the
766 real .ly should look, and what should be left MAIN_STR (meant
767 for the main file). The .ly is written, and scheduled in
770 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
772 TODO has format [basename, extension, extension, ... ]
776 (type, body, opts) = chunk
779 (type, body, opts, complete_body) = chunk
780 assert type == 'mudela'
781 file_body = compose_full_body (body, opts)
782 basename = `abs(hash (file_body))`
784 m = re.search ('filename="(.*?)"', o)
786 basename = m.group (1)
787 if not taken_file_names.has_key(basename):
788 taken_file_names[basename] = 0
790 taken_file_names[basename] = taken_file_names[basename] + 1
791 basename = basename + "-%i" % taken_file_names[basename]
792 # writes the file if necessary, returns true if it was written
794 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
795 needed_filetypes = ['tex']
798 needed_filetypes.append('eps')
799 needed_filetypes.append('png')
800 if 'eps' in opts and not ('eps' in needed_filetypes):
801 needed_filetypes.append('eps')
802 outname = os.path.join(g_outdir, basename)
803 if not os.path.isfile(outname + '.tex') \
804 or os.stat(outname+'.ly')[stat.ST_MTIME] > \
805 os.stat(outname+'.tex')[stat.ST_MTIME]:
806 todo = needed_filetypes
811 if 'verbatim' in opts:
812 newbody = output_verbatim (body)
813 elif 'mbverbatim' in opts:
814 newbody = output_mbverbatim (complete_body)
817 m = re.search ('intertext="(.*?)"', o)
819 newbody = newbody + m.group (1) + "\n\n"
820 if format == 'latex':
825 else: # format == 'texi'
827 newbody = newbody + get_output(s) % {'fn': basename }
828 return ('mudela', newbody, opts, todo, basename)
830 def process_mudela_blocks(outname, chunks):#ugh rename
832 # Count sections/chapters.
835 c = schedule_mudela_block (c)
836 elif c[0] == 'numcols':
837 paperguru.m_num_cols = c[2]
842 def find_eps_dims (match):
843 "Fill in dimensions of EPS files."
846 dims = bounding_box_dimensions (fn)
848 return '%ipt' % dims[0]
852 sys.stderr.write ("invoking `%s'\n" % cmd)
855 error ('Error command exited with value %d\n' % st)
858 def compile_all_files (chunks):
873 if base + '.ly' not in tex:
874 tex.append (base + '.ly')
875 elif e == 'png' and g_do_pictures:
881 lilyopts = map (lambda x: '-I ' + x, include_path)
882 lilyopts = string.join (lilyopts, ' ' )
883 texfiles = string.join (tex, ' ')
884 system ('lilypond %s %s' % (lilyopts, texfiles))
886 system(r"tex '\nonstopmode \input %s'" % e)
887 system(r"dvips -E -o %s %s" % (e + '.eps', e))
889 cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
890 cmd = cmd % (g + '.eps', g + '.png')
896 def update_file (body, name):
898 write the body if it has changed
909 f = open (name , 'w')
916 def getopt_args (opts):
917 "Construct arguments (LONG, SHORT) for getopt from list of options."
932 def option_help_str (o):
933 "Transform one option description (4-tuple ) into neatly formatted string"
951 return ' ' + sh + sep + long + arg
954 def options_help_str (opts):
955 "Convert a list of options into a neatly formatted string"
961 s = option_help_str (o)
962 strs.append ((s, o[3]))
968 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
972 sys.stdout.write("""Usage: mudela-book [options] FILE\n
973 Generate hybrid LaTeX input from Latex + mudela
976 sys.stdout.write (options_help_str (option_definitions))
977 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
981 Report bugs to bug-gnu-music@gnu.org.
983 Written by Tom Cato Amundsen <tca@gnu.org> and
984 Han-Wen Nienhuys <hanwen@cs.uu.nl>
990 def write_deps (fn, target):
991 sys.stdout.write('writing `%s\'\n' % os.path.join(g_outdir, fn))
992 f = open (os.path.join(g_outdir, fn), 'w')
993 f.write ('%s%s: ' % (g_dep_prefix, target))
994 for d in __main__.read_files:
998 __main__.read_files = []
1001 sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
1003 def print_version ():
1005 sys.stdout.write (r"""Copyright 1998--1999
1006 Distributed under terms of the GNU General Public License. It comes with
1010 def do_file(input_filename):
1013 my_outname = outname
1015 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
1016 my_depname = my_outname + '.dep'
1018 chunks = read_doc_file(input_filename)
1019 chunks = new_chop_chunks(chunks, 'mudela', make_mudela)
1020 chunks = new_chop_chunks(chunks, 'mudela-file', make_mudela_file)
1021 chunks = new_chop_chunks(chunks, 'mudela-block', make_mudela_block)
1022 chunks = chop_chunks(chunks, 'singleline-comment', do_ignore)
1023 chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
1024 chunks = chop_chunks(chunks, 'numcols', do_columns)
1026 #for c in chunks: print "c:", c;
1028 scan_preamble(chunks)
1029 chunks = process_mudela_blocks(my_outname, chunks)
1031 if __main__.g_run_lilypond:
1032 compile_all_files (chunks)
1036 if c[0] == 'mudela' and 'eps' in c[2]:
1037 body = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, c[1])
1038 newchunks.append (('mudela', body))
1040 newchunks.append (c)
1043 if chunks and chunks[0][0] == 'input':
1044 chunks[0] = ('input', completize_preamble (chunks[0][1]))
1046 foutn = os.path.join(g_outdir, my_outname + '.' + format)
1047 sys.stderr.write ("Writing `%s'\n" % foutn)
1048 fout = open (foutn, 'w')
1054 write_deps (my_depname, foutn)
1059 (sh, long) = getopt_args (__main__.option_definitions)
1060 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1061 except getopt.error, msg:
1062 sys.stderr.write("error: %s" % msg)
1070 if o == '--include' or o == '-I':
1071 include_path.append (a)
1072 elif o == '--version' or o == '-v':
1075 elif o == '--format' or o == '-f':
1077 elif o == '--outname' or o == '-o':
1080 sys.stderr.write("Mudela-book is confused by --outname on multiple files")
1083 elif o == '--help' or o == '-h':
1085 elif o == '--no-lily' or o == '-n':
1086 __main__.g_run_lilypond = 0
1087 elif o == '--dependencies' or o == '-M':
1089 elif o == '--default-music-fontsize':
1090 default_music_fontsize = string.atoi (a)
1091 elif o == '--default-mudela-fontsize':
1092 print "--default-mudela-fontsize is deprecated, use --default-music-fontsize"
1093 default_music_fontsize = string.atoi (a)
1094 elif o == '--force-music-fontsize':
1095 g_force_mudela_fontsize = string.atoi(a)
1096 elif o == '--force-mudela-fontsize':
1097 print "--force-mudela-fontsize is deprecated, use --default-mudela-fontsize"
1098 g_force_mudela_fontsize = string.atoi(a)
1099 elif o == '--dep-prefix':
1101 elif o == '--no-pictures':
1103 elif o == '--read-lys':
1105 elif o == '--outdir':
1110 if os.path.isfile(g_outdir):
1111 error ("outdir is a file: %s" % g_outdir)
1112 if not os.path.exists(g_outdir):
1114 for input_filename in files:
1115 do_file(input_filename)
1118 # Petr, ik zou willen dat ik iets zinvoller deed,
1119 # maar wat ik kan ik doen, het verandert toch niets?