2 # vim: set noexpandtab:
4 # * Figure out clean set of options. Hmm, isn't it pretty ok now?
5 # * add support for .lilyrc
8 # todo: dimension handling (all the x2y) is clumsy.
10 # This is was the idea for handling of comments:
11 # Multiline comments, @ignore .. @end ignore is scanned for
12 # in read_doc_file, and the chunks are marked as 'ignore', so
13 # mudela-book will not touch them any more. The content of the
14 # chunks are written to the output file. Also 'include' and 'input'
15 # regex has to check if they are commented out.
17 # Then it is scanned for 'mudela', 'mudela-file' and 'mudela-block'.
18 # These three regex's has to check if they are on a commented line,
19 # % for latex, @c for texinfo.
21 # Then lines that are commented out with % (latex) and @c (Texinfo)
22 # are put into chunks marked 'ignore'. This cannot be done before
23 # searching for the mudela-blocks because % is also the comment character
26 # The the rest of the rexeces are searched for. They don't have to test
27 # if they are on a commented out line.
39 program_version
= '@TOPLEVEL_VERSION@'
40 if program_version
== '@' + 'TOPLEVEL_VERSION' + '@':
41 program_version
= '1.3.106'
43 include_path
= [os
.getcwd()]
46 # g_ is for global (?)
48 g_here_dir
= os
.getcwd ()
51 g_force_mudela_fontsize
= 0
59 default_music_fontsize
= 16
60 default_text_fontsize
= 12
66 # the dimentions are from geometry.sty
67 'a0paper': (mm2pt(841), mm2pt(1189)),
68 'a1paper': (mm2pt(595), mm2pt(841)),
69 'a2paper': (mm2pt(420), mm2pt(595)),
70 'a3paper': (mm2pt(297), mm2pt(420)),
71 'a4paper': (mm2pt(210), mm2pt(297)),
72 'a5paper': (mm2pt(149), mm2pt(210)),
73 'b0paper': (mm2pt(1000), mm2pt(1414)),
74 'b1paper': (mm2pt(707), mm2pt(1000)),
75 'b2paper': (mm2pt(500), mm2pt(707)),
76 'b3paper': (mm2pt(353), mm2pt(500)),
77 'b4paper': (mm2pt(250), mm2pt(353)),
78 'b5paper': (mm2pt(176), mm2pt(250)),
79 'letterpaper': (in2pt(8.5), in2pt(11)),
80 'legalpaper': (in2pt(8.5), in2pt(14)),
81 'executivepaper': (in2pt(7.25), in2pt(10.5))}
82 self
.m_use_geometry
= None
83 self
.m_papersize
= 'letterpaper'
87 self
.m_geo_landscape
= 0
88 self
.m_geo_width
= None
89 self
.m_geo_textwidth
= None
90 self
.m_geo_lmargin
= None
91 self
.m_geo_rmargin
= None
92 self
.m_geo_includemp
= None
93 self
.m_geo_marginparwidth
= {10: 57, 11: 50, 12: 35}
94 self
.m_geo_marginparsep
= {10: 11, 11: 10, 12: 10}
95 self
.m_geo_x_marginparwidth
= None
96 self
.m_geo_x_marginparsep
= None
98 def set_geo_option(self
, name
, value
):
99 if name
== 'body' or name
== 'text':
100 if type(value
) == type(""):
101 self
._set
_dimen
('m_geo_textwidth', value
)
103 self
._set
_dimen
('m_geo_textwidth', value
[0])
105 elif name
== 'portrait':
106 self
.m_geo_landscape
= 0
107 elif name
== 'reversemp' or name
== 'reversemarginpar':
108 if self
.m_geo_includemp
== None:
109 self
.m_geo_includemp
= 1
110 elif name
== 'marginparwidth' or name
== 'marginpar':
111 self
._set
_dimen
('m_geo_x_marginparwidth', value
)
112 self
.m_geo_includemp
= 1
113 elif name
== 'marginparsep':
114 self
._set
_dimen
('m_geo_x_marginparsep', value
)
115 self
.m_geo_includemp
= 1
116 elif name
== 'scale':
117 if type(value
) == type(""):
118 self
.m_geo_width
= self
.get_paperwidth() * float(value
)
120 self
.m_geo_width
= self
.get_paperwidth() * float(value
[0])
121 elif name
== 'hscale':
122 self
.m_geo_width
= self
.get_paperwidth() * float(value
)
123 elif name
== 'left' or name
== 'lmargin':
124 self
._set
_dimen
('m_geo_lmargin', value
)
125 elif name
== 'right' or name
== 'rmargin':
126 self
._set
_dimen
('m_geo_rmargin', value
)
127 elif name
== 'hdivide' or name
== 'divide':
128 if value
[0] not in ('*', ''):
129 self
._set
_dimen
('m_geo_lmargin', value
[0])
130 if value
[1] not in ('*', ''):
131 self
._set
_dimen
('m_geo_width', value
[1])
132 if value
[2] not in ('*', ''):
133 self
._set
_dimen
('m_geo_rmargin', value
[2])
134 elif name
== 'hmargin':
135 if type(value
) == type(""):
136 self
._set
_dimen
('m_geo_lmargin', value
)
137 self
._set
_dimen
('m_geo_rmargin', value
)
139 self
._set
_dimen
('m_geo_lmargin', value
[0])
140 self
._set
_dimen
('m_geo_rmargin', value
[1])
141 elif name
== 'margin':#ugh there is a bug about this option in
142 # the geometry documentation
143 if type(value
) == type(""):
144 self
._set
_dimen
('m_geo_lmargin', value
)
145 self
._set
_dimen
('m_geo_rmargin', value
)
147 self
._set
_dimen
('m_geo_lmargin', value
[0])
148 self
._set
_dimen
('m_geo_rmargin', value
[0])
149 elif name
== 'total':
150 if type(value
) == type(""):
151 self
._set
_dimen
('m_geo_width', value
)
153 self
._set
_dimen
('m_geo_width', value
[0])
154 elif name
== 'width' or name
== 'totalwidth':
155 self
._set
_dimen
('m_geo_width', value
)
156 elif name
== 'paper' or name
== 'papername':
157 self
.m_papersize
= value
158 elif name
[-5:] == 'paper':
159 self
.m_papersize
= name
161 self
._set
_dimen
('m_geo_'+name
, value
)
162 def _set_dimen(self
, name
, value
):
163 if type(value
) == type("") and value
[-2:] == 'pt':
164 self
.__dict
__[name
] = float(value
[:-2])
165 elif type(value
) == type("") and value
[-2:] == 'mm':
166 self
.__dict
__[name
] = mm2pt(float(value
[:-2]))
167 elif type(value
) == type("") and value
[-2:] == 'cm':
168 self
.__dict
__[name
] = 10 * mm2pt(float(value
[:-2]))
169 elif type(value
) == type("") and value
[-2:] == 'in':
170 self
.__dict
__[name
] = in2pt(float(value
[:-2]))
172 self
.__dict
__[name
] = value
174 print "LatexPaper:\n-----------"
175 for v
in self
.__dict
__.keys():
177 print v
, self
.__dict
__[v
]
179 def get_linewidth(self
):
180 w
= self
._calc
_linewidth
()
181 if self
.m_num_cols
== 2:
185 def get_paperwidth(self
):
186 #if self.m_use_geometry:
187 return self
.m_paperdef
[self
.m_papersize
][self
.m_landscape
or self
.m_geo_landscape
]
188 #return self.m_paperdef[self.m_papersize][self.m_landscape]
190 def _calc_linewidth(self
):
191 # since geometry sometimes ignores 'includemp', this is
192 # more complicated than it should be
194 if self
.m_geo_includemp
:
195 if self
.m_geo_x_marginparsep
is not None:
196 mp
= mp
+ self
.m_geo_x_marginparsep
198 mp
= mp
+ self
.m_geo_marginparsep
[self
.m_fontsize
]
199 if self
.m_geo_x_marginparwidth
is not None:
200 mp
= mp
+ self
.m_geo_x_marginparwidth
202 mp
= mp
+ self
.m_geo_marginparwidth
[self
.m_fontsize
]
203 if self
.__body
:#ugh test if this is necessary
206 return a
== None, b
== None, c
== None
207 if not self
.m_use_geometry
:
208 return latex_linewidths
[self
.m_papersize
][self
.m_fontsize
]
210 if tNone(self
.m_geo_lmargin
, self
.m_geo_width
,
211 self
.m_geo_rmargin
) == (1, 1, 1):
212 if self
.m_geo_textwidth
:
213 return self
.m_geo_textwidth
214 w
= self
.get_paperwidth() * 0.8
216 elif tNone(self
.m_geo_lmargin
, self
.m_geo_width
,
217 self
.m_geo_rmargin
) == (0, 1, 1):
218 if self
.m_geo_textwidth
:
219 return self
.m_geo_textwidth
220 return self
.f1(self
.m_geo_lmargin
, mp
)
221 elif tNone(self
.m_geo_lmargin
, self
.m_geo_width
,
222 self
.m_geo_rmargin
) == (1, 1, 0):
223 if self
.m_geo_textwidth
:
224 return self
.m_geo_textwidth
225 return self
.f1(self
.m_geo_rmargin
, mp
)
226 elif tNone(self
.m_geo_lmargin
, self
.m_geo_width
,
227 self
.m_geo_rmargin
) \
228 in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
229 if self
.m_geo_textwidth
:
230 return self
.m_geo_textwidth
231 return self
.m_geo_width
- mp
232 elif tNone(self
.m_geo_lmargin
, self
.m_geo_width
,
233 self
.m_geo_rmargin
) in ((0, 1, 0), (0, 0, 0)):
234 w
= self
.get_paperwidth() - self
.m_geo_lmargin
- self
.m_geo_rmargin
- mp
238 raise "Never do this!"
240 tmp
= self
.get_paperwidth() - m
* 2 - mp
245 tmp
= self
.get_paperwidth() - self
.m_geo_lmargin \
253 self
.m_papersize
= 'a4'
255 def get_linewidth(self
):
256 return texi_linewidths
[self
.m_papersize
][self
.m_fontsize
]
262 def em2pt(x
, fontsize
):
263 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize
] * x
264 def ex2pt(x
, fontsize
):
265 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize
] * x
268 # indices are no. of columns, papersize, fontsize
269 # Why can't this be calculated?
271 'a4paper':{10: 345, 11: 360, 12: 390},
272 'a4paper-landscape': {10: 598, 11: 596, 12:592},
273 'a5paper':{10: 276, 11: 276, 12: 276},
274 'b5paper':{10: 345, 11: 356, 12: 356},
275 'letterpaper':{10: 345, 11: 360, 12: 390},
276 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
277 'legalpaper': {10: 345, 11: 360, 12: 390},
278 'executivepaper':{10: 345, 11: 360, 12: 379}}
283 'smallbook': {12: 361},
284 'texidefault': {12: 433}}
286 option_definitions
= [
287 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
288 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
289 ('DIM', '', 'default-mudela-fontsize', 'deprecated, use --default-music-fontsize'),
290 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline mudela. DIM is assumed be to in points'),
291 ('DIM', '', 'force-mudela-fontsize', 'deprecated, use --force-music-fontsize'),
292 ('DIR', 'I', 'include', 'include path'),
293 ('', 'M', 'dependencies', 'write dependencies'),
294 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
295 ('', 'n', 'no-lily', 'don\'t run lilypond'),
296 ('', '', 'no-pictures', "don\'t generate pictures"),
297 ('', '', 'read-lys', "don't write ly files."),
298 ('FILE', 'o', 'outname', 'filename main output file'),
299 ('FILE', '', 'outdir', "where to place generated files"),
300 ('', 'v', 'version', 'print version information' ),
301 ('', 'h', 'help', 'print help'),
304 # format specific strings, ie. regex-es for input, and % strings for output
307 'output-mudela-fragment' : r
"""\begin[eps,singleline,%s]{mudela}
314 'output-mudela':r
"""\begin[%s]{mudela}
317 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
318 'output-default-post': "\\def\postMudelaExample{}\n",
319 'output-default-pre': "\\def\preMudelaExample{}\n",
320 'usepackage-graphics': '\\usepackage{graphics}\n',
321 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
322 'output-tex': '\\preMudelaExample \\input %(fn)s.tex \\postMudelaExample\n',
323 'pagebreak': r
'\pagebreak',
325 'texi' : {'output-mudela': """@mudela[%s]
329 'output-mudela-fragment': """@mudela[%s]
330 \context Staff\context Voice{ %s }
333 'output-verbatim': r
"""@example
338 # do some tweaking: @ is needed in some ps stuff.
339 # override EndLilyPondOutput, since @tex is done
340 # in a sandbox, you can't do \input lilyponddefs at the
341 # top of the document.
343 # should also support fragment in
345 'output-all': r
"""@tex
348 \def\EndLilyPondOutput{}
360 def output_verbatim (body
):
361 if __main__
.format
== 'texi':
362 body
= re
.sub ('([@{}])', '@\\1', body
)
363 return get_output ('output-verbatim') % body
367 'latex': {'input': r
'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
368 'include': r
'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
369 'option-sep' : ', *',
370 'header': r
"\\documentclass\s*(\[.*?\])?",
371 'geometry': r
"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
372 'preamble-end': r
'(?P<code>\\begin{document})',
373 'verbatim': r
"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
374 'verb': r
"(?P<code>\\verb(?P<del>.).*?(?P=del))",
375 'mudela-file': r
'(?m)^[^%\n]*?(?P<match>\\mudelafile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
376 'mudela' : r
'(?m)^[^%\n]*?(?P<match>\\mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
377 'mudela-block': r
"(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{mudela}(?P<code>.*?)\\end{mudela})",
378 'def-post-re': r
"\\def\\postMudelaExample",
379 'def-pre-re': r
"\\def\\preMudelaExample",
380 'usepackage-graphics': r
"\usepackage{graphics}",
381 'intertext': r
',?\s*intertext=\".*?\"',
382 'multiline-comment': no_match
,
383 'singleline-comment': r
"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
384 'numcols': r
"(?P<code>\\(?P<num>one|two)column)",
388 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
391 'preamble-end': no_match
,
392 'landscape': no_match
,
393 'verbatim': r
"""(?s)(?P<code>@example\s.*?@end example\s)""",
394 'verb': r
"""(?P<code>@code{.*?})""",
395 'mudela-file': '(?m)^(?!@c)(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
396 'mudela' : '(?m)^(?!@c)(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
397 'mudela-block': r
"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end mudela\s))""",
398 'option-sep' : ', *',
399 'intertext': r
',?\s*intertext=\".*?\"',
400 'multiline-comment': r
"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
401 'singleline-comment': r
"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
407 for r
in re_dict
.keys ():
410 for k
in olddict
.keys ():
411 newdict
[k
] = re
.compile (olddict
[k
])
425 def get_output (name
):
426 return output_dict
[format
][name
]
429 return re_dict
[format
][name
]
431 def bounding_box_dimensions(fname
):
435 error ("Error opening `%s'" % fname
)
437 s
= re
.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
439 return (int(s
.group(3))-int(s
.group(1)),
440 int(s
.group(4))-int(s
.group(2)))
446 sys
.stderr
.write (str + "\n Exiting ... \n\n")
450 def compose_full_body (body
, opts
):
451 """Construct the mudela code to send to Lilypond.
452 Add stuff to BODY using OPTS as options."""
453 music_size
= default_music_fontsize
454 latex_size
= default_text_fontsize
456 if g_force_mudela_fontsize
:
457 music_size
= g_force_mudela_fontsize
459 m
= re
.match ('([0-9]+)pt', o
)
461 music_size
= string
.atoi(m
.group (1))
463 m
= re
.match ('latexfontsize=([0-9]+)pt', o
)
465 latex_size
= string
.atoi (m
.group (1))
467 if re
.search ('\\\\score', body
):
471 if 'fragment' in opts
:
473 if 'nonfragment' in opts
:
476 if is_fragment
and not 'multiline' in opts
:
477 opts
.append('singleline')
478 if 'singleline' in opts
:
481 l
= paperguru
.get_linewidth()
483 if 'relative' in opts
:#ugh only when is_fragment
484 body
= '\\relative c { %s }' % body
493 optstring
= string
.join (opts
, ' ')
494 optstring
= re
.sub ('\n', ' ', optstring
)
496 %% Generated by mudela-book.py; options are %s %%ughUGH not original options
497 \include "paper%d.ly"
498 \paper { linewidth = %f \pt; }
499 """ % (optstring
, music_size
, l
) + body
502 def parse_options_string(s
):
504 r1
= re
.compile("((\w+)={(.*?)})((,\s*)|$)")
505 r2
= re
.compile("((\w+)=(.*?))((,\s*)|$)")
506 r3
= re
.compile("(\w+?)((,\s*)|$)")
511 d
[m
.group(2)] = re
.split(",\s*", m
.group(3))
516 d
[m
.group(2)] = m
.group(3)
523 print "trøbbel:%s:" % s
526 def scan_latex_preamble(chunks
):
527 # first we want to scan the \documentclass line
528 # it should be the first non-comment line
531 if chunks
[idx
][0] == 'ignore':
534 m
= get_re ('header').match(chunks
[idx
][1])
535 options
= re
.split (',[\n \t]*', m
.group(1)[1:-1])
538 paperguru
.m_landscape
= 1
539 m
= re
.match("(.*?)paper", o
)
541 paperguru
.m_papersize
= m
.group()
543 m
= re
.match("(\d\d)pt", o
)
545 paperguru
.m_fontsize
= int(m
.group(1))
548 while chunks
[idx
][0] != 'preamble-end':
549 if chunks
[idx
] == 'ignore':
552 m
= get_re ('geometry').search(chunks
[idx
][1])
554 paperguru
.m_use_geometry
= 1
555 o
= parse_options_string(m
.group('options'))
557 paperguru
.set_geo_option(k
, o
[k
])
560 def scan_texi_preamble (chunks
):
561 # this is not bulletproof..., it checks the first 10 chunks
564 if chunks
[idx
][0] == 'input':
565 if string
.find(chunks
[idx
][1], "@afourpaper") != -1:
566 paperguru
.m_papersize
= 'a4'
567 elif string
.find(chunks
[idx
][1], "@afourwide") != -1:
568 paperguru
.m_papersize
= 'a4wide'
569 elif string
.find(chunks
[idx
][1], "@smallbook") != -1:
570 paperguru
.m_papersize
= 'smallbook'
572 if idx
== 10 or idx
== len(chunks
):
575 def scan_preamble (chunks
):
576 if __main__
.format
== 'texi':
577 scan_texi_preamble(chunks
)
579 assert __main__
.format
== 'latex'
580 scan_latex_preamble(chunks
)
583 def completize_preamble (chunks
):
584 if __main__
.format
== 'texi':
586 pre_b
= post_b
= graphics_b
= None
588 if chunk
[0] == 'preamble-end':
590 if chunk
[0] == 'input':
591 m
= get_re('def-pre-re').search(chunk
[1])
594 if chunk
[0] == 'input':
595 m
= get_re('def-post-re').search(chunk
[1])
598 if chunk
[0] == 'input':
599 m
= get_re('usepackage-graphics').search(chunk
[1])
603 while chunks
[x
][0] != 'preamble-end':
606 chunks
.insert(x
, ('input', get_output ('output-default-pre')))
608 chunks
.insert(x
, ('input', get_output ('output-default-post')))
610 chunks
.insert(x
, ('input', get_output ('usepackage-graphics')))
615 def find_file (name
):
617 for a
in include_path
:
619 nm
= os
.path
.join (a
, name
)
621 __main__
.read_files
.append (nm
)
628 error ("File not found `%s'\n" % name
)
631 def do_ignore(match_object
):
632 return [('ignore', match_object
.group('code'))]
633 def do_preamble_end(match_object
):
634 return [('preamble-end', match_object
.group('code'))]
636 def make_verbatim(match_object
):
637 return [('verbatim', match_object
.group('code'))]
639 def make_verb(match_object
):
640 return [('verb', match_object
.group('code'))]
642 def do_include_file(m
):
644 return [('input', get_output ('pagebreak'))] \
645 + read_doc_file(m
.group('filename')) \
646 + [('input', get_output ('pagebreak'))]
648 def do_input_file(m
):
649 return read_doc_file(m
.group('filename'))
652 if m
.group('options'):
653 options
= m
.group('options')
656 return [('input', get_output('output-mudela-fragment') %
657 (options
, m
.group('code')))]
659 def make_mudela_file(m
):
660 if m
.group('options'):
661 options
= m
.group('options')
664 return [('input', get_output('output-mudela') %
665 (options
, find_file(m
.group('filename'))))]
667 def make_mudela_block(m
):
668 if m
.group('options'):
669 options
= get_re('option-sep').split (m
.group('options'))
672 options
= filter(lambda s
: s
!= '', options
)
673 return [('mudela', m
.group('code'), options
)]
676 if __main__
.format
!= 'latex':
678 if m
.group('num') == 'one':
679 return [('numcols', m
.group('code'), 1)]
680 if m
.group('num') == 'two':
681 return [('numcols', m
.group('code'), 2)]
683 def chop_chunks(chunks
, re_name
, func
, use_match
=0):
689 m
= get_re (re_name
).search (str)
691 newchunks
.append (('input', str))
695 newchunks
.append (('input', str[:m
.start ('match')]))
697 newchunks
.append (('input', str[:m
.start (0)]))
698 #newchunks.extend(func(m))
699 # python 1.5 compatible:
700 newchunks
= newchunks
+ func(m
)
701 str = str [m
.end(0):]
706 def read_doc_file (filename
):
707 """Read the input file, find verbatim chunks and do \input and \include
710 str = find_file(filename
)
712 if __main__
.format
== '':
713 latex
= re
.search ('\\\\document', str[:200])
714 texinfo
= re
.search ('@node|@setfilename', str[:200])
715 if (texinfo
and latex
) or not (texinfo
or latex
):
716 error("error: can't determine format, please specify")
718 __main__
.format
= 'texi'
720 __main__
.format
= 'latex'
721 if __main__
.format
== 'texi':
722 __main__
.paperguru
= TexiPaper()
724 __main__
.paperguru
= LatexPaper()
725 chunks
= [('input', str)]
726 # we have to check for verbatim before doing include,
727 # because we don't want to include files that are mentioned
728 # inside a verbatim environment
729 chunks
= chop_chunks(chunks
, 'verbatim', make_verbatim
)
730 chunks
= chop_chunks(chunks
, 'verb', make_verb
)
731 chunks
= chop_chunks(chunks
, 'multiline-comment', do_ignore
)
733 chunks
= chop_chunks(chunks
, 'include', do_include_file
, 1)
734 chunks
= chop_chunks(chunks
, 'input', do_input_file
, 1)
738 taken_file_names
= {}
739 def schedule_mudela_block (chunk
):
740 """Take the body and options from CHUNK, figure out how the
741 real .ly should look, and what should be left MAIN_STR (meant
742 for the main file). The .ly is written, and scheduled in
745 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
747 TODO has format [basename, extension, extension, ... ]
750 (type, body
, opts
) = chunk
751 assert type == 'mudela'
752 file_body
= compose_full_body (body
, opts
)
753 basename
= `
abs(hash (file_body
))`
755 m
= re
.search ('filename="(.*?)"', o
)
757 basename
= m
.group (1)
758 if not taken_file_names
.has_key(basename
):
759 taken_file_names
[basename
] = 0
761 taken_file_names
[basename
] = taken_file_names
[basename
] + 1
762 basename
= basename
+ "-%i" % taken_file_names
[basename
]
764 update_file(file_body
, os
.path
.join(g_outdir
, basename
) + '.ly')
765 needed_filetypes
= ['tex']
768 needed_filetypes
.append('eps')
769 needed_filetypes
.append('png')
770 if 'eps' in opts
and not ('eps' in needed_filetypes
):
771 needed_filetypes
.append('eps')
772 outname
= os
.path
.join(g_outdir
, basename
)
773 def f(base
, ext1
, ext2
):
774 a
= os
.path
.isfile(base
+ ext2
)
775 if (os
.path
.isfile(base
+ ext1
) and
776 os
.path
.isfile(base
+ ext2
) and
777 os
.stat(base
+ext1
)[stat
.ST_MTIME
] >
778 os
.stat(base
+ext2
)[stat
.ST_MTIME
]) or \
779 not os
.path
.isfile(base
+ ext2
):
782 if 'tex' in needed_filetypes
and f(outname
, '.ly', '.tex'):
784 if 'eps' in needed_filetypes
and f(outname
, '.tex', '.eps'):
786 if 'png' in needed_filetypes
and f(outname
, '.eps', '.png'):
789 if 'verbatim' in opts
:
790 newbody
= output_verbatim (body
)
793 m
= re
.search ('intertext="(.*?)"', o
)
795 newbody
= newbody
+ m
.group (1) + "\n\n"
796 if format
== 'latex':
801 else: # format == 'texi'
803 newbody
= newbody
+ get_output(s
) % {'fn': basename
}
804 return ('mudela', newbody
, opts
, todo
, basename
)
806 def process_mudela_blocks(outname
, chunks
):#ugh rename
808 # Count sections/chapters.
811 c
= schedule_mudela_block (c
)
812 elif c
[0] == 'numcols':
813 paperguru
.m_num_cols
= c
[2]
818 def find_eps_dims (match
):
819 "Fill in dimensions of EPS files."
822 dims
= bounding_box_dimensions (fn
)
824 fn
= os
.path
.join(g_outdir
, fn
)
826 return '%ipt' % dims
[0]
830 sys
.stderr
.write ("invoking `%s'\n" % cmd
)
833 error ('Error command exited with value %d\n' % st
)
836 def compile_all_files (chunks
):
851 if base
+ '.ly' not in tex
:
852 tex
.append (base
+ '.ly')
853 elif e
== 'png' and g_do_pictures
:
859 # fixme: be sys-independent.
861 if g_outdir
and x
[0] <> '/' :
862 x
= os
.path
.join (g_here_dir
, x
)
865 incs
= map (incl_opt
, include_path
)
866 lilyopts
= string
.join (incs
, ' ' )
867 texfiles
= string
.join (tex
, ' ')
868 system ('lilypond %s %s' % (lilyopts
, texfiles
))
870 system(r
"tex '\nonstopmode \input %s'" % e
)
871 system(r
"dvips -E -o %s %s" % (e
+ '.eps', e
))
873 cmd
= r
"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
874 cmd
= cmd
% (g
+ '.eps', g
+ '.png')
880 def update_file (body
, name
):
882 write the body if it has changed
893 f
= open (name
, 'w')
900 def getopt_args (opts
):
901 "Construct arguments (LONG, SHORT) for getopt from list of options."
916 def option_help_str (o
):
917 "Transform one option description (4-tuple ) into neatly formatted string"
935 return ' ' + sh
+ sep
+ long + arg
938 def options_help_str (opts
):
939 "Convert a list of options into a neatly formatted string"
945 s
= option_help_str (o
)
946 strs
.append ((s
, o
[3]))
952 str = str + '%s%s%s\n' % (s
[0], ' ' * (w
- len(s
[0]) + 3), s
[1])
956 sys
.stdout
.write("""Usage: mudela-book [options] FILE\n
957 Generate hybrid LaTeX input from Latex + mudela
960 sys
.stdout
.write (options_help_str (option_definitions
))
961 sys
.stdout
.write (r
"""Warning all output is written in the CURRENT directory
965 Report bugs to bug-gnu-music@gnu.org.
967 Written by Tom Cato Amundsen <tca@gnu.org> and
968 Han-Wen Nienhuys <hanwen@cs.uu.nl>
974 def write_deps (fn
, target
):
975 sys
.stdout
.write('writing `%s\'\n' % os
.path
.join(g_outdir
, fn
))
976 f
= open (os
.path
.join(g_outdir
, fn
), 'w')
977 f
.write ('%s%s: ' % (g_dep_prefix
, target
))
978 for d
in __main__
.read_files
:
982 __main__
.read_files
= []
985 sys
.stdout
.write ('mudela-book (GNU LilyPond) %s\n' % program_version
)
987 def print_version ():
989 sys
.stdout
.write (r
"""Copyright 1998--1999
990 Distributed under terms of the GNU General Public License. It comes with
994 def do_file(input_filename
):
999 my_outname
= os
.path
.basename(os
.path
.splitext(input_filename
)[0])
1000 my_depname
= my_outname
+ '.dep'
1002 chunks
= read_doc_file(input_filename
)
1003 chunks
= chop_chunks(chunks
, 'mudela', make_mudela
, 1)
1004 chunks
= chop_chunks(chunks
, 'mudela-file', make_mudela_file
, 1)
1005 chunks
= chop_chunks(chunks
, 'mudela-block', make_mudela_block
, 1)
1006 chunks
= chop_chunks(chunks
, 'singleline-comment', do_ignore
, 1)
1007 chunks
= chop_chunks(chunks
, 'preamble-end', do_preamble_end
)
1008 chunks
= chop_chunks(chunks
, 'numcols', do_columns
)
1010 #for c in chunks: print "c:", c;
1012 scan_preamble(chunks
)
1013 chunks
= process_mudela_blocks(my_outname
, chunks
)
1015 if __main__
.g_run_lilypond
:
1016 compile_all_files (chunks
)
1020 if c
[0] == 'mudela' and 'eps' in c
[2]:
1021 body
= re
.sub (r
"""\\mudelaepswidth{(.*?)}""", find_eps_dims
, c
[1])
1022 newchunks
.append (('mudela', body
))
1024 newchunks
.append (c
)
1027 chunks
= completize_preamble (chunks
)
1028 foutn
= os
.path
.join(g_outdir
, my_outname
+ '.' + format
)
1029 sys
.stderr
.write ("Writing `%s'\n" % foutn
)
1030 fout
= open (foutn
, 'w')
1036 write_deps (my_depname
, foutn
)
1041 (sh
, long) = getopt_args (__main__
.option_definitions
)
1042 (options
, files
) = getopt
.getopt(sys
.argv
[1:], sh
, long)
1043 except getopt
.error
, msg
:
1044 sys
.stderr
.write("error: %s" % msg
)
1052 if o
== '--include' or o
== '-I':
1053 include_path
.append (a
)
1054 elif o
== '--version' or o
== '-v':
1057 elif o
== '--format' or o
== '-f':
1059 elif o
== '--outname' or o
== '-o':
1062 sys
.stderr
.write("Mudela-book is confused by --outname on multiple files")
1065 elif o
== '--help' or o
== '-h':
1067 elif o
== '--no-lily' or o
== '-n':
1068 __main__
.g_run_lilypond
= 0
1069 elif o
== '--dependencies' or o
== '-M':
1071 elif o
== '--default-music-fontsize':
1072 default_music_fontsize
= string
.atoi (a
)
1073 elif o
== '--default-mudela-fontsize':
1074 print "--default-mudela-fontsize is deprecated, use --default-music-fontsize"
1075 default_music_fontsize
= string
.atoi (a
)
1076 elif o
== '--force-music-fontsize':
1077 g_force_mudela_fontsize
= string
.atoi(a
)
1078 elif o
== '--force-mudela-fontsize':
1079 print "--force-mudela-fontsize is deprecated, use --default-mudela-fontsize"
1080 g_force_mudela_fontsize
= string
.atoi(a
)
1081 elif o
== '--dep-prefix':
1083 elif o
== '--no-pictures':
1085 elif o
== '--read-lys':
1087 elif o
== '--outdir':
1092 if os
.path
.isfile(g_outdir
):
1093 error ("outdir is a file: %s" % g_outdir
)
1094 if not os
.path
.exists(g_outdir
):
1096 for input_filename
in files
:
1097 do_file(input_filename
)
1100 # Petr, ik zou willen dat ik iets zinvoller deed,
1101 # maar wat ik kan ik doen, het verandert toch niets?