2 # vim: set noexpandtab:
4 # * junk --outdir for --output
5 # * Figure out clean set of options.
7 # * EndLilyPondOutput is def'd as vfil. Causes large white gaps.
8 # * texinfo: add support for @pagesize
10 # todo: dimension handling (all the x2y) is clumsy. (tca: Thats
11 # because the values are taken directly from texinfo.tex,
12 # geometry.sty and article.cls. Give me a hint, and I'll
16 # TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
19 # This is was the idea for handling of comments:
20 # Multiline comments, @ignore .. @end ignore is scanned for
21 # in read_doc_file, and the chunks are marked as 'ignore', so
22 # lilypond-book will not touch them any more. The content of the
23 # chunks are written to the output file. Also 'include' and 'input'
24 # regex has to check if they are commented out.
26 # Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
27 # These three regex's has to check if they are on a commented line,
28 # % for latex, @c for texinfo.
30 # Then lines that are commented out with % (latex) and @c (Texinfo)
31 # are put into chunks marked 'ignore'. This cannot be done before
32 # searching for the lilypond-blocks because % is also the comment character
35 # The the rest of the rexeces are searched for. They don't have to test
36 # if they are on a commented out line.
47 # Handle bug in Python 1.6-2.1
49 # there are recursion limits for some patterns in Python 1.6 til 2.1.
50 # fix this by importing the 1.5.2 implementation pre instead. Fix by Mats.
52 if float (sys.version[0:3]) < 2.2:
62 # Attempt to fix problems with limited stack size set by Python!
63 # Sets unlimited stack size. Note that the resource module only
64 # is available on UNIX.
67 resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
71 errorport = sys.stderr
78 gettext.bindtextdomain ('lilypond', localedir)
79 gettext.textdomain ('lilypond')
86 errorport.write (s + '\n')
89 program_version = '@TOPLEVEL_VERSION@'
90 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
91 program_version = '1.5.53'
93 # if set, LILYPONDPREFIX must take prevalence
94 # if datadir is not set, we're doing a build and LILYPONDPREFIX
95 datadir = '@local_lilypond_datadir@'
97 if os.environ.has_key ('LILYPONDPREFIX') :
98 datadir = os.environ['LILYPONDPREFIX']
100 datadir = '@local_lilypond_datadir@'
102 while datadir[-1] == os.sep:
103 datadir= datadir[:-1]
105 kpse = os.popen ('kpsexpand \$TEXMF').read()
106 kpse = re.sub('[ \t\n]+$','', kpse)
107 type1_paths = os.popen ('kpsewhich -expand-path=\$T1FONTS').read ()
110 # TODO: * prevent multiple addition.
111 # * clean TEXINPUTS, MFINPUTS, TFMFONTS,
112 # as these take prevalence over $TEXMF
113 # and thus may break tex run?
114 'TEXMF' : "{%s,%s}" % (datadir, kpse) ,
115 'GS_FONTPATH' : type1_paths,
116 'GS_LIB' : datadir + '/ps',
119 # tex needs lots of memory, more than it gets by default on Debian
120 non_path_environment = {
121 'extra_mem_top' : '1000000',
122 'extra_mem_bottom' : '1000000',
123 'pool_size' : '250000',
126 def setup_environment ():
127 # $TEXMF is special, previous value is already taken care of
128 if os.environ.has_key ('TEXMF'):
129 del os.environ['TEXMF']
131 for key in environment.keys ():
132 val = environment[key]
133 if os.environ.has_key (key):
134 val = val + os.pathsep + os.environ[key]
135 os.environ[key] = val
137 for key in non_path_environment.keys ():
138 val = non_path_environment[key]
139 os.environ[key] = val
141 include_path = [os.getcwd()]
144 # g_ is for global (?)
146 g_here_dir = os.getcwd ()
149 g_force_music_fontsize = 0
158 default_music_fontsize = 16
159 default_text_fontsize = 12
164 self.m_document_preamble = []
167 def find_latex_dims(self):
169 fname = os.path.join(g_outdir, "lily-tmp.tex")
171 fname = "lily-tmp.tex"
175 error ("Error creating temporary file '%s'" % fname)
176 for s in self.m_document_preamble:
181 \typeout{\columnsep \the\columnsep}
182 \typeout{\textwidth \the\textwidth}
187 re_dim = re.compile(r"\\(\w+)\s+(\d+\.\d+)")
188 p = os.popen("latex %s" % fname)
191 ln = string.strip(ln)
194 if m.groups()[0] in ('textwidth', 'columnsep'):
195 self.__dict__['m_%s' % m.groups()[0]] = float(m.groups()[1])
199 os.remove (os.path.splitext(fname)[0]+".aux")
200 os.remove (os.path.splitext(fname)[0]+".log")
203 def get_linewidth(self):
204 if self.m_num_cols == 1:
207 w = (self.m_textwidth - self.m_columnsep)/2
208 if self.m_multicols > 1:
209 return (w - self.m_columnsep*(self.m_multicols-1)) \
216 self.m_papersize = 'letterpaper'
218 def get_linewidth(self):
219 return html_linewidths[self.m_papersize][self.m_fontsize]
223 self.m_papersize = 'letterpaper'
225 def get_linewidth(self):
226 return texi_linewidths[self.m_papersize][self.m_fontsize]
232 def em2pt(x, fontsize = 10):
233 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
234 def ex2pt(x, fontsize = 10):
235 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
240 dimension_conversion_dict ={
242 'cm': lambda x: mm2pt(10*x),
249 # Convert numeric values, with or without specific dimension, to floats.
251 def conv_dimen_to_float(value):
252 if type(value) == type(""):
253 m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
256 num = string.atof(m.group (1))
257 conv = dimension_conversion_dict[m.group(2)]
261 elif re.match ("^[0-9.]+$",value):
267 'afourpaper': {12: mm2pt(160)},
268 'afourwide': {12: in2pt(6.5)},
269 'afourlatex': {12: mm2pt(150)},
270 'smallbook': {12: in2pt(5)},
271 'letterpaper': {12: in2pt(6)}}
274 'afourpaper': {12: mm2pt(160)},
275 'afourwide': {12: in2pt(6.5)},
276 'afourlatex': {12: mm2pt(150)},
277 'smallbook': {12: in2pt(5)},
278 'letterpaper': {12: in2pt(6)}}
280 option_definitions = [
281 ('EXT', 'f', 'format', 'use output format EXT (texi [default], latex, html)'),
282 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
283 ('DIM', '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
284 ('OPT', '', 'extra-options' , 'Pass OPT quoted to the lilypond command line'),
285 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
286 ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
287 ('', 'h', 'help', 'this help'),
288 ('DIR', 'I', 'include', 'include path'),
289 ('', 'M', 'dependencies', 'write dependencies'),
290 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
291 ('', 'n', 'no-lily', 'don\'t run lilypond'),
292 ('', '', 'no-pictures', "don\'t generate pictures"),
293 ('', '', 'no-music', "strip all lilypond blocks from output"),
294 ('', '', 'read-lys', "don't write ly files."),
295 ('FILE', 'o', 'outname', 'filename main output file'),
296 ('FILE', '', 'outdir', "where to place generated files"),
297 ('', 'V', 'verbose', 'verbose' ),
298 ('', 'v', 'version', 'print version information' ),
301 # format specific strings, ie. regex-es for input, and % strings for output
303 'html' : {'output-lilypond': '''<lilypond%s>
306 'output-filename' : r'''
309 <pre>%s</pre></a>:''',
310 'output-lilypond-fragment': '''<lilypond%s>
311 \context Staff\context Voice{ %s }
313 'output-noinline': r'''
314 <!-- generated: %(fn)s.png !-->
318 'output-verbatim': r'''<pre>
321 'output-small-verbatim': r'''<font size=-1><pre>
325 ## Ugh we need to differentiate on origin:
326 ## lilypond-block origin wants an extra <p>, but
327 ## inline music doesn't.
328 ## possibly other center options?
330 <a href="%(fn)s.png">
331 <img align="center" valign="center" border="0" src="%(fn)s.png" alt="[picture of music]"></a>
335 'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
342 'output-filename' : r'''
347 'output-lilypond': r'''\begin[%s]{lilypond}
351 'output-verbatim': r'''\begin{verbatim}%s\end{verbatim}%%
353 'output-small-verbatim': r'''{\small\begin{verbatim}%s\end{verbatim}}%%''',
354 'output-default-post': "\\def\postLilypondExample{}\n",
355 'output-default-pre': "\\def\preLilypondExample{}\n",
356 'usepackage-graphics': '\\usepackage{graphics}\n',
357 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s}}',
358 'output-noinline': r'''
359 %% generated: %(fn)s.eps
361 'output-tex': '{\\preLilypondExample \\input %(fn)s.tex \\postLilypondExample\n}',
362 'pagebreak': r'\pagebreak',
365 'texi' : {'output-lilypond': '''@lilypond[%s]
369 'output-filename' : r'''
377 'output-lilypond-fragment': '''@lilypond[%s]
378 \context Staff\context Voice{ %s }
380 'output-noinline': r'''
381 @c generated: %(fn)s.png
384 'output-small-verbatim': r'''@smallexample
388 'output-verbatim': r'''@example
393 # do some tweaking: @ is needed in some ps stuff.
394 # override EndLilyPondOutput, since @tex is done
395 # in a sandbox, you can't do \input lilyponddefs at the
396 # top of the document.
398 # should also support fragment in
400 # ugh, the <p> below breaks inline images...
406 \def\EndLilyPondOutput{}
412 <a href="%(fn)s.png">
413 <img border=0 src="%(fn)s.png" alt="[picture of music]">
421 def output_verbatim (body, small):
422 if __main__.format == 'html':
423 body = re.sub ('&', '&', body)
424 body = re.sub ('>', '>', body)
425 body = re.sub ('<', '<', body)
426 elif __main__.format == 'texi':
427 body = re.sub ('([@{}])', '@\\1', body)
430 key = 'output-small-verbatim'
432 key = 'output-verbatim'
433 return get_output (key) % body
436 #warning: this uses extended regular expressions. Tread with care.
440 # (?P -- name parameter
441 # *? -- match non-greedily.
448 'preamble-end': no_match,
449 'landscape': no_match,
450 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
451 'verb': r'''(?P<code><pre>.*?</pre>)''',
452 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
453 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
454 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
455 'option-sep' : '\s*',
456 'intertext': r',?\s*intertext=\".*?\"',
457 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
458 'singleline-comment': no_match,
460 'multicols': no_match,
463 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
464 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
465 'option-sep' : ',\s*',
466 'header': r"\n*\\documentclass\s*(\[.*?\])?",
467 'preamble-end': r'(?P<code>\\begin{document})',
468 'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
469 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
470 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
471 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
472 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
473 'def-post-re': r"\\def\\postLilypondExample",
474 'def-pre-re': r"\\def\\preLilypondExample",
475 'usepackage-graphics': r"\usepackage{graphics}",
476 'intertext': r',?\s*intertext=\".*?\"',
477 'multiline-comment': no_match,
478 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
479 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
480 'multicols': r"(?P<code>\\(?P<be>begin|end){multicols}({(?P<num>\d+)?})?)",
484 # why do we have distinction between @mbinclude and @include?
488 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
491 'preamble-end': no_match,
492 'landscape': no_match,
493 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
494 'verb': r'''(?P<code>@code{.*?})''',
495 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
496 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
497 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end +lilypond)\s''',
498 'option-sep' : ',\s*',
499 'intertext': r',?\s*intertext=\".*?\"',
500 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
501 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
503 'multicols': no_match,
508 for r in re_dict.keys ():
511 for k in olddict.keys ():
513 newdict[k] = re.compile (olddict[k])
515 print 'invalid regexp: %s' % olddict[k]
517 # we'd like to catch and reraise a more detailed error, but
518 # alas, the exceptions changed across the 1.5/2.1 boundary.
533 def get_output (name):
534 return output_dict[format][name]
537 return re_dict[format][name]
539 def bounding_box_dimensions(fname):
541 fname = os.path.join(g_outdir, fname)
545 error ("Error opening `%s'" % fname)
547 s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
550 gs = map (lambda x: string.atoi (x), s.groups ())
551 return (int (gs[2] - gs[0] + 0.5),
552 int (gs[3] - gs[1] + 0.5))
557 sys.stderr.write (str + "\n Exiting ... \n\n")
561 def compose_full_body (body, opts):
562 '''Construct the lilypond code to send to Lilypond.
563 Add stuff to BODY using OPTS as options.'''
564 music_size = default_music_fontsize
565 if g_force_music_fontsize:
566 music_size = g_force_music_fontsize
570 if not g_force_music_fontsize:
571 m = re.match ('([0-9]+)pt', o)
573 music_size = string.atoi(m.group (1))
575 m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
577 f = float (m.group (1))
578 indent = 'indent = %f\\%s' % (f, m.group (2))
580 m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
582 f = float (m.group (1))
583 linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
585 if re.search ('\\\\score', body):
589 if 'fragment' in opts:
591 if 'nofragment' in opts:
594 if is_fragment and not 'multiline' in opts:
595 opts.append('singleline')
597 if 'singleline' in opts:
598 linewidth = 'linewidth = -1.0'
600 l = __main__.paperguru.get_linewidth ()
601 linewidth = 'linewidth = %f\pt' % l
603 if 'noindent' in opts:
604 indent = 'indent = 0.0\mm'
607 m= re.search ('relative(.*)', o)
611 v = string.atoi (m.group (1))
618 pitch = pitch + '\,' * v
620 pitch = pitch + '\'' * v
622 body = '\\relative %s { %s }' %(pitch, body)
631 optstring = string.join (opts, ' ')
632 optstring = re.sub ('\n', ' ', optstring)
634 %% Generated automatically by: lilypond-book.py
636 \include "paper%d.ly"
641 ''' % (optstring, music_size, linewidth, indent) + body
643 # ughUGH not original options
646 def scan_html_preamble (chunks):
649 def scan_latex_preamble(chunks):
650 # First we want to scan the \documentclass line
651 # it should be the first non-comment line.
652 # The only thing we really need to know about the \documentclass line
653 # is if there are one or two columns to begin with.
656 if chunks[idx][0] == 'ignore':
659 m = get_re ('header').match(chunks[idx][1])
661 error ("Latex documents must start with a \documentclass command")
663 options = re.split (',[\n \t]*', m.group(1)[1:-1])
666 if 'twocolumn' in options:
667 paperguru.m_num_cols = 2
670 # Then we add everythin before \begin{document} to
671 # paperguru.m_document_preamble so that we can later write this header
672 # to a temporary file in find_latex_dims() to find textwidth.
673 while idx < len(chunks) and chunks[idx][0] != 'preamble-end':
674 if chunks[idx] == 'ignore':
677 paperguru.m_document_preamble.append(chunks[idx][1])
679 paperguru.find_latex_dims()
681 def scan_texi_preamble (chunks):
682 # this is not bulletproof..., it checks the first 10 chunks
683 for c in chunks[:10]:
685 for s in ('afourpaper', 'afourwide', 'letterpaper',
686 'afourlatex', 'smallbook'):
687 if string.find(c[1], "@%s" % s) != -1:
688 paperguru.m_papersize = s
691 def scan_preamble (chunks):
692 if __main__.format == 'html':
693 scan_html_preamble (chunks)
694 elif __main__.format == 'latex':
695 scan_latex_preamble (chunks)
696 elif __main__.format == 'texi':
697 scan_texi_preamble (chunks)
700 def completize_preamble (chunks):
701 if __main__.format != 'latex':
703 pre_b = post_b = graphics_b = None
705 if chunk[0] == 'preamble-end':
707 if chunk[0] == 'input':
708 m = get_re('def-pre-re').search(chunk[1])
711 if chunk[0] == 'input':
712 m = get_re('def-post-re').search(chunk[1])
716 if chunk[0] == 'input':
717 m = get_re('usepackage-graphics').search(chunk[1])
721 while x < len (chunks) and chunks[x][0] != 'preamble-end':
728 chunks.insert(x, ('input', get_output ('output-default-pre')))
730 chunks.insert(x, ('input', get_output ('output-default-post')))
732 chunks.insert(x, ('input', get_output ('usepackage-graphics')))
738 def find_file (name):
740 Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
744 return (sys.stdin.read (), '<stdin>')
747 for a in include_path:
749 nm = os.path.join (a, name)
751 __main__.read_files.append (nm)
756 sys.stderr.write ("Reading `%s'\n" % nm)
757 return (f.read (), nm)
759 error ("File not found `%s'\n" % name)
762 def do_ignore(match_object):
763 return [('ignore', match_object.group('code'))]
764 def do_preamble_end(match_object):
765 return [('preamble-end', match_object.group('code'))]
767 def make_verbatim(match_object):
768 return [('verbatim', match_object.group('code'))]
770 def make_verb(match_object):
771 return [('verb', match_object.group('code'))]
773 def do_include_file(m):
775 return [('input', get_output ('pagebreak'))] \
776 + read_doc_file(m.group('filename')) \
777 + [('input', get_output ('pagebreak'))]
779 def do_input_file(m):
780 return read_doc_file(m.group('filename'))
782 def make_lilypond(m):
783 if m.group('options'):
784 options = m.group('options')
787 return [('input', get_output('output-lilypond-fragment') %
788 (options, m.group('code')))]
790 def make_lilypond_file(m):
793 Find @lilypondfile{bla.ly} occurences and substitute bla.ly
794 into a @lilypond .. @end lilypond block.
798 if m.group('options'):
799 options = m.group('options')
802 (content, nm) = find_file(m.group('filename'))
803 options = "filename=%s," % nm + options
805 return [('input', get_output('output-lilypond') %
808 def make_lilypond_block(m):
812 if m.group('options'):
813 options = get_re('option-sep').split (m.group('options'))
816 options = filter(lambda s: s != '', options)
817 return [('lilypond', m.group('code'), options)]
820 if __main__.format != 'latex':
822 if m.group('num') == 'one':
823 return [('numcols', m.group('code'), 1)]
824 if m.group('num') == 'two':
825 return [('numcols', m.group('code'), 2)]
828 if __main__.format != 'latex':
830 if m.group('be') == 'begin':
831 return [('multicols', m.group('code'), int(m.group('num')))]
833 return [('multicols', m.group('code'), 1)]
836 def chop_chunks(chunks, re_name, func, use_match=0):
842 m = get_re (re_name).search (str)
844 newchunks.append (('input', str))
848 newchunks.append (('input', str[:m.start ('match')]))
850 newchunks.append (('input', str[:m.start (0)]))
851 #newchunks.extend(func(m))
852 # python 1.5 compatible:
853 newchunks = newchunks + func(m)
854 str = str [m.end(0):]
859 def determine_format (str):
860 if __main__.format == '':
862 html = re.search ('(?i)<[dh]tml', str[:200])
863 latex = re.search (r'''\\document''', str[:200])
864 texi = re.search ('@node|@setfilename', str[:200])
869 if html and not latex and not texi:
871 elif latex and not html and not texi:
873 elif texi and not html and not latex:
876 error ("can't determine format, please specify")
879 if __main__.paperguru == None:
880 if __main__.format == 'html':
882 elif __main__.format == 'latex':
884 elif __main__.format == 'texi':
887 __main__.paperguru = g
890 def read_doc_file (filename):
891 '''Read the input file, find verbatim chunks and do \input and \include
893 (str, path) = find_file(filename)
894 determine_format (str)
896 chunks = [('input', str)]
898 # we have to check for verbatim before doing include,
899 # because we don't want to include files that are mentioned
900 # inside a verbatim environment
901 chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
902 chunks = chop_chunks(chunks, 'verb', make_verb)
903 chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
905 chunks = chop_chunks(chunks, 'include', do_include_file, 1)
906 chunks = chop_chunks(chunks, 'input', do_input_file, 1)
910 taken_file_names = {}
911 def schedule_lilypond_block (chunk):
912 '''Take the body and options from CHUNK, figure out how the
913 real .ly should look, and what should be left MAIN_STR (meant
914 for the main file). The .ly is written, and scheduled in
917 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
919 TODO has format [basename, extension, extension, ... ]
922 (type, body, opts) = chunk
923 assert type == 'lilypond'
924 file_body = compose_full_body (body, opts)
925 ## Hmm, we should hash only lilypond source, and skip the
928 basename = 'lily-' + `abs(hash (file_body))`
930 m = re.search ('filename="(.*?)"', o)
932 basename = m.group (1)
933 if not taken_file_names.has_key(basename):
934 taken_file_names[basename] = 0
936 taken_file_names[basename] = taken_file_names[basename] + 1
937 basename = basename + "-%i" % taken_file_names[basename]
939 update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
940 needed_filetypes = ['tex']
942 if format == 'html' or format == 'texi':
943 needed_filetypes.append ('eps')
944 needed_filetypes.append ('png')
945 if 'eps' in opts and not ('eps' in needed_filetypes):
946 needed_filetypes.append('eps')
947 pathbase = os.path.join (g_outdir, basename)
948 def f (base, ext1, ext2):
949 a = os.path.isfile(base + ext2)
950 if (os.path.isfile(base + ext1) and
951 os.path.isfile(base + ext2) and
952 os.stat(base+ext1)[stat.ST_MTIME] >
953 os.stat(base+ext2)[stat.ST_MTIME]) or \
954 not os.path.isfile(base + ext2):
957 if 'tex' in needed_filetypes and f(pathbase, '.ly', '.tex'):
959 if 'eps' in needed_filetypes and f(pathbase, '.tex', '.eps'):
961 if 'png' in needed_filetypes and f(pathbase, '.eps', '.png'):
965 if 'printfilename' in opts:
967 m= re.match ("filename=(.*)", o)
969 newbody = newbody + get_output ("output-filename") % (m.group(1), basename + '.ly', m.group(1))
973 if 'smallverbatim' in opts:
974 newbody = newbody + output_verbatim (body, 1)
975 elif 'verbatim' in opts:
976 newbody = newbody + output_verbatim (body, 0)
979 m = re.search ('intertext="(.*?)"', o)
981 newbody = newbody + m.group (1) + "\n\n"
983 if 'noinline' in opts:
984 s = 'output-noinline'
985 elif format == 'latex':
990 else: # format == 'html' or format == 'texi':
992 newbody = newbody + get_output (s) % {'fn': basename }
993 return ('lilypond', newbody, opts, todo, basename)
995 def process_lilypond_blocks(chunks):#ugh rename
997 # Count sections/chapters.
999 if c[0] == 'lilypond':
1000 c = schedule_lilypond_block (c)
1001 elif c[0] == 'numcols':
1002 paperguru.m_num_cols = c[2]
1003 elif c[0] == 'multicols':
1004 paperguru.m_multicols = c[2]
1005 newchunks.append (c)
1011 sys.stderr.write ("invoking `%s'\n" % cmd)
1012 st = os.system (cmd)
1014 error ('Error command exited with value %d\n' % st)
1017 def quiet_system (cmd, name):
1019 progress ( _("Running %s...") % name)
1020 cmd = cmd + ' 1> /dev/null 2> /dev/null'
1024 def get_bbox (filename):
1025 system ('gs -sDEVICE=bbox -q -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename))
1027 box = open (filename + '.bbox').read()
1028 m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', box)
1031 gr = map (string.atoi, m.groups ())
1035 def make_pixmap (name):
1036 bbox = get_bbox (name + '.eps')
1038 fo = open (name + '.trans.eps' , 'w')
1039 fo.write ('%d %d translate\n' % (-bbox[0]+margin, -bbox[1]+margin))
1044 x = (2* margin + bbox[2] - bbox[0]) * res / 72.
1045 y = (2* margin + bbox[3] - bbox[1]) * res / 72.
1047 cmd = r'''gs -g%dx%d -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r%d -dNOPAUSE %s %s -c quit > %s'''
1049 cmd = cmd % (x, y, res, name + '.trans.eps', name + '.eps',name + '.png')
1052 status = system (cmd)
1057 os.unlink (name + '.png')
1058 error ("Removing output file")
1060 def compile_all_files (chunks):
1067 if c[0] != 'lilypond':
1076 if base + '.ly' not in tex:
1077 tex.append (base + '.ly')
1078 elif e == 'png' and g_do_pictures:
1084 # fixme: be sys-independent.
1086 if g_outdir and x[0] != '/' :
1087 x = os.path.join (g_here_dir, x)
1090 incs = map (incl_opt, include_path)
1091 lilyopts = string.join (incs, ' ' )
1093 lilyopts = lilyopts + ' --dependencies '
1095 lilyopts = lilyopts + '--dep-prefix=' + g_outdir + '/'
1096 texfiles = string.join (tex, ' ')
1097 cmd = 'lilypond --header=texidoc %s %s %s' \
1098 % (lilyopts, g_extra_opts, texfiles)
1103 # Ugh, fixing up dependencies for .tex generation
1106 depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep', x), tex)
1111 text=re.sub ('\n([^:\n]*):', '\n' + foutn + ':', text)
1117 cmd = r"echo $TEXMF; tex '\nonstopmode \input %s'" % e
1118 quiet_system (cmd, 'TeX')
1120 cmd = r"dvips -E -o %s %s" % (e + '.eps', e)
1121 quiet_system (cmd, 'dvips')
1129 def update_file (body, name):
1131 write the body if it has changed
1142 f = open (name , 'w')
1149 def getopt_args (opts):
1150 "Construct arguments (LONG, SHORT) for getopt from list of options."
1155 short = short + o[1]
1163 return (short, long)
1165 def option_help_str (o):
1166 "Transform one option description (4-tuple ) into neatly formatted string"
1184 return ' ' + sh + sep + long + arg
1187 def options_help_str (opts):
1188 "Convert a list of options into a neatly formatted string"
1194 s = option_help_str (o)
1195 strs.append ((s, o[3]))
1201 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
1205 sys.stdout.write('''Usage: lilypond-book [options] FILE\n
1206 Generate hybrid LaTeX input from Latex + lilypond
1209 sys.stdout.write (options_help_str (option_definitions))
1210 sys.stdout.write (r'''Warning all output is written in the CURRENT directory
1214 Report bugs to bug-lilypond@gnu.org.
1216 Written by Tom Cato Amundsen <tca@gnu.org> and
1217 Han-Wen Nienhuys <hanwen@cs.uu.nl>
1223 def write_deps (fn, target, chunks):
1225 sys.stderr.write('Writing `%s\'\n' % os.path.join(g_outdir, fn))
1226 f = open (os.path.join(g_outdir, fn), 'w')
1227 f.write ('%s%s: ' % (g_dep_prefix, target))
1228 for d in read_files:
1232 if c[0] == 'lilypond':
1233 (type, body, opts, todo, basename) = c;
1234 basenames.append (basename)
1237 d=g_outdir + '/' + d
1239 #if not os.isfile (d): # thinko?
1240 if not re.search ('/', d):
1241 d = g_dep_prefix + d
1242 f.write ('%s.tex ' % d)
1244 #if len (basenames):
1245 # for d in basenames:
1246 # f.write ('%s.ly ' % d)
1247 # f.write (' : %s' % target)
1252 def identify (stream):
1253 stream.write ('lilypond-book (GNU LilyPond) %s\n' % program_version)
1255 def print_version ():
1256 identify (sys.stdout)
1257 sys.stdout.write (r'''Copyright 1998--1999
1258 Distributed under terms of the GNU General Public License. It comes with
1263 def check_texidoc (chunks):
1266 if c[0] == 'lilypond':
1267 (type, body, opts, todo, basename) = c;
1268 pathbase = os.path.join (g_outdir, basename)
1269 if os.path.isfile (pathbase + '.texidoc'):
1270 body = '\n@include %s.texidoc\n' % basename + body
1271 c = (type, body, opts, todo, basename)
1276 ## what's this? Docme --hwn
1278 def fix_epswidth (chunks):
1281 if c[0] != 'lilypond' or 'eps' not in c[2]:
1282 newchunks.append (c)
1287 m = re.match ('magnification=([0-9.]+)', o)
1289 mag = string.atof (m.group (1))
1291 def replace_eps_dim (match, lmag = mag):
1292 filename = match.group (1)
1293 dims = bounding_box_dimensions (filename)
1295 return '%fpt' % (dims[0] *lmag)
1297 body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
1298 newchunks.append(('lilypond', body, c[2], c[3], c[4]))
1303 ##docme: why global?
1305 def do_file(input_filename):
1307 chunks = read_doc_file(input_filename)
1308 chunks = chop_chunks(chunks, 'lilypond', make_lilypond, 1)
1309 chunks = chop_chunks(chunks, 'lilypond-file', make_lilypond_file, 1)
1310 chunks = chop_chunks(chunks, 'lilypond-block', make_lilypond_block, 1)
1311 chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
1312 chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
1313 chunks = chop_chunks(chunks, 'numcols', do_columns)
1314 chunks = chop_chunks(chunks, 'multicols', do_multicols)
1316 #for c in chunks: print "c:", c;
1318 scan_preamble(chunks)
1319 chunks = process_lilypond_blocks(chunks)
1322 if __main__.g_run_lilypond:
1323 compile_all_files (chunks)
1324 chunks = fix_epswidth (chunks)
1326 if __main__.format == 'texi':
1327 chunks = check_texidoc (chunks)
1330 chunks = completize_preamble (chunks)
1336 my_outname = outname
1337 elif input_filename == '-' or input_filename == "/dev/stdin":
1340 my_outname = os.path.basename (os.path.splitext(input_filename)[0]) + '.' + format
1341 my_depname = my_outname + '.dep'
1343 if my_outname == '-' or my_outname == '/dev/stdout':
1346 __main__.do_deps = 0
1348 foutn = os.path.join (g_outdir, my_outname)
1349 sys.stderr.write ("Writing `%s'\n" % foutn)
1350 fout = open (foutn, 'w')
1357 write_deps (my_depname, foutn, chunks)
1361 (sh, long) = getopt_args (__main__.option_definitions)
1362 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
1363 except getopt.error, msg:
1364 sys.stderr.write("error: %s" % msg)
1372 if o == '--include' or o == '-I':
1373 include_path.append (a)
1374 elif o == '--version' or o == '-v':
1377 elif o == '--verbose' or o == '-V':
1378 __main__.verbose_p = 1
1379 elif o == '--format' or o == '-f':
1381 elif o == '--outname' or o == '-o':
1384 sys.stderr.write("Lilypond-book is confused by --outname on multiple files")
1387 elif o == '--help' or o == '-h':
1389 elif o == '--no-lily' or o == '-n':
1390 __main__.g_run_lilypond = 0
1391 elif o == '--dependencies' or o == '-M':
1393 elif o == '--default-music-fontsize':
1394 default_music_fontsize = string.atoi (a)
1395 elif o == '--default-lilypond-fontsize':
1396 print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
1397 default_music_fontsize = string.atoi (a)
1398 elif o == '--extra-options':
1400 elif o == '--force-music-fontsize':
1401 g_force_music_fontsize = string.atoi(a)
1402 elif o == '--force-lilypond-fontsize':
1403 print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
1404 g_force_music_fontsize = string.atoi(a)
1405 elif o == '--dep-prefix':
1407 elif o == '--no-pictures':
1409 elif o == '--no-music':
1411 elif o == '--read-lys':
1413 elif o == '--outdir':
1416 identify (sys.stderr)
1418 if os.path.isfile(g_outdir):
1419 error ("outdir is a file: %s" % g_outdir)
1420 if not os.path.exists(g_outdir):
1422 setup_environment ()
1423 for input_filename in files:
1424 do_file(input_filename)
1427 # Petr, ik zou willen dat ik iets zinvoller deed,
1428 # maar wat ik kan ik doen, het verandert toch niets?