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