* scripts/lilypond-book.py (option_definitions): typo
[lilypond.git] / scripts / lilypond-book.py
blobdf3aba4508d816b92d25ea2e3f7692573e3de7c7
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_name = 'lilypond-book'
107 verbose_p = 0
108 pseudo_filter_p = 0
109 original_dir = os.getcwd ()
112 preview_resolution = 90
114 ## FIXME
115 ## ly2dvi: silly name?
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', _ ("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', _ ("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')
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'
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 += ' 1>/dev/stderr'
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 ly2dvi
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 %(pageimages)s''',
382 'latex': {
384 'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
385 \context Staff <
386 \context Voice{
390 \end{lilypond}''',
391 'output-filename' : r'''\verb+%s+:\\
392 %% %s
393 %% %s
394 ''',
396 # verbatim text is always finished with \n
397 'output-verbatim': r'''\begin{verbatim}
398 %s\end{verbatim}
399 ''',
400 # verbatim text is always finished with \n
401 'output-small-verbatim': r'''{\small\begin{verbatim}
402 %s\end{verbatim}}
403 ''',
404 'output-default-post': "\\def\postLilypondExample{}\n",
405 'output-default-pre': "\\def\preLilypondExample{}\n",
406 'usepackage-graphics': '\\usepackage{graphics}\n',
407 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s}}',
408 'output-noinline': r'''
409 %% generated: %(fn)s.eps
410 ''',
411 'output-latex-quoted': r'''{\preLilypondExample
412 \input %(fn)s.tex
413 \postLilypondExample}''',
414 'output-latex-noquote': r'''{\parindent 0pt
415 \preLilypondExample
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[ \n\t]+(?P<filename>[^\t \n]*))',
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 for o in opts:
693 m= re.search ('relative(.*)', o)
694 v = 0
695 if m:
696 try:
697 v = string.atoi (m.group (1))
698 except ValueError:
699 pass
701 v = v + 1
702 pitch = 'c'
703 if v < 0:
704 pitch = pitch + '\,' * v
705 elif v > 0:
706 pitch = pitch + '\'' * v
708 body = '\\relative %s { %s }' % (pitch, body)
710 if is_fragment:
711 body = r'''
712 \score {
713 \notes {
717 ''' % body
719 opts = uniq (opts)
720 optstring = string.join (opts, ' ')
721 optstring = re.sub ('\n', ' ', optstring)
722 body = r'''
723 %% Generated automatically by: lilypond-book.py
724 %% options are %s
725 \include "paper%d.ly"
726 \paper {
731 ''' % (optstring, music_size, linewidth, indent, notime) + body
733 # ughUGH not original options
734 return body
736 def scan_html_preamble (chunks):
737 return
739 def scan_latex_preamble (chunks):
740 # First we want to scan the \documentclass line
741 # it should be the first non-comment line.
742 # The only thing we really need to know about the \documentclass line
743 # is if there are one or two columns to begin with.
744 idx = 0
745 while 1:
746 if chunks[idx][0] == 'ignore':
747 idx = idx + 1
748 continue
749 m = get_re ('header').match (chunks[idx][1])
750 if not m:
751 error ("Latex documents must start with a \documentclass command")
752 if m.group (1):
753 options = re.split (',[\n \t]*', m.group (1)[1:-1])
754 else:
755 options = []
756 if 'twocolumn' in options:
757 paperguru.m_num_cols = 2
758 break
761 # Then we add everything before \begin{document} to
762 # paperguru.m_document_preamble so that we can later write this header
763 # to a temporary file in find_latex_dims() to find textwidth.
764 while idx < len (chunks) and chunks[idx][0] != 'preamble-end':
765 if chunks[idx] == 'ignore':
766 idx = idx + 1
767 continue
768 paperguru.m_document_preamble.append (chunks[idx][1])
769 idx = idx + 1
771 if len (chunks) == idx:
772 error ("Didn't find end of preamble (\\begin{document})")
774 paperguru.find_latex_dims ()
776 def scan_texi_preamble (chunks):
777 # this is not bulletproof..., it checks the first 10 chunks
778 for c in chunks[:10]:
779 if c[0] == 'input':
780 for s in ('afourpaper', 'afourwide', 'letterpaper',
781 'afourlatex', 'smallbook'):
782 if string.find (c[1], "@%s" % s) != -1:
783 paperguru.m_papersize = s
786 def scan_preamble (chunks):
787 global format
788 if format == 'html':
789 scan_html_preamble (chunks)
790 elif format == 'latex':
791 scan_latex_preamble (chunks)
792 elif format == 'texi':
793 scan_texi_preamble (chunks)
796 def completize_preamble (chunks):
797 global format
798 if format != 'latex':
799 return chunks
800 pre_b = post_b = graphics_b = None
801 for chunk in chunks:
802 if chunk[0] == 'preamble-end':
803 break
804 if chunk[0] == 'input':
805 m = get_re ('def-pre-re').search (chunk[1])
806 if m:
807 pre_b = 1
808 if chunk[0] == 'input':
809 m = get_re ('def-post-re').search (chunk[1])
810 if m:
811 post_b = 1
813 if chunk[0] == 'input':
814 m = get_re ('usepackage-graphics').search (chunk[1])
815 if m:
816 graphics_b = 1
817 x = 0
818 while x < len (chunks) and chunks[x][0] != 'preamble-end':
819 x = x + 1
821 if x == len (chunks):
822 return chunks
824 if not pre_b:
825 chunks.insert (x, ('input', get_output ('output-default-pre')))
826 if not post_b:
827 chunks.insert (x, ('input', get_output ('output-default-post')))
828 if not graphics_b:
829 chunks.insert (x, ('input', get_output ('usepackage-graphics')))
831 return chunks
834 read_files = []
835 def find_file (name):
837 Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
840 if name == '-':
841 return (sys.stdin.read (), '<stdin>')
842 f = None
843 nm = ''
844 for a in include_path:
845 try:
846 nm = os.path.join (a, name)
847 f = open (nm)
848 global read_files
849 read_files.append (nm)
850 break
851 except IOError:
852 pass
853 if f:
854 sys.stderr.write ("Reading `%s'\n" % nm)
855 return (f.read (), nm)
856 else:
857 error ("File not found `%s'\n" % name)
858 return ('', '')
860 def do_ignore (match_object):
861 return [('ignore', match_object.group ('code'))]
862 def do_preamble_end (match_object):
863 return [('preamble-end', match_object.group ('code'))]
865 def make_verbatim (match_object):
866 return [('verbatim', match_object.group ('code'))]
868 def make_verb (match_object):
869 return [('verb', match_object.group ('code'))]
871 def do_include_file (m):
872 "m: MatchObject"
873 return [('input', get_output ('pagebreak'))] \
874 + read_doc_file (m.group ('filename')) \
875 + [('input', get_output ('pagebreak'))]
877 def do_input_file (m):
878 return read_doc_file (m.group ('filename'))
880 def make_lilypond (m):
881 if m.group ('options'):
882 options = m.group ('options')
883 else:
884 options = ''
885 return [('input', get_output ('output-lilypond-fragment') %
886 (options, m.group ('code')))]
888 def make_lilypond_file (m):
891 Find @lilypondfile{bla.ly} occurences and substitute bla.ly
892 into a @lilypond .. @end lilypond block.
896 if m.group ('options'):
897 options = get_re ('option-sep').split (m.group ('options'))
898 else:
899 options = []
900 (content, nm) = find_file (m.group ('filename'))
901 options.append ("filename=%s" % nm)
904 return [('lilypond', content, options)]
907 def make_ly2dvi_block (m):
910 Find <ly2dvifile .. >
913 return [('ly2dvi', m.group ('filename'), m.group ('options'))]
916 def make_lilypond_block (m):
917 if not g_do_music:
918 return []
920 if m.group ('options'):
921 options = get_re ('option-sep').split (m.group ('options'))
922 else:
923 options = []
924 options = filter (lambda s: s != '', options)
925 return [('lilypond', m.group ('code'), options)]
928 def do_columns (m):
929 global format
930 if format != 'latex':
931 return []
932 if m.group ('num') == 'one':
933 return [('numcols', m.group ('code'), 1)]
934 if m.group ('num') == 'two':
935 return [('numcols', m.group ('code'), 2)]
937 def do_multicols (m):
938 global format
939 if format != 'latex':
940 return []
941 if m.group ('be') == 'begin':
942 return [('multicols', m.group ('code'), int (m.group ('num')))]
943 else:
944 return [('multicols', m.group ('code'), 1)]
945 return []
947 def chop_chunks (chunks, re_name, func, use_match=0):
948 newchunks = []
949 for c in chunks:
950 if c[0] == 'input':
951 str = c[1]
952 while str:
953 m = get_re (re_name).search (str)
954 if m == None:
955 newchunks.append (('input', str))
956 str = ''
957 else:
958 if use_match:
959 newchunks.append (('input', str[:m.start ('match')]))
960 else:
961 newchunks.append (('input', str[:m.start (0)]))
962 #newchunks.extend (func (m))
963 # python 1.5 compatible:
964 newchunks = newchunks + func (m)
965 str = str [m.end (0):]
966 else:
967 newchunks.append (c)
968 return newchunks
970 def determine_format (str):
973 SIDE EFFECT! This sets FORMAT and PAPERGURU
977 global format
978 if format == '':
979 html = re.search ('(?i)<[dh]tml', str[:200])
980 latex = re.search (r'''\\document''', str[:200])
981 texi = re.search ('@node|@setfilename', str[:200])
983 f = ''
984 g = None
986 if html and not latex and not texi:
987 f = 'html'
988 elif latex and not html and not texi:
989 f = 'latex'
990 elif texi and not html and not latex:
991 f = 'texi'
992 else:
993 error ("can't determine format, please specify")
994 format = f
996 global paperguru
997 if paperguru == None:
998 if format == 'html':
999 g = HtmlPaper ()
1000 elif format == 'latex':
1001 g = LatexPaper ()
1002 elif format == 'texi':
1003 g = TexiPaper ()
1005 paperguru = g
1008 def read_doc_file (filename):
1009 '''Read the input file, find verbatim chunks and do \input and \include
1011 (str, path) = find_file (filename)
1012 determine_format (str)
1014 chunks = [('input', str)]
1016 # we have to check for verbatim before doing include,
1017 # because we don't want to include files that are mentioned
1018 # inside a verbatim environment
1019 chunks = chop_chunks (chunks, 'verbatim', make_verbatim)
1021 chunks = chop_chunks (chunks, 'verb', make_verb)
1022 chunks = chop_chunks (chunks, 'multiline-comment', do_ignore)
1023 #ugh fix input
1024 chunks = chop_chunks (chunks, 'include', do_include_file, 1)
1025 chunks = chop_chunks (chunks, 'input', do_input_file, 1)
1026 return chunks
1029 taken_file_names = {}
1031 def unique_file_name (body):
1032 return 'lily-' + `abs (hash (body))`
1034 def schedule_lilypond_block (chunk):
1035 '''Take the body and options from CHUNK, figure out how the
1036 real .ly should look. The .ly is written, and scheduled in
1037 TODO.
1039 Return: a single chunk.
1041 The chunk pertaining to the lilypond output
1042 has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
1043 where TODO has format [basename, extension, extension, ... ]
1046 (type, body, opts) = chunk
1047 assert type == 'lilypond'
1048 file_body = compose_full_body (body, opts)
1049 ## Hmm, we should hash only lilypond source, and skip the
1050 ## %options are ...
1051 ## comment line
1052 basename = unique_file_name (file_body)
1053 for o in opts:
1054 m = re.search ('filename="(.*?)"', o)
1055 if m:
1056 basename = m.group (1)
1057 if not taken_file_names.has_key (basename):
1058 taken_file_names[basename] = 0
1059 else:
1060 taken_file_names[basename] = taken_file_names[basename] + 1
1061 basename = basename + "-%i" % taken_file_names[basename]
1062 update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
1063 needed_filetypes = ['tex']
1065 if format == 'html' or g_make_html:
1066 needed_filetypes.append ('eps')
1067 needed_filetypes.append ('png')
1068 if 'eps' in opts and not ('eps' in needed_filetypes):
1069 needed_filetypes.append ('eps')
1071 pathbase = os.path.join (g_outdir, basename)
1072 def must_rebuild (base, ext1, ext2):
1074 f2 = base + ext2
1075 f1 = base + ext1
1076 fp2 = base + '-page1' + ext2
1078 isfile2 = os.path.isfile (f2)
1080 if not isfile2 and os.path.isfile (fp2):
1081 f2 = fp2
1082 isfile2 = os.path.isfile (fp2)
1084 if (os.path.isfile (f2) and isfile2 and
1085 os.stat (f1)[stat.ST_MTIME] >
1086 os.stat (f2)[stat.ST_MTIME]) or \
1087 not isfile2:
1089 return 1
1091 todo = []
1092 if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'):
1093 todo.append ('tex')
1094 if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'):
1095 todo.append ('eps')
1096 if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'):
1097 todo.append ('png')
1099 return ('lilypond', body, opts, todo, basename)
1101 def format_lilypond_block (chunk):
1104 Figure out what should be left MAIN_STR (meant
1105 for the main file) from a lilypond chunk: process
1106 verbatim, and other options. Return: multiple chunks.
1112 return_chunks = []
1114 (type, body, opts, todo, basename) = chunk
1115 assert type == 'lilypond'
1118 newbody = ''
1119 filename_chunk = None
1120 if 'printfilename' in opts:
1121 for o in opts:
1122 m= re.match ("filename=(.*)", o)
1123 if m:
1124 template = get_output ("output-filename")
1125 b = basename + '.ly'
1126 human_base = os.path.basename (m.group (1))
1128 ## todo: include path, but strip
1129 ## first part of the path.
1130 filename_chunk = ('input', template % (human_base, b,human_base))
1131 break
1134 if 'smallverbatim' in opts:
1135 newbody += output_verbatim (body, 1)
1136 elif 'verbatim' in opts:
1137 newbody += output_verbatim (body, 0)
1139 for o in opts:
1140 m = re.search ('intertext="(.*?)"', o)
1141 if m:
1142 newbody = newbody + "\n"
1143 if format == 'texi':
1144 newbody = newbody + "@noindent\n"
1145 elif format == 'latex':
1146 newbody = newbody + "\\noindent\n"
1147 newbody = newbody + m.group (1) + "\n"
1149 if 'noinline' in opts:
1150 s = 'output-noinline'
1151 elif format == 'latex':
1152 if 'eps' in opts:
1153 s = 'output-eps'
1154 else:
1155 if 'quote' in opts:
1156 s = 'output-latex-quoted'
1157 else:
1158 s = 'output-latex-noquote'
1159 elif format == 'texi':
1160 if 'quote' in opts:
1161 s = 'output-texi-quoted'
1162 else:
1163 s = 'output-texi-noquote'
1164 else: # format == 'html'
1165 s = 'output-html'
1167 def html_pages (basename):
1168 pat = os.path.join (g_outdir, "%s-page*.png"% basename)
1170 files = glob.glob (pat)
1173 template = '''<img align="center" valign="center"
1174 border="0" src="%s" alt="[picture of music]">'''
1176 str = ''
1177 if files == []:
1178 files = [basename+'.png' ]
1179 else:
1180 files = map (os.path.basename, files)
1182 for f in files:
1183 str += template % f
1185 str = '<a href="%s.ly">%s</a>' % (basename, str)
1187 return str
1190 newbody = newbody + get_output (s) % {'fn': basename,
1191 'htmlimages': html_pages(basename)
1194 if filename_chunk:
1195 return_chunks += [filename_chunk]
1197 return_chunks += [('lilypond', newbody, opts, todo, basename)]
1199 return return_chunks
1201 def format_lilypond_output_bodies (chunks):
1202 newchunks = []
1203 for c in chunks:
1205 if c[0] == 'lilypond':
1206 newchunks += format_lilypond_block (c)
1207 else:
1208 newchunks.append (c)
1210 return newchunks
1214 def process_lilypond_blocks (chunks):#ugh rename
1215 newchunks = []
1216 # Count sections/chapters.
1217 for c in chunks:
1218 if c[0] == 'lilypond':
1219 c = schedule_lilypond_block (c)
1220 elif c[0] == 'numcols':
1221 paperguru.m_num_cols = c[2]
1222 elif c[0] == 'multicols':
1223 paperguru.m_multicols = c[2]
1225 newchunks.append (c)
1227 return newchunks
1229 def process_ly2dvi_blocks (chunks):
1231 def process_ly2dvi_block (chunk):
1234 Run ly2dvi script on filename specified in CHUNK.
1235 This is only supported for HTML output.
1237 In HTML output it will leave a download menu with ps/pdf/midi etc. in
1238 a separate HTML file, and a title + preview in the main html file,
1239 linking to the menu.
1242 (tag, name, opts) = chunk
1243 assert format == 'html'
1244 (content, original_name) = find_file (name)
1246 original_name = os.path.basename (original_name)
1248 base = unique_file_name (content)
1249 outname = base + '.ly'
1250 changed = update_file (content, outname)
1252 preview = base + ".png"
1253 preview_page = base + '-page1.png'
1255 if changed or not (os.path.isfile (preview) or
1256 os.path.isfile (preview_page)):
1258 ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) )
1260 ly.make_ps_images (base)
1261 ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
1263 def size_str (fn):
1264 b = os.stat(fn)[stat.ST_SIZE]
1265 if b < 1024:
1266 return '%d bytes' % b
1267 elif b < (2 << 20):
1268 return '%d kb' % (b >> 10)
1269 else:
1270 return '%d mb' % (b >> 20)
1272 exts = {
1273 'pdf' : "Print (PDF, %s)",
1274 'ps.gz' : "Print (gzipped PostScript, %s)",
1275 'png' : "View (PNG, %s)",
1276 'midi' : "Listen (MIDI, %s)",
1277 'ly' : "View source code (%s)",
1280 menu = ''
1281 page_files = glob.glob ('%s-page*.png' % base)
1283 for p in string.split (page_files, '\n'):
1284 p = p.strip()
1285 if os.path.isfile (p):
1286 sz = size_str (p)
1287 page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
1288 page = page % sz
1289 menu += '<li><a href="%s">%s</a>' % (p, page)
1291 ext_order = ['ly', 'pdf', 'ps.gz', 'midi']
1292 for e in ext_order:
1293 fn = base + '.' + e
1294 print 'checking,' , fn
1295 if not os.path.isfile (fn):
1296 continue
1298 entry = exts[e] % size_str (fn)
1300 ## TODO: do something like
1301 ## this for texinfo/latex as well ?
1303 menu += '<li><a href="%s">%s</a>\n\n' % (fn, entry)
1306 explanatory_para = """The pictures are 90dpi
1307 anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS
1308 use scalable fonts and should look OK at any resolution."""
1310 separate_menu =r'''
1311 <title>LilyPond example %s</title>
1313 <h1>%s</h1>
1314 <p><img src="%s">
1315 <p>%s
1317 <ul>%s</ul>''' % (original_name,original_name, preview, explanatory_para, menu)
1319 open (base + '.html','w'). write (separate_menu)
1321 inline_menu = '<p/><a href="%s.html"><img src="%s"><p/></a>' % (base, original_name, preview)
1323 return ('ly2dvi', inline_menu)
1325 newchunks = []
1326 for c in chunks:
1327 if c[0] == 'ly2dvi':
1328 c = process_ly2dvi_block (c)
1329 newchunks.append (c)
1331 return newchunks
1333 def compile_all_files (chunks):
1334 global foutn
1335 eps = []
1336 tex = []
1337 png = []
1339 for c in chunks:
1340 if c[0] != 'lilypond':
1341 continue
1343 base = c[4]
1344 exts = c[3]
1345 for e in exts:
1346 if e == 'eps':
1347 eps.append (base)
1348 elif e == 'tex':
1349 #ugh
1350 if base + '.ly' not in tex:
1351 tex.append (base + '.ly')
1352 elif e == 'png' and g_do_pictures:
1353 png.append (base)
1354 d = os.getcwd ()
1355 if g_outdir:
1356 os.chdir (g_outdir)
1357 if tex:
1358 # fixme: be sys-independent.
1359 def incl_opt (x):
1360 if g_outdir and x[0] != '/' :
1361 x = os.path.join (g_here_dir, x)
1362 return ' -I %s' % x
1364 incs = map (incl_opt, include_path)
1365 lilyopts = string.join (incs)
1366 if do_deps:
1367 lilyopts += ' --dependencies'
1368 if g_outdir:
1369 lilyopts += ' --dep-prefix=' + g_outdir + '/'
1370 lilyopts += ' --header=texidoc'
1371 texfiles = string.join (tex)
1372 cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts,
1373 texfiles))
1374 ly.system (cmd, ignore_error = 0, progress_p = 1)
1377 # Ugh, fixing up dependencies for .tex generation
1379 if do_deps:
1380 depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep',
1381 x), tex)
1383 for i in depfiles:
1384 f =open (i)
1385 text=f.read ()
1386 f.close ()
1387 text=re.sub ('\n([^:\n]*):',
1388 '\n' + foutn + ':', text)
1389 f = open (i, 'w')
1390 f.write (text)
1391 f.close ()
1393 def to_eps (file):
1394 cmd = r"latex '\nonstopmode \input %s'" % file
1395 # Ugh. (La)TeX writes progress and error messages on stdout
1396 # Redirect to stderr
1397 cmd += ' 1>/dev/stderr'
1398 ly.system (cmd)
1399 ly.system ("dvips -E -o %s.eps %s" % (file, file))
1400 map (to_eps, eps)
1402 map (ly.make_ps_images, map (lambda x: x + '.eps', png))
1403 os.chdir (d)
1406 def update_file (body, name):
1408 write the body if it has changed. Return whether BODY has changed.
1410 same = 0
1411 try:
1412 f = open (name)
1413 fs = f.read (-1)
1414 same = (fs == body)
1415 except:
1416 pass
1418 if not same:
1419 f = open (name , 'w')
1420 f.write (body)
1421 f.close ()
1423 return not same
1426 def write_deps (fn, target, chunks):
1427 global read_files
1428 sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn))
1429 f = open (os.path.join (g_outdir, fn), 'w')
1430 f.write ('%s%s: ' % (g_dep_prefix, target))
1431 for d in read_files:
1432 f.write ('%s ' % d)
1435 ## There used to be code to write .tex dependencies, but
1436 ## that is silly: lilypond-book has its own dependency scheme
1437 ## to ensure that all lily-XXX.tex files are there
1440 f.write ('\n')
1441 f.close ()
1442 read_files = []
1444 def check_texidoc (chunks):
1445 ## TODO: put file name in front of texidoc.
1447 n = []
1448 for c in chunks:
1449 if c[0] == 'lilypond':
1450 (type, body, opts, todo, basename) = c;
1451 pathbase = os.path.join (g_outdir, basename)
1452 if os.path.isfile (pathbase + '.texidoc') \
1453 and 'notexidoc' not in opts:
1454 n.append( ('input', '\n@include %s.texidoc\n\n' % basename))
1455 n.append (c)
1456 return n
1459 ## what's this? Docme --hwn
1461 def fix_epswidth (chunks):
1462 newchunks = []
1463 for c in chunks:
1464 if c[0] != 'lilypond' or 'eps' not in c[2]:
1465 newchunks.append (c)
1466 continue
1468 mag = 1.0
1469 for o in c[2]:
1470 m = re.match ('magnification=([0-9.]+)', o)
1471 if m:
1472 mag = string.atof (m.group (1))
1474 def replace_eps_dim (match, lmag = mag):
1475 filename = match.group (1)
1476 dims = bounding_box_dimensions (filename)
1478 return '%fpt' % (dims[0] *lmag)
1480 body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
1481 newchunks.append (('lilypond', body, c[2], c[3], c[4]))
1483 return newchunks
1486 ##docme: why global?
1487 foutn=""
1489 def do_file (input_filename):
1490 chunks = read_doc_file (input_filename)
1491 chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1)
1492 chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1)
1493 chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1)
1494 chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1)
1495 chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1)
1496 chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
1497 chunks = chop_chunks (chunks, 'numcols', do_columns)
1498 chunks = chop_chunks (chunks, 'multicols', do_multicols)
1500 scan_preamble (chunks)
1501 chunks = process_lilypond_blocks (chunks)
1502 chunks = process_ly2dvi_blocks (chunks)
1504 # Do It.
1505 global g_run_lilypond
1506 if g_run_lilypond:
1507 compile_all_files (chunks)
1508 chunks = fix_epswidth (chunks)
1511 chunks = format_lilypond_output_bodies (chunks)
1512 global format
1513 if format == 'texi':
1514 chunks = check_texidoc (chunks)
1517 x = 0
1518 chunks = completize_preamble (chunks)
1520 global foutn
1522 if outname:
1523 my_outname = outname
1524 elif input_filename == '-' or input_filename == "/dev/stdin":
1525 my_outname = '-'
1526 else:
1527 my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format
1528 my_depname = my_outname + '.dep'
1530 if my_outname == '-' or my_outname == '/dev/stdout':
1531 fout = sys.stdout
1532 foutn = "<stdout>"
1533 global do_deps
1534 do_deps = 0
1535 else:
1536 foutn = os.path.join (g_outdir, my_outname)
1537 sys.stderr.write ("Writing `%s'\n" % foutn)
1538 fout = open (foutn, 'w')
1539 for c in chunks:
1540 fout.write (c[1])
1541 fout.close ()
1542 # should chmod -w
1544 if do_deps:
1545 write_deps (my_depname, foutn, chunks)
1547 outname = ''
1548 try:
1549 (sh, long) = ly.getopt_args (option_definitions)
1550 (options, files) = getopt.getopt (sys.argv[1:], sh, long)
1552 except getopt.error, msg:
1553 sys.stderr.write ('\n')
1554 ly.error (_ ("getopt says: `%s\'" % s))
1555 sys.stderr.write ('\n')
1556 ly.help ()
1557 ly.exit (2)
1559 do_deps = 0
1560 for opt in options:
1561 o = opt[0]
1562 a = opt[1]
1564 if o == '--include' or o == '-I':
1565 include_path.append (a)
1566 elif o == '--version' or o == '-v':
1567 ly.identify (sys.stdout)
1568 sys.exit (0)
1569 elif o == '--verbose' or o == '-V':
1570 verbose_p = 1
1571 elif o == '--format' or o == '-f':
1572 format = a
1573 if a == 'texi-html':
1574 format = 'texi'
1575 g_make_html = 1
1576 elif o == '--outname' or o == '-o':
1577 if len (files) > 1:
1578 #HACK
1579 sys.stderr.write ("Lilypond-book is confused by --outname on multiple files")
1580 sys.exit (1)
1581 outname = a
1582 elif o == '--help' or o == '-h':
1583 ly.help ()
1584 sys.exit (0)
1585 elif o == '--no-lily' or o == '-n':
1586 g_run_lilypond = 0
1587 elif o == '--preview-resolution':
1588 preview_resolution = string.atoi (a)
1589 elif o == '--dependencies' or o == '-M':
1590 do_deps = 1
1591 elif o == '--default-music-fontsize':
1592 default_music_fontsize = string.atoi (a)
1593 elif o == '--default-lilypond-fontsize':
1594 print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
1595 default_music_fontsize = string.atoi (a)
1596 elif o == '--extra-options':
1597 g_extra_opts = a
1598 elif o == '--force-music-fontsize':
1599 g_force_music_fontsize = string.atoi (a)
1600 elif o == '--force-lilypond-fontsize':
1601 print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
1602 g_force_music_fontsize = string.atoi (a)
1603 elif o == '--dep-prefix':
1604 g_dep_prefix = a
1605 elif o == '--no-pictures':
1606 g_do_pictures = 0
1607 elif o == '--no-music':
1608 g_do_music = 0
1609 elif o == '--outdir':
1610 g_outdir = a
1611 elif o == '--warranty' or o == '-w':
1612 #status = os.system ('lilypond -w')
1613 if 1 or status:
1614 ly.warranty ()
1615 sys.exit (0)
1617 ly.identify (sys.stderr)
1619 if g_outdir:
1620 if os.path.isfile (g_outdir):
1621 error ("outdir is a file: %s" % g_outdir)
1622 if not os.path.exists (g_outdir):
1623 os.mkdir (g_outdir)
1625 if not files:
1626 ly.help ()
1627 ly.error (_ ("no files specified on command line"))
1628 ly.exit (2)
1630 ly.setup_environment ()
1633 for input_filename in files:
1634 do_file (input_filename)
1638 # Petr, ik zou willen dat ik iets zinvoller deed,
1639 # maar wat ik kan ik doen, het verandert toch niets?
1640 # --hwn 20/aug/99