release commit
[lilypond.git] / scripts / lilypond-book.py
blobf6358cc133ca77c64a59393cad5ca4146e4414ef
1 #!@PYTHON@
2 # vim: set noexpandtab:
4 """
6 TODO:
7 * junk --outdir for--output
8 * Figure out clean set of options.
10 * texinfo: add support for @pagesize
12 todo: dimension handling (all the x2y) is clumsy. (tca: Thats
13 because the values are taken directly from texinfo.tex,
14 geometry.sty and article.cls. Give me a hint, and I'll
15 fix it.)
18 TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
22 This is a slightly hairy program. The general approach is as follows
23 The input string is chopped up in chunks, i.e. , a list of tuples
25 with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE)
27 This list is built step by step: first ignore and verbatim commands
28 are handled, delivering a list of chunks.
30 then all chunks containing lilypond commands are chopped up
32 when all chunks have their final form, all bodies from lilypond blocks are
33 extracted, and if applicable, written do disk and run through lilypond.
36 tags supported
38 ignore
39 lilypond
40 input
41 verb
42 verbatim
43 multicols
44 numcols
49 """
51 # This is was the idea for handling of comments:
52 # Multiline comments, @ignore .. @end ignore is scanned for
53 # in read_doc_file, and the chunks are marked as 'ignore', so
54 # lilypond-book will not touch them any more. The content of the
55 # chunks are written to the output file. Also 'include' and 'input'
56 # regex has to check if they are commented out.
59 # Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
60 # These three regex's has to check if they are on a commented line,
61 # % for latex, @c for texinfo.
63 # Then lines that are commented out with % (latex) and @c (Texinfo)
64 # are put into chunks marked 'ignore'. This cannot be done before
65 # searching for the lilypond-blocks because % is also the comment character
66 # for lilypond.
68 # The the rest of the rexeces are searched for. They don't have to test
69 # if they are on a commented out line.
71 import glob
72 import stat
73 import string
76 ################################################################
77 # Users of python modules should include this snippet
78 # and customize variables below.
80 # We'll suffer this path init stuff as long as we don't install our
81 # python packages in <prefix>/lib/pythonx.y (and don't kludge around
82 # it as we do with teTeX on Red Hat Linux: set some environment var
83 # (PYTHONPATH) in profile)
85 # If set, LILYPONDPREFIX must take prevalence
86 # if datadir is not set, we're doing a build and LILYPONDPREFIX
87 import getopt, os, sys
88 datadir = '@local_lilypond_datadir@'
89 if not os.path.isdir (datadir):
90 datadir = '@lilypond_datadir@'
91 if os.environ.has_key ('LILYPONDPREFIX') :
92 datadir = os.environ['LILYPONDPREFIX']
93 while datadir[-1] == os.sep:
94 datadir= datadir[:-1]
96 sys.path.insert (0, os.path.join (datadir, 'python'))
98 # Customize these
99 #if __name__ == '__main__':
101 import lilylib as ly
102 global _;_=ly._
103 global re;re = ly.re
105 # lilylib globals
106 program_version = '@TOPLEVEL_VERSION@'
107 program_name = 'lilypond-book'
108 verbose_p = 0
109 pseudo_filter_p = 0
110 original_dir = os.getcwd ()
113 preview_resolution = 90
115 ## FIXME
116 ## do -P or -p by default?
117 ##help_summary = _ ("Run LilyPond using LaTeX for titling")
118 help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
119 copyright = ('Tom Cato Amundsen <tca@gnu.org>',
120 'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
122 option_definitions = [
123 (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")),
124 (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")),
125 (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")),
126 (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")),
127 (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed to be in points")),
128 (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")),
129 ('', 'h', 'help', _ ("print this help")),
130 (_ ("DIR"), 'I', 'include', _ ("include path")),
131 ('', 'M', 'dependencies', _ ("write dependencies")),
132 (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")),
133 ('', 'n', 'no-lily', _ ("don't run lilypond")),
134 ('', '', 'no-pictures', _ ("don't generate pictures")),
135 ('', '', 'no-music', _ ("strip all lilypond blocks from output")),
136 (_ ("FILE"), 'o', 'outname', _ ("filename main output file")),
137 (_ ("FILE"), '', 'outdir', _ ("where to place generated files")),
138 (_ ('RES'), '', 'preview-resolution',
139 _ ("set the resolution of the preview to RES")),
140 ('', 'V', 'verbose', _ ("be verbose")),
141 ('', 'v', 'version', _ ("print version information")),
142 ('', 'w', 'warranty', _ ("show warranty and copyright")),
145 # format specific strings, ie. regex-es for input, and % strings for output
147 # global variables
149 include_path = [os.getcwd ()]
151 #lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond'
153 lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin')
155 # only use installed binary when we're installed too.
156 if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
157 lilypond_binary = 'lilypond-bin'
161 ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi')
163 # only use installed binary when we're installed too.
164 if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
165 ly2dvi_binary = 'ly2dvi'
169 g_extra_opts = ''
170 g_here_dir = os.getcwd ()
171 g_dep_prefix = ''
172 g_outdir = ''
173 g_force_music_fontsize = 0
174 g_do_pictures = 1
175 g_do_music = 1
176 g_make_html = 0
178 format = ''
179 g_run_lilypond = 1
180 no_match = 'a\ba'
182 default_music_fontsize = 16
183 default_text_fontsize = 12
184 paperguru = None
186 ################################################################
187 # Dimension handling for LaTeX.
189 class LatexPaper:
190 def __init__ (self):
191 self.m_document_preamble = []
192 self.m_num_cols = 1
193 self.m_multicols = 1
195 def find_latex_dims (self):
196 if g_outdir:
197 fname = os.path.join (g_outdir, "lily-tmp.tex")
198 else:
199 fname = "lily-tmp.tex"
200 try:
201 f = open (fname, "w")
202 except IOError:
203 error ("Error creating temporary file '%s'" % fname)
205 for s in self.m_document_preamble:
206 f.write (s)
207 f.write (r"""
208 \begin{document}
209 \typeout{---}
210 \typeout{\columnsep \the\columnsep}
211 \typeout{\textwidth \the\textwidth}
212 \typeout{---}
213 \end{document}
214 """)
215 f.close ()
216 re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)")
218 cmd = "latex '\\nonstopmode \input %s'" % fname
219 # Ugh. (La)TeX writes progress and error messages on stdout
220 # Redirect to stderr
221 cmd = '(( %s >&2 ) >&- )' % cmd
222 status = ly.system (cmd, ignore_error = 1)
223 signal = 0xf & status
224 exit_status = status >> 8
226 if status:
227 ly.error (_ ("LaTeX failed."))
228 ly.error (_ ("The error log is as follows:"))
230 #URG see lilypond
231 try:
232 lns = open ('lily-tmp.log').readlines ()
233 except:
234 lns = ''
235 countdown = -3
236 for ln in lns:
237 sys.stderr.write (ln)
238 if re.match ('^!', ln):
239 countdown = 3
241 if countdown == 0:
242 break
244 if countdown > 0:
245 countdown = countdown -1
247 sys.stderr.write (" ... (further messages elided)...\n")
248 sys.exit (1)
250 lns = open ('lily-tmp.log').readlines ()
251 for ln in lns:
252 ln = string.strip (ln)
253 m = re_dim.match (ln)
254 if m:
255 if m.groups ()[0] in ('textwidth', 'columnsep'):
256 self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1])
258 try:
259 os.remove (fname)
260 os.remove (os.path.splitext (fname)[0]+".aux")
261 os.remove (os.path.splitext (fname)[0]+".log")
262 except:
263 pass
265 if not self.__dict__.has_key ('m_textwidth'):
266 raise 'foo!'
268 def get_linewidth (self):
269 if self.m_num_cols == 1:
270 w = self.m_textwidth
271 else:
272 w = (self.m_textwidth - self.m_columnsep)/2
273 if self.m_multicols > 1:
274 return (w - self.m_columnsep* (self.m_multicols-1)) \
275 / self.m_multicols
276 return w
279 class HtmlPaper:
280 def __init__ (self):
281 self.m_papersize = 'letterpaper'
282 self.m_fontsize = 12
283 def get_linewidth (self):
284 return html_linewidths[self.m_papersize][self.m_fontsize]
286 class TexiPaper:
287 def __init__ (self):
288 self.m_papersize = 'letterpaper'
289 self.m_fontsize = 12
290 def get_linewidth (self):
291 return texi_linewidths[self.m_papersize][self.m_fontsize]
293 def mm2pt (x):
294 return x * 2.8452756
295 def in2pt (x):
296 return x * 72.26999
297 def em2pt (x, fontsize = 10):
298 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
299 def ex2pt (x, fontsize = 10):
300 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
302 def pt2pt (x):
303 return x
305 dimension_conversion_dict ={
306 'mm': mm2pt,
307 'cm': lambda x: mm2pt (10*x),
308 'in': in2pt,
309 'em': em2pt,
310 'ex': ex2pt,
311 'pt': pt2pt
314 # Convert numeric values, with or without specific dimension, to floats.
315 # Keep other strings
316 def conv_dimen_to_float (value):
317 if type (value) == type (""):
318 m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
319 if m:
320 unit = m.group (2)
321 num = string.atof (m.group (1))
322 conv = dimension_conversion_dict[m.group (2)]
324 value = conv (num)
326 elif re.match ("^[0-9.]+$",value):
327 value = float (value)
329 return value
331 texi_linewidths = {
332 'afourpaper': {12: mm2pt (160)},
333 'afourwide': {12: in2pt (6.5)},
334 'afourlatex': {12: mm2pt (150)},
335 'smallbook': {12: in2pt (5)},
336 'letterpaper': {12: in2pt (6)}}
338 html_linewidths = {
339 'afourpaper': {12: mm2pt (160)},
340 'afourwide': {12: in2pt (6.5)},
341 'afourlatex': {12: mm2pt (150)},
342 'smallbook': {12: in2pt (5)},
343 'letterpaper': {12: in2pt (6)}}
346 ################################################################
347 # How to output various structures.
348 output_dict= {
351 'html' : {
353 'output-filename' : r'''
354 <!-- %s >
355 <a href="%s">
356 <pre>%s</pre></a>:''',
357 'output-lilypond-fragment': '''<lilypond%s>
358 \context Staff\context Voice{ %s }
359 </lilypond>''',
360 'output-noinline': r'''
361 <!-- generated: %(fn)s.png !-->
362 ''',
363 ## maybe <hr> ?
364 'pagebreak': None,
365 # Verbatim text is always finished with \n. FIXME: For HTML,
366 # this newline should be removed.
367 'output-verbatim': r'''<pre>
368 %s</pre>''',
369 # Verbatim text is always finished with \n. FIXME: For HTML,
370 # this newline should be removed.
371 'output-small-verbatim': r'''<font size=-1><pre>
372 %s</pre></font>''',
373 ## Ugh we need to differentiate on origin:
374 ## lilypond-block origin wants an extra <p>, but
375 ## inline music doesn't.
376 ## possibly other center options?
377 'output-html': r'''
378 %(htmlimages)s''',
382 'latex': {
384 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond}
385 \context Voice{
388 \end{lilypond}''',
389 'output-filename' : r'''\verb+%s+:\\
390 %% %s
391 %% %s
392 ''',
394 # verbatim text is always finished with \n
395 'output-verbatim': r'''\begin{verbatim}
396 %s\end{verbatim}
397 ''',
398 # verbatim text is always finished with \n
399 'output-small-verbatim': r'''{\small\begin{verbatim}
400 %s\end{verbatim}}
401 ''',
402 'output-default-post': "\\def\postLilyPondExample{}\n",
403 'output-default-pre': "\\def\preLilyPondExample{}\n",
404 'usepackage-graphics': '\\usepackage{graphics}\n',
405 'output-eps': '\\noindent\includegraphics{%(fn)s}',
406 'output-noinline': r'''
407 %% generated: %(fn)s.eps
408 ''',
409 'output-latex-quoted': r'''{\preLilyPondExample
410 \def\lilypondbook{}
411 \input %(fn)s.tex
412 \postLilyPondExample}''',
413 'output-latex-noquote': r'''{\parindent 0pt
414 \preLilyPondExample
415 \def\lilypondbook{}
416 \input %(fn)s.tex
417 \postLilyPondExample}''',
418 'pagebreak': r'\pagebreak',
422 'texi' : {
425 'output-filename' : r'''
426 @ifnothtml
427 @file{%s}:@*
428 @end ifnothtml
429 @ifhtml
430 @uref{%s,@file{%s}}
431 @end ifhtml
432 ''',
433 'output-lilypond-fragment': '''@lilypond[%s]
434 \context Staff\context Voice{ %s }
435 @end lilypond ''',
436 'output-noinline': r'''
437 @c generated: %(fn)s.png
438 ''',
439 'pagebreak': None,
440 # verbatim text is always finished with \n
441 'output-small-verbatim': r'''@smallexample
442 %s@end smallexample
443 ''',
444 # verbatim text is always finished with \n
445 'output-verbatim': r'''@example
446 %s@end example
447 ''',
448 # do some tweaking: @ is needed in some ps stuff.
450 # ugh, the <p> below breaks inline images...
451 'output-texi-noquote': r'''@tex
452 \catcode`\@=12
453 \parindent 0pt
454 \def\lilypondbook{}
455 \input %(fn)s.tex
456 \catcode`\@=0
457 @end tex
458 @html
459 <p>%(htmlimages)s
461 @end html
462 ''',
463 'output-texi-quoted': r'''@quotation
464 @tex
465 \catcode`\@=12
466 \def\lilypondbook{}
467 \input %(fn)s.tex
468 \catcode`\@=0
469 @end tex
470 @html
471 <p>%(htmlimages)s
473 @end html
474 @end quotation
475 ''',
480 def output_verbatim (body, small):
481 global format
482 if format == 'html':
483 body = re.sub ('&', '&amp;', body)
484 body = re.sub ('>', '&gt;', body)
485 body = re.sub ('<', '&lt;', body)
486 elif format == 'texi':
487 # clumsy workaround for python 2.2 pre bug.
488 body = re.sub ('@', '@@', body)
489 body = re.sub ('{', '@{', body)
490 body = re.sub ('}', '@}', body)
492 if small:
493 key = 'output-small-verbatim'
494 else:
495 key = 'output-verbatim'
496 return get_output (key) % body
499 ################################################################
500 # Recognize special sequences in the input
503 # Warning: This uses extended regular expressions. Tread with care.
505 # legenda
507 # (?P<name>regex) -- assign result of REGEX to NAME
508 # *? -- match non-greedily.
509 # (?m) -- multiline regex: make ^ and $ match at each line
510 # (?s) -- make the dot match all characters including newline
511 re_dict = {
512 'html': {
513 'include': no_match,
514 'input': no_match,
515 'header': no_match,
516 'preamble-end': no_match,
517 'landscape': no_match,
518 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
519 'verb': r'''(?P<code><pre>.*?</pre>)''',
520 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
521 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
522 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
523 'option-sep' : '\s*',
524 'intertext': r',?\s*intertext=\".*?\"',
525 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
526 'singleline-comment': no_match,
527 'numcols': no_match,
528 'multicols': no_match,
529 'ly2dvi': r'(?m)(?P<match><ly2dvifile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</ly2dvifile>)',
532 'latex': {
533 'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
534 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
535 'option-sep' : ',\s*',
536 'header': r"\n*\\documentclass\s*(\[.*?\])?",
537 'preamble-end': r'(?P<code>\\begin\s*{document})',
538 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
539 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
540 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
541 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
542 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
543 'def-post-re': r"\\def\\postLilyPondExample",
544 'def-pre-re': r"\\def\\preLilyPondExample",
545 'usepackage-graphics': r"\usepackage\s*{graphics}",
546 'intertext': r',?\s*intertext=\".*?\"',
547 'multiline-comment': no_match,
548 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
549 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
550 'multicols': r"(?P<code>\\(?P<be>begin|end)\s*{multicols}({(?P<num>\d+)?})?)",
551 'ly2dvi': no_match,
555 # why do we have distinction between @mbinclude and @include?
557 'texi': {
558 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude\s+(?P<filename>\S*))',
559 'input': no_match,
560 'header': no_match,
561 'preamble-end': no_match,
562 'landscape': no_match,
563 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
564 'verb': r'''(?P<code>@code{.*?})''',
565 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
566 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
567 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
568 'option-sep' : ',\s*',
569 'intertext': r',?\s*intertext=\".*?\"',
570 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
571 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
572 'numcols': no_match,
573 'multicols': no_match,
574 'ly2dvi': no_match,
579 for r in re_dict.keys ():
580 olddict = re_dict[r]
581 newdict = {}
582 for k in olddict.keys ():
583 try:
584 newdict[k] = re.compile (olddict[k])
585 except:
586 print 'invalid regexp: %s' % olddict[k]
588 ## we'd like to catch and reraise a more
589 ## detailed error, but alas, the exceptions
590 ## changed across the 1.5/2.1 boundary.
592 raise "Invalid re"
593 re_dict[r] = newdict
596 def uniq (list):
597 list.sort ()
598 s = list
599 list = []
600 for x in s:
601 if x not in list:
602 list.append (x)
603 return list
606 def get_output (name):
607 return output_dict[format][name]
609 def get_re (name):
610 return re_dict[format][name]
612 def bounding_box_dimensions (fname):
613 if g_outdir:
614 fname = os.path.join (g_outdir, fname)
615 try:
616 fd = open (fname)
617 except IOError:
618 error ("Error opening `%s'" % fname)
619 str = fd.read ()
620 s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
621 if s:
623 gs = map (lambda x: string.atoi (x), s.groups ())
624 return (int (gs[2] - gs[0] + 0.5),
625 int (gs[3] - gs[1] + 0.5))
626 else:
627 return (0,0)
629 def error (str):
630 sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n")
631 raise 'Exiting.'
634 def compose_full_body (body, opts):
635 '''Construct the lilypond code to send to LilyPond.
636 Add stuff to BODY using OPTS as options.'''
637 music_size = default_music_fontsize
638 if g_force_music_fontsize:
639 music_size = g_force_music_fontsize
640 indent = ''
641 linewidth = ''
642 notime = ''
643 for o in opts:
644 if not g_force_music_fontsize:
645 m = re.match ('([0-9]+)pt', o)
646 if m:
647 music_size = string.atoi (m.group (1))
649 m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
650 if m:
651 f = float (m.group (1))
652 indent = 'indent = %f\\%s' % (f, m.group (2))
654 m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
655 if m:
656 f = float (m.group (1))
657 linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
659 if re.search ('\\\\score', body):
660 is_fragment = 0
661 else:
662 is_fragment = 1
663 if 'fragment' in opts:
664 is_fragment = 1
665 if 'nofragment' in opts:
666 is_fragment = 0
668 if is_fragment and not 'multiline' in opts:
669 opts.append ('singleline')
671 if 'raggedright' in opts or 'singleline' in opts:
672 if not linewidth:
673 linewidth = 'raggedright = ##t'
674 if not indent:
675 indent = 'indent = 0.0\mm'
676 elif not linewidth:
677 global paperguru
678 l = paperguru.get_linewidth ()
679 linewidth = 'linewidth = %f\pt' % l
681 if 'noindent' in opts:
682 indent = 'indent = 0.0\mm'
684 if 'notime' in opts:
685 notime = r'''
686 \translator {
687 \StaffContext
688 \remove Time_signature_engraver
692 orig_name = ''
693 for o in opts:
694 m= re.search ('relative(.*)', o)
695 v = 0
696 if m:
697 try:
698 v = string.atoi (m.group (1))
699 except ValueError:
700 pass
702 v = v + 1
703 pitch = 'c'
704 if v < 0:
705 pitch = pitch + '\,' * v
706 elif v > 0:
707 pitch = pitch + '\'' * v
709 body = '\\relative %s { %s }' % (pitch, body)
710 m =re.search ("filename=(.*)", o)
711 if m:
712 orig_name = m.group (1)
714 if is_fragment:
715 body = r'''
716 \score {
717 \notes {
721 ''' % body
723 opts = uniq (opts)
724 optstring = string.join (opts, ' ')
725 optstring = re.sub ('\n', ' ', optstring)
726 body = r'''
727 %% Generated automatically by: lilypond-book.py
728 %% options are %s
729 \include "paper%d.ly"
730 \paper {
735 ''' % (optstring, music_size, linewidth, indent, notime) + body
737 if orig_name:
738 body = '\\renameinput \"%s\"\n%s' % (orig_name, body)
741 # ughUGH not original options
742 return body
744 def scan_html_preamble (chunks):
745 return
747 def scan_latex_preamble (chunks):
748 # First we want to scan the \documentclass line
749 # it should be the first non-comment line.
750 # The only thing we really need to know about the \documentclass line
751 # is if there are one or two columns to begin with.
752 idx = 0
753 while 1:
754 if chunks[idx][0] == 'ignore':
755 idx = idx + 1
756 continue
757 m = get_re ('header').match (chunks[idx][1])
758 if not m:
759 error ("Latex documents must start with a \documentclass command")
760 if m.group (1):
761 options = re.split (r',\s*', m.group (1)[1:-1])
762 else:
763 options = []
764 if 'twocolumn' in options:
765 paperguru.m_num_cols = 2
766 break
769 # Then we add everything before \begin{document} to
770 # paperguru.m_document_preamble so that we can later write this header
771 # to a temporary file in find_latex_dims() to find textwidth.
772 while idx < len (chunks) and chunks[idx][0] != 'preamble-end':
773 if chunks[idx] == 'ignore':
774 idx = idx + 1
775 continue
776 paperguru.m_document_preamble.append (chunks[idx][1])
777 idx = idx + 1
779 if len (chunks) == idx:
780 error ("Didn't find end of preamble (\\begin{document})")
782 paperguru.find_latex_dims ()
784 def scan_texi_preamble (chunks):
785 # this is not bulletproof..., it checks the first 10 chunks
786 for c in chunks[:10]:
787 if c[0] == 'input':
788 for s in ('afourpaper', 'afourwide', 'letterpaper',
789 'afourlatex', 'smallbook'):
790 if string.find (c[1], "@%s" % s) != -1:
791 paperguru.m_papersize = s
794 def scan_preamble (chunks):
795 global format
796 if format == 'html':
797 scan_html_preamble (chunks)
798 elif format == 'latex':
799 scan_latex_preamble (chunks)
800 elif format == 'texi':
801 scan_texi_preamble (chunks)
804 def completize_preamble (chunks):
805 global format
806 if format != 'latex':
807 return chunks
808 pre_b = post_b = graphics_b = None
809 for chunk in chunks:
810 if chunk[0] == 'preamble-end':
811 break
812 if chunk[0] == 'input':
813 m = get_re ('def-pre-re').search (chunk[1])
814 if m:
815 pre_b = 1
816 if chunk[0] == 'input':
817 m = get_re ('def-post-re').search (chunk[1])
818 if m:
819 post_b = 1
821 if chunk[0] == 'input':
822 m = get_re ('usepackage-graphics').search (chunk[1])
823 if m:
824 graphics_b = 1
825 x = 0
826 while x < len (chunks) and chunks[x][0] != 'preamble-end':
827 x = x + 1
829 if x == len (chunks):
830 return chunks
832 if not pre_b:
833 chunks.insert (x, ('input', get_output ('output-default-pre')))
834 if not post_b:
835 chunks.insert (x, ('input', get_output ('output-default-post')))
836 if not graphics_b:
837 chunks.insert (x, ('input', get_output ('usepackage-graphics')))
839 return chunks
842 read_files = []
843 def find_file (name):
845 Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
848 if name == '-':
849 return (sys.stdin.read (), '<stdin>')
850 f = None
851 nm = ''
852 for a in include_path:
853 try:
854 nm = os.path.join (a, name)
855 f = open (nm)
856 global read_files
857 read_files.append (nm)
858 break
859 except IOError:
860 pass
861 if f:
862 sys.stderr.write ("Reading `%s'\n" % nm)
863 return (f.read (), nm)
864 else:
865 error ("File not found `%s'\n" % name)
866 return ('', '')
868 def do_ignore (match_object):
869 return [('ignore', match_object.group ('code'))]
870 def do_preamble_end (match_object):
871 return [('preamble-end', match_object.group ('code'))]
873 def make_verbatim (match_object):
874 return [('verbatim', match_object.group ('code'))]
876 def make_verb (match_object):
877 return [('verb', match_object.group ('code'))]
879 def do_include_file (m):
880 "m: MatchObject"
881 return [('input', get_output ('pagebreak'))] \
882 + read_doc_file (m.group ('filename')) \
883 + [('input', get_output ('pagebreak'))]
885 def do_input_file (m):
886 return read_doc_file (m.group ('filename'))
888 def make_lilypond (m):
889 if m.group ('options'):
890 options = m.group ('options')
891 else:
892 options = ''
893 return [('input', get_output ('output-lilypond-fragment') %
894 (options, m.group ('code')))]
896 def make_lilypond_file (m):
899 Find @lilypondfile{bla.ly} occurences and substitute bla.ly
900 into a @lilypond .. @end lilypond block.
904 if m.group ('options'):
905 options = get_re ('option-sep').split (m.group ('options'))
906 else:
907 options = []
908 (content, nm) = find_file (m.group ('filename'))
909 options.append ("filename=%s" % nm)
910 (path, base) = os.path.split (nm)
912 if path not in include_path:
913 include_path.append (path)
915 return [('lilypond', content, options)]
918 def make_ly2dvi_block (m):
921 Find <ly2dvifile .. >
924 return [('ly2dvi', m.group ('filename'), m.group ('options'))]
927 def make_lilypond_block (m):
928 if not g_do_music:
929 return []
931 if m.group ('options'):
932 options = get_re ('option-sep').split (m.group ('options'))
933 else:
934 options = []
935 options = filter (lambda s: s != '', options)
936 return [('lilypond', m.group ('code'), options)]
939 def do_columns (m):
940 global format
941 if format != 'latex':
942 return []
943 if m.group ('num') == 'one':
944 return [('numcols', m.group ('code'), 1)]
945 if m.group ('num') == 'two':
946 return [('numcols', m.group ('code'), 2)]
948 def do_multicols (m):
949 global format
950 if format != 'latex':
951 return []
952 if m.group ('be') == 'begin':
953 return [('multicols', m.group ('code'), int (m.group ('num')))]
954 else:
955 return [('multicols', m.group ('code'), 1)]
956 return []
958 def chop_chunks (chunks, re_name, func, use_match=0):
959 newchunks = []
960 for c in chunks:
961 if c[0] == 'input':
962 str = c[1]
963 while str:
964 m = get_re (re_name).search (str)
965 if m == None:
966 newchunks.append (('input', str))
967 str = ''
968 else:
969 if use_match:
970 newchunks.append (('input', str[:m.start ('match')]))
971 else:
972 newchunks.append (('input', str[:m.start (0)]))
973 #newchunks.extend (func (m))
974 # python 1.5 compatible:
975 newchunks = newchunks + func (m)
976 str = str [m.end (0):]
977 else:
978 newchunks.append (c)
979 return newchunks
981 def determine_format (str):
984 SIDE EFFECT! This sets FORMAT and PAPERGURU
988 global format
989 if format == '':
990 html = re.search ('(?i)<[dh]tml', str[:200])
991 latex = re.search (r'''\\document''', str[:200])
992 texi = re.search ('@node|@setfilename', str[:200])
994 f = ''
995 g = None
997 if html and not latex and not texi:
998 f = 'html'
999 elif latex and not html and not texi:
1000 f = 'latex'
1001 elif texi and not html and not latex:
1002 f = 'texi'
1003 else:
1004 error ("can't determine format, please specify")
1005 format = f
1007 global paperguru
1008 if paperguru == None:
1009 if format == 'html':
1010 g = HtmlPaper ()
1011 elif format == 'latex':
1012 g = LatexPaper ()
1013 elif format == 'texi':
1014 g = TexiPaper ()
1016 paperguru = g
1019 def read_doc_file (filename):
1020 '''Read the input file, find verbatim chunks and do \input and \include
1022 (str, path) = find_file (filename)
1023 determine_format (str)
1025 chunks = [('input', str)]
1027 # we have to check for verbatim before doing include,
1028 # because we don't want to include files that are mentioned
1029 # inside a verbatim environment
1030 chunks = chop_chunks (chunks, 'verbatim', make_verbatim)
1032 chunks = chop_chunks (chunks, 'verb', make_verb)
1033 chunks = chop_chunks (chunks, 'multiline-comment', do_ignore)
1034 #ugh fix input
1035 chunks = chop_chunks (chunks, 'include', do_include_file, 1)
1036 chunks = chop_chunks (chunks, 'input', do_input_file, 1)
1037 return chunks
1040 taken_file_names = {}
1042 def unique_file_name (body):
1043 return 'lily-' + `abs (hash (body))`
1045 def schedule_lilypond_block (chunk):
1046 '''Take the body and options from CHUNK, figure out how the
1047 real .ly should look. The .ly is written, and scheduled in
1048 TODO.
1050 Return: a single chunk.
1052 The chunk pertaining to the lilypond output
1053 has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
1054 where TODO has format [basename, extension, extension, ... ]
1057 (type, body, opts) = chunk
1058 assert type == 'lilypond'
1059 file_body = compose_full_body (body, opts)
1060 ## Hmm, we should hash only lilypond source, and skip the
1061 ## %options are ...
1062 ## comment line
1063 basename = unique_file_name (file_body)
1064 for o in opts:
1065 m = re.search ('filename="(.*?)"', o)
1066 if m:
1067 basename = m.group (1)
1068 if not taken_file_names.has_key (basename):
1069 taken_file_names[basename] = 0
1070 else:
1071 taken_file_names[basename] = taken_file_names[basename] + 1
1072 basename = basename + "-t%i" % taken_file_names[basename]
1073 update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
1074 needed_filetypes = ['tex']
1076 if format == 'html' or g_make_html:
1077 needed_filetypes.append ('eps')
1078 needed_filetypes.append ('png')
1079 if 'eps' in opts and not ('eps' in needed_filetypes):
1080 needed_filetypes.append ('eps')
1082 pathbase = os.path.join (g_outdir, basename)
1083 def must_rebuild (base, ext1, ext2):
1085 f2 = base + ext2
1086 f1 = base + ext1
1087 fp2 = base + '-page1' + ext2
1089 isfile2 = os.path.isfile (f2)
1091 if not isfile2 and os.path.isfile (fp2):
1092 f2 = fp2
1093 isfile2 = os.path.isfile (fp2)
1095 if (os.path.isfile (f2) and isfile2 and
1096 os.stat (f1)[stat.ST_MTIME] >
1097 os.stat (f2)[stat.ST_MTIME]) or \
1098 not isfile2:
1100 return 1
1102 todo = []
1103 if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'):
1104 todo.append ('tex')
1105 if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'):
1106 todo.append ('eps')
1107 if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'):
1108 todo.append ('png')
1110 return ('lilypond', body, opts, todo, basename)
1112 def format_lilypond_block (chunk):
1115 Figure out what should be left MAIN_STR (meant
1116 for the main file) from a lilypond chunk: process
1117 verbatim, and other options. Return: multiple chunks.
1123 return_chunks = []
1125 (type, body, opts, todo, basename) = chunk
1126 assert type == 'lilypond'
1129 newbody = ''
1130 filename_chunk = None
1131 if 'printfilename' in opts:
1132 for o in opts:
1133 m= re.match ("filename=(.*)", o)
1134 if m:
1135 template = get_output ("output-filename")
1136 b = basename + '.ly'
1137 human_base = os.path.basename (m.group (1))
1139 ## todo: include path, but strip
1140 ## first part of the path.
1141 filename_chunk = ('input', template % (human_base, b,human_base))
1142 break
1145 if 'smallverbatim' in opts:
1146 newbody += output_verbatim (body, 1)
1147 elif 'verbatim' in opts:
1148 newbody += output_verbatim (body, 0)
1150 for o in opts:
1151 m = re.search ('intertext="(.*?)"', o)
1152 if m:
1153 newbody = newbody + "\n"
1154 if format == 'texi':
1155 newbody = newbody + "@noindent\n"
1156 elif format == 'latex':
1157 newbody = newbody + "\\noindent\n"
1158 newbody = newbody + m.group (1) + "\n"
1160 if 'noinline' in opts:
1161 s = 'output-noinline'
1162 elif format == 'latex':
1163 if 'quote' in opts:
1164 s = 'output-latex-quoted'
1165 elif 'eps' in opts:
1166 s = 'output-eps'
1167 else:
1168 s = 'output-latex-noquote'
1169 elif format == 'texi':
1170 if 'quote' in opts:
1171 s = 'output-texi-quoted'
1172 else:
1173 s = 'output-texi-noquote'
1174 else: # format == 'html'
1175 s = 'output-html'
1177 def html_pages (basename):
1178 pat = os.path.join (g_outdir, "%s-page*.png"% basename)
1180 files = glob.glob (pat)
1183 template = '''<img align="center" valign="center"
1184 border="0" src="%s" alt="[picture of music]">'''
1186 str = ''
1187 if files == []:
1188 files = [basename+'.png' ]
1189 else:
1190 files = map (os.path.basename, files)
1192 for f in files:
1193 str += template % f
1195 str = '<a href="%s.ly">%s</a>' % (basename, str)
1197 return str
1200 newbody = newbody + get_output (s) % {'fn': basename,
1201 'htmlimages': html_pages(basename)
1204 if filename_chunk:
1205 return_chunks += [filename_chunk]
1207 return_chunks += [('lilypond', newbody, opts, todo, basename)]
1209 return return_chunks
1211 def format_lilypond_output_bodies (chunks):
1212 newchunks = []
1213 for c in chunks:
1215 if c[0] == 'lilypond':
1216 newchunks += format_lilypond_block (c)
1217 else:
1218 newchunks.append (c)
1220 return newchunks
1224 def process_lilypond_blocks (chunks):#ugh rename
1225 newchunks = []
1226 # Count sections/chapters.
1227 for c in chunks:
1228 if c[0] == 'lilypond':
1229 c = schedule_lilypond_block (c)
1230 elif c[0] == 'numcols':
1231 paperguru.m_num_cols = c[2]
1232 elif c[0] == 'multicols':
1233 paperguru.m_multicols = c[2]
1235 newchunks.append (c)
1237 return newchunks
1239 def process_ly2dvi_blocks (chunks):
1241 def process_ly2dvi_block (chunk):
1244 Run ly2dvi script on filename specified in CHUNK.
1245 This is only supported for HTML output.
1247 In HTML output it will leave a download menu with ps/pdf/midi etc. in
1248 a separate HTML file, and a title + preview in the main html file,
1249 linking to the menu.
1252 (tag, name, opts) = chunk
1253 assert format == 'html'
1254 (content, original_name) = find_file (name)
1256 original_name = os.path.basename (original_name)
1258 base = unique_file_name (content)
1259 outname = base + '.ly'
1260 changed = update_file (content, outname)
1262 preview = base + ".preview.png"
1263 preview_page = base + '-page1.png'
1265 if changed or not (os.path.isfile (preview) or
1266 os.path.isfile (preview_page)):
1268 ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) )
1270 ly.make_ps_images (base + '.ps')
1271 ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
1273 def size_str (fn):
1274 b = os.stat(fn)[stat.ST_SIZE]
1275 if b < 1024:
1276 return '%d bytes' % b
1277 elif b < (2 << 20):
1278 return '%d kb' % (b >> 10)
1279 else:
1280 return '%d mb' % (b >> 20)
1282 exts = {
1283 'pdf' : "Print (PDF, %s)",
1284 'ps.gz' : "Print (gzipped PostScript, %s)",
1285 'png' : "View (PNG, %s)",
1286 'midi' : "Listen (MIDI, %s)",
1287 'ly' : "View source code (%s)",
1290 menu = ''
1291 page_files = glob.glob ('%s-page*.png' % base)
1293 for p in page_files:
1294 p = p.strip()
1295 if os.path.isfile (p):
1296 sz = size_str (p)
1297 page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
1298 page = page % sz
1299 menu += '<li><a href="%s">%s</a>' % (p, page)
1301 ext_order = ['ly', 'pdf', 'ps.gz', 'midi']
1302 for e in ext_order:
1303 fn = base + '.' + e
1304 print 'checking,' , fn
1305 if not os.path.isfile (fn):
1306 continue
1308 entry = exts[e] % size_str (fn)
1310 ## TODO: do something like
1311 ## this for texinfo/latex as well ?
1313 menu += '<li><a href="%s">%s</a>\n\n' % (fn, entry)
1316 explanatory_para = """The pictures are 90dpi
1317 anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS
1318 use scalable fonts and should look OK at any resolution."""
1320 separate_menu =r'''
1321 <title>LilyPond example %s</title>
1323 <h1>%s</h1>
1324 <p><img src="%s">
1325 <p>%s
1327 <ul>%s</ul>''' % (original_name,original_name, preview, explanatory_para, menu)
1329 open (base + '.html','w'). write (separate_menu)
1331 inline_menu = '<p/><a href="%s.html"><img alt="%s" src="%s"></a><p/>' % (base, original_name, preview)
1333 return ('ly2dvi', inline_menu)
1335 newchunks = []
1336 for c in chunks:
1337 if c[0] == 'ly2dvi':
1338 c = process_ly2dvi_block (c)
1339 newchunks.append (c)
1341 return newchunks
1343 def compile_all_files (chunks):
1344 global foutn
1345 eps = []
1346 tex = []
1347 png = []
1349 for c in chunks:
1350 if c[0] != 'lilypond':
1351 continue
1353 base = c[4]
1354 exts = c[3]
1355 for e in exts:
1356 if e == 'eps':
1357 eps.append (base)
1358 elif e == 'tex':
1359 #ugh
1360 if base + '.ly' not in tex:
1361 tex.append (base + '.ly')
1362 elif e == 'png' and g_do_pictures:
1363 png.append (base)
1364 d = os.getcwd ()
1365 if g_outdir:
1366 os.chdir (g_outdir)
1367 if tex:
1368 # fixme: be sys-independent.
1369 def incl_opt (x):
1370 if g_outdir and x[0] != '/' :
1371 x = os.path.join (g_here_dir, x)
1372 return ' -I %s' % x
1374 incs = map (incl_opt, include_path)
1375 lilyopts = string.join (incs)
1376 if do_deps:
1377 lilyopts += ' --dependencies'
1378 if g_outdir:
1379 lilyopts += ' --dep-prefix=' + g_outdir + '/'
1380 lilyopts += ' --header=texidoc'
1381 texfiles = string.join (tex)
1382 cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts,
1383 texfiles))
1385 ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@')
1387 ly.system (cmd, ignore_error = 0, progress_p = 1)
1390 # Ugh, fixing up dependencies for .tex generation
1392 if do_deps:
1393 depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep',
1394 x), tex)
1396 for i in depfiles:
1397 f =open (i)
1398 text=f.read ()
1399 f.close ()
1400 text=re.sub ('\n([^:\n]*):',
1401 '\n' + foutn + ':', text)
1402 f = open (i, 'w')
1403 f.write (text)
1404 f.close ()
1406 def to_eps (file):
1407 cmd = r"latex '\nonstopmode \input %s'" % file
1408 # Ugh. (La)TeX writes progress and error messages on stdout
1409 # Redirect to stderr
1410 cmd = '(( %s >&2 ) >&- )' % cmd
1412 ly.system (cmd)
1413 ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file))
1414 map (to_eps, eps)
1416 map (ly.make_ps_images, map (lambda x: x + '.eps', png))
1417 os.chdir (d)
1420 def update_file (body, name):
1422 write the body if it has changed. Return whether BODY has changed.
1424 same = 0
1425 try:
1426 f = open (name)
1427 fs = f.read (-1)
1428 same = (fs == body)
1429 except:
1430 pass
1432 if not same:
1433 f = open (name , 'w')
1434 f.write (body)
1435 f.close ()
1437 return not same
1440 def write_deps (fn, target, chunks):
1441 global read_files
1442 sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn))
1443 f = open (os.path.join (g_outdir, fn), 'w')
1444 f.write ('%s%s: ' % (g_dep_prefix, target))
1445 for d in read_files:
1446 f.write ('%s ' % d)
1449 ## There used to be code to write .tex dependencies, but
1450 ## that is silly: lilypond-book has its own dependency scheme
1451 ## to ensure that all lily-XXX.tex files are there
1454 f.write ('\n')
1455 f.close ()
1456 read_files = []
1458 def check_texidoc (chunks):
1459 ## TODO: put file name in front of texidoc.
1461 n = []
1462 for c in chunks:
1463 if c[0] == 'lilypond':
1464 (type, body, opts, todo, basename) = c;
1465 pathbase = os.path.join (g_outdir, basename)
1466 if os.path.isfile (pathbase + '.texidoc') \
1467 and 'notexidoc' not in opts:
1468 n.append( ('input', '\n@include %s.texidoc\n\n' % basename))
1469 n.append (c)
1470 return n
1473 ## what's this? Docme --hwn
1475 def fix_epswidth (chunks):
1476 newchunks = []
1477 for c in chunks:
1478 if c[0] != 'lilypond' or 'eps' not in c[2]:
1479 newchunks.append (c)
1480 continue
1482 mag = 1.0
1483 for o in c[2]:
1484 m = re.match ('magnification=([0-9.]+)', o)
1485 if m:
1486 mag = string.atof (m.group (1))
1488 def replace_eps_dim (match, lmag = mag):
1489 filename = match.group (1)
1490 dims = bounding_box_dimensions (filename)
1492 return '%fpt' % (dims[0] *lmag)
1494 body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
1495 newchunks.append (('lilypond', body, c[2], c[3], c[4]))
1497 return newchunks
1500 ##docme: why global?
1501 foutn=""
1503 def do_file (input_filename):
1504 chunks = read_doc_file (input_filename)
1505 chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1)
1506 chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1)
1507 chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1)
1508 chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1)
1509 chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1)
1510 chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
1511 chunks = chop_chunks (chunks, 'numcols', do_columns)
1512 chunks = chop_chunks (chunks, 'multicols', do_multicols)
1514 scan_preamble (chunks)
1515 chunks = process_lilypond_blocks (chunks)
1516 chunks = process_ly2dvi_blocks (chunks)
1518 # Do It.
1519 global g_run_lilypond
1520 if g_run_lilypond:
1521 compile_all_files (chunks)
1522 chunks = fix_epswidth (chunks)
1525 chunks = format_lilypond_output_bodies (chunks)
1526 global format
1527 if format == 'texi':
1528 chunks = check_texidoc (chunks)
1531 x = 0
1532 chunks = completize_preamble (chunks)
1534 global foutn
1536 if outname:
1537 my_outname = outname
1538 elif input_filename == '-' or input_filename == "/dev/stdin":
1539 my_outname = '-'
1540 else:
1541 my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format
1542 my_depname = my_outname + '.dep'
1544 if my_outname == '-' or my_outname == '/dev/stdout':
1545 fout = sys.stdout
1546 foutn = "<stdout>"
1547 global do_deps
1548 do_deps = 0
1549 else:
1550 foutn = os.path.join (g_outdir, my_outname)
1551 sys.stderr.write ("Writing `%s'\n" % foutn)
1552 fout = open (foutn, 'w')
1553 for c in chunks:
1554 fout.write (c[1])
1555 fout.close ()
1556 # should chmod -w
1558 if do_deps:
1559 write_deps (my_depname, foutn, chunks)
1561 outname = ''
1562 try:
1563 (sh, long) = ly.getopt_args (option_definitions)
1564 (options, files) = getopt.getopt (sys.argv[1:], sh, long)
1566 except getopt.error, msg:
1567 sys.stderr.write ('\n')
1568 ly.error (_ ("getopt says: `%s\'" % s))
1569 sys.stderr.write ('\n')
1570 ly.help ()
1571 ly.exit (2)
1573 do_deps = 0
1574 for opt in options:
1575 o = opt[0]
1576 a = opt[1]
1578 if o == '--include' or o == '-I':
1579 include_path.append (a)
1580 elif o == '--version' or o == '-v':
1581 ly.identify (sys.stdout)
1582 sys.exit (0)
1583 elif o == '--verbose' or o == '-V':
1584 verbose_p = 1
1585 elif o == '--format' or o == '-f':
1586 format = a
1587 if a == 'texi-html':
1588 format = 'texi'
1589 g_make_html = 1
1590 elif o == '--outname' or o == '-o':
1591 if len (files) > 1:
1592 #HACK
1593 sys.stderr.write ("lilypond-book is confused by --outname on multiple files")
1594 sys.exit (1)
1595 outname = a
1596 elif o == '--help' or o == '-h':
1597 ly.help ()
1598 sys.exit (0)
1599 elif o == '--no-lily' or o == '-n':
1600 g_run_lilypond = 0
1601 elif o == '--preview-resolution':
1602 preview_resolution = string.atoi (a)
1603 elif o == '--dependencies' or o == '-M':
1604 do_deps = 1
1605 elif o == '--default-music-fontsize':
1606 default_music_fontsize = string.atoi (a)
1607 elif o == '--default-lilypond-fontsize':
1608 print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
1609 default_music_fontsize = string.atoi (a)
1610 elif o == '--extra-options':
1611 g_extra_opts = a
1612 elif o == '--force-music-fontsize':
1613 g_force_music_fontsize = string.atoi (a)
1614 elif o == '--force-lilypond-fontsize':
1615 print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
1616 g_force_music_fontsize = string.atoi (a)
1617 elif o == '--dep-prefix':
1618 g_dep_prefix = a
1619 elif o == '--no-pictures':
1620 g_do_pictures = 0
1621 elif o == '--no-music':
1622 g_do_music = 0
1623 elif o == '--outdir':
1624 g_outdir = a
1625 elif o == '--warranty' or o == '-w':
1626 #status = os.system ('lilypond -w')
1627 if 1 or status:
1628 ly.warranty ()
1629 sys.exit (0)
1631 ly.identify (sys.stderr)
1633 if g_outdir:
1634 if os.path.isfile (g_outdir):
1635 error ("outdir is a file: %s" % g_outdir)
1636 if not os.path.exists (g_outdir):
1637 os.mkdir (g_outdir)
1639 if not files:
1640 ly.help ()
1641 ly.error (_ ("no files specified on command line"))
1642 ly.exit (2)
1644 ly.setup_environment ()
1647 for input_filename in files:
1648 do_file (input_filename)
1652 # Petr, ik zou willen dat ik iets zinvoller deed,
1653 # maar wat ik kan ik doen, het verandert toch niets?
1654 # --hwn 20/aug/99