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