]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/ly2dvi.py
patch::: 1.3.130.jcn5
[lilypond.git] / scripts / ly2dvi.py
index 25da9f8fce53a942c5982d455ceb079546208335..5d97714123d75a6755d1eafd6c5e87947d585e52 100644 (file)
@@ -1,5 +1,15 @@
 #!@PYTHON@
 
+
+# TODO:
+#
+# * Rewrite this.  The control structure is too hairy.
+# * (c) on page 1
+# * more helpful info on lily crashes
+# * Should use files in /tmp/ only.  This potentially messes with
+# user generated files in the CWD
+
+
 """
 =======================================================================
 LilyPond to dvi converter
@@ -14,7 +24,7 @@ Output: DVI file
 """
 
 name = 'ly2dvi'
-version = '0.0.12'
+version = '@TOPLEVEL_VERSION@'
 errorlog = ''
 
 import sys
@@ -24,12 +34,19 @@ import re
 import string
 import time
 import glob
+import tempfile
+
+# Can't grep localized msgs
+os.environ['LC_ALL'] = ''
+os.environ['LANG'] = ''
+os.environ['LC_LANG'] = ''
+
 
 
 class Input:
     """
     This class handles all ly2dvi.py input file methods
-
+    
     Public methods:
     
     __init__()  Constructor
@@ -126,18 +143,19 @@ class Input:
         varTable = [
             #   regexp              set method
             #   ------              ----------
-            ( 'language',        Props.setLanguage ),
-            ( 'latexheaders',    Props.setHeader ),
-            ( 'orientation',     Props.setOrientation ),
-            ( 'paperpapersize',  Props.setPaperZize ),
-            ( 'papertextheight', Props.setTextHeight ),
-            ( 'paperlinewidth',  Props.setLineWidth ),
-            ( 'filename',        Props.setFilename ),
+            ( 'language',         Props.setLanguage ),
+            ( 'latexheaders',     Props.setHeader ),
+            ( 'latexpackages',    Props.setPackages ),
+            ( 'paperorientation', Props.setOrientation ),
+            ( 'paperpapersize',   Props.setPaperZize ),
+            ( 'papertextheight',  Props.setTextHeight ),
+            ( 'paperlinewidth',   Props.setLineWidth ),
+            ( 'filename',         Props.setFilename ),
             ]
 
         titles={}
         for line in this.__fd.readlines():
-            m=re.match('\\\\def\\\\mudela([\w]+){(.*)}',line)
+            m=re.match('\\\\def\\\\lilypond([\w]+){(.*)}',line)
             if m:
                 for var in varTable:
                     if m.group(1) == var[0]:
@@ -157,7 +175,7 @@ class TeXOutput:
     This class handles all ly2dvi.py output file methods
 
     private methods:
-     __mudelaDefs(opt)  Send title info to output file
+     __lilypondDefs(opt)  Send title info to output file
 
     Public methods:
     __init__()  Constructor
@@ -178,7 +196,7 @@ class TeXOutput:
     #
     # __medelaDefs
     #
-    def __mudelaDefs(this,opt):
+    def __lilypondDefs(this,opt):
         """
         Write titles to output
 
@@ -189,7 +207,7 @@ class TeXOutput:
 
         titles = Props.get('titles')
         for key in titles.keys():
-            this.write('%s\\mudela%s{%s}%%\n' % (opt,key,titles[key]))
+            this.write('%s\\lilypond%s{%s}%%\n' % (opt,key,titles[key]))
 
     #
     # write
@@ -210,11 +228,11 @@ class TeXOutput:
     #
     def start(this,file):
         """
-        Start LaTeX file.  Calculates the horizontal and vertical
-        margin using pagewidth, pageheight, linewidth, and textheight.
-        Creates temporary output filename and opens it for write.
-        Sends the LaTeX header information to output.  Lastly sends
-        the title information to output.
+        Start LaTeX file. Sets the linewidth (and possibly the
+        textheight) and leaves the page layout to the geometry
+        package. Creates temporary output filename and opens it
+        for write. Sends the LaTeX header information to output.
+        Lastly sends the title information to output.
 
         input:  file  output file name 
         output: None
@@ -222,55 +240,59 @@ class TeXOutput:
         """
 
         now=time.asctime(time.localtime(time.time()))
-        linewidth = Props.get('linewidth')
-        textheight = Props.get('textheight')
 
-        if Props.get('orientation') == 'landscape':
-            pagewidth = Props.get('pageheight')
-            pageheight = Props.get('pagewidth')
+        # Only set the textheight if it was explicitly set by the user,
+        # otherwise use the default. Helps to handle landscape correctly!
+        if Props.get('textheight') > 0:
+            textheightsetting = ',textheight=' + `Props.get('textheight')` + 'pt'
         else:
-            pageheight = Props.get('pageheight')
-            pagewidth = Props.get('pagewidth')
-                                
-        horizontalMarginArg =  ( (pagewidth - linewidth)/2 )   
-        verticalMarginArg =  ( (pageheight - textheight)/2  )
+            textheightsetting = ''
 
-        top="""\
+
+        top= r"""
 %% Creator: %s
-%% Automatically generated from  %s, %s
+%% Generated automatically by: %s, from %s, at %s
 
-\\documentclass[%s]{article}
+\documentclass[%s]{article}
 
 %s 
-\\usepackage{geometry}
-\\usepackage[latin1]{inputenc} 
-%%\\usepackage[T1]{fontenc} 
-%s 
-%%\\addtolength{\\oddsidemargin}{-1cm} 
-%%\\addtolength{\\topmargin}{-1cm} 
-%%\\setlength{\\textwidth}{%s} 
-%%\\setlength{\\textheight}{%s} 
-\\geometry{width=%spt, left=%spt, height=%spt, top=%spt} 
-\\input lilyponddefs 
-\\input titledefs 
-%s 
-\\begin{document}
-""" % ( program_id(), Props.get('filename'), now, Props.get('papersize'),
-        Props.get('language'), Props.get('pagenumber'), linewidth, textheight,
-        linewidth, horizontalMarginArg, textheight, verticalMarginArg,
-        Props.get('header') )
+\usepackage{geometry}
+\usepackage[latin1]{inputenc} 
+%%\usepackage[T1]{fontenc} 
+%%
+%% don not waste unused space at bottom of page
+%% (unless we have footnotes ...)
+%%\headheight9pt
+%%\headsep0pt
+%% Maybe this is too drastic, but let us give it a try.
+\geometry{width=%spt%s,headheight=2mm,headsep=0pt,footskip=2mm,%s} 
+\input{titledefs}
+%s
+\makeatletter
+\renewcommand{\@oddhead}{\parbox{\textwidth}%%
+    {\mbox{}\small\theheader\hfill\textbf{\thepage}}}%%
+%% UGR.
+%%\renewcommand{\@evenhead}{eve!{\small\lilypondinstrument{,}\quad\textbf{\thepage}}\hfil}%%
+\renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\thefooter}}%%
+%s
+\begin{document}
+""" % ( program_id(), program_id(), Props.get('filename'), now, Props.get('papersize'),
+        Props.get('language'), Props.get('linewidth'), textheightsetting, 
+        Props.get('orientation'), Props.get('header'), Props.get('pagenumber'))
         
-        pathcomp = os.path.splitext(file)
-        this.__base = pathcomp[0]
-        this.__outfile = '%s.%d%s' % (pathcomp[0], os.getpid(), pathcomp[1])
+        base, ext = os.path.splitext(file)
+        this.__base = base
+        tempfile.template= base + '_ly'
+        this.__outfile = tempfile.mktemp(ext)
+        base, ext = os.path.splitext(this.__outfile)
+        this.__tmpbase = base
         try:
             this.__fd = open(this.__outfile,"w")
         except:
             sys.exit('ExitNoWrite', this.__outfile)
         this.write(top)
-        this.__mudelaDefs('')
+        this.__lilypondDefs('')
         this.write("""\
-\\cmrtwenty% ugh
 \\makelilytitle
 """) 
 
@@ -291,13 +313,13 @@ class TeXOutput:
         this.write("""\
 \\def\\theopus{}%
 \\def\\thepiece{}%
-\\def\\mudelaopus{}%
-\\def\\mudelapiece{}%
+\\def\\lilypondopus{}%
+\\def\\lilypondpiece{}%
 """)
-        this.__mudelaDefs("\\def")
+        this.__lilypondDefs("\\def")
         this.write("""\
-\\def\\theopus{\\mudelaopus}% ugh
-\\def\\thepiece{\\mudelapiece}%
+\\def\\theopus{\\lilypondopus}% ugh
+\\def\\thepiece{\\lilypondpiece}%
 \\makelilypiecetitle
 """)
 
@@ -316,13 +338,21 @@ class TeXOutput:
 
         outfile=this.__base + '.dvi'
         if Props.get('output') != '':
+           if not os.path.exists(Props.get('output')):
+                   os.mkdir(Props.get('output'))
+
             outfile = os.path.join(Props.get('output'), outfile )
             
-        this.write("""\
-\\vfill\\hfill{\\mudelatagline}
-\\end{document}
+        this.write(r"""
+%% \vfill\hfill{\lilypondtagline}
+\makeatletter
+\renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\lilypondtagline}}%%
+\makeatother
+\end{document}
 """)
         this.__fd.close()
+        if os.path.isfile(outfile):
+            os.remove(outfile)
         if ( os.name == 'posix' ):
             stat = os.system('latex \'\\nonstopmode \\input %s\'' %
                              (this.__outfile))
@@ -331,23 +361,30 @@ class TeXOutput:
                              (this.__outfile))
         if stat:
             sys.exit('ExitBadLatex')
-        if os.path.isfile(outfile):
-            os.remove(outfile)
-        os.rename(this.__base + '.' + str(os.getpid()) + '.dvi', outfile)
-        sys.stderr.write( '\n' + program_id() + ': dvi file name is %s\n\n'
-                   % (outfile))
+        if not os.path.isfile(outfile):
+               os.rename(this.__tmpbase + '.dvi', outfile)
+               
+        sys.stderr.write('\n' + program_id() + ': dvi file name is %s\n\n'
+                        % (outfile))
 
         if Props.get('postscript'):
+            dvipsopts=''
+            if Props.get('orientation') == 'landscape':
+                dvipsopts=dvipsopts + ' -t landscape'
             psoutfile=this.__base + '.ps'
             if Props.get('output') != '':
                 psoutfile = os.path.join(Props.get('output'), psoutfile )
-            stat = os.system('dvips -o %s %s' % (psoutfile,outfile))
+            stat = os.system('dvips %s -o %s %s' % (dvipsopts,psoutfile,outfile))
             if stat:
                 sys.exit('ExitBadPostscript')
             
 
 \f
 
+
+# ARG! THIS CODE IS BLOATED:
+# FIXME: Junk all set/get methods.
+
 class Properties:
     """
     This class handles all ly2dvi.py property manipulation
@@ -368,7 +405,7 @@ class Properties:
         # Requester     Description
         # ---------     -----------
         # init          Initial default values
-        # file          The values found in the lilypond generated TeX files
+        # file          The values found in the LilyPond generated TeX files
         # environment   Envrionment variables LILYINCLUDE, LILYPONDPREFIX
         # rcfile        $LILYPONDPREFIX/.lilyrc
         # rcfile        $HOME/.lilyrc
@@ -389,8 +426,6 @@ class Properties:
             this.__roverrideTable[i[1]]=i[0]
         
         this.__data = {
-            'pagewidth'    :  [597, this.__overrideTable['init']],
-            'pageheight'   :  [845, this.__overrideTable['init']],
             'papersize'    :  ['a4paper', this.__overrideTable['init']],
             'textheight'   :  [0, this.__overrideTable['init']],
             'linewidth'    :  [500, this.__overrideTable['init']],
@@ -453,18 +488,19 @@ class Properties:
         t=''
        if os.environ.has_key ('MFINPUTS'):
                t = os.environ['MFINPUTS'] 
-        os.environ['MFINPUTS'] = os.pathsep + t + \
+        os.environ['MFINPUTS'] = t + os.pathsep + \
                                  os.path.join(this.get('root'), 'mf')
 
         if os.environ.has_key('TMP'):
             this.__set('tmp',os.environ['TMP'],'environment')
 
-        
+
+    def read_titledefs (this):
        fd=this.get_texfile_path ('titledefs.tex')
         mudefs=[]    
 
         for line in fd.readlines():
-            m=re.match('\\\\newcommand\*{\\\\mudela([\w]+)}',line)
+            m=re.match('\\\\newcommand\*{\\\\lilypond([\w]+)}',line)
             if m:
                 mudefs.append(m.group(1))
        fd.close
@@ -537,6 +573,7 @@ class Properties:
             ( 'KEEPLY2DVI',     this.setKeeply2dvi ),
             ( 'LANGUAGE',       this.setLanguage ),
             ( 'LATEXHF',        this.setHeader ),
+            ( 'LATEXPKG',       this.setPackages ),
             ( 'LILYINCLUDE',    this.setInclude ),
             ( 'LILYPONDPREFIX', this.setRoot ),
             ( 'NONUMBER',       this.setNonumber ),
@@ -619,8 +656,6 @@ class Properties:
         for paper in paperTable:
             if re.match(paper[0],size):
                 found=1
-                this.__set('pagewidth',paper[1],requester)
-                this.__set('pageheight',paper[2],requester)
                 this.__set('papersize',paper[3],requester)
                 break
 
@@ -787,12 +822,18 @@ class Properties:
     # Set latex header name
     #
     def setHeader(this,head, requester):
-       this.__set('header',head,requester)
+       this.__set('header','\\input{' + head + '}'+this.get('header'),requester)
+
+    #
+    # Set latex package name
+    #
+    def setPackages(this,pkgs, requester):
+       this.__set('header','\\usepackage{' + pkgs + '}'+this.get('header'),requester)
 
     #
     # Set or Clear Dependencies flag to generate makefile dependencies
     #
-    def setDependencies(this, requester):      
+    def setDependencies(this, value, requester):       
         """
         Set or Clear dependencies flag
         """
@@ -809,7 +850,7 @@ class Properties:
        this.__set('tmp',dir,requester)
 
     #
-    # Set mudela source file name
+    # Set lilypond source file name
     #
     def setFilename(this,file, requester):     
        this.__set('filename',file,requester)
@@ -850,7 +891,7 @@ class Properties:
     #
     def setRoot(this,path, requester): 
         """
-        Set lilypond root directory
+        Set LilyPond root directory
         """
 
         os.environ['LILYPONDPREFIX'] = path
@@ -882,18 +923,16 @@ def getLilyopts():
     inc = ''   
     if len(Props.get('include')) > 0: 
         inc = string.join (map (lambda x: '-I "%s"' % x, Props.get('include')))
-    else:
-
-        if Props.get('dependencies'):
-            dep=' -d'
-        else:
-            dep=''
-       return inc + dep
-    return inc
+    dep=''
+    if Props.get('dependencies'):
+        dep=' --dependencies'
+    return inc + dep
 
-def writeLilylog(contents):
+def writeLilylog(file,contents):
     if Props.get('keeplilypond'):
-        file='lilylog.' + str(os.getpid())
+        base, ext = os.path.splitext(file)
+        tempfile.template=base + "_li"
+        file=tempfile.mktemp('.log')
         output = Props.get('output')
         if output != '':
             file = os.path.join( output, file )
@@ -907,7 +946,7 @@ def writeLilylog(contents):
 def getTeXFile(contents):
     texfiles=[]
     for line in string.split(contents,'\n'):
-        m = re.search('^Paper output to (.+)\.\.\.', line)
+        m = re.search('paper output to (.+)\.\.\.', line)
         if m:
             texfiles.append(m.group(1))
 
@@ -916,6 +955,14 @@ def getTeXFile(contents):
     else:
         return texfiles
 
+def getDepFiles (log):
+    files=[]
+    for line in string.split (log,'\n'):
+        m = re.search ("dependencies output to (.+)\.\.\.", line)
+        if m:
+            files.append (m.group (1))
+    return files
+
 def unc2dos(path):
     """
     Convert a path of format //<drive>/this/that/the/other to
@@ -928,7 +975,7 @@ def unc2dos(path):
     
 
 def program_id ():
-    return name + ' ' + version;
+    return 'ly2dvi (GNU LilyPond) ' + version;
 
 
 def mailaddress():
@@ -941,32 +988,37 @@ def mailaddress():
 def identify ():
     sys.stderr.write (program_id () + '\n')
 
+def print_version ():
+    sys.stdout.write (program_id () + '\n')
+
 def help ():
-    sys.stderr.write (
-        'Generate dvi file from mudela or lilypond output\n'
-        'Usage: ' + name + ' [OPTION]... [FILE]...\n'
-        '\n'
-        'Options:\n'
-        '  -D,--debug           increase verbosity\n'
-        '  -F,--headers=        name of additional LaTeX headers file\n'
-        '  -H,--Height=         set paper height (points) (see manual page)\n'
-        '  -I,--include=DIR     add DIR to LilyPond\'s search path\n'
-        '  -K,--keeplilypond    keep lilypond output files\n'
-        '  -L,--landscape       set landscape orientation\n'
-        '  -N,--nonumber        switch off page numbering\n'
-        '  -O,--orientation=    set orientation (obsolete - use -L instead)\n'
-        '  -P,--postscript      generate postscript file\n'
-        '  -W,--Width=          set paper width (points) (see manual page)\n'
-        '  -d,--dependencies    tell lilypond make a dependencies file\n'
-        '  -h,--help            this help text\n'
-        '  -k,--keeply2dvi      keep ly2dvi output files\n'
-        '  -l,--language=       give LaTeX language (babel)\n'
-        '  -o,--output=         set output directory\n'
-        '  -p,--papersize=      give LaTeX papersize (eg. a4)\n'
-        '  -s,--separate        run all files separately through LaTeX\n'
-        '\n'
-        'files may be (a mix of) input to or output from lilypond(1)\n'
-        )
+    sys.stdout.write (
+"""Usage: %s [OPTION]... [FILE]...
+
+Generate dvi file from LilyPond source/output
+
+Options:
+  -D,--debug           increase verbosity
+  -F,--headers=        name of additional LaTeX headers file
+  -H,--Height=         set paper height (points) (see manual page)
+  -I,--include=DIR     add DIR to LilyPond\'s search path
+  -K,--keeplilypond    keep LilyPond output files
+  -L,--landscape       set landscape orientation
+  -N,--nonumber        switch off page numbering
+  -O,--orientation=    set orientation (obsolete -- use -L instead)
+  -P,--postscript      generate PostScript file
+  -W,--Width=          set paper width (points) (see manual page)
+  -M,--dependencies    tell LilyPond to make a dependencies file
+  -h,--help            this help text
+  -k,--keeply2dvi      keep ly2dvi output files
+  -l,--language=       give LaTeX language (babel)
+  -o,--outdir=         set output directory
+     --output=         set output directory
+  -p,--papersize=      give LaTeX papersize (eg. a4)
+  -s,--separate        run all files separately through LaTeX
+
+files may be (a mix of) input to or output from LilyPond(1)
+""" % name)
 
 \f
 
@@ -975,20 +1027,22 @@ def help ():
 #
 
 def main():
-    """Generate dvi files from lilypond source/output"""
+    """Generate dvi files from LilyPond source/output"""
 
     infile = Input()
     outfile = TeXOutput()
     texInputFiles=[]
+    tempfile.tempdir=""
 
     (options, files) = getopt.getopt (sys.argv[1:],
-                                      'DF:H:I:KLNPW:dhkl:o:p:s',
+                                      'DF:H:I:KLNPW:Mhkl:o:p:s',
                                       ['debug', 'headers=', 'Height=',
                                        'include=', 'keeplilypond', 'landscape',
                                        'nonumber', 'Width=', 'dependencies',
                                        'help', 'keeply2dvi', 'language=',
-                                       'output=', 'papersize=', 'separate',
-                                       'postscript'])
+                                       'outdir=', 'output=', 'version',
+                                       'papersize=', 'separate', 'postscript'])
+
     for opt in options:
         o = opt[0]
         a = opt[1]
@@ -1008,16 +1062,16 @@ def main():
            Props.setNonumber(1,'commandline')
         elif o == '--Width' or o == '-W':
            Props.setLineWidth(a,'commandline')
-        elif o == '--dependencies' or o == '-d':
+        elif o == '--dependencies' or o == '-M':
            Props.setDependencies(1,'commandline')
         elif o == '--help' or o == '-h':
             help()
-            return 0
+           sys.exit (0)
         elif o == '--keeply2dvi' or o == '-k':
            Props.setKeeply2dvi(1,'commandline')
         elif o == '--language' or o == '-l':
            Props.setLanguage(a,'commandline')
-        elif o == '--output' or o == '-o':
+        elif o == '--outdir' or o == '-o' or o == '--output':
            Props.setOutput(a,'commandline')
         elif o == '--papersize' or o == '-p':
            Props.setPaperZize(a,'commandline')
@@ -1025,7 +1079,16 @@ def main():
            Props.setSeparate(1,'commandline')
         elif o == '--postscript' or o == '-P':
            Props.setPostscript(1,'commandline')
-
+       elif o == '--version':
+           print_version ()
+           return 0
+       else:
+           print o
+           raise getopt.error
+           
+    identify()
+    Props.read_titledefs ()
+    
     if len(files):
         for file in files:
             infile.open(file)
@@ -1059,7 +1122,8 @@ def main():
                 if stat:
                     sys.exit('ExitBadLily', cmd )
                 texFiles=getTeXFile(log)
-                writeLilylog(log)
+                depFiles=getDepFiles (log)
+                writeLilylog(file,log)
                 Props.addLilyOutputFiles(texFiles,'program')
                 texInputFiles = texInputFiles + texFiles
             else:
@@ -1073,7 +1137,7 @@ def main():
             if Props.get('debug'):
                 Props.printProps()
             if firstfile:
-                outfile.start(file)
+                outfile.start(file)  # allow for specified name
             else:
                 outfile.next()
             outfile.write("""\
@@ -1085,6 +1149,19 @@ def main():
                 firstfile=0
         if not Props.get('separate'):
             outfile.end()
+
+        # --outdir mess
+        if Props.get ('output'):
+            outdir=Props.get ('output')
+            for i in depFiles:
+                text=open (i).read ()
+                # ugh, should use lilypond -o DIR/foo.tex
+                # or --dep-prefix to fix dependencies
+                text=re.sub ('\n([^:]*).tex', '\n' + outdir + '/\\1.dvi', text)
+                text=re.sub (' ([^:]*).tex', ' ' + outdir + '/\\1.dvi', text)
+                open (os.path.join (outdir, i), 'w').write (text)
+                os.remove (i)
+
     else:
         help()
         sys.exit('ExitBadArgs','No files specified')
@@ -1101,8 +1178,8 @@ ExitTable = {
     'ExitBadWidth'         : ['Invalid Width specification', 6 ],
     'ExitBadOrient'        : ['Invalid Orientation specification', 7 ],
     'ExitNoWrite'          : ['Permission denied', 8 ],
-    'ExitNoTeXName'        : ['hmm, I could not find an output file name', 9 ],
-    'ExitBadLily'          : ['Lilypond failed', 10 ],
+    'ExitNoTeXName'        : ['Hmm, I could not find an output file name', 9 ],
+    'ExitBadLily'          : ['LilyPond failed', 10 ],
     'ExitBadLatex'         : ['Latex failed', 11 ],
     'ExitBadPostscript'    : ['Postscript failed', 12 ],
     'ExitUnknown'          : ['Unknown Exit Code', 20 ],
@@ -1114,13 +1191,12 @@ def cleanup():
     if not Props.get('keeplilypond'):
         lilyfiles = Props.get('lilyOutputFiles')
     if not Props.get('keeply2dvi'):
-        tmpfiles = glob.glob('*.' + str(os.getpid()) + '.*' )
+        tmpfiles = glob.glob('*_ly[0-9]*.*')
     for file in lilyfiles + tmpfiles:
         if os.path.isfile(file):
             os.remove(file)
 
 
-identify()
 Props = Properties()
 
 try: