]> git.donarmstrong.com Git - lilypond.git/blob - scripts/lilypond-book.py
Handle printfilename also with verbatim
[lilypond.git] / scripts / lilypond-book.py
1 #!@PYTHON@
2 # vim: set noexpandtab:
3 # TODO:
4 # * junk --outdir for --output 
5 # * Figure out clean set of options.
6 # * 
7 # * EndLilyPondOutput is def'd as vfil. Causes large white gaps.
8 # * texinfo: add support for @pagesize
9
10 # todo: dimension handling (all the x2y) is clumsy. (tca: Thats
11 #       because the values are taken directly from texinfo.tex,
12 #       geometry.sty and article.cls. Give me a hint, and I'll
13 #       fix it.)
14
15 #
16 # TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips. 
17
18
19 # This is was the idea for handling of comments:
20 #       Multiline comments, @ignore .. @end ignore is scanned for
21 #       in read_doc_file, and the chunks are marked as 'ignore', so
22 #       lilypond-book will not touch them any more. The content of the
23 #       chunks are written to the output file. Also 'include' and 'input'
24 #       regex has to check if they are commented out.
25 #
26 #       Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
27 #       These three regex's has to check if they are on a commented line,
28 #       % for latex, @c for texinfo.
29 #
30 #       Then lines that are commented out with % (latex) and @c (Texinfo)
31 #       are put into chunks marked 'ignore'. This cannot be done before
32 #       searching for the lilypond-blocks because % is also the comment character
33 #       for lilypond.
34 #
35 #       The the rest of the rexeces are searched for. They don't have to test
36 #       if they are on a commented out line.
37
38
39
40 import os
41 import stat
42 import string
43 import getopt
44 import sys
45 import __main__
46
47 # Handle bug in Python 1.6-2.1
48 #
49 # there are recursion limits for some patterns in Python 1.6 til 2.1. 
50 # fix this by importing the 1.5.2 implementation pre instead. Fix by Mats.
51
52 if float (sys.version[0:3]) < 2.2:
53         try:
54                 import pre
55                 re = pre
56                 del pre
57         except ImportError:
58                 import re
59 else:
60         import re
61
62 # Attempt to fix problems with limited stack size set by Python!
63 # Sets unlimited stack size. Note that the resource module only
64 # is available on UNIX.
65 try:
66        import resource
67        resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
68 except:
69        pass
70
71 errorport = sys.stderr
72 verbose_p = 0
73
74
75
76 try:
77         import gettext
78         gettext.bindtextdomain ('lilypond', localedir)
79         gettext.textdomain ('lilypond')
80         _ = gettext.gettext
81 except:
82         def _ (s):
83                 return s
84
85 def progress (s):
86         errorport.write (s + '\n')
87
88
89 program_version = '@TOPLEVEL_VERSION@'
90 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
91         program_version = '1.5.53'
92
93 # if set, LILYPONDPREFIX must take prevalence
94 # if datadir is not set, we're doing a build and LILYPONDPREFIX 
95 datadir = '@local_lilypond_datadir@'
96
97 if os.environ.has_key ('LILYPONDPREFIX') :
98         datadir = os.environ['LILYPONDPREFIX']
99 else:
100         datadir = '@local_lilypond_datadir@'
101
102 while datadir[-1] == os.sep:
103         datadir= datadir[:-1]
104
105 kpse = os.popen ('kpsexpand \$TEXMF').read()
106 kpse = re.sub('[ \t\n]+$','', kpse)
107 type1_paths = os.popen ('kpsewhich -expand-path=\$T1FONTS').read ()
108
109 environment = {
110         # TODO: * prevent multiple addition.
111         #       * clean TEXINPUTS, MFINPUTS, TFMFONTS,
112         #         as these take prevalence over $TEXMF
113         #         and thus may break tex run?
114         'TEXMF' : "{%s,%s}" % (datadir, kpse) ,
115         'GS_FONTPATH' : type1_paths,
116         'GS_LIB' : datadir + '/ps',
117 }
118
119 # tex needs lots of memory, more than it gets by default on Debian
120 non_path_environment = {
121         'extra_mem_top' : '1000000',
122         'extra_mem_bottom' : '1000000',
123         'pool_size' : '250000',
124 }
125
126 def setup_environment ():
127         # $TEXMF is special, previous value is already taken care of
128         if os.environ.has_key ('TEXMF'):
129                 del os.environ['TEXMF']
130  
131         for key in environment.keys ():
132                 val = environment[key]
133                 if os.environ.has_key (key):
134                         val = val + os.pathsep + os.environ[key]
135                 os.environ[key] = val
136
137         for key in non_path_environment.keys ():
138                 val = non_path_environment[key]
139                 os.environ[key] = val
140
141 include_path = [os.getcwd()]
142
143
144 # g_ is for global (?)
145 g_extra_opts = ''
146 g_here_dir = os.getcwd ()
147 g_dep_prefix = ''
148 g_outdir = ''
149 g_force_music_fontsize = 0
150 g_read_lys = 0
151 g_do_pictures = 1
152 g_do_music = 1
153
154 format = ''
155 g_run_lilypond = 1
156 no_match = 'a\ba'
157
158 default_music_fontsize = 16
159 default_text_fontsize = 12
160 paperguru = None
161
162 class LatexPaper:
163         def __init__(self):
164                 self.m_document_preamble = []
165                 self.m_num_cols = 1
166                 self.m_multicols = 1
167         def find_latex_dims(self):
168                 if g_outdir:
169                         fname = os.path.join(g_outdir, "lily-tmp.tex")
170                 else:
171                         fname = "lily-tmp.tex"
172                 try:
173                         f = open(fname, "w")
174                 except IOError:
175                         error ("Error creating temporary file '%s'" % fname)
176                 for s in self.m_document_preamble:
177                         f.write(s)
178                 f.write(r"""
179 \begin{document}
180 \typeout{---}
181 \typeout{\columnsep \the\columnsep}
182 \typeout{\textwidth \the\textwidth}
183 \typeout{---}
184 \end{document}
185                 """)
186                 f.close()
187                 re_dim = re.compile(r"\\(\w+)\s+(\d+\.\d+)")
188                 p = os.popen("latex %s" % fname)
189                 ln = p.readline()
190                 while ln:
191                         ln = string.strip(ln)
192                         m = re_dim.match(ln)
193                         if m:
194                                 if m.groups()[0] in ('textwidth', 'columnsep'):
195                                         self.__dict__['m_%s' % m.groups()[0]] = float(m.groups()[1])
196                         ln = p.readline()
197                 try:
198                         os.remove (fname)
199                         os.remove (os.path.splitext(fname)[0]+".aux")
200                         os.remove (os.path.splitext(fname)[0]+".log")
201                 except:
202                         pass
203         def get_linewidth(self):
204                 if self.m_num_cols == 1:
205                         w = self.m_textwidth
206                 else:
207                         w = (self.m_textwidth - self.m_columnsep)/2
208                 if self.m_multicols > 1:
209                         return (w - self.m_columnsep*(self.m_multicols-1)) \
210                            / self.m_multicols
211                 return w
212
213
214 class HtmlPaper:
215         def __init__(self):
216                 self.m_papersize = 'letterpaper'
217                 self.m_fontsize = 12
218         def get_linewidth(self):
219                 return html_linewidths[self.m_papersize][self.m_fontsize]
220
221 class TexiPaper:
222         def __init__(self):
223                 self.m_papersize = 'letterpaper'
224                 self.m_fontsize = 12
225         def get_linewidth(self):
226                 return texi_linewidths[self.m_papersize][self.m_fontsize]
227
228 def mm2pt(x):
229         return x * 2.8452756
230 def in2pt(x):
231         return x * 72.26999
232 def em2pt(x, fontsize = 10):
233         return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
234 def ex2pt(x, fontsize = 10):
235         return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
236
237 def pt2pt(x):
238         return x
239
240 dimension_conversion_dict ={
241         'mm': mm2pt,
242         'cm': lambda x: mm2pt(10*x),
243         'in': in2pt,
244         'em': em2pt,
245         'ex': ex2pt,
246         'pt': pt2pt
247         }
248
249 # Convert numeric values, with or without specific dimension, to floats.
250 # Keep other strings
251 def conv_dimen_to_float(value):
252         if type(value) == type(""):
253                 m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
254                 if m:
255                         unit = m.group (2)
256                         num = string.atof(m.group (1))
257                         conv =  dimension_conversion_dict[m.group(2)]
258                         
259                         value = conv(num)
260                 
261                 elif re.match ("^[0-9.]+$",value):
262                         value = float(value)
263
264         return value
265
266 texi_linewidths = {
267         'afourpaper': {12: mm2pt(160)},
268         'afourwide': {12: in2pt(6.5)},
269         'afourlatex': {12: mm2pt(150)},
270         'smallbook': {12: in2pt(5)},
271         'letterpaper': {12: in2pt(6)}}
272
273 html_linewidths = {
274         'afourpaper': {12: mm2pt(160)},
275         'afourwide': {12: in2pt(6.5)},
276         'afourlatex': {12: mm2pt(150)},
277         'smallbook': {12: in2pt(5)},
278         'letterpaper': {12: in2pt(6)}}
279
280 option_definitions = [
281         ('EXT', 'f', 'format', 'use output format EXT (texi [default], latex, html)'),
282         ('DIM',  '', 'default-music-fontsize', 'default fontsize for music.  DIM is assumed to be in points'),
283         ('DIM',  '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
284         ('OPT', '', 'extra-options' , 'Pass OPT quoted to the lilypond command line'),
285         ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
286         ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
287         ('', 'h', 'help', 'this help'),
288         ('DIR', 'I', 'include', 'include path'),
289         ('', 'M', 'dependencies', 'write dependencies'),
290         ('PREF', '',  'dep-prefix', 'prepend PREF before each -M dependency'),
291         ('', 'n', 'no-lily', 'don\'t run lilypond'),
292         ('', '', 'no-pictures', "don\'t generate pictures"),
293         ('', '', 'no-music', "strip all lilypond blocks from output"),  
294         ('', '', 'read-lys', "don't write ly files."),
295         ('FILE', 'o', 'outname', 'filename main output file'),
296         ('FILE', '', 'outdir', "where to place generated files"),
297         ('', 'V', 'verbose', 'verbose' ),
298         ('', 'v', 'version', 'print version information' ),
299         ]
300
301 # format specific strings, ie. regex-es for input, and % strings for output
302 output_dict= {
303         'html' : {'output-lilypond': '''<lilypond%s>
304 %s
305 </lilypond>''',
306                 'output-filename' : r'''
307
308 <pre>%s</pre>:''',        
309                   'output-lilypond-fragment': '''<lilypond%s>
310 \context Staff\context Voice{ %s }
311 </lilypond>''',
312                   'output-noinline': r'''
313 <!-- generated: %(fn)s.png !-->
314 ''',
315                   ## maybe <hr> ?
316                   'pagebreak': None,
317                   'output-verbatim': r'''<pre>
318 %s
319 </pre>''',
320                   'output-small-verbatim': r'''<font size=-1><pre>
321 %s
322 </pre></font>''',
323
324                   ## Ugh we need to differentiate on origin:
325                   ## lilypond-block origin wants an extra <p>, but
326                   ## inline music doesn't.
327                   ## possibly other center options?
328                   'output-all': r'''
329 <a href="%(fn)s.png">
330 <img align="center" valign="center" border="0" src="%(fn)s.png" alt="[picture of music]"></a>
331 ''',
332                   },
333         'latex': {
334                 'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
335   \context Staff <
336     \context Voice{
337       %s
338     }
339   >
340 \end{lilypond}''',
341                 'output-filename' : r'''
342
343 \verb+%s+:''',
344                 'output-lilypond': r'''\begin[%s]{lilypond}
345 %s
346 \end{lilypond}
347 ''',
348                 'output-verbatim': r'''\begin{verbatim}%s\end{verbatim}%%
349 ''',
350                 'output-small-verbatim': r'''{\small\begin{verbatim}%s\end{verbatim}}%%''',
351                 'output-default-post': "\\def\postLilypondExample{}\n",
352                 'output-default-pre': "\\def\preLilypondExample{}\n",
353                 'usepackage-graphics': '\\usepackage{graphics}\n',
354                 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
355                 'output-noinline': r'''
356 %% generated: %(fn)s.eps
357 ''',
358                 'output-tex': '{\\preLilypondExample \\input %(fn)s.tex \\postLilypondExample\n}',
359                 'pagebreak': r'\pagebreak',
360                 },
361         
362         'texi' : {'output-lilypond': '''@lilypond[%s]
363 %s
364 @end lilypond 
365 ''',
366                 'output-filename' : r'''
367
368 @file{%s}:''',    
369                   'output-lilypond-fragment': '''@lilypond[%s]
370 \context Staff\context Voice{ %s }
371 @end lilypond ''',
372                   'output-noinline': r'''
373 @c generated: %(fn)s.png                  
374 ''',
375                   'pagebreak': None,
376                   'output-small-verbatim': r'''@smallexample
377 %s
378 @end smallexample
379 ''',
380                   'output-verbatim': r'''@example
381 %s
382 @end example
383 ''',
384
385 # do some tweaking: @ is needed in some ps stuff.
386 # override EndLilyPondOutput, since @tex is done
387 # in a sandbox, you can't do \input lilyponddefs at the
388 # top of the document.
389
390 # should also support fragment in
391
392 # ugh, the <p> below breaks inline images...
393                   
394                   'output-all': r'''
395 @tex
396 \catcode`\@=12
397 \input lilyponddefs
398 \def\EndLilyPondOutput{}
399 \input %(fn)s.tex
400 \catcode`\@=0
401 @end tex
402 @html
403 <p>
404 <a href="%(fn)s.png">
405 <img border=0 src="%(fn)s.png" alt="[picture of music]">
406 </a>
407 @end html
408 ''',
409                 }
410         
411         }
412
413 def output_verbatim (body, small):
414         if __main__.format == 'html':
415                 body = re.sub ('&', '&amp;', body)
416                 body = re.sub ('>', '&gt;', body)
417                 body = re.sub ('<', '&lt;', body)
418         elif __main__.format == 'texi':
419                 body = re.sub ('([@{}])', '@\\1', body)
420
421         if small:
422                 key = 'output-small-verbatim'
423         else:
424                 key = 'output-verbatim'
425         return get_output (key) % body
426
427
428 #warning: this uses extended regular expressions. Tread with care.
429
430 # legenda
431
432 # (?P  -- name parameter
433 # *? -- match non-greedily.
434 # (?m)  -- ?  
435 re_dict = {
436         'html': {
437                  'include':  no_match,
438                  'input': no_match,
439                  'header': no_match,
440                  'preamble-end': no_match,
441                  'landscape': no_match,
442                  'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
443                  'verb': r'''(?P<code><pre>.*?</pre>)''',
444                  'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
445                  'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
446                  'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
447                   'option-sep' : '\s*',
448                   'intertext': r',?\s*intertext=\".*?\"',
449                   'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
450                   'singleline-comment': no_match,
451                   'numcols': no_match,
452                   'multicols': no_match,
453                  },
454         
455         'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
456                   'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
457                   'option-sep' : ',\s*',
458                   'header': r"\n*\\documentclass\s*(\[.*?\])?",
459                   'preamble-end': r'(?P<code>\\begin{document})',
460                   'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
461                   'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
462                   'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
463                   'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
464                   'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
465                   'def-post-re': r"\\def\\postLilypondExample",
466                   'def-pre-re': r"\\def\\preLilypondExample",
467                   'usepackage-graphics': r"\usepackage{graphics}",
468                   'intertext': r',?\s*intertext=\".*?\"',
469                   'multiline-comment': no_match,
470                   'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
471                   'numcols': r"(?P<code>\\(?P<num>one|two)column)",
472                   'multicols': r"(?P<code>\\(?P<be>begin|end){multicols}({(?P<num>\d+)?})?)",
473                   },
474
475
476         # why do we have distinction between @mbinclude and @include?
477
478         
479         'texi': {
480                  'include':  '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
481                  'input': no_match,
482                  'header': no_match,
483                  'preamble-end': no_match,
484                  'landscape': no_match,
485                  'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
486                  'verb': r'''(?P<code>@code{.*?})''',
487                  'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
488                  'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
489                  'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end +lilypond)\s''',
490                  'option-sep' : ',\s*',
491                  'intertext': r',?\s*intertext=\".*?\"',
492                  'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
493                  'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
494                  'numcols': no_match,
495                  'multicols': no_match,
496                  }
497         }
498
499
500 for r in re_dict.keys ():
501         olddict = re_dict[r]
502         newdict = {}
503         for k in olddict.keys ():
504                 try:
505                         newdict[k] = re.compile (olddict[k])
506                 except:
507                         print 'invalid regexp: %s' % olddict[k]
508
509                         # we'd like to catch and reraise a more detailed  error, but
510                         # alas, the exceptions changed across the 1.5/2.1 boundary.
511                         raise "Invalid re"
512         re_dict[r] = newdict
513
514         
515 def uniq (list):
516         list.sort ()
517         s = list
518         list = []
519         for x in s:
520                 if x not in list:
521                         list.append (x)
522         return list
523                 
524
525 def get_output (name):
526         return  output_dict[format][name]
527
528 def get_re (name):
529         return  re_dict[format][name]
530
531 def bounding_box_dimensions(fname):
532         if g_outdir:
533                 fname = os.path.join(g_outdir, fname)
534         try:
535                 fd = open(fname)
536         except IOError:
537                 error ("Error opening `%s'" % fname)
538         str = fd.read ()
539         s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
540         if s:
541                 
542                 gs = map (lambda x: string.atoi (x), s.groups ())
543                 return (int (gs[2] - gs[0] + 0.5),
544                         int (gs[3] - gs[1] + 0.5))
545         else:
546                 return (0,0)
547
548 def error (str):
549         sys.stderr.write (str + "\n  Exiting ... \n\n")
550         raise 'Exiting.'
551
552
553 def compose_full_body (body, opts):
554         '''Construct the lilypond code to send to Lilypond.
555         Add stuff to BODY using OPTS as options.'''
556         music_size = default_music_fontsize
557         if g_force_music_fontsize:
558                 music_size = g_force_music_fontsize
559         indent = ''
560         linewidth = ''
561         for o in opts:
562                 if not g_force_music_fontsize:
563                         m = re.match ('([0-9]+)pt', o)
564                         if m:
565                                 music_size = string.atoi(m.group (1))
566
567                 m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
568                 if m:
569                         f = float (m.group (1))
570                         indent = 'indent = %f\\%s' % (f, m.group (2))
571                         
572                 m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
573                 if m:
574                         f = float (m.group (1))
575                         linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
576
577         if re.search ('\\\\score', body):
578                 is_fragment = 0
579         else:
580                 is_fragment = 1
581         if 'fragment' in opts:
582                 is_fragment = 1
583         if 'nofragment' in opts:
584                 is_fragment = 0
585
586         if is_fragment and not 'multiline' in opts:
587                 opts.append('singleline')
588                 
589         if 'singleline' in opts:
590                 linewidth = 'linewidth = -1.0'
591         elif not linewidth:
592                 l = __main__.paperguru.get_linewidth ()
593                 linewidth = 'linewidth = %f\pt' % l
594
595         if 'noindent' in opts:
596                 indent = 'indent = 0.0\mm'
597
598         for o in opts:
599                 m= re.search ('relative(.*)', o)
600                 v = 0
601                 if m:
602                         try:
603                                 v = string.atoi (m.group (1))
604                         except ValueError:
605                                 pass
606
607                         v = v + 1
608                         pitch = 'c'
609                         if v < 0:
610                                 pitch = pitch + '\,' * v
611                         elif v > 0:
612                                 pitch = pitch + '\'' * v
613
614                         body = '\\relative %s { %s }' %(pitch, body)
615         
616         if is_fragment:
617                 body = r'''\score { 
618  \notes { %s }
619   \paper { }  
620 }''' % body
621
622         opts = uniq (opts)
623         optstring = string.join (opts, ' ')
624         optstring = re.sub ('\n', ' ', optstring)
625         body = r'''
626 %% Generated automatically by: lilypond-book.py
627 %% options are %s  
628 \include "paper%d.ly"
629 \paper  {
630   %s
631   %s
632
633 ''' % (optstring, music_size, linewidth, indent) + body
634
635         # ughUGH not original options
636         return body
637
638 def scan_html_preamble (chunks):
639         return
640
641 def scan_latex_preamble(chunks):
642         # First we want to scan the \documentclass line
643         # it should be the first non-comment line.
644         # The only thing we really need to know about the \documentclass line
645         # is if there are one or two columns to begin with.
646         idx = 0
647         while 1:
648                 if chunks[idx][0] == 'ignore':
649                         idx = idx + 1
650                         continue
651                 m = get_re ('header').match(chunks[idx][1])
652                 if not m:
653                         error ("Latex documents must start with a \documentclass command")
654                 if m.group (1):
655                         options = re.split (',[\n \t]*', m.group(1)[1:-1])
656                 else:
657                         options = []
658                 if 'twocolumn' in options:
659                         paperguru.m_num_cols = 2
660                 break
661
662         # Then we add everythin before \begin{document} to
663         # paperguru.m_document_preamble so that we can later write this header
664         # to a temporary file in find_latex_dims() to find textwidth.
665         while idx < len(chunks) and chunks[idx][0] != 'preamble-end':
666                 if chunks[idx] == 'ignore':
667                         idx = idx + 1
668                         continue
669                 paperguru.m_document_preamble.append(chunks[idx][1])
670                 idx = idx + 1
671         paperguru.find_latex_dims()
672
673 def scan_texi_preamble (chunks):
674         # this is not bulletproof..., it checks the first 10 chunks
675         for c in chunks[:10]:
676                 if c[0] == 'input':
677                         for s in ('afourpaper', 'afourwide', 'letterpaper',
678                                   'afourlatex', 'smallbook'):
679                                 if string.find(c[1], "@%s" % s) != -1:
680                                         paperguru.m_papersize = s
681
682
683 def scan_preamble (chunks):
684         if __main__.format == 'html':
685                 scan_html_preamble (chunks)
686         elif __main__.format == 'latex':
687                 scan_latex_preamble (chunks)
688         elif __main__.format == 'texi':
689                 scan_texi_preamble (chunks)
690                 
691
692 def completize_preamble (chunks):
693         if __main__.format != 'latex':
694                 return chunks
695         pre_b = post_b = graphics_b = None
696         for chunk in chunks:
697                 if chunk[0] == 'preamble-end':
698                         break
699                 if chunk[0] == 'input':
700                         m = get_re('def-pre-re').search(chunk[1])
701                         if m:
702                                 pre_b = 1
703                 if chunk[0] == 'input':
704                         m = get_re('def-post-re').search(chunk[1])
705                         if m:
706                                 post_b = 1
707                                 
708                 if chunk[0] == 'input':
709                         m = get_re('usepackage-graphics').search(chunk[1])
710                         if m:
711                                 graphics_b = 1
712         x = 0
713         while x < len (chunks) and   chunks[x][0] != 'preamble-end':
714                 x = x + 1
715
716         if x == len(chunks):
717                 return chunks
718         
719         if not pre_b:
720                 chunks.insert(x, ('input', get_output ('output-default-pre')))
721         if not post_b:
722                 chunks.insert(x, ('input', get_output ('output-default-post')))
723         if not graphics_b:
724                 chunks.insert(x, ('input', get_output ('usepackage-graphics')))
725
726         return chunks
727
728
729 read_files = []
730 def find_file (name):
731         '''
732         Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
733         '''
734
735         if name == '-':
736                 return (sys.stdin.read (), '<stdin>')
737         f = None
738         nm = ''
739         for a in include_path:
740                 try:
741                         nm = os.path.join (a, name)
742                         f = open (nm)
743                         __main__.read_files.append (nm)
744                         break
745                 except IOError:
746                         pass
747         if f:
748                 sys.stderr.write ("Reading `%s'\n" % nm)
749                 return (f.read (), nm)
750         else:
751                 error ("File not found `%s'\n" % name)
752                 return ('', '')
753
754 def do_ignore(match_object):
755         return [('ignore', match_object.group('code'))]
756 def do_preamble_end(match_object):
757         return [('preamble-end', match_object.group('code'))]
758
759 def make_verbatim(match_object):
760         return [('verbatim', match_object.group('code'))]
761
762 def make_verb(match_object):
763         return [('verb', match_object.group('code'))]
764
765 def do_include_file(m):
766         "m: MatchObject"
767         return [('input', get_output ('pagebreak'))] \
768              + read_doc_file(m.group('filename')) \
769              + [('input', get_output ('pagebreak'))] 
770
771 def do_input_file(m):
772         return read_doc_file(m.group('filename'))
773
774 def make_lilypond(m):
775         if m.group('options'):
776                 options = m.group('options')
777         else:
778                 options = ''
779         return [('input', get_output('output-lilypond-fragment') % 
780                         (options, m.group('code')))]
781
782 def make_lilypond_file(m):
783         '''
784
785         Find @lilypondfile{bla.ly} occurences and substitute bla.ly
786         into a @lilypond .. @end lilypond block.
787         
788         '''
789         
790         if m.group('options'):
791                 options = m.group('options')
792         else:
793                 options = ''
794         (content, nm) = find_file(m.group('filename'))
795         options = "filename=%s," % nm + options
796
797         return [('input', get_output('output-lilypond') %
798                         (options, content))]
799
800 def make_lilypond_block(m):
801         if not g_do_music:
802                 return []
803         
804         if m.group('options'):
805                 options = get_re('option-sep').split (m.group('options'))
806         else:
807             options = []
808         options = filter(lambda s: s != '', options)
809         return [('lilypond', m.group('code'), options)]
810
811 def do_columns(m):
812         if __main__.format != 'latex':
813                 return []
814         if m.group('num') == 'one':
815                 return [('numcols', m.group('code'), 1)]
816         if m.group('num') == 'two':
817                 return [('numcols', m.group('code'), 2)]
818
819 def do_multicols(m):
820         if __main__.format != 'latex':
821                 return []
822         if m.group('be') == 'begin':
823                 return [('multicols', m.group('code'), int(m.group('num')))]
824         else:
825                 return [('multicols', m.group('code'), 1)]
826         return []
827
828 def chop_chunks(chunks, re_name, func, use_match=0):
829         newchunks = []
830         for c in chunks:
831                 if c[0] == 'input':
832                         str = c[1]
833                         while str:
834                                 m = get_re (re_name).search (str)
835                                 if m == None:
836                                         newchunks.append (('input', str))
837                                         str = ''
838                                 else:
839                                         if use_match:
840                                                 newchunks.append (('input', str[:m.start ('match')]))
841                                         else:
842                                                 newchunks.append (('input', str[:m.start (0)]))
843                                         #newchunks.extend(func(m))
844                                         # python 1.5 compatible:
845                                         newchunks = newchunks + func(m)
846                                         str = str [m.end(0):]
847                 else:
848                         newchunks.append(c)
849         return newchunks
850
851 def determine_format (str):
852         if __main__.format == '':
853                 
854                 html = re.search ('(?i)<[dh]tml', str[:200])
855                 latex = re.search (r'''\\document''', str[:200])
856                 texi = re.search ('@node|@setfilename', str[:200])
857
858                 f = ''
859                 g = None
860                 
861                 if html and not latex and not texi:
862                         f = 'html'
863                 elif latex and not html and not texi:
864                         f = 'latex'
865                 elif texi and not html and not latex:
866                         f = 'texi'
867                 else:
868                         error ("can't determine format, please specify")
869                 __main__.format = f
870
871         if __main__.paperguru == None:
872                 if __main__.format == 'html':
873                         g = HtmlPaper ()
874                 elif __main__.format == 'latex':
875                         g = LatexPaper ()
876                 elif __main__.format == 'texi':
877                         g = TexiPaper ()
878                         
879                 __main__.paperguru = g
880
881
882 def read_doc_file (filename):
883         '''Read the input file, find verbatim chunks and do \input and \include
884         '''
885         (str, path) = find_file(filename)
886         determine_format (str)
887         
888         chunks = [('input', str)]
889         
890         # we have to check for verbatim before doing include,
891         # because we don't want to include files that are mentioned
892         # inside a verbatim environment
893         chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
894         chunks = chop_chunks(chunks, 'verb', make_verb)
895         chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
896         #ugh fix input
897         chunks = chop_chunks(chunks, 'include', do_include_file, 1)
898         chunks = chop_chunks(chunks, 'input', do_input_file, 1)
899         return chunks
900
901
902 taken_file_names = {}
903 def schedule_lilypond_block (chunk):
904         '''Take the body and options from CHUNK, figure out how the
905         real .ly should look, and what should be left MAIN_STR (meant
906         for the main file).  The .ly is written, and scheduled in
907         TODO.
908
909         Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
910
911         TODO has format [basename, extension, extension, ... ]
912         
913         '''
914         (type, body, opts) = chunk
915         assert type == 'lilypond'
916         file_body = compose_full_body (body, opts)
917         ## Hmm, we should hash only lilypond source, and skip the
918         ## %options are ...
919         ## comment line
920         basename = 'lily-' + `abs(hash (file_body))`
921         for o in opts:
922                 m = re.search ('filename="(.*?)"', o)
923                 if m:
924                         basename = m.group (1)
925                         if not taken_file_names.has_key(basename):
926                                 taken_file_names[basename] = 0
927                         else:
928                                 taken_file_names[basename] = taken_file_names[basename] + 1
929                                 basename = basename + "-%i" % taken_file_names[basename]
930         if not g_read_lys:
931                 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
932         needed_filetypes = ['tex']
933
934         if format == 'html' or format == 'texi':
935                 needed_filetypes.append ('eps')
936                 needed_filetypes.append ('png')
937         if 'eps' in opts and not ('eps' in needed_filetypes):
938                 needed_filetypes.append('eps')
939         pathbase = os.path.join (g_outdir, basename)
940         def f (base, ext1, ext2):
941                 a = os.path.isfile(base + ext2)
942                 if (os.path.isfile(base + ext1) and
943                     os.path.isfile(base + ext2) and
944                                 os.stat(base+ext1)[stat.ST_MTIME] >
945                                 os.stat(base+ext2)[stat.ST_MTIME]) or \
946                                 not os.path.isfile(base + ext2):
947                         return 1
948         todo = []
949         if 'tex' in needed_filetypes and f(pathbase, '.ly', '.tex'):
950                 todo.append('tex')
951         if 'eps' in needed_filetypes and f(pathbase, '.tex', '.eps'):
952                 todo.append('eps')
953         if 'png' in needed_filetypes and f(pathbase, '.eps', '.png'):
954                 todo.append('png')
955         newbody = ''
956
957         if 'printfilename' in opts:
958                 for o in opts:
959                         m= re.match ("filename=(.*)", o)
960                         if m:
961                                 newbody = newbody + get_output ("output-filename") % m.group(1)
962                                 break
963                 
964
965         if 'smallverbatim' in opts:
966                 newbody = newbody + output_verbatim (body, 1)
967         elif 'verbatim' in opts:
968                 newbody = newbody + output_verbatim (body, 0)
969
970         for o in opts:
971                 m = re.search ('intertext="(.*?)"', o)
972                 if m:
973                         newbody = newbody  + m.group (1) + "\n\n"
974         
975         if 'noinline' in opts:
976                 s = 'output-noinline'
977         elif format == 'latex':
978                 if 'eps' in opts:
979                         s = 'output-eps'
980                 else:
981                         s = 'output-tex'
982         else: # format == 'html' or format == 'texi':
983                 s = 'output-all'
984         newbody = newbody + get_output (s) % {'fn': basename }
985         return ('lilypond', newbody, opts, todo, basename)
986
987 def process_lilypond_blocks(chunks):#ugh rename
988         newchunks = []
989         # Count sections/chapters.
990         for c in chunks:
991                 if c[0] == 'lilypond':
992                         c = schedule_lilypond_block (c)
993                 elif c[0] == 'numcols':
994                         paperguru.m_num_cols = c[2]
995                 elif c[0] == 'multicols':
996                         paperguru.m_multicols = c[2]
997                 newchunks.append (c)
998         return newchunks
999
1000
1001
1002 def system (cmd):
1003         sys.stderr.write ("invoking `%s'\n" % cmd)
1004         st = os.system (cmd)
1005         if st:
1006                 error ('Error command exited with value %d\n' % st)
1007         return st
1008
1009 def quiet_system (cmd, name):
1010         if not verbose_p:
1011                 progress ( _("Running %s...") % name)
1012                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
1013
1014         return system (cmd)
1015
1016 def get_bbox (filename):
1017         system ('gs -sDEVICE=bbox -q  -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename))
1018
1019         box = open (filename + '.bbox').read()
1020         m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', box)
1021         gr = []
1022         if m:
1023                 gr = map (string.atoi, m.groups ())
1024         
1025         return gr
1026
1027 def make_pixmap (name):
1028         bbox = get_bbox (name + '.eps')
1029         margin = 0
1030         fo = open (name + '.trans.eps' , 'w')
1031         fo.write ('%d %d translate\n' % (-bbox[0]+margin, -bbox[1]+margin))
1032         fo.close ()
1033         
1034         res = 90
1035
1036         x = (2* margin + bbox[2] - bbox[0]) * res / 72.
1037         y = (2* margin + bbox[3] - bbox[1]) * res / 72.
1038
1039         cmd = r'''gs -g%dx%d -sDEVICE=pnggray  -dTextAlphaBits=4 -dGraphicsAlphaBits=4  -q -sOutputFile=- -r%d -dNOPAUSE %s %s -c quit  > %s'''
1040         
1041         cmd = cmd % (x, y, res, name + '.trans.eps', name + '.eps',name + '.png')
1042         status = 0
1043         try:
1044                 status = system (cmd)
1045         except:
1046                 status = -1
1047
1048         if status:
1049                 os.unlink (name + '.png')
1050                 error ("Removing output file")
1051
1052 def compile_all_files (chunks):
1053         global foutn
1054         eps = []
1055         tex = []
1056         png = []
1057
1058         for c in chunks:
1059                 if c[0] != 'lilypond':
1060                         continue
1061                 base  = c[4]
1062                 exts = c[3]
1063                 for e in exts:
1064                         if e == 'eps':
1065                                 eps.append (base)
1066                         elif e == 'tex':
1067                                 #ugh
1068                                 if base + '.ly' not in tex:
1069                                         tex.append (base + '.ly')
1070                         elif e == 'png' and g_do_pictures:
1071                                 png.append (base)
1072         d = os.getcwd()
1073         if g_outdir:
1074                 os.chdir(g_outdir)
1075         if tex:
1076                 # fixme: be sys-independent.
1077                 def incl_opt (x):
1078                         if g_outdir and x[0] != '/' :
1079                                 x = os.path.join (g_here_dir, x)
1080                         return ' -I %s' % x
1081
1082                 incs = map (incl_opt, include_path)
1083                 lilyopts = string.join (incs, ' ' )
1084                 if do_deps:
1085                         lilyopts = lilyopts + ' --dependencies '
1086                         if g_outdir:
1087                                 lilyopts = lilyopts + '--dep-prefix=' + g_outdir + '/'
1088                 texfiles = string.join (tex, ' ')
1089                 cmd = 'lilypond --header=texidoc %s %s %s' \
1090                       % (lilyopts, g_extra_opts, texfiles)
1091
1092                 system (cmd)
1093
1094                 #
1095                 # Ugh, fixing up dependencies for .tex generation
1096                 #
1097                 if do_deps:
1098                         depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep', x), tex)
1099                         for i in depfiles:
1100                                 f =open (i)
1101                                 text=f.read ()
1102                                 f.close ()
1103                                 text=re.sub ('\n([^:\n]*):', '\n' + foutn + ':', text)
1104                                 f = open (i, 'w')
1105                                 f.write (text)
1106                                 f.close ()
1107
1108         for e in eps:
1109                 cmd = r"echo $TEXMF; tex '\nonstopmode \input %s'" % e
1110                 quiet_system (cmd, 'TeX')
1111                 
1112                 cmd = r"dvips -E -o %s %s" % (e + '.eps', e)
1113                 quiet_system (cmd, 'dvips')
1114                 
1115         for g in png:
1116                 make_pixmap (g)
1117                 
1118         os.chdir (d)
1119
1120
1121 def update_file (body, name):
1122         '''
1123         write the body if it has changed
1124         '''
1125         same = 0
1126         try:
1127                 f = open (name)
1128                 fs = f.read (-1)
1129                 same = (fs == body)
1130         except:
1131                 pass
1132
1133         if not same:
1134                 f = open (name , 'w')
1135                 f.write (body)
1136                 f.close ()
1137         
1138         return not same
1139
1140
1141 def getopt_args (opts):
1142         "Construct arguments (LONG, SHORT) for getopt from  list of options."
1143         short = ''
1144         long = []
1145         for o in opts:
1146                 if o[1]:
1147                         short = short + o[1]
1148                         if o[0]:
1149                                 short = short + ':'
1150                 if o[2]:
1151                         l = o[2]
1152                         if o[0]:
1153                                 l = l + '='
1154                         long.append (l)
1155         return (short, long)
1156
1157 def option_help_str (o):
1158         "Transform one option description (4-tuple ) into neatly formatted string"
1159         sh = '  '       
1160         if o[1]:
1161                 sh = '-%s' % o[1]
1162
1163         sep = ' '
1164         if o[1] and o[2]:
1165                 sep = ','
1166                 
1167         long = ''
1168         if o[2]:
1169                 long= '--%s' % o[2]
1170
1171         arg = ''
1172         if o[0]:
1173                 if o[2]:
1174                         arg = '='
1175                 arg = arg + o[0]
1176         return '  ' + sh + sep + long + arg
1177
1178
1179 def options_help_str (opts):
1180         "Convert a list of options into a neatly formatted string"
1181         w = 0
1182         strs =[]
1183         helps = []
1184
1185         for o in opts:
1186                 s = option_help_str (o)
1187                 strs.append ((s, o[3]))
1188                 if len (s) > w:
1189                         w = len (s)
1190
1191         str = ''
1192         for s in strs:
1193                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
1194         return str
1195
1196 def help():
1197         sys.stdout.write('''Usage: lilypond-book [options] FILE\n
1198 Generate hybrid LaTeX input from Latex + lilypond
1199 Options:
1200 ''')
1201         sys.stdout.write (options_help_str (option_definitions))
1202         sys.stdout.write (r'''Warning all output is written in the CURRENT directory
1203
1204
1205
1206 Report bugs to bug-lilypond@gnu.org.
1207
1208 Written by Tom Cato Amundsen <tca@gnu.org> and
1209 Han-Wen Nienhuys <hanwen@cs.uu.nl>
1210 ''')
1211
1212         sys.exit (0)
1213
1214
1215 def write_deps (fn, target, chunks):
1216         global read_files
1217         sys.stderr.write('Writing `%s\'\n' % os.path.join(g_outdir, fn))
1218         f = open (os.path.join(g_outdir, fn), 'w')
1219         f.write ('%s%s: ' % (g_dep_prefix, target))
1220         for d in read_files:
1221                 f.write ('%s ' %  d)
1222         basenames=[]
1223         for c in chunks:
1224                 if c[0] == 'lilypond':
1225                         (type, body, opts, todo, basename) = c;
1226                         basenames.append (basename)
1227         for d in basenames:
1228                 if g_outdir:
1229                         d=g_outdir + '/' + d
1230                 if g_dep_prefix:
1231                         #if not os.isfile (d): # thinko?
1232                         if not re.search ('/', d):
1233                                 d = g_dep_prefix + d
1234                 f.write ('%s.tex ' %  d)
1235         f.write ('\n')
1236         #if len (basenames):
1237         #       for d in basenames:
1238         #               f.write ('%s.ly ' %  d)
1239         #       f.write (' : %s' % target)
1240         f.write ('\n')
1241         f.close ()
1242         read_files = []
1243
1244 def identify (stream):
1245         stream.write ('lilypond-book (GNU LilyPond) %s\n' % program_version)
1246
1247 def print_version ():
1248         identify (sys.stdout)
1249         sys.stdout.write (r'''Copyright 1998--1999
1250 Distributed under terms of the GNU General Public License. It comes with
1251 NO WARRANTY.
1252 ''')
1253
1254
1255 def check_texidoc (chunks):
1256         n = []
1257         for c in chunks:
1258                 if c[0] == 'lilypond':
1259                         (type, body, opts, todo, basename) = c;
1260                         pathbase = os.path.join (g_outdir, basename)
1261                         if os.path.isfile (pathbase + '.texidoc'):
1262                                 body = '\n@include %s.texidoc\n' % basename + body
1263                                 c = (type, body, opts, todo, basename)
1264                 n.append (c)
1265         return n
1266
1267
1268 ## what's this? Docme --hwn
1269 ##
1270 def fix_epswidth (chunks):
1271         newchunks = []
1272         for c in chunks:
1273                 if c[0] != 'lilypond' or 'eps' not in c[2]:
1274                         newchunks.append (c)
1275                         continue
1276
1277                 mag = 1.0
1278                 for o in c[2]:
1279                         m  = re.match ('magnification=([0-9.]+)', o)
1280                         if m:
1281                                 mag = string.atof (m.group (1))
1282
1283                 def replace_eps_dim (match, lmag = mag):
1284                         filename = match.group (1)
1285                         dims = bounding_box_dimensions (filename)
1286
1287                         return '%fpt' % (dims[0] *lmag)
1288         
1289                 body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
1290                 newchunks.append(('lilypond', body, c[2], c[3], c[4]))
1291                         
1292         return newchunks
1293
1294
1295 ##docme: why global?
1296 foutn=""
1297 def do_file(input_filename):
1298
1299         chunks = read_doc_file(input_filename)
1300         chunks = chop_chunks(chunks, 'lilypond', make_lilypond, 1)
1301         chunks = chop_chunks(chunks, 'lilypond-file', make_lilypond_file, 1)
1302         chunks = chop_chunks(chunks, 'lilypond-block', make_lilypond_block, 1)
1303         chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
1304         chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
1305         chunks = chop_chunks(chunks, 'numcols', do_columns)
1306         chunks = chop_chunks(chunks, 'multicols', do_multicols)
1307         #print "-" * 50
1308         #for c in chunks: print "c:", c;
1309         #sys.exit()
1310         scan_preamble(chunks)
1311         chunks = process_lilypond_blocks(chunks)
1312
1313         # Do It.
1314         if __main__.g_run_lilypond:
1315                 compile_all_files (chunks)
1316                 chunks = fix_epswidth (chunks)
1317
1318         if __main__.format == 'texi':
1319                 chunks = check_texidoc (chunks)
1320
1321         x = 0
1322         chunks = completize_preamble (chunks)
1323
1324
1325         global foutn
1326
1327         if outname:
1328                 my_outname = outname
1329         elif input_filename == '-' or input_filename == "/dev/stdin":
1330                 my_outname = '-'
1331         else:
1332                 my_outname = os.path.basename (os.path.splitext(input_filename)[0]) + '.' + format
1333         my_depname = my_outname + '.dep'                
1334         
1335         if my_outname == '-' or my_outname == '/dev/stdout':
1336                 fout = sys.stdout
1337                 foutn = "<stdout>"
1338                 __main__.do_deps = 0
1339         else:
1340                 foutn = os.path.join (g_outdir, my_outname)
1341                 sys.stderr.write ("Writing `%s'\n" % foutn)
1342                 fout = open (foutn, 'w')
1343         for c in chunks:
1344                 fout.write (c[1])
1345         fout.close ()
1346         # should chmod -w
1347
1348         if do_deps:
1349                 write_deps (my_depname, foutn, chunks)
1350
1351 outname = ''
1352 try:
1353         (sh, long) = getopt_args (__main__.option_definitions)
1354         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1355 except getopt.error, msg:
1356         sys.stderr.write("error: %s" % msg)
1357         sys.exit(1)
1358
1359 do_deps = 0
1360 for opt in options:     
1361         o = opt[0]
1362         a = opt[1]
1363
1364         if o == '--include' or o == '-I':
1365                 include_path.append (a)
1366         elif o == '--version' or o == '-v':
1367                 print_version ()
1368                 sys.exit  (0)
1369         elif o == '--verbose' or o == '-V':
1370                 __main__.verbose_p = 1
1371         elif o == '--format' or o == '-f':
1372                 __main__.format = a
1373         elif o == '--outname' or o == '-o':
1374                 if len(files) > 1:
1375                         #HACK
1376                         sys.stderr.write("Lilypond-book is confused by --outname on multiple files")
1377                         sys.exit(1)
1378                 outname = a
1379         elif o == '--help' or o == '-h':
1380                 help ()
1381         elif o == '--no-lily' or o == '-n':
1382                 __main__.g_run_lilypond = 0
1383         elif o == '--dependencies' or o == '-M':
1384                 do_deps = 1
1385         elif o == '--default-music-fontsize':
1386                 default_music_fontsize = string.atoi (a)
1387         elif o == '--default-lilypond-fontsize':
1388                 print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
1389                 default_music_fontsize = string.atoi (a)
1390         elif o == '--extra-options':
1391                 g_extra_opts = a
1392         elif o == '--force-music-fontsize':
1393                 g_force_music_fontsize = string.atoi(a)
1394         elif o == '--force-lilypond-fontsize':
1395                 print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
1396                 g_force_music_fontsize = string.atoi(a)
1397         elif o == '--dep-prefix':
1398                 g_dep_prefix = a
1399         elif o == '--no-pictures':
1400                 g_do_pictures = 0
1401         elif o == '--no-music':
1402                 g_do_music = 0
1403         elif o == '--read-lys':
1404                 g_read_lys = 1
1405         elif o == '--outdir':
1406                 g_outdir = a
1407
1408 identify (sys.stderr)
1409 if g_outdir:
1410         if os.path.isfile(g_outdir):
1411                 error ("outdir is a file: %s" % g_outdir)
1412         if not os.path.exists(g_outdir):
1413                 os.mkdir(g_outdir)
1414 setup_environment ()
1415 for input_filename in files:
1416         do_file(input_filename)
1417         
1418 #
1419 # Petr, ik zou willen dat ik iets zinvoller deed,
1420 # maar wat ik kan ik doen, het verandert toch niets?
1421 #   --hwn 20/aug/99