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