]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/lilypond-book.py
''
[lilypond.git] / scripts / lilypond-book.py
index 09d6f6b9b22ba698c0d1ce556fa2f767dffeaf0e..cbb84e7b84ef6843c0e7f15f564b0a2184771d57 100644 (file)
@@ -40,8 +40,6 @@
 import os
 import stat
 import string
-
-
 import getopt
 import sys
 import __main__
@@ -50,16 +48,45 @@ import operator
 # Handle bug in Python 1.6-2.1
 #
 # there are recursion limits for some patterns in Python 1.6 til 2.1. 
-# fix this by importing pre instead. Fix by Mats.
+# fix this by importing the 1.5.2 implementation pre instead. Fix by Mats.
 
-# todo: should check Python version first.
-try:
-       import pre
-       re = pre
-       del pre
-except ImportError:
+if float (sys.version[0:3]) < 2.2:
+       try:
+               import pre
+               re = pre
+               del pre
+       except ImportError:
+               import re
+else:
        import re
 
+# Attempt to fix problems with limited stack size set by Python!
+# Sets unlimited stack size. Note that the resource module only
+# is available on UNIX.
+try:
+       import resource
+       resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
+except:
+       pass
+
+errorport = sys.stderr
+verbose_p = 0
+
+
+
+try:
+       import gettext
+       gettext.bindtextdomain ('lilypond', localedir)
+       gettext.textdomain ('lilypond')
+       _ = gettext.gettext
+except:
+       def _ (s):
+               return s
+
+def progress (s):
+       errorport.write (s + '\n')
+
+
 program_version = '@TOPLEVEL_VERSION@'
 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
        program_version = '1.5.53'
@@ -76,15 +103,17 @@ else:
 while datadir[-1] == os.sep:
        datadir= datadir[:-1]
 
-# Try to cater for bad installations of LilyPond, that have
-# broken TeX setup.  Just hope this doesn't hurt good TeX
-# setups.  Maybe we should check if kpsewhich can find
-# feta16.{afm,mf,tex,tfm}, and only set env upon failure.
+kpse = os.popen ('kpsexpand \$TEXMF').read()
+kpse = re.sub('[ \t\n]+$','', kpse)
+type1_paths = os.popen ('kpsewhich -expand-path=\$T1FONTS').read ()
+
 environment = {
-       'MFINPUTS' : datadir + '/mf:',
-       'TEXINPUTS': datadir + '/tex:' + datadir + '/ps:.:',
-       'TFMFONTS' : datadir + '/tfm:',
-       'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
+       # TODO: * prevent multiple addition.
+       #       * clean TEXINPUTS, MFINPUTS, TFMFONTS,
+       #         as these take prevalence over $TEXMF
+       #         and thus may break tex run?
+       'TEXMF' : "{%s,%s}" % (datadir, kpse) ,
+       'GS_FONTPATH' : type1_paths,
        'GS_LIB' : datadir + '/ps',
 }
 
@@ -96,6 +125,10 @@ non_path_environment = {
 }
 
 def setup_environment ():
+       # $TEXMF is special, previous value is already taken care of
+       if os.environ.has_key ('TEXMF'):
+               del os.environ['TEXMF']
        for key in environment.keys ():
                val = environment[key]
                if os.environ.has_key (key):
@@ -104,7 +137,6 @@ def setup_environment ():
 
        for key in non_path_environment.keys ():
                val = non_path_environment[key]
-               print '%s=%s' % (key,val)
                os.environ[key] = val
 
 include_path = [os.getcwd()]
@@ -119,6 +151,7 @@ g_force_lilypond_fontsize = 0
 g_read_lys = 0
 g_do_pictures = 1
 g_num_cols = 1
+g_do_music = 1
 
 format = ''
 g_run_lilypond = 1
@@ -324,6 +357,13 @@ class LatexPaper:
                        return 0
                return tmp
 
+class HtmlPaper:
+       def __init__(self):
+               self.m_papersize = 'letterpaper'
+               self.m_fontsize = 12
+       def get_linewidth(self):
+               return html_linewidths[self.m_papersize][self.m_fontsize]
+
 class TexiPaper:
        def __init__(self):
                self.m_papersize = 'letterpaper'
@@ -390,42 +430,77 @@ texi_linewidths = {
        'smallbook': {12: in2pt(5)},
        'letterpaper': {12: in2pt(6)}}
 
+html_linewidths = {
+       'afourpaper': {12: mm2pt(160)},
+       'afourwide': {12: in2pt(6.5)},
+       'afourlatex': {12: mm2pt(150)},
+       'smallbook': {12: in2pt(5)},
+       'letterpaper': {12: in2pt(6)}}
+
 option_definitions = [
-  ('EXT', 'f', 'format', 'set format.  EXT is one of texi and latex.'),
-  ('DIM',  '', 'default-music-fontsize', 'default fontsize for music.  DIM is assumed to be in points'),
-  ('DIM',  '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
-  ('OPT', '', 'extra-options' , 'Pass OPT quoted to the lilypond command line'),
-  ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
-  ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
-  ('DIR', 'I', 'include', 'include path'),
-  ('', 'M', 'dependencies', 'write dependencies'),
-  ('PREF', '',  'dep-prefix', 'prepend PREF before each -M dependency'),
-  ('', 'n', 'no-lily', 'don\'t run lilypond'),
-  ('', '', 'no-pictures', "don\'t generate pictures"),
-  ('', '', 'read-lys', "don't write ly files."),
-  ('FILE', 'o', 'outname', 'filename main output file'),
-  ('FILE', '', 'outdir', "where to place generated files"),
-  ('', 'v', 'version', 'print version information' ),
-  ('', 'h', 'help', 'print help'),
-  ]
+       ('EXT', 'f', 'format', 'use output format EXT (texi [default], latex, html)'),
+       ('DIM',  '', 'default-music-fontsize', 'default fontsize for music.  DIM is assumed to be in points'),
+       ('DIM',  '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
+       ('OPT', '', 'extra-options' , 'Pass OPT quoted to the lilypond command line'),
+       ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
+       ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
+       ('', 'h', 'help', 'this help'),
+       ('DIR', 'I', 'include', 'include path'),
+       ('', 'M', 'dependencies', 'write dependencies'),
+       ('PREF', '',  'dep-prefix', 'prepend PREF before each -M dependency'),
+       ('', 'n', 'no-lily', 'don\'t run lilypond'),
+       ('', '', 'no-pictures', "don\'t generate pictures"),
+       ('', '', 'no-music', "strip all lilypond blocks from output"),  
+       ('', '', 'read-lys', "don't write ly files."),
+       ('FILE', 'o', 'outname', 'filename main output file'),
+       ('FILE', '', 'outdir', "where to place generated files"),
+       ('', 'V', 'verbose', 'verbose' ),
+       ('', 'v', 'version', 'print version information' ),
+       ]
 
 # format specific strings, ie. regex-es for input, and % strings for output
 output_dict= {
+       'html' : {'output-lilypond': '''<lilypond%s>
+%s
+</lilypond>''',
+               'output-filename' : r'''
+
+<pre>%s</pre>:''',       
+                 'output-lilypond-fragment': '''<lilypond%s>
+\context Staff\context Voice{ %s }
+</lilypond>''',
+                 'output-noinline': r'''
+<!-- generated: %(fn)s.png !-->
+''',
+                 ## maybe <hr> ?
+                 'pagebreak': None,
+                 'output-verbatim': r'''<pre>
+%s
+</pre>''',
+                 ## Ugh we need to differentiate on origin:
+                 ## lilypond-block origin wants an extra <p>, but
+                 ## inline music doesn't.
+                 ## possibly other center options?
+                 'output-all': r'''
+<a href="%(fn)s.png">
+<img align="center" valign="center" border="0" src="%(fn)s.png" alt="[picture of music]"></a>
+''',
+                 },
        'latex': {
-               'output-lilypond-fragment' : r"""\begin[eps,singleline,%s]{lilypond}
+               'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
   \context Staff <
     \context Voice{
       %s
     }
   >
-\end{lilypond}""",
+\end{lilypond}''',
                'output-filename' : r'''
 
 \verb+%s+:''',
-               'output-lilypond': r"""\begin[%s]{lilypond}
+               'output-lilypond': r'''\begin[%s]{lilypond}
 %s
 \end{lilypond}
-""",
+''',
                'output-verbatim': r'''\begin{verbatim}%s\end{verbatim}%%
 ''',
                'output-default-post': "\\def\postLilypondExample{}\n",
@@ -439,24 +514,24 @@ output_dict= {
                'pagebreak': r'\pagebreak',
                },
        
-       'texi' : {'output-lilypond': """@lilypond[%s]
+       'texi' : {'output-lilypond': '''@lilypond[%s]
 %s
 @end lilypond 
-""",
+''',
                'output-filename' : r'''
 
 @file{%s}:''',   
-                 'output-lilypond-fragment': """@lilypond[%s]
+                 'output-lilypond-fragment': '''@lilypond[%s]
 \context Staff\context Voice{ %s }
-@end lilypond """,
+@end lilypond ''',
                  'output-noinline': r'''
 @c generated: %(fn)s.png                 
 ''',
                  'pagebreak': None,
-                 'output-verbatim': r"""@example
+                 'output-verbatim': r'''@example
 %s
 @end example
-""",
+''',
 
 # do some tweaking: @ is needed in some ps stuff.
 # override EndLilyPondOutput, since @tex is done
@@ -464,8 +539,10 @@ output_dict= {
 # top of the document.
 
 # should also support fragment in
+
+# ugh, the <p> below breaks inline images...
                  
-                 'output-all': r"""
+                 'output-all': r'''
 @tex
 \catcode`\@=12
 \input lilyponddefs
@@ -479,22 +556,47 @@ output_dict= {
 <img border=0 src="%(fn)s.png" alt="[picture of music]">
 </a>
 @end html
-""",
+''',
                }
+       
        }
 
 def output_verbatim (body):
-       if __main__.format == 'texi':
+       if __main__.format == 'html':
+               body = re.sub ('&', '&amp;', body)
+               body = re.sub ('>', '&gt;', body)
+               body = re.sub ('<', '&lt;', body)
+       elif __main__.format == 'texi':
                body = re.sub ('([@{}])', '@\\1', body)
        return get_output ('output-verbatim') % body
 
 
 #warning: this uses extended regular expressions. Tread with care.
 
-# legenda (?P  name parameter
-# *? match non-greedily.
+# legenda
 
+# (?P  -- name parameter
+# *? -- match non-greedily.
+# (?m)  -- ?  
 re_dict = {
+       'html': {
+                'include':  no_match,
+                'input': no_match,
+                'header': no_match,
+                'preamble-end': no_match,
+                'landscape': no_match,
+                'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
+                'verb': r'''(?P<code><pre>.*?</pre>)''',
+                'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
+                'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
+                'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
+                 'option-sep' : '\s*',
+                 'intertext': r',?\s*intertext=\".*?\"',
+                 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
+                 'singleline-comment': no_match,
+                 'numcols': no_match,
+                },
+       
        'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
                  'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
                  'option-sep' : ',\s*',
@@ -525,16 +627,16 @@ re_dict = {
                 'header': no_match,
                 'preamble-end': no_match,
                 'landscape': no_match,
-                'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
-                'verb': r"""(?P<code>@code{.*?})""",
+                'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
+                'verb': r'''(?P<code>@code{.*?})''',
                 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
                 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
-                'lilypond-block': r"""(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s""",
-                 'option-sep' : ',\s*',
-                 'intertext': r',?\s*intertext=\".*?\"',
-                 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
-                 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
-                 'numcols': no_match,
+                'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end +lilypond)\s''',
+                'option-sep' : ',\s*',
+                'intertext': r',?\s*intertext=\".*?\"',
+                'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
+                'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
+                'numcols': no_match,
                 }
        }
 
@@ -593,8 +695,8 @@ def error (str):
 
 
 def compose_full_body (body, opts):
-       """Construct the lilypond code to send to Lilypond.
-       Add stuff to BODY using OPTS as options."""
+       '''Construct the lilypond code to send to Lilypond.
+       Add stuff to BODY using OPTS as options.'''
        music_size = default_music_fontsize
        latex_size = default_text_fontsize
        indent = ''
@@ -707,6 +809,9 @@ def parse_options_string(s):
                error ("format of option string invalid (was `%')" % s)
        return d
 
+def scan_html_preamble (chunks):
+       return
+
 def scan_latex_preamble(chunks):
        # first we want to scan the \documentclass line
        # it should be the first non-comment line
@@ -732,7 +837,7 @@ def scan_latex_preamble(chunks):
                                        paperguru.m_fontsize = int(m.group(1))
                break
        
-       while chunks[idx][0] != 'preamble-end':
+       while idx < len(chunks) and chunks[idx][0] != 'preamble-end':
                if chunks[idx] == 'ignore':
                        idx = idx + 1
                        continue
@@ -753,16 +858,18 @@ def scan_texi_preamble (chunks):
                                if string.find(c[1], "@%s" % s) != -1:
                                        paperguru.m_papersize = s
 
+
 def scan_preamble (chunks):
-       if __main__.format == 'texi':
-               scan_texi_preamble(chunks)
-       else:
-               assert __main__.format == 'latex'
-               scan_latex_preamble(chunks)
+       if __main__.format == 'html':
+               scan_html_preamble (chunks)
+       elif __main__.format == 'latex':
+               scan_latex_preamble (chunks)
+       elif __main__.format == 'texi':
+               scan_texi_preamble (chunks)
                
 
 def completize_preamble (chunks):
-       if __main__.format == 'texi':
+       if __main__.format != 'latex':
                return chunks
        pre_b = post_b = graphics_b = None
        for chunk in chunks:
@@ -776,28 +883,36 @@ def completize_preamble (chunks):
                        m = get_re('def-post-re').search(chunk[1])
                        if m:
                                post_b = 1
+                               
                if chunk[0] == 'input':
                        m = get_re('usepackage-graphics').search(chunk[1])
                        if m:
                                graphics_b = 1
        x = 0
-       while chunks[x][0] != 'preamble-end':
+       while x < len (chunks) and   chunks[x][0] != 'preamble-end':
                x = x + 1
+
+       if x == len(chunks):
+               return chunks
+       
        if not pre_b:
                chunks.insert(x, ('input', get_output ('output-default-pre')))
        if not post_b:
                chunks.insert(x, ('input', get_output ('output-default-post')))
        if not graphics_b:
                chunks.insert(x, ('input', get_output ('usepackage-graphics')))
+
        return chunks
 
 
 read_files = []
 def find_file (name):
-       """
+       '''
        Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
-       """
-       
+       '''
+
+       if name == '-':
+               return (sys.stdin.read (), '<stdin>')
        f = None
        nm = ''
        for a in include_path:
@@ -844,12 +959,12 @@ def make_lilypond(m):
                        (options, m.group('code')))]
 
 def make_lilypond_file(m):
-       """
+       '''
 
        Find @lilypondfile{bla.ly} occurences and substitute bla.ly
        into a @lilypond .. @end lilypond block.
        
-       """
+       '''
        
        if m.group('options'):
                options = m.group('options')
@@ -862,6 +977,9 @@ def make_lilypond_file(m):
                        (options, content))]
 
 def make_lilypond_block(m):
+       if not g_do_music:
+               return []
+       
        if m.group('options'):
                options = get_re('option-sep').split (m.group('options'))
        else:
@@ -878,57 +996,62 @@ def do_columns(m):
                return [('numcols', m.group('code'), 2)]
        
 def chop_chunks(chunks, re_name, func, use_match=0):
-    newchunks = []
-    for c in chunks:
-        if c[0] == 'input':
-            str = c[1]
-            while str:
-                m = get_re (re_name).search (str)
-                if m == None:
-                    newchunks.append (('input', str))
-                    str = ''
-                else:
-                   if use_match:
-                        newchunks.append (('input', str[:m.start ('match')]))
-                   else:
-                        newchunks.append (('input', str[:m.start (0)]))
-                    #newchunks.extend(func(m))
-                   # python 1.5 compatible:
-                   newchunks = newchunks + func(m)
-                    str = str [m.end(0):]
-        else:
-            newchunks.append(c)
-    return newchunks
+       newchunks = []
+       for c in chunks:
+               if c[0] == 'input':
+                       str = c[1]
+                       while str:
+                               m = get_re (re_name).search (str)
+                               if m == None:
+                                       newchunks.append (('input', str))
+                                       str = ''
+                               else:
+                                       if use_match:
+                                               newchunks.append (('input', str[:m.start ('match')]))
+                                       else:
+                                               newchunks.append (('input', str[:m.start (0)]))
+                                       #newchunks.extend(func(m))
+                                       # python 1.5 compatible:
+                                       newchunks = newchunks + func(m)
+                                       str = str [m.end(0):]
+               else:
+                       newchunks.append(c)
+       return newchunks
 
 def determine_format (str):
        if __main__.format == '':
                
-               latex =  re.search ('\\\\document', str[:200])
-               texinfo =  re.search ('@node|@setfilename', str[:200])
+               html = re.search ('(?i)<[dh]tml', str[:200])
+               latex = re.search (r'''\\document''', str[:200])
+               texi = re.search ('@node|@setfilename', str[:200])
 
                f = ''
                g = None
                
-               if texinfo and latex == None:
-                       f = 'texi'
-               elif latex and texinfo == None: 
+               if html and not latex and not texi:
+                       f = 'html'
+               elif latex and not html and not texi:
                        f = 'latex'
+               elif texi and not html and not latex:
+                       f = 'texi'
                else:
-                       error("error: can't determine format, please specify")
+                       error ("can't determine format, please specify")
                __main__.format = f
 
        if __main__.paperguru == None:
-               if __main__.format == 'texi':
-                       g = TexiPaper()
-               else:
-                       g = LatexPaper()
+               if __main__.format == 'html':
+                       g = HtmlPaper ()
+               elif __main__.format == 'latex':
+                       g = LatexPaper ()
+               elif __main__.format == 'texi':
+                       g = TexiPaper ()
                        
                __main__.paperguru = g
 
 
 def read_doc_file (filename):
-       """Read the input file, find verbatim chunks and do \input and \include
-       """
+       '''Read the input file, find verbatim chunks and do \input and \include
+       '''
        (str, path) = find_file(filename)
        determine_format (str)
        
@@ -948,7 +1071,7 @@ def read_doc_file (filename):
 
 taken_file_names = {}
 def schedule_lilypond_block (chunk):
-       """Take the body and options from CHUNK, figure out how the
+       '''Take the body and options from CHUNK, figure out how the
        real .ly should look, and what should be left MAIN_STR (meant
        for the main file).  The .ly is written, and scheduled in
        TODO.
@@ -957,31 +1080,34 @@ def schedule_lilypond_block (chunk):
 
        TODO has format [basename, extension, extension, ... ]
        
-       """
+       '''
        (type, body, opts) = chunk
        assert type == 'lilypond'
        file_body = compose_full_body (body, opts)
+       ## Hmm, we should hash only lilypond source, and skip the
+       ## %options are ...
+       ## comment line
        basename = 'lily-' + `abs(hash (file_body))`
        for o in opts:
                m = re.search ('filename="(.*?)"', o)
                if m:
                        basename = m.group (1)
                        if not taken_file_names.has_key(basename):
-                           taken_file_names[basename] = 0
+                               taken_file_names[basename] = 0
                        else:
-                           taken_file_names[basename] = taken_file_names[basename] + 1
-                           basename = basename + "-%i" % taken_file_names[basename]
+                               taken_file_names[basename] = taken_file_names[basename] + 1
+                               basename = basename + "-%i" % taken_file_names[basename]
        if not g_read_lys:
                update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
        needed_filetypes = ['tex']
 
-       if format  == 'texi':
-               needed_filetypes.append('eps')
-               needed_filetypes.append('png')
+       if format == 'html' or format == 'texi':
+               needed_filetypes.append ('eps')
+               needed_filetypes.append ('png')
        if 'eps' in opts and not ('eps' in needed_filetypes):
                needed_filetypes.append('eps')
        pathbase = os.path.join (g_outdir, basename)
-       def f(base, ext1, ext2):
+       def f (base, ext1, ext2):
                a = os.path.isfile(base + ext2)
                if (os.path.isfile(base + ext1) and
                    os.path.isfile(base + ext2) and
@@ -1021,12 +1147,12 @@ def schedule_lilypond_block (chunk):
                        s = 'output-eps'
                else:
                        s = 'output-tex'
-       else: # format == 'texi'
+       else: # format == 'html' or format == 'texi':
                s = 'output-all'
        newbody = newbody + get_output (s) % {'fn': basename }
        return ('lilypond', newbody, opts, todo, basename)
 
-def process_lilypond_blocks(outname, chunks):#ugh rename
+def process_lilypond_blocks(chunks):#ugh rename
        newchunks = []
        # Count sections/chapters.
        for c in chunks:
@@ -1046,6 +1172,12 @@ def system (cmd):
                error ('Error command exited with value %d\n' % st)
        return st
 
+def quiet_system (cmd, name):
+       if not verbose_p:
+               progress ( _("Running %s...") % name)
+               cmd = cmd + ' 1> /dev/null 2> /dev/null'
+
+       return system (cmd)
 
 def get_bbox (filename):
        system ('gs -sDEVICE=bbox -q  -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename))
@@ -1070,9 +1202,11 @@ def make_pixmap (name):
        x = (2* margin + bbox[2] - bbox[0]) * res / 72.
        y = (2* margin + bbox[3] - bbox[1]) * res / 72.
 
-       cmd = r"""gs -g%dx%d -sDEVICE=pgm  -dTextAlphaBits=4 -dGraphicsAlphaBits=4  -q -sOutputFile=- -r%d -dNOPAUSE %s %s -c quit | pnmtopng > %s"""
+       cmd = r'''gs -g%dx%d -sDEVICE=pnggray  -dTextAlphaBits=4 -dGraphicsAlphaBits=4  -q -sOutputFile=- -r%d -dNOPAUSE %s %s -c quit  > %s'''
        
        cmd = cmd % (x, y, res, name + '.trans.eps', name + '.eps',name + '.png')
+       quiet_system (cmd, 'gs')
+
        try:
                status = system (cmd)
        except:
@@ -1116,7 +1250,10 @@ def compile_all_files (chunks):
                        if g_outdir:
                                lilyopts = lilyopts + '--dep-prefix=' + g_outdir + '/'
                texfiles = string.join (tex, ' ')
-               system ('lilypond --header=texidoc %s %s %s' % (lilyopts, g_extra_opts, texfiles))
+               cmd = 'lilypond --header=texidoc %s %s %s' \
+                     % (lilyopts, g_extra_opts, texfiles)
+
+               system (cmd)
 
                #
                # Ugh, fixing up dependencies for .tex generation
@@ -1133,8 +1270,11 @@ def compile_all_files (chunks):
                                f.close ()
 
        for e in eps:
-               system(r"tex '\nonstopmode \input %s'" % e)
-               system(r"dvips -E -o %s %s" % (e + '.eps', e))
+               cmd = r"echo $TEXMF; tex '\nonstopmode \input %s'" % e
+               quiet_system (cmd, 'TeX')
+               
+               cmd = r"dvips -E -o %s %s" % (e + '.eps', e)
+               quiet_system (cmd, 'dvips')
                
        for g in png:
                make_pixmap (g)
@@ -1143,9 +1283,9 @@ def compile_all_files (chunks):
 
 
 def update_file (body, name):
-       """
+       '''
        write the body if it has changed
-       """
+       '''
        same = 0
        try:
                f = open (name)
@@ -1218,12 +1358,12 @@ def options_help_str (opts):
        return str
 
 def help():
-       sys.stdout.write("""Usage: lilypond-book [options] FILE\n
+       sys.stdout.write('''Usage: lilypond-book [options] FILE\n
 Generate hybrid LaTeX input from Latex + lilypond
 Options:
-""")
+''')
        sys.stdout.write (options_help_str (option_definitions))
-       sys.stdout.write (r"""Warning all output is written in the CURRENT directory
+       sys.stdout.write (r'''Warning all output is written in the CURRENT directory
 
 
 
@@ -1231,14 +1371,14 @@ Report bugs to bug-lilypond@gnu.org.
 
 Written by Tom Cato Amundsen <tca@gnu.org> and
 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-""")
+''')
 
        sys.exit (0)
 
 
 def write_deps (fn, target, chunks):
        global read_files
-       sys.stdout.write('Writing `%s\'\n' % os.path.join(g_outdir, fn))
+       sys.stderr.write('Writing `%s\'\n' % os.path.join(g_outdir, fn))
        f = open (os.path.join(g_outdir, fn), 'w')
        f.write ('%s%s: ' % (g_dep_prefix, target))
        for d in read_files:
@@ -1265,15 +1405,15 @@ def write_deps (fn, target, chunks):
        f.close ()
        read_files = []
 
-def identify():
-       sys.stdout.write ('lilypond-book (GNU LilyPond) %s\n' % program_version)
+def identify (stream):
+       stream.write ('lilypond-book (GNU LilyPond) %s\n' % program_version)
 
 def print_version ():
-       identify()
-       sys.stdout.write (r"""Copyright 1998--1999
+       identify (sys.stdout)
+       sys.stdout.write (r'''Copyright 1998--1999
 Distributed under terms of the GNU General Public License. It comes with
 NO WARRANTY.
-""")
+''')
 
 
 def check_texidoc (chunks):
@@ -1310,21 +1450,15 @@ def fix_epswidth (chunks):
 
                        return '%fpt' % (dims[0] *lmag)
        
-               body = re.sub (r"""\\lilypondepswidth{(.*?)}""", replace_eps_dim, c[1])
+               body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
                newchunks.append(('lilypond', body, c[2], c[3], c[4]))
                        
        return newchunks
 
 
+##docme: why global?
 foutn=""
 def do_file(input_filename):
-       global foutn
-       file_settings = {}
-       if outname:
-               my_outname = outname
-       else:
-               my_outname = os.path.basename(os.path.splitext(input_filename)[0])
-       my_depname = my_outname + '.dep'                
 
        chunks = read_doc_file(input_filename)
        chunks = chop_chunks(chunks, 'lilypond', make_lilypond, 1)
@@ -1337,9 +1471,7 @@ def do_file(input_filename):
        #for c in chunks: print "c:", c;
        #sys.exit()
        scan_preamble(chunks)
-       chunks = process_lilypond_blocks(my_outname, chunks)
-
-       foutn = os.path.join (g_outdir, my_outname + '.' + format)
+       chunks = process_lilypond_blocks(chunks)
 
        # Do It.
        if __main__.g_run_lilypond:
@@ -1351,8 +1483,26 @@ def do_file(input_filename):
 
        x = 0
        chunks = completize_preamble (chunks)
-       sys.stderr.write ("Writing `%s'\n" % foutn)
-       fout = open (foutn, 'w')
+
+
+       global foutn
+
+       if outname:
+               my_outname = outname
+       elif input_filename == '-' or input_filename == "/dev/stdin":
+               my_outname = '-'
+       else:
+               my_outname = os.path.basename (os.path.splitext(input_filename)[0]) + '.' + format
+       my_depname = my_outname + '.dep'                
+       
+       if my_outname == '-' or my_outname == '/dev/stdout':
+               fout = sys.stdout
+               foutn = "<stdout>"
+               __main__.do_deps = 0
+       else:
+               foutn = os.path.join (g_outdir, my_outname)
+               sys.stderr.write ("Writing `%s'\n" % foutn)
+               fout = open (foutn, 'w')
        for c in chunks:
                fout.write (c[1])
        fout.close ()
@@ -1380,6 +1530,8 @@ for opt in options:
        elif o == '--version' or o == '-v':
                print_version ()
                sys.exit  (0)
+       elif o == '--verbose' or o == '-V':
+               __main__.verbose_p = 1
        elif o == '--format' or o == '-f':
                __main__.format = a
        elif o == '--outname' or o == '-o':
@@ -1410,12 +1562,14 @@ for opt in options:
                g_dep_prefix = a
        elif o == '--no-pictures':
                g_do_pictures = 0
+       elif o == '--no-music':
+               g_do_music = 0
        elif o == '--read-lys':
                g_read_lys = 1
        elif o == '--outdir':
                g_outdir = a
 
-identify()
+identify (sys.stderr)
 if g_outdir:
        if os.path.isfile(g_outdir):
                error ("outdir is a file: %s" % g_outdir)