]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/lilypond-book.py
''
[lilypond.git] / scripts / lilypond-book.py
index 4163ec4ed26b555e1eb488db2e86980fd400de51..cf10c42f20c5ce06d1459ee828596409249723aa 100644 (file)
 #       geometry.sty and article.cls. Give me a hint, and I'll
 #       fix it.)
 
+#
+# TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips. 
+# 
+
 # This is was the idea for handling of comments:
 #      Multiline comments, @ignore .. @end ignore is scanned for
 #      in read_doc_file, and the chunks are marked as 'ignore', so
@@ -31,6 +35,8 @@
 #      The the rest of the rexeces are searched for. They don't have to test
 #      if they are on a commented out line.
 
+
+
 import os
 import stat
 import string
@@ -45,13 +51,22 @@ program_version = '@TOPLEVEL_VERSION@'
 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
        program_version = '1.5.18'
 
-#
+# if set, LILYPONDPREFIX must take prevalence
+# if datadir is not set, we're doing a build and LILYPONDPREFIX 
+datadir = '@datadir@'
+
+if os.environ.has_key ('LILYPONDPREFIX') :
+       datadir = os.environ['LILYPONDPREFIX']
+else:
+       datadir = '@datadir@'
+
+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.
-#
-datadir = '@datadir@'
 environment = {
        'MFINPUTS' : datadir + '/mf:',
        'TEXINPUTS': datadir + '/tex:' + datadir + '/ps:.:',
@@ -60,6 +75,13 @@ environment = {
        'GS_LIB' : datadir + '/ps',
 }
 
+# tex needs lots of memory, more than it gets by default on Debian
+non_path_environment = {
+       'extra_mem_top' : '1000000',
+       'extra_mem_bottom' : '1000000',
+       'pool_size' : '250000',
+}
+
 def setup_environment ():
        for key in environment.keys ():
                val = environment[key]
@@ -67,13 +89,16 @@ def setup_environment ():
                        val = val + os.pathsep + os.environ[key]
                os.environ[key] = val
 
-
+       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()]
 
 
 # g_ is for global (?)
-
+g_extra_opts = ''
 g_here_dir = os.getcwd ()
 g_dep_prefix = ''
 g_outdir = ''
@@ -81,6 +106,7 @@ g_force_lilypond_fontsize = 0
 g_read_lys = 0
 g_do_pictures = 1
 g_num_cols = 1
+
 format = ''
 g_run_lilypond = 1
 no_match = 'a\ba'
@@ -126,6 +152,16 @@ class LatexPaper:
                self.m_geo_x_marginparsep = None
                self.__body = None
        def set_geo_option(self, name, value):
+
+               if type(value) == type(""):
+                       m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
+                       if m:
+                               unit = m.group (2)
+                               num = string.atof(m.group (1))
+                               conv =  dimension_conversion_dict[m.group(2)]
+
+                               value = conv(num)
+
                if name == 'body' or name == 'text':
                        if type(value) == type(""):
                                self.m_geo_textwidth =  value
@@ -301,6 +337,7 @@ def pt2pt(x):
 
 dimension_conversion_dict ={
        'mm': mm2pt,
+       'cm': lambda x: mm2pt(10*x),
        'in': in2pt,
        'em': em2pt,
        'ex': ex2pt,
@@ -332,6 +369,7 @@ 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'),
@@ -439,7 +477,9 @@ re_dict = {
                  },
 
 
-       # why do we have distinction between @mbinclude and @include? 
+       # why do we have distinction between @mbinclude and @include?
+
+       
        'texi': {
                 'include':  '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
                 'input': no_match,
@@ -448,9 +488,9 @@ re_dict = {
                 'landscape': no_match,
                 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
                 'verb': r"""(?P<code>@code{.*?})""",
-                'lilypond-file': '(?m)^(?!@c)(?P<match>@lilypondfile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
-                'lilypond' : '(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
-                'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
+                '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",
@@ -464,7 +504,14 @@ for r in re_dict.keys ():
        olddict = re_dict[r]
        newdict = {}
        for k in olddict.keys ():
-               newdict[k] = re.compile (olddict[k])
+               try:
+                       newdict[k] = re.compile (olddict[k])
+               except:
+                       print 'invalid regexp: %s' % olddict[k]
+
+                       # we'd like to catch and reraise a more detailed  error, but
+                       # alas, the exceptions changed across the 1.5/2.1 boundary.
+                       raise "Invalid re"
        re_dict[r] = newdict
 
        
@@ -494,8 +541,10 @@ def bounding_box_dimensions(fname):
        str = fd.read ()
        s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
        if s:
-               return (int(s.group(3))-int(s.group(1)), 
-                       int(s.group(4))-int(s.group(2)))
+               
+               gs = map (lambda x: string.atoi (x), s.groups ())
+               return (int (gs[2] - gs[0] + 0.5),
+                       int (gs[3] - gs[1] + 0.5))
        else:
                return (0,0)
 
@@ -608,7 +657,7 @@ def scan_latex_preamble(chunks):
                        idx = idx + 1
                        continue
                m = get_re ('header').match(chunks[idx][1])
-               if m.group (1):
+               if m <> None and m.group (1):
                        options = re.split (',[\n \t]*', m.group(1)[1:-1])
                else:
                        options = []
@@ -622,8 +671,8 @@ def scan_latex_preamble(chunks):
                                m = re.match("(\d\d)pt", o)
                                if m:
                                        paperguru.m_fontsize = int(m.group(1))
-                       
                break
+       
        while chunks[idx][0] != 'preamble-end':
                if chunks[idx] == 'ignore':
                        idx = idx + 1
@@ -927,16 +976,6 @@ def process_lilypond_blocks(outname, chunks):#ugh rename
        return newchunks
 
 
-def find_eps_dims (match):
-       "Fill in dimensions of EPS files."
-       
-       fn =match.group (1)
-       dims = bounding_box_dimensions (fn)
-       if g_outdir:
-               fn = os.path.join(g_outdir, fn)
-       
-       return '%ipt' % dims[0]
-
 
 def system (cmd):
        sys.stderr.write ("invoking `%s'\n" % cmd)
@@ -945,6 +984,39 @@ def system (cmd):
                error ('Error command exited with value %d\n' % st)
        return st
 
+
+def get_bbox (filename):
+       system ('gs -sDEVICE=bbox -q  -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename))
+
+       box = open (filename + '.bbox').read()
+       m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', box)
+       gr = []
+       if m:
+               gr = map (string.atoi, m.groups ())
+       
+       return gr
+
+def make_pixmap (name):
+       bbox = get_bbox (name + '.eps')
+       margin = 0
+       fo = open (name + '.trans.eps' , 'w')
+       fo.write ('%d %d translate\n' % (-bbox[0]+margin, -bbox[1]+margin))
+       fo.close ()
+       
+       res = 90
+
+       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 = cmd % (x, y, res, name + '.trans.eps', name + '.eps',name + '.png')
+       try:
+               status = system (cmd)
+       except:
+               os.unlink (name + '.png')
+               error ("Removing output file")
+
 def compile_all_files (chunks):
        global foutn
        eps = []
@@ -982,7 +1054,7 @@ def compile_all_files (chunks):
                        if g_outdir:
                                lilyopts = lilyopts + '--dep-prefix=' + g_outdir + '/'
                texfiles = string.join (tex, ' ')
-               system ('lilypond --header=texidoc %s %s' % (lilyopts, texfiles))
+               system ('lilypond --header=texidoc %s %s %s' % (lilyopts, g_extra_opts, texfiles))
 
                #
                # Ugh, fixing up dependencies for .tex generation
@@ -1001,14 +1073,9 @@ def compile_all_files (chunks):
        for e in eps:
                system(r"tex '\nonstopmode \input %s'" % e)
                system(r"dvips -E -o %s %s" % (e + '.eps', e))
+               
        for g in png:
-               cmd = r"""gs -sDEVICE=pgm  -dTextAlphaBits=4 -dGraphicsAlphaBits=4  -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
-               cmd = cmd % (g + '.eps', g + '.png')
-               try:
-                       status = system (cmd)
-               except:
-                       os.unlink (g + '.png')
-                       error ("Removing output file")
+               make_pixmap (g)
                
        os.chdir (d)
 
@@ -1098,7 +1165,7 @@ Options:
 
 
 
-Report bugs to bug-gnu-music@gnu.org.
+Report bugs to bug-lilypond@gnu.org.
 
 Written by Tom Cato Amundsen <tca@gnu.org> and
 Han-Wen Nienhuys <hanwen@cs.uu.nl>
@@ -1159,14 +1226,31 @@ def check_texidoc (chunks):
                n.append (c)
        return n
 
+
+## what's this? Docme --hwn
+##
 def fix_epswidth (chunks):
        newchunks = []
        for c in chunks:
-               if c[0] == 'lilypond' and 'eps' in c[2]:
-                       body = re.sub (r"""\\lilypondepswidth{(.*?)}""", find_eps_dims, c[1])
-                       newchunks.append(('lilypond', body, c[2], c[3], c[4]))
-               else:
+               if c[0] <> 'lilypond' or 'eps' not in c[2]:
                        newchunks.append (c)
+                       continue
+
+               mag = 1.0
+               for o in c[2]:
+                       m  = re.match ('magnification=([0-9.]+)', o)
+                       if m:
+                               mag = string.atof (m.group (1))
+
+               def replace_eps_dim (match, lmag = mag):
+                       filename = match.group (1)
+                       dims = bounding_box_dimensions (filename)
+
+                       return '%fpt' % (dims[0] *lmag)
+       
+               body = re.sub (r"""\\lilypondepswidth{(.*?)}""", replace_eps_dim, c[1])
+               newchunks.append(('lilypond', body, c[2], c[3], c[4]))
+                       
        return newchunks
 
 
@@ -1253,6 +1337,8 @@ for opt in options:
        elif o == '--default-lilypond-fontsize':
                print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
                default_music_fontsize = string.atoi (a)
+       elif o == '--extra-options':
+               g_extra_opts = a
        elif o == '--force-music-fontsize':
                g_force_lilypond_fontsize = string.atoi(a)
        elif o == '--force-lilypond-fontsize':