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