2 # vim: set noexpandtab:
4 # * Figure out clean set of options. Hmm, isn't it pretty ok now?
5 # * add support for .lilyrc
8 # This is was the idea for handling of comments:
9 # Multiline comments, @ignore .. @end ignore is scanned for
10 # in read_doc_file, and the chunks are marked as 'ignore', so
11 # mudela-book will not touch them any more. The content of the
12 # chunks are written to the output file. Also 'include' and 'input'
13 # regex has to check if they are commented out.
15 # Then it is scanned for 'mudela', 'mudela-file' and 'mudela-block'.
16 # These three regex's has to check if they are on a commented line,
17 # % for latex, @c for texinfo.
19 # Then lines that are commented out with % (latex) and @c (Texinfo)
20 # are put into chunks marked 'ignore'. This cannot be done before
21 # searching for the mudela-blocks because % is also the comment character
24 # The the rest of the rexeces are searched for. They don't have to test
25 # if they are on a commented out line.
37 program_version = '@TOPLEVEL_VERSION@'
38 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
39 program_version = '1.3.85'
41 include_path = [os.getcwd()]
45 g_force_mudela_fontsize = 0
53 default_music_fontsize = 16
54 default_text_fontsize = 12
60 # the dimentions are from geometry.sty
61 'a0paper': (mm2pt(841), mm2pt(1189)),
62 'a1paper': (mm2pt(595), mm2pt(841)),
63 'a2paper': (mm2pt(420), mm2pt(595)),
64 'a3paper': (mm2pt(297), mm2pt(420)),
65 'a4paper': (mm2pt(210), mm2pt(297)),
66 'a5paper': (mm2pt(149), mm2pt(210)),
67 'b0paper': (mm2pt(1000), mm2pt(1414)),
68 'b1paper': (mm2pt(707), mm2pt(1000)),
69 'b2paper': (mm2pt(500), mm2pt(707)),
70 'b3paper': (mm2pt(353), mm2pt(500)),
71 'b4paper': (mm2pt(250), mm2pt(353)),
72 'b5paper': (mm2pt(176), mm2pt(250)),
73 'letterpaper': (in2pt(8.5), in2pt(11)),
74 'legalpaper': (in2pt(8.5), in2pt(14)),
75 'executivepaper': (in2pt(7.25), in2pt(10.5))}
76 self.m_use_geometry = None
77 self.m_papersize = 'letterpaper'
81 self.m_geo_landscape = 0
82 self.m_geo_width = None
83 self.m_geo_textwidth = None
84 self.m_geo_lmargin = None
85 self.m_geo_rmargin = None
86 self.m_geo_includemp = None
87 self.m_geo_marginparwidth = {10: 57, 11: 50, 12: 35}
88 self.m_geo_marginparsep = {10: 11, 11: 10, 12: 10}
89 self.m_geo_x_marginparwidth = None
90 self.m_geo_x_marginparsep = None
92 def set_geo_option(self, name, value):
93 if name == 'body' or name == 'text':
94 if type(value) == type(""):
95 self._set_dimen('m_geo_textwidth', value)
97 self._set_dimen('m_geo_textwidth', value[0])
99 elif name == 'portrait':
100 self.m_geo_landscape = 0
101 elif name == 'reversemp' or name == 'reversemarginpar':
102 if self.m_geo_includemp == None:
103 self.m_geo_includemp = 1
104 elif name == 'marginparwidth' or name == 'marginpar':
105 self._set_dimen('m_geo_x_marginparwidth', value)
106 self.m_geo_includemp = 1
107 elif name == 'marginparsep':
108 self._set_dimen('m_geo_x_marginparsep', value)
109 self.m_geo_includemp = 1
110 elif name == 'scale':
111 if type(value) == type(""):
112 self.m_geo_width = self.get_paperwidth() * float(value)
114 self.m_geo_width = self.get_paperwidth() * float(value[0])
115 elif name == 'hscale':
116 self.m_geo_width = self.get_paperwidth() * float(value)
117 elif name == 'left' or name == 'lmargin':
118 self._set_dimen('m_geo_lmargin', value)
119 elif name == 'right' or name == 'rmargin':
120 self._set_dimen('m_geo_rmargin', value)
121 elif name == 'hdivide' or name == 'divide':
122 if value[0] not in ('*', ''):
123 self._set_dimen('m_geo_lmargin', value[0])
124 if value[1] not in ('*', ''):
125 self._set_dimen('m_geo_width', value[1])
126 if value[2] not in ('*', ''):
127 self._set_dimen('m_geo_rmargin', value[2])
128 elif name == 'hmargin':
129 if type(value) == type(""):
130 self._set_dimen('m_geo_lmargin', value)
131 self._set_dimen('m_geo_rmargin', value)
133 self._set_dimen('m_geo_lmargin', value[0])
134 self._set_dimen('m_geo_rmargin', value[1])
135 elif name == 'margin':#ugh there is a bug about this option in
136 # the geometry documentation
137 if type(value) == type(""):
138 self._set_dimen('m_geo_lmargin', value)
139 self._set_dimen('m_geo_rmargin', value)
141 self._set_dimen('m_geo_lmargin', value[0])
142 self._set_dimen('m_geo_rmargin', value[0])
143 elif name == 'total':
144 if type(value) == type(""):
145 self._set_dimen('m_geo_width', value)
147 self._set_dimen('m_geo_width', value[0])
148 elif name == 'width' or name == 'totalwidth':
149 self._set_dimen('m_geo_width', value)
150 elif name == 'paper' or name == 'papername':
151 self.m_papersize = value
152 elif name[-5:] == 'paper':
153 self.m_papersize = name
155 self._set_dimen('m_geo_'+name, value)
156 def _set_dimen(self, name, value):
157 if type(value) == type("") and value[-2:] == 'pt':
158 self.__dict__[name] = float(value[:-2])
159 elif type(value) == type("") and value[-2:] == 'mm':
160 self.__dict__[name] = mm2pt(float(value[:-2]))
161 elif type(value) == type("") and value[-2:] == 'cm':
162 self.__dict__[name] = 10 * mm2pt(float(value[:-2]))
163 elif type(value) == type("") and value[-2:] == 'in':
164 self.__dict__[name] = in2pt(float(value[:-2]))
166 self.__dict__[name] = value
168 print "LatexPaper:\n-----------"
169 for v in self.__dict__.keys():
171 print v, self.__dict__[v]
173 def get_linewidth(self):
174 w = self._calc_linewidth()
175 if self.m_num_cols == 2:
179 def get_paperwidth(self):
180 #if self.m_use_geometry:
181 return self.m_paperdef[self.m_papersize][self.m_landscape or self.m_geo_landscape]
182 #return self.m_paperdef[self.m_papersize][self.m_landscape]
184 def _calc_linewidth(self):
185 # since geometry sometimes ignores 'includemp', this is
186 # more complicated than it should be
188 if self.m_geo_includemp:
189 if self.m_geo_x_marginparsep is not None:
190 mp = mp + self.m_geo_x_marginparsep
192 mp = mp + self.m_geo_marginparsep[self.m_fontsize]
193 if self.m_geo_x_marginparwidth is not None:
194 mp = mp + self.m_geo_x_marginparwidth
196 mp = mp + self.m_geo_marginparwidth[self.m_fontsize]
197 if self.__body:#ugh test if this is necessary
200 return a == None, b == None, c == None
201 if not self.m_use_geometry:
202 return latex_linewidths[self.m_papersize][self.m_fontsize]
204 if tNone(self.m_geo_lmargin, self.m_geo_width,
205 self.m_geo_rmargin) == (1, 1, 1):
206 if self.m_geo_textwidth:
207 return self.m_geo_textwidth
208 w = self.get_paperwidth() * 0.8
210 elif tNone(self.m_geo_lmargin, self.m_geo_width,
211 self.m_geo_rmargin) == (0, 1, 1):
212 if self.m_geo_textwidth:
213 return self.m_geo_textwidth
214 return self.f1(self.m_geo_lmargin, mp)
215 elif tNone(self.m_geo_lmargin, self.m_geo_width,
216 self.m_geo_rmargin) == (1, 1, 0):
217 if self.m_geo_textwidth:
218 return self.m_geo_textwidth
219 return self.f1(self.m_geo_rmargin, mp)
220 elif tNone(self.m_geo_lmargin, self.m_geo_width,
221 self.m_geo_rmargin) \
222 in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
223 if self.m_geo_textwidth:
224 return self.m_geo_textwidth
225 return self.m_geo_width - mp
226 elif tNone(self.m_geo_lmargin, self.m_geo_width,
227 self.m_geo_rmargin) in ((0, 1, 0), (0, 0, 0)):
228 w = self.get_paperwidth() - self.m_geo_lmargin - self.m_geo_rmargin - mp
232 raise "Never do this!"
234 tmp = self.get_paperwidth() - m * 2 - mp
239 tmp = self.get_paperwidth() - self.m_geo_lmargin \
247 self.m_papersize = 'a4'
249 def get_linewidth(self):
250 return texi_linewidths[self.m_papersize][self.m_fontsize]
256 def em2pt(x, fontsize):
257 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
258 def ex2pt(x, fontsize):
259 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
262 # indices are no. of columns, papersize, fontsize
263 # Why can't this be calculated?
265 'a4paper':{10: 345, 11: 360, 12: 390},
266 'a4paper-landscape': {10: 598, 11: 596, 12:592},
267 'a5paper':{10: 276, 11: 276, 12: 276},
268 'b5paper':{10: 345, 11: 356, 12: 356},
269 'letterpaper':{10: 345, 11: 360, 12: 390},
270 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
271 'legalpaper': {10: 345, 11: 360, 12: 390},
272 'executivepaper':{10: 345, 11: 360, 12: 379}}
277 'smallbook': {12: 361},
278 'texidefault': {12: 433}}
280 option_definitions = [
281 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
282 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
283 ('DIM', '', 'default-mudela-fontsize', 'deprecated, use --default-music-fontsize'),
284 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline mudela. DIM is assumed be to in points'),
285 ('DIM', '', 'force-mudela-fontsize', 'deprecated, use --force-music-fontsize'),
286 ('DIR', 'I', 'include', 'include path'),
287 ('', 'M', 'dependencies', 'write dependencies'),
288 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
289 ('', 'n', 'no-lily', 'don\'t run lilypond'),
290 ('', '', 'no-pictures', "don\'t generate pictures"),
291 ('', '', 'read-lys', "don't write ly files."),
292 ('FILE', 'o', 'outname', 'filename main output file'),
293 ('FILE', '', 'outdir', "where to place generated files"),
294 ('', 'v', 'version', 'print version information' ),
295 ('', 'h', 'help', 'print help'),
298 # format specific strings, ie. regex-es for input, and % strings for output
301 'output-mudela-fragment' : r"""\begin[eps,singleline,%s]{mudela}
308 'output-mudela':r"""\begin[%s]{mudela}
311 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
312 'output-default-post': "\\def\postMudelaExample{}\n",
313 'output-default-pre': "\\def\preMudelaExample{}\n",
314 'usepackage-graphics': '\\usepackage{graphics}\n',
315 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
316 'output-tex': '\\preMudelaExample \\input %(fn)s.tex \\postMudelaExample\n',
317 'pagebreak': r'\pagebreak',
319 'texi' : {'output-mudela': """@mudela[%s]
323 'output-mudela-fragment': """@mudela[%s]
324 \context Staff\context Voice{ %s }
327 'output-verbatim': r"""@example
332 # do some tweaking: @ is needed in some ps stuff.
333 # override EndLilyPondOutput, since @tex is done
334 # in a sandbox, you can't do \input lilyponddefs at the
335 # top of the document.
337 # should also support fragment in
339 'output-all': r"""@tex
342 \def\EndLilyPondOutput{}
354 def output_verbatim (body):
355 if __main__.format == 'texi':
356 body = re.sub ('([@{}])', '@\\1', body)
357 return get_output ('output-verbatim') % body
361 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
362 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
363 'option-sep' : ', *',
364 'header': r"\\documentclass\s*(\[.*?\])?",
365 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
366 'preamble-end': r'(?P<code>\\begin{document})',
367 'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
368 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
369 'mudela-file': r'(?m)^[^%\n]*?(?P<match>\\mudelafile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
370 'mudela' : r'(?m)^[^%\n]*?(?P<match>\\mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
371 'mudela-block': r"(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{mudela}(?P<code>.*?)\\end{mudela})",
372 'def-post-re': r"\\def\\postMudelaExample",
373 'def-pre-re': r"\\def\\preMudelaExample",
374 'usepackage-graphics': r"\usepackage{graphics}",
375 'intertext': r',?\s*intertext=\".*?\"',
376 'multiline-comment': no_match,
377 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
378 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
382 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
385 'preamble-end': no_match,
386 'landscape': no_match,
387 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
388 'verb': r"""(?P<code>@code{.*?})""",
389 'mudela-file': '(?m)^(?!@c)(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
390 'mudela' : '(?m)^(?!@c)(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
391 'mudela-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end mudela\s))""",
392 'option-sep' : ', *',
393 'intertext': r',?\s*intertext=\".*?\"',
394 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
395 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
401 for r in re_dict.keys ():
404 for k in olddict.keys ():
405 newdict[k] = re.compile (olddict[k])
419 def get_output (name):
420 return output_dict[format][name]
423 return re_dict[format][name]
425 def bounding_box_dimensions(fname):
429 error ("Error opening `%s'" % fname)
431 s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
433 return (int(s.group(3))-int(s.group(1)),
434 int(s.group(4))-int(s.group(2)))
440 sys.stderr.write (str + "\n Exiting ... \n\n")
444 def compose_full_body (body, opts):
445 """Construct the mudela code to send to Lilypond.
446 Add stuff to BODY using OPTS as options."""
447 music_size = default_music_fontsize
448 latex_size = default_text_fontsize
450 if g_force_mudela_fontsize:
451 music_size = g_force_mudela_fontsize
453 m = re.match ('([0-9]+)pt', o)
455 music_size = string.atoi(m.group (1))
457 m = re.match ('latexfontsize=([0-9]+)pt', o)
459 latex_size = string.atoi (m.group (1))
461 if re.search ('\\\\score', body):
465 if 'fragment' in opts:
467 if 'nonfragment' in opts:
470 if is_fragment and not 'multiline' in opts:
471 opts.append('singleline')
472 if 'singleline' in opts:
475 l = paperguru.get_linewidth()
477 if 'relative' in opts:#ugh only when is_fragment
478 body = '\\relative c { %s }' % body
487 optstring = string.join (opts, ' ')
488 optstring = re.sub ('\n', ' ', optstring)
490 %% Generated by mudela-book.py; options are %s %%ughUGH not original options
491 \include "paper%d.ly"
492 \paper { linewidth = %f \pt; }
493 """ % (optstring, music_size, l) + body
496 def parse_options_string(s):
498 r1 = re.compile("((\w+)={(.*?)})((,\s*)|$)")
499 r2 = re.compile("((\w+)=(.*?))((,\s*)|$)")
500 r3 = re.compile("(\w+?)((,\s*)|$)")
505 d[m.group(2)] = re.split(",\s*", m.group(3))
510 d[m.group(2)] = m.group(3)
517 print "trøbbel:%s:" % s
520 def scan_latex_preamble(chunks):
521 # first we want to scan the \documentclass line
522 # it should be the first non-comment line
525 if chunks[idx][0] == 'ignore':
528 m = get_re ('header').match(chunks[idx][1])
529 options = re.split (',[\n \t]*', m.group(1)[1:-1])
532 paperguru.m_landscape = 1
533 m = re.match("(.*?)paper", o)
535 paperguru.m_papersize = m.group()
537 m = re.match("(\d\d)pt", o)
539 paperguru.m_fontsize = int(m.group(1))
542 while chunks[idx][0] != 'preamble-end':
543 if chunks[idx] == 'ignore':
546 m = get_re ('geometry').search(chunks[idx][1])
548 paperguru.m_use_geometry = 1
549 o = parse_options_string(m.group('options'))
551 paperguru.set_geo_option(k, o[k])
554 def scan_texi_preamble (chunks):
555 # this is not bulletproof..., it checks the first 10 chunks
558 if chunks[idx][0] == 'input':
559 if string.find(chunks[idx][1], "@afourpaper") != -1:
560 paperguru.m_papersize = 'a4'
561 elif string.find(chunks[idx][1], "@afourwide") != -1:
562 paperguru.m_papersize = 'a4wide'
563 elif string.find(chunks[idx][1], "@smallbook") != -1:
564 paperguru.m_papersize = 'smallbook'
566 if idx == 10 or idx == len(chunks):
569 def scan_preamble (chunks):
570 if __main__.format == 'texi':
571 scan_texi_preamble(chunks)
573 assert __main__.format == 'latex'
574 scan_latex_preamble(chunks)
577 def completize_preamble (chunks):
578 if __main__.format == 'texi':
580 pre_b = post_b = graphics_b = None
582 if chunk[0] == 'preamble-end':
584 if chunk[0] == 'input':
585 m = get_re('def-pre-re').search(chunk[1])
588 if chunk[0] == 'input':
589 m = get_re('def-post-re').search(chunk[1])
592 if chunk[0] == 'input':
593 m = get_re('usepackage-graphics').search(chunk[1])
597 while chunks[x][0] != 'preamble-end':
600 chunks.insert(x, ('input', get_output ('output-default-pre')))
602 chunks.insert(x, ('input', get_output ('output-default-post')))
604 chunks.insert(x, ('input', get_output ('usepackage-graphics')))
609 def find_file (name):
611 for a in include_path:
613 nm = os.path.join (a, name)
615 __main__.read_files.append (nm)
622 error ("File not found `%s'\n" % name)
625 def do_ignore(match_object):
626 return [('ignore', match_object.group('code'))]
627 def do_preamble_end(match_object):
628 return [('preamble-end', match_object.group('code'))]
630 def make_verbatim(match_object):
631 return [('verbatim', match_object.group('code'))]
633 def make_verb(match_object):
634 return [('verb', match_object.group('code'))]
636 def do_include_file(m):
638 return [('input', get_output ('pagebreak'))] \
639 + read_doc_file(m.group('filename')) \
640 + [('input', get_output ('pagebreak'))]
642 def do_input_file(m):
643 return read_doc_file(m.group('filename'))
646 if m.group('options'):
647 options = m.group('options')
650 return [('input', get_output('output-mudela-fragment') %
651 (options, m.group('code')))]
653 def make_mudela_file(m):
654 if m.group('options'):
655 options = m.group('options')
658 return [('input', get_output('output-mudela') %
659 (options, find_file(m.group('filename'))))]
661 def make_mudela_block(m):
662 if m.group('options'):
663 options = get_re('option-sep').split (m.group('options'))
666 options = filter(lambda s: s != '', options)
667 return [('mudela', m.group('code'), options)]
670 if __main__.format != 'latex':
672 if m.group('num') == 'one':
673 return [('numcols', m.group('code'), 1)]
674 if m.group('num') == 'two':
675 return [('numcols', m.group('code'), 2)]
677 def chop_chunks(chunks, re_name, func, use_match=0):
683 m = get_re (re_name).search (str)
685 newchunks.append (('input', str))
689 newchunks.append (('input', str[:m.start ('match')]))
691 newchunks.append (('input', str[:m.start (0)]))
692 #newchunks.extend(func(m))
693 # python 1.5 compatible:
694 newchunks = newchunks + func(m)
695 str = str [m.end(0):]
700 def read_doc_file (filename):
701 """Read the input file, find verbatim chunks and do \input and \include
704 str = find_file(filename)
706 if __main__.format == '':
707 latex = re.search ('\\\\document', str[:200])
708 texinfo = re.search ('@node|@setfilename', str[:200])
709 if (texinfo and latex) or not (texinfo or latex):
710 error("error: can't determine format, please specify")
712 __main__.format = 'texi'
714 __main__.format = 'latex'
715 if __main__.format == 'texi':
716 __main__.paperguru = TexiPaper()
718 __main__.paperguru = LatexPaper()
719 chunks = [('input', str)]
720 # we have to check for verbatim before doing include,
721 # because we don't want to include files that are mentioned
722 # inside a verbatim environment
723 chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
724 chunks = chop_chunks(chunks, 'verb', make_verb)
725 chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
727 chunks = chop_chunks(chunks, 'include', do_include_file, 1)
728 chunks = chop_chunks(chunks, 'input', do_input_file, 1)
732 taken_file_names = {}
733 def schedule_mudela_block (chunk):
734 """Take the body and options from CHUNK, figure out how the
735 real .ly should look, and what should be left MAIN_STR (meant
736 for the main file). The .ly is written, and scheduled in
739 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
741 TODO has format [basename, extension, extension, ... ]
744 (type, body, opts) = chunk
745 assert type == 'mudela'
746 file_body = compose_full_body (body, opts)
747 basename = `abs(hash (file_body))`
749 m = re.search ('filename="(.*?)"', o)
751 basename = m.group (1)
752 if not taken_file_names.has_key(basename):
753 taken_file_names[basename] = 0
755 taken_file_names[basename] = taken_file_names[basename] + 1
756 basename = basename + "-%i" % taken_file_names[basename]
758 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
759 needed_filetypes = ['tex']
762 needed_filetypes.append('eps')
763 needed_filetypes.append('png')
764 if 'eps' in opts and not ('eps' in needed_filetypes):
765 needed_filetypes.append('eps')
766 outname = os.path.join(g_outdir, basename)
767 def f(base, ext1, ext2):
768 a = os.path.isfile(base + ext2)
769 if (os.path.isfile(base + ext1) and
770 os.path.isfile(base + ext2) and
771 os.stat(base+ext1)[stat.ST_MTIME] >
772 os.stat(base+ext2)[stat.ST_MTIME]) or \
773 not os.path.isfile(base + ext2):
776 if 'tex' in needed_filetypes and f(outname, '.ly', '.tex'):
778 if 'eps' in needed_filetypes and f(outname, '.tex', '.eps'):
780 if 'png' in needed_filetypes and f(outname, '.eps', '.png'):
783 if 'verbatim' in opts:
784 newbody = output_verbatim (body)
787 m = re.search ('intertext="(.*?)"', o)
789 newbody = newbody + m.group (1) + "\n\n"
790 if format == 'latex':
795 else: # format == 'texi'
797 newbody = newbody + get_output(s) % {'fn': basename }
798 return ('mudela', newbody, opts, todo, basename)
800 def process_mudela_blocks(outname, chunks):#ugh rename
802 # Count sections/chapters.
805 c = schedule_mudela_block (c)
806 elif c[0] == 'numcols':
807 paperguru.m_num_cols = c[2]
812 def find_eps_dims (match):
813 "Fill in dimensions of EPS files."
816 dims = bounding_box_dimensions (fn)
818 return '%ipt' % dims[0]
822 sys.stderr.write ("invoking `%s'\n" % cmd)
825 error ('Error command exited with value %d\n' % st)
828 def compile_all_files (chunks):
843 if base + '.ly' not in tex:
844 tex.append (base + '.ly')
845 elif e == 'png' and g_do_pictures:
851 lilyopts = map (lambda x: '-I ' + x, include_path)
852 lilyopts = string.join (lilyopts, ' ' )
853 texfiles = string.join (tex, ' ')
854 system ('lilypond %s %s' % (lilyopts, texfiles))
856 system(r"tex '\nonstopmode \input %s'" % e)
857 system(r"dvips -E -o %s %s" % (e + '.eps', e))
859 cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
860 cmd = cmd % (g + '.eps', g + '.png')
866 def update_file (body, name):
868 write the body if it has changed
879 f = open (name , 'w')
886 def getopt_args (opts):
887 "Construct arguments (LONG, SHORT) for getopt from list of options."
902 def option_help_str (o):
903 "Transform one option description (4-tuple ) into neatly formatted string"
921 return ' ' + sh + sep + long + arg
924 def options_help_str (opts):
925 "Convert a list of options into a neatly formatted string"
931 s = option_help_str (o)
932 strs.append ((s, o[3]))
938 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
942 sys.stdout.write("""Usage: mudela-book [options] FILE\n
943 Generate hybrid LaTeX input from Latex + mudela
946 sys.stdout.write (options_help_str (option_definitions))
947 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
951 Report bugs to bug-gnu-music@gnu.org.
953 Written by Tom Cato Amundsen <tca@gnu.org> and
954 Han-Wen Nienhuys <hanwen@cs.uu.nl>
960 def write_deps (fn, target):
961 sys.stdout.write('writing `%s\'\n' % os.path.join(g_outdir, fn))
962 f = open (os.path.join(g_outdir, fn), 'w')
963 f.write ('%s%s: ' % (g_dep_prefix, target))
964 for d in __main__.read_files:
968 __main__.read_files = []
971 sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
973 def print_version ():
975 sys.stdout.write (r"""Copyright 1998--1999
976 Distributed under terms of the GNU General Public License. It comes with
980 def do_file(input_filename):
985 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
986 my_depname = my_outname + '.dep'
988 chunks = read_doc_file(input_filename)
989 chunks = chop_chunks(chunks, 'mudela', make_mudela, 1)
990 chunks = chop_chunks(chunks, 'mudela-file', make_mudela_file, 1)
991 chunks = chop_chunks(chunks, 'mudela-block', make_mudela_block, 1)
992 chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
993 chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
994 chunks = chop_chunks(chunks, 'numcols', do_columns)
996 #for c in chunks: print "c:", c;
998 scan_preamble(chunks)
999 chunks = process_mudela_blocks(my_outname, chunks)
1001 if __main__.g_run_lilypond:
1002 compile_all_files (chunks)
1006 if c[0] == 'mudela' and 'eps' in c[2]:
1007 body = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, c[1])
1008 newchunks.append (('mudela', body))
1010 newchunks.append (c)
1013 chunks = completize_preamble (chunks)
1014 foutn = os.path.join(g_outdir, my_outname + '.' + format)
1015 sys.stderr.write ("Writing `%s'\n" % foutn)
1016 fout = open (foutn, 'w')
1022 write_deps (my_depname, foutn)
1027 (sh, long) = getopt_args (__main__.option_definitions)
1028 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1029 except getopt.error, msg:
1030 sys.stderr.write("error: %s" % msg)
1038 if o == '--include' or o == '-I':
1039 include_path.append (a)
1040 elif o == '--version' or o == '-v':
1043 elif o == '--format' or o == '-f':
1045 elif o == '--outname' or o == '-o':
1048 sys.stderr.write("Mudela-book is confused by --outname on multiple files")
1051 elif o == '--help' or o == '-h':
1053 elif o == '--no-lily' or o == '-n':
1054 __main__.g_run_lilypond = 0
1055 elif o == '--dependencies' or o == '-M':
1057 elif o == '--default-music-fontsize':
1058 default_music_fontsize = string.atoi (a)
1059 elif o == '--default-mudela-fontsize':
1060 print "--default-mudela-fontsize is deprecated, use --default-music-fontsize"
1061 default_music_fontsize = string.atoi (a)
1062 elif o == '--force-music-fontsize':
1063 g_force_mudela_fontsize = string.atoi(a)
1064 elif o == '--force-mudela-fontsize':
1065 print "--force-mudela-fontsize is deprecated, use --default-mudela-fontsize"
1066 g_force_mudela_fontsize = string.atoi(a)
1067 elif o == '--dep-prefix':
1069 elif o == '--no-pictures':
1071 elif o == '--read-lys':
1073 elif o == '--outdir':
1078 if os.path.isfile(g_outdir):
1079 error ("outdir is a file: %s" % g_outdir)
1080 if not os.path.exists(g_outdir):
1082 for input_filename in files:
1083 do_file(input_filename)
1086 # Petr, ik zou willen dat ik iets zinvoller deed,
1087 # maar wat ik kan ik doen, het verandert toch niets?