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