]> git.donarmstrong.com Git - lilypond.git/blob - scripts/mudela-book.py
release: 1.3.7
[lilypond.git] / scripts / mudela-book.py
1 #!@PYTHON@
2
3 import os
4 import string
5 import re
6 import getopt
7 import sys
8 import __main__
9
10
11 initfile = ''
12 program_version = '@TOPLEVEL_VERSION@'
13
14 cwd = os.getcwd ()
15 include_path = [cwd]
16 dep_prefix = ''
17
18 # TODO: Figure out clean set of options.
19
20 # BUG: does not handle \verb|\begin{verbatim}\end{verbatim}| correctly.
21 # Should make a joint RE for \verb and \begin, \end{verbatim}
22 #
23
24 default_music_fontsize = 16
25 default_text_fontsize = 12
26
27 # latex linewidths:
28 # indices are no. of columns, papersize,  fontsize
29 # Why can't this be calculated?
30 latex_linewidths = {
31  1: {'a4':{10: 345, 11: 360, 12: 390},
32          'a5':{10: 276, 11: 276, 12: 276},
33          'b5':{10: 345, 11: 356, 12: 356},
34          'letter':{10: 345, 11: 360, 12: 390},
35          'legal': {10: 345, 11: 360, 12: 390},
36          'executive':{10: 345, 11: 360, 12: 379}},
37  2: {'a4':{10: 167, 11: 175, 12: 190},
38          'a5':{10: 133, 11: 133, 12: 133},
39          'b5':{10: 167, 11: 173, 12: 173},
40          'letter':{10: 167, 11: 175, 12: 190},
41          'legal':{10: 167, 11: 175, 12: 190},
42          'executive':{10: 167, 11: 175, 12: 184}}}
43
44
45 options = [
46   ('DIM',  '', 'default-mudela-fontsize', 'default fontsize for music.  DIM is assumed to in points'),
47   ('EXT', 'f', 'format', 'set format.  EXT is one of texi and latex.'),
48   ('', 'h', 'help', 'print help'),
49   ('DIR', 'I', 'include', 'include path'),
50   ('', '', 'init', 'mudela-book initfile'),
51 #  ('DIM', '', 'force-mudela-fontsize', 'force fontsize for all inline mudela. DIM is assumed to in points'),
52   ('', '', 'force-verbatim', 'make all mudela verbatim'),
53   ('', 'M', 'dependencies', 'write dependencies'),
54   ('', 'n', 'no-lily', 'don\'t run lilypond'),
55   ('', '', 'no-pictures', "don\'t generate pictures"),
56   ('FILE', 'o', 'outname', 'prefix for filenames'),
57   ('', 'v', 'version', 'print version information' ),
58   ('PREF', '',  'dep-prefix', 'prepend PREF before each -M dependency')
59   ]
60
61 format = ''
62 run_lilypond = 1
63 use_hash = 1
64 no_match = 'a\ba'
65 do_pictures = 1
66
67 # format specific strings, ie. regex-es for input, and % strings for output
68 output_dict= {
69         'latex': {
70                 'output-mudela-fragment' : r"""\begin[eps,fragment%s]{mudela}
71   \context Staff <
72     \context Voice{
73       %s
74     }
75   >
76 \end{mudela}""", 
77                 'output-mudela':r"""\begin[%s]{mudela}
78 %s
79 \end{mudela}""",
80                 'output-verbatim': r"""\begin{verbatim}%s\end{verbatim}""",
81                 'output-default-post': r"""\def\postMudelaExample{}""",
82                 'output-default-pre': r"""\def\preMudelaExample{}""",
83                 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%s.eps}}{\includegraphics{%s.eps}}',
84                 'output-tex': '\\preMudelaExample \\input %s.tex \\postMudelaExample\n'
85                 },
86         'texi' : {'output-mudela': """@mudela[%s]
87 %s
88 @end mudela
89 """,
90                   'output-verbatim': r"""@example
91 %s
92 @end example
93 """,
94
95 # do some tweaking: @ is needed in some ps stuff.
96 # override EndLilyPondOutput, since @tex is done
97 # in a sandbox, you can't do \input lilyponddefs at the
98 # top of the document.
99                   'output-all': r"""@tex
100 \catcode`\@=12
101 \input lilyponddefs
102 \def\EndLilyPondOutput{}
103 \input %s.tex
104 \catcode`\@=0
105 @end tex
106 @html
107 <img src=%s.png>
108 @end html
109 """,
110                 }
111         }
112
113 def output_verbatim (body):
114         if __main__.format == 'texi':
115                 body = re.sub ('([@{}])', '@\\1', body)
116         return get_output ('output-verbatim') % body
117
118 re_dict = {
119         'latex': {'input': '\\\\mbinput{?([^}\t \n}]*)',
120                   'include': '\\\\mbinclude{([^}]+)}',
121                  
122                   'comma-sep' : ', *',
123                   'header': r"""\\documentclass(\[.*?\])?""",
124                   'preamble-end': '\\\\begin{document}',
125                   'verbatim': r"""(?s)\\begin{verbatim}(.*?)\\end{verbatim}""",
126                   'verb': r"""\\verb(.)(.*?)\1""",
127                   'mudela-file': '\\\\mudelafile(\[[^\\]]+\])?{([^}]+)}',
128                   'mudela' : '\\\\mudela(\[.*?\])?{(.*?)}',
129                   'mudela-block': r"""(?s)\\begin(\[.*?\])?{mudela}(.*?)\\end{mudela}""",
130                   'interesting-cs': '\\\\(chapter|section|twocolumn|onecolumn)',
131                   'def-post-re': r"""\\def\\postMudelaExample""",
132                   'def-pre-re': r"""\\def\\preMudelaExample""",           
133                   },
134         
135         'texi': {
136                  'input':  '@mbinclude[ \n\t]+([^\t \n]*)',# disabled
137                  'include': no_match,
138                  'header': no_match,
139                  'preamble-end': no_match,
140                  'verbatim': r"""(?s)@example(.*?)@end example$""",
141                  'verb': r"""@code{(.*?)}""",
142                  'mudela-file': '@mudelafile(\[[^\\]]+\])?{([^}]+)}',
143                  'mudela' : '@mudela(\[.*?\])?{(.*?)}',
144                  'mudela-block': r"""(?s)@mudela(\[.*?\])?(.*?)@end mudela""",
145                  'interesting-cs': r"""[\\@](chapter|section)""",
146                   'comma-sep' : ', *',           
147                  }
148         }
149
150
151 for r in re_dict.keys ():
152         olddict = re_dict[r]
153         newdict = {}
154         for k in olddict.keys ():
155                 newdict[k] = re.compile (olddict[k])
156         re_dict[r] = newdict
157
158         
159 def uniq (list):
160         list.sort ()
161         s = list
162         list = []
163         for x in s:
164                 if x not in list:
165                         list.append (x)
166         return list
167                 
168
169 def get_output (name):
170         return  output_dict[format][name]
171
172 def get_re (name):
173         return  re_dict[format][name]
174
175
176 def bounding_box_dimensions(fname):
177         try:
178                 fd = open(fname)
179         except IOError:
180                 error ("Error opening `%s'" % fname)
181         str = fd.read ()
182         s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
183         if s:
184                 return (int(s.group(3))-int(s.group(1)), 
185                         int(s.group(4))-int(s.group(2)))
186         else:
187                 return (0,0)
188
189
190
191 read_files = []
192 def find_file (name):
193         f = None
194         for a in include_path:
195                 try:
196                         nm = os.path.join (a, name)
197                         f = open (nm)
198                         __main__.read_files.append (nm)
199                         break
200                 except IOError:
201                         pass
202
203
204         if f:
205                 return f.read ()
206         else:
207                 error ("File not found `%s'\n" % name)
208                 return ''
209
210 def error (str):
211         sys.stderr.write (str + "\n  Exiting ... \n\n")
212         raise 'Exiting.'
213
214
215 def compose_full_body (body, opts):
216         "Construct the text of an input file: add stuff to BODY using OPTS as options."
217         paper = 'a4'
218         music_size = default_music_fontsize
219         latex_size = default_text_fontsize
220
221         cols = 1
222         for o in opts:
223                 m = re.search ('^(.*)paper$', o)
224                 if m:
225                         paper = m.group (1)
226                 
227
228                 m = re.match ('([0-9]+)pt', o)
229                 if m:
230                         music_size = string.atoi(m.group (1))
231
232                 m = re.match ('latexfontsize=([0-9]+)pt', o)
233                 if m:
234                         latex_size = string.atoi (m.group (1))
235
236
237
238         if 'twocolumn' in opts:
239                 cols = 2
240                 
241
242         # urg: breaks on \include of full score
243         # Use nofly option if you want to \include full score.
244         if 'nofly'  not in opts and not re.search ('\\\\score', body):
245                 opts.append ('fragment')
246
247         if 'fragment' in opts and 'nosingleline' not in opts:
248                 opts.append ('singleline')
249
250         if 'singleline' in opts:
251                 l = -1.0;
252         else:
253                 l = latex_linewidths[cols][paper][latex_size]
254
255
256         if 'relative' in opts:
257                 body = '\\relative c { %s }' % body
258
259         
260         if 'fragment' in opts:
261                 body = r"""\score { 
262   \notes { %s }
263   \paper { }  
264 }""" % body
265
266         opts = uniq (opts)
267         optstring = string.join (opts, ' ')
268         optstring = re.sub ('\n', ' ', optstring)
269         
270         body = r"""
271 %% Generated by mudela-book.py; options are %s
272 \include "paper%d.ly"
273 \paper  { linewidth = %f \pt; } 
274 """ % (optstring, music_size, l) + body
275
276         return body
277
278 def find_inclusion_chunks (regex, surround, str):
279         chunks = []
280         while str:
281                 m = regex.search (str)
282
283                 if m == None:
284                         chunks.append (('input', str))
285                         str = ''
286                         break
287
288                 chunks.append (('input', str[: m.start (0)]))
289                 chunks.append (('input', surround))
290                 chunks = chunks +  read_doc_file (m.group (1))
291
292                 chunks.append (('input', surround))
293
294                 str = str [m.end (0):]
295         return chunks
296
297 def find_include_chunks (str):
298         return find_inclusion_chunks (get_re ('include'), '\\newpage', str)
299
300 def find_input_chunks (str):
301         return find_inclusion_chunks (get_re ('input'), '', str)        
302
303 def read_doc_file (filename):
304         """Read the input file, substituting for \input, \include, \mudela{} and \mudelafile"""
305         str = ''
306         str = find_file(filename)
307
308         if __main__.format == '':
309                 latex =  re.search ('\\\\document', str[:200])
310                 texinfo =  re.search ('@node', str[:200])
311                 if (texinfo and latex) or not (texinfo or latex):
312                         error("error: can't determine format, please specify")
313                 if texinfo:
314                         __main__.format = 'texi'
315                 else:
316                         __main__.format = 'latex'
317                         
318         chunks = [('input', str)]
319
320         for func in (find_verbatim_chunks, find_verb_chunks, find_include_chunks, find_input_chunks):
321                 newchunks = []
322                 for c in chunks:
323                         if c[0] == 'input':
324                                 newchunks = newchunks + func (c[1])
325                         else:
326                                 newchunks.append (c)
327                 chunks = newchunks
328         
329         return chunks
330
331
332
333 def scan_preamble (str):
334         options = []
335         m = get_re ('header').search( str)
336
337         # should extract paper & fontsz.
338         if m and m.group (1):
339                 options = options + re.split (',[\n \t]*', m.group(1)[1:-1])
340
341         def verbose_fontsize ( x):
342                 # o ??
343                 #if o.match('[0-9]+pt'):
344                 if re.match('[0-9]+pt', x):
345                         return 'latexfontsize=' + x
346                 else:
347                         return x 
348                         
349         options = map (verbose_fontsize, options)
350
351         return options
352
353
354 def completize_preamble (str):
355         m = get_re ('preamble-end').search( str)
356         if not m:
357                 return str
358         
359         preamble = str [:m.start (0)]
360         str = str [m.start(0):]
361         
362         if not get_re('def-post-re').search (preamble):
363                 preamble = preamble + get_output('output-default-post')
364         if not get_re ('def-pre-re').search(  preamble):
365                 preamble = preamble + get_output ('output-default-pre')
366
367         # UGH ! BUG!
368         #if  re.search ('\\\\includegraphics', str) and not re.search ('usepackage{graphics}',str):
369
370         preamble = preamble + '\\usepackage{graphics}\n'
371
372         return preamble + str
373
374 def find_verbatim_chunks (str):
375         """Chop STR into a list of tagged chunks, ie. tuples of form
376         (TYPE_STR, CONTENT_STR), where TYPE_STR is one of 'input' and 'verbatim'
377
378         """
379
380         chunks = []
381         while str:
382                 m = get_re ('verbatim').search( str)
383                 if m == None:
384                         chunks.append( ('input', str))
385                         str = ''
386                 else:
387                         chunks.append (('input', str[:m.start (0)]))
388                         chunks.append (('verbatim', m.group (0)))
389                 
390                         str = str [m.end(0):]
391                 
392         return chunks
393
394 def find_verb_chunks (str):
395
396         chunks = []
397         while str:
398                 m = get_re ("verb").search(str)
399                 if  m == None:
400                         chunks.append (('input', str))
401                         str = ''
402                 else:
403                         chunks.append (('input', str[:m.start (0)]))
404                         chunks.append (('verbatim', m.group (0)))
405                         str = str [m.end(0):]
406
407         return chunks
408                         
409
410
411 def find_mudela_shorthand_chunks (str):
412         return [('input', find_mudela_shorthands(str))]
413         
414 def find_mudela_shorthands (b):
415         def mudela_short (match):
416                 "Find \mudela{}, and substitute appropriate \begin / \end blocks."
417                 opts = match.group (1)
418                 if opts:
419                         opts = ',' + opts[1:-1]
420                 else:
421                         opts = ''
422                 return get_output ('output-mudela-fragment')  % (opts, match.group (2))
423
424         def mudela_file (match):
425                 "Find \mudelafile, and substitute appropriate \begin / \end blocks."
426                 fn = match.group (2)
427                 str = find_file (fn)
428                 opts = match.group (1)
429                 if opts:
430                         opts = opts[1:-1]
431                         opts = re.split (',[ \n\t]*', opts)
432                 else:
433                         opts = []
434
435                 if re.search ('.fly$', fn):
436                         opts.append ('fly')
437                 elif re.search ('.sly$', fn):
438                         opts = opts + [ 'fly','fragment']
439                 elif re.search ('.ly$', fn):
440                         opts .append ('nofly')
441                         
442                 str_opts = string.join (opts, ',')
443
444                 str = ("%% copied from file `%s'\n" % fn) + str 
445                 return get_output ('output-mudela') % (str_opts, str)
446   
447         b = get_re('mudela-file').sub (mudela_file, b)
448         b = get_re('mudela').sub (mudela_short, b)
449         return b
450         
451 def find_mudela_chunks (str):
452         """Find mudela blocks, while watching for verbatim. Returns
453         (STR,MUDS) with  substituted for the blocks in STR,
454         and the blocks themselves MUDS"""
455   
456         chunks = []
457         while str:
458                 m = get_re ("mudela-block").search( str)
459                 if not m:
460                         chunks.append (('input', str))
461                         str = ''
462                         break
463
464                 chunks.append (('input', str[:m.start (0)]))
465                 
466                 opts = m.group (1)
467                 if opts:
468                         opts = opts[1:-1]
469                 else:
470                         opts = ''
471                 optlist = get_re('comma-sep').split (opts)
472                 
473                 body = m.group (2)
474                 chunks.append (('mudela', body, optlist))
475   
476                 str = str [m.end (0):]
477   
478         return chunks
479   
480   
481   
482 def advance_counters (counter, opts, str):
483         """Advance chap/sect counters,
484         revise OPTS. Return the new counter tuple"""
485         
486         (chapter, section, count) = counter
487         done = ''
488         while str:
489                 m = get_re ('interesting-cs').search(str)
490                 if not m:
491                         done = done + str
492                         str = ''
493                         break
494                 
495                 done = done + str[:m.end (0)]
496                 str = str[m.end(0):]
497                 g = m.group (1)
498
499                 if g == 'twocolumn':
500                         opts.append ('twocolumn')
501                 elif g  == 'onecolumn':
502                         try:
503                                 opts.remove ('twocolumn')
504                         except IndexError:
505                                 pass
506                 elif g == 'chapter':
507                         (chapter, section, count)  = (chapter + 1, 0, 0)
508                 elif g == 'section':
509                         (section, count)  = (section + 1, 0)
510                         
511
512         return (chapter, section, count)
513
514
515 def schedule_mudela_block (base, chunk, extra_opts):
516         """Take the body and options from CHUNK, figure out how the
517         real .ly should look, and what should be left MAIN_STR (meant
518         for the main file).  The .ly is written, and scheduled in
519         TODO.
520
521         Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
522
523         TODO has format [basename, extension, extension, ... ]
524         
525         """
526
527         (type, body, opts) = chunk
528         assert type == 'mudela'
529         opts = opts +  extra_opts
530         
531         newbody = ''
532         if 'verbatim' in opts:
533                 newbody = output_verbatim (body)
534
535         file_body = compose_full_body (body, opts)
536         basename = base
537         if __main__.use_hash:
538                 basename = `abs(hash (file_body))`
539         updated = update_file (file_body, basename + '.ly')
540         todo = [basename]                       # UGH.
541
542         if not os.path.isfile (basename + '.tex') or updated:
543                 todo.append ('tex')
544                 updated = 1
545
546         for o in opts:
547                 m = re.search ('intertext="(.*?)"', o)
548                 if m:
549                         newbody = newbody  + m.group (1)
550
551         if format == 'texi':
552                 opts.append ('png')
553
554         if 'png' in opts:
555                 opts.append ('eps')
556
557         if 'eps' in opts and ('tex' in todo or
558                               not os.path.isfile (basename + '.eps')):
559                 todo.append ('eps')
560
561         if 'png' in opts and ('eps' in todo or
562                               not os.path.isfile (basename + '.png')):
563                 todo.append ('png')
564
565         if format == 'latex':
566                 if 'eps' in opts :
567                         newbody = newbody + get_output ('output-eps') %  (basename, basename)
568                 else:
569                         newbody = newbody + get_output ('output-tex') % basename
570
571         elif format == 'texi':
572                 newbody = newbody + get_output ('output-all') % (basename, basename) 
573
574         return ('mudela', newbody, opts, todo, base)
575
576
577 def find_eps_dims (match):
578         "Fill in dimensions of EPS files."
579         
580         fn =match.group (1)
581         dims = bounding_box_dimensions (fn)
582
583         return '%ipt' % dims[0]
584
585
586 def print_chunks (ch):
587         for c in ch:
588                 print '-->%s\n%s' % (c[0], c[1])
589                 if len (c) > 2:
590                         print '==>%s' % list (c[2:])
591         print foo
592
593
594 def transform_input_file (in_filename, out_filename):
595         """Read the input, and deliver a list of chunks
596         ready for writing.
597
598         """
599
600         chunks = read_doc_file (in_filename)
601
602         #.  Process \mudela and \mudelafile.
603         for func in [find_mudela_shorthand_chunks,
604                      find_mudela_chunks]:
605                 newchunks = []
606                 for c in chunks:
607                         if c[0] == 'input':
608                                 newchunks = newchunks + func (c[1])
609                         else:
610                                 newchunks.append (c)
611                 chunks = newchunks
612
613         opts = []
614         if chunks:
615                 opts = scan_preamble (chunks[0][1]) 
616         
617         (chap,sect,count) = (0,0,0)
618         newchunks = []
619         # Count sections/chapters.
620         for c in chunks:
621                 if c[0] == 'input':
622                         (chap,sect,count) = advance_counters((chap,sect,count), opts, c[1])
623                 elif c[0] == 'mudela':
624                         base = '%s-%d.%d.%d' % (out_filename, chap, sect, count)
625                         count = count + 1
626                         c = schedule_mudela_block (base, c, opts)
627                         
628                 newchunks.append (c)
629
630         chunks = newchunks
631         newchunks = []
632
633         # Do It.
634         if __main__.run_lilypond:
635                 compile_all_files (chunks)
636                 
637                 # finishing touch.
638                 for c in chunks:
639                         if c[0] == 'mudela' and 'eps' in c[2]:
640                                 body = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, c[1])
641                                 newchunks.append (('mudela', body))
642                         else:
643                                 newchunks.append (c)
644                 chunks = newchunks
645                 
646         if chunks and chunks[0][0] == 'input':
647                 chunks[0] = ('input', completize_preamble (chunks[0][1]))
648
649         return chunks
650
651 def system (cmd):
652         sys.stderr.write ("invoking `%s'\n" % cmd)
653         st = os.system (cmd)
654         if st:
655                 error ('Error command exited with value %d\n' % st)
656         return st
657
658 def compile_all_files (chunks):
659         eps = []
660         tex = []
661         png = []
662         hash_dict = {}
663
664         for c in chunks:
665                 if c[0] <> 'mudela':
666                         continue
667                 base  = c[3][0]
668                 exts = c[3][1:]
669                 for e in exts:
670                         if e == 'eps':
671                                 eps.append (base)
672                         elif e == 'tex':
673                                 tex.append (base + '.ly')
674                         elif e == 'png' and do_pictures:
675                                 png.append (base)
676
677                 if __main__.use_hash:
678                         hash_dict[c[4]] = c[3][0]
679
680         if tex:
681                 lilyopts = map (lambda x:  '-I ' + x, include_path)
682                 lilyopts = string.join (lilyopts, ' ' )
683                 texfiles = string.join (tex, ' ')
684                 system ('lilypond %s %s' % (lilyopts, texfiles))
685
686         for e in eps:
687                 cmd = r"""tex '\nonstopmode \input %s'; dvips -E -o %s %s""" % \
688                       (e, e + '.eps', e)
689                 system (cmd)
690
691         for g in png:
692                 cmd = r"""gs -sDEVICE=pgm  -dTextAlphaBits=4 -dGraphicsAlphaBits=4  -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
693
694                 cmd = cmd % (g + '.eps', g + '.png')
695                 system (cmd)
696
697         if __main__.use_hash:
698                 name = ''
699                 last_name = ''
700                 f = 0
701                 ks = hash_dict.keys ()
702                 ks.sort ()
703                 for i in ks:
704                         name = re.sub ("(.*)-[0-9]+\.[0-9]+\.[0-9]+", "\\1", i)
705                         name = name + '.mix'
706                         if name != last_name:
707                                 if last_name:
708                                         f.close ()
709                                 f = open (name, 'w')
710                                 last_name = name
711                         f.write ("%s:%s\n" % (i, hash_dict[i]))
712
713         
714 def update_file (body, name):
715         same = 0
716         try:
717                 f = open (name)
718                 fs = f.read (-1)
719                 same = (fs == body)
720         except:
721                 pass
722
723         if not same:
724                 f = open (name , 'w')
725                 f.write (body)
726                 f.close ()
727
728         
729         return not same
730
731
732
733 def getopt_args (opts):
734         "Construct arguments (LONG, SHORT) for getopt from  list of options."
735         short = ''
736         long = []
737         for o in opts:
738                 if o[1]:
739                         short = short + o[1]
740                         if o[0]:
741                                 short = short + ':'
742                 if o[2]:
743                         l = o[2]
744                         if o[0]:
745                                 l = l + '='
746                         long.append (l)
747         return (short, long)
748
749 def option_help_str (o):
750         "Transform one option description (4-tuple ) into neatly formatted string"
751         sh = '  '       
752         if o[1]:
753                 sh = '-%s' % o[1]
754
755         sep = ' '
756         if o[1] and o[2]:
757                 sep = ','
758                 
759         long = ''
760         if o[2]:
761                 long= '--%s' % o[2]
762
763         arg = ''
764         if o[0]:
765                 if o[2]:
766                         arg = '='
767                 arg = arg + o[0]
768         return '  ' + sh + sep + long + arg
769
770
771 def options_help_str (opts):
772         "Convert a list of options into a neatly formatted string"
773         w = 0
774         strs =[]
775         helps = []
776         for o in opts:
777                 s = option_help_str (o)
778                 strs.append ((s, o[3]))
779                 if len (s) > w:
780                         w = len (s)
781
782         str = ''
783         for s in strs:
784                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
785         return str
786
787 def help():
788         sys.stdout.write("""Usage: mudela-book [options] FILE\n
789 Generate hybrid LaTeX input from Latex + mudela
790 Options:
791 """)
792         sys.stdout.write (options_help_str (options))
793         sys.stdout.write (r"""Warning all output is written in the CURRENT directory
794
795
796
797 Report bugs to bug-gnu-music@gnu.org.
798
799 Written by Tom Cato Amundsen <tomcato@xoommail.com> and
800 Han-Wen Nienhuys <hanwen@cs.uu.nl>
801 """)
802
803         sys.exit (0)
804
805
806 def write_deps (fn, target):
807         sys.stdout.write('writing `%s\'\n' % fn)
808
809         f = open (fn, 'w')
810         
811         f.write ('%s%s: ' % (dep_prefix, target))
812         for d in __main__.read_files:
813                 f.write ('%s ' %  d)
814         f.write ('\n')
815         f.close ()
816         __main__.read_files = []
817
818 def identify():
819         sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
820
821 def print_version ():
822         identify()
823         sys.stdout.write (r"""Copyright 1998--1999
824 Distributed under terms of the GNU General Public License. It comes with
825 NO WARRANTY.
826 """)
827
828
829 outname = ''
830 try:
831         (sh, long) = getopt_args (__main__.options)
832         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
833 except getopt.error, msg:
834         sys.stderr.write("error: %s" % msg)
835         sys.exit(1)
836
837 do_deps = 0
838 for opt in options:     
839         o = opt[0]
840         a = opt[1]
841
842         if o == '--include' or o == '-I':
843                 include_path.append (a)
844         elif o == '--version':
845                 print_version ()
846                 sys.exit  (0)
847
848         elif o == '--format' or o == '-o':
849                 __main__.format = a
850         elif o == '--outname' or o == '-o':
851                 if len(files) > 1:
852                         #HACK
853                         sys.stderr.write("Mudela-book is confused by --outname on multiple files")
854                         sys.exit(1)
855                 outname = a
856         elif o == '--help' or o == '-h':
857                 help ()
858         elif o == '--no-lily' or o == '-n':
859                 __main__.run_lilypond = 0
860         elif o == '--dependencies':
861                 do_deps = 1
862         elif o == '--default-mudela-fontsize':
863                 default_music_fontsize = string.atoi (a)
864         elif o == '--init':
865                 initfile =  a
866         elif o == '--dep-prefix':
867                 dep_prefix = a
868         elif o == '--no-pictures':
869                 do_pictures = 0
870
871 identify()
872
873 for input_filename in files:
874         file_settings = {}
875         if outname:
876                 my_outname = outname
877         else:
878                 my_outname = os.path.basename(os.path.splitext(input_filename)[0])
879         my_depname = my_outname + '.dep'                
880
881         chunks = transform_input_file (input_filename, my_outname)
882
883         foutn = my_outname + '.' + format
884         sys.stderr.write ("Writing `%s'\n" % foutn)
885         fout = open (foutn, 'w')
886         for c in chunks:
887                 fout.write (c[1])
888         fout.close ()
889
890         if do_deps:
891                 write_deps (my_depname, foutn)
892
893
894
895 #
896 # Petr, ik zou willen dat ik iets zinvoller deed,
897 # maar wat ik kan ik doen, het verandert toch niets?
898 #   --hwn 20/aug/99