A rough draft of ly2dvi32.py is enclosed.
Disclaimer,
The present state relies on the proposed Windows-NT binary
distribution directory structure. Therefore mileage will vary.
Actually it will most likely catch an exception attempting to locate
titledefs. But I think it is best just to get it out there so we can
rip it apart.
Please be candid with your comments, for I am new to Python.
Take care my friends,
Jeffrey B. Reed
--
Jeffrey B. Reed
[EMAIL PROTECTED]
#!/bin/python
name = 'ly2dvi'
version = '0.0.1'
import sys
import os
import getopt
import re
import string
import time
import glob
class Input:
def __init__(this):
this.__fd = None
def open(this,file):
for i in [''] + Props.get('include')[0:]:
ifile = os.path.join(i,file)
for j in ['','.ly','.fly']:
jfile = ifile+j
try:
this.__fd = open( jfile, 'r' )
return
except:
pass
sys.exit('ExitNotFound', file)
def close(this):
this.__fd.close()
def type(this):
firstline = this.__fd.readline()
this.__fd.seek(0)
if ( re.match('% Creator: GNU LilyPond [0-9]+[.0-9]+',firstline ) ):
return 'output'
else:
return 'source'
#
# Scan file for variable settings
#
def setVars(this):
"""Scan source file for variable settings"""
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 ),
]
titles={}
line='prime the pump' # ugh
while line:
line=this.__fd.readline()
m=re.match('\\\\def\\\\mudela([\w]+){(.*)}',line)
if( m ):
for var in varTable:
if ( m.group(1) == var[0] ):
var[1](m.group(2),'file')
break
for var in Props.get('titledefs'):
if ( m.group(1) == var ):
titles[var]=m.group(2)
break
Props.setTitles(titles,'file')
this.__fd.seek(0)
class TeXOutput:
def __init__(this):
this.__fd = None
this.__base = ''
this.__outfile = ''
def write(this,str):
this.__fd.write(str)
def start(this,file):
"""Start the latex file"""
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')
else:
pageheight = Props.get('pageheight')
pagewidth = Props.get('pagewidth')
horizontalMarginArg = ( (pagewidth - linewidth)/2 )
verticalMarginArg = ( (pageheight - textheight)/2 )
top="""\
%% Creator: %s
%% Automatically generated from %s, %s
\\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') )
pathcomp = os.path.splitext(file)
this.__base = pathcomp[0]
this.__outfile = '%s.%d%s' % (pathcomp[0], os.getpid(), pathcomp[1])
try:
this.__fd = open(this.__outfile,"w")
except:
sys.exit('ExitNoWrite', this.__outfile)
this.write(top)
this.__mudelaDefs('')
this.write("""\
\\cmrtwenty% ugh
\\makelilytitle
""")
def next(this):
this.write("""\
\\def\\theopus{}%
\\def\\thepiece{}%
\\def\\mudelaopus{}%
\\def\\mudelapiece{}%
""")
this.__mudelaDefs("\\def")
this.write("""\
\\def\\theopus{\\mudelaopus}% ugh
\\def\\thepiece{\\mudelapiece}%
\\makelilypiecetitle
""")
def __mudelaDefs(this,opt):
titles = Props.get('titles')
for key in titles.keys():
this.write('%s\\mudela%s{%s}%%\n' % (opt,key,titles[key]))
def end(this):
outfile=this.__base + '.dvi'
if ( Props.get('output') != '' ):
outfile = os.path.join(Props.get('output'), outfile )
this.write("""\
\\vfill\\hfill{\\LilyIdString}
\\end{document}
""")
this.__fd.close()
stat = os.system('latex \\nonstopmode \\input %s' %
(this.__outfile))
if ( stat ):
sys.exit('ExitBadLatex')
if ( os.path.isfile(outfile) ):
os.remove(outfile)
os.rename(this.__base + '.' + str(os.getpid()) + '.dvi', outfile)
class Properties:
def __set(this,var,value,requester):
if ( this.__overrideTable[requester] < this.__data[var][1] ):
return 0
else:
this.__data[var] = [value, this.__overrideTable[requester]]
def get(this,var):
if ( var == 'include' or var == 'lilyOutputFiles' ):
return this.__data[var][0][0:] # return a copy not a ref
else:
return this.__data[var][0]
def __init__(this):
this.__overrideTable = {
'init' : 0,
'environment' : 1,
'rcfile' : 2,
'file' : 3,
'commandline' : 4,
'program' : 5
}
this.__roverrideTable = {} # reverse lookup
for i in this.__overrideTable.items():
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' : [0, this.__overrideTable['init']],
'orientation' : ['portrait', this.__overrideTable['init']],
'language' : ['%', this.__overrideTable['init']],
'include' : [[], this.__overrideTable['init']],
'debug' : [0, this.__overrideTable['init']],
'keeplilypond' : [0, this.__overrideTable['init']],
'keeply2dvi' : [0, this.__overrideTable['init']],
'pagenumber' : ['%', this.__overrideTable['init']],
'separate' : [0, this.__overrideTable['init']],
'output' : ['', this.__overrideTable['init']],
'header' : ['%', this.__overrideTable['init']],
'dependencies' : [0, this.__overrideTable['init']],
'root' : ['', this.__overrideTable['init']],
'tmp' : ['d:\tmp', this.__overrideTable['init']],
'filename' : ['', this.__overrideTable['init']],
'titledefs' : [[], this.__overrideTable['init']],
'titles' : [{}, this.__overrideTable['init']],
'lilyOutputFiles' : [[], this.__overrideTable['init']],
}
if( os.environ.has_key('LILYINCLUDE') ):
tmp=this.get('include')
for s in string.split(os.environ['LILYINCLUDE'],os.pathsep):
tmp.append(s)
this.__set('include', tmp, 'environment')
if( os.environ.has_key('LILYPOND')):
this.__set('root',os.environ['LILYPOND'], 'environment')
else:
p=os.path.split(sys.argv[0])
p=os.path.split(p[0])
this.__set('root',p[0],'init')
os.environ['TEXINPUTS']= os.path.join(this.get('root'), 'texmf',
'tex', 'lilypond' )
if( os.environ.has_key('TMP') ):
this.__set('tmp',os.environ['TMP'],'environment')
if( not os.environ.has_key('HOME') ):
if ( os.environ.has_key('HOMEDRIVE') and \
os.environ.has_key('HOMEPATH')):
os.environ['HOME'] = os.environ['HOMEDRIVE'] + \
os.environ['HOMEPATH']
else:
os.environ['HOME'] = os.curdir
file = os.path.join(this.get('root'), 'texmf', 'tex', 'lilypond',
'titledefs.tex' )
try:
fd=open( file, "r" )
except:
sys.exit('ExitNotFound',file)
mudefs=[]
line='prime the pump' # ugh
while line:
line=fd.readline()
m=re.match('\\\\newcommand\*{\\\\mudela([\w]+)}',line)
if( m ):
mudefs.append(m.group(1))
fd.close
this.__set('titledefs', mudefs, 'init')
#
# Read rc file
#
def rcfile(this):
"""Read RCfile"""
varTable = [
# name set method
# ---- ----------
( 'LILYPOND', this.setInclude ),
( 'LANGUAGE', this.setLanguage ),
( 'LATEXHF', this.setHeader ),
( 'ORIENTATION', this.setOrientation ),
( 'OUTPUTDIR', this.setOutput ),
( 'PAPERSIZE', this.setPaperZize ),
( 'PHEIGHT', this.setTextHeight ),
( 'TMP', this.setTmp ),
( 'PWIDTH', this.setLineWidth ),
]
for d in [os.path.join(this.get('root'),'share','lilypond'), \
os.environ['HOME'], os.curdir ]:
file=os.path.join(d,'.lilyrc')
try:
fd = open( file, 'r' )
except:
continue
line='prime the pump' # ugh
while line:
line=fd.readline()
if( re.match('#.*',line) ):
continue
m=re.search('([\w]+)=(.*)',line)
if( m ):
for var in varTable:
if ( m.group(1) == var[0] ):
var[1](m.group(2),'rcfile')
break
fd.close
#
# Set paper size
#
def setPaperZize(this,size,requester):
paperTable = [
# regex width height name
# ----- ----- ------ ----
( 'a0.*', 2389, 3381, 'a0paper' ),
( 'a1$|a1p.*', 1690, 2389, 'a1paper' ),
( 'a2.*', 1194, 1690, 'a2paper' ),
( 'a3.*', 845, 1194, 'a3paper' ),
( 'a4.*', 597, 845, 'a4paper' ),
( 'a5.*', 423, 597, 'a5paper' ),
( 'a6.*', 298, 423, 'a6paper' ),
( 'a7.*', 211, 298, 'a7paper' ),
( 'a8.*', 305, 211, 'a8paper' ),
( 'a9.*', 105, 305, 'a9paper' ),
( 'a10.*', 74, 105, 'a10paper' ),
( 'b0.*', 2847, 4023, 'b0paper' ),
( 'b1.*', 2012, 2847, 'b1paper' ),
( 'b2.*', 1423, 2012, 'b2paper' ),
( 'b3.*', 1006, 1423, 'b3paper' ),
( 'b4.*', 712, 1006, 'b4paper' ),
( 'b5.*', 503, 712, 'b5paper' ),
( 'archA$', 650, 867, 'archApaper' ),
( 'archB$', 867, 1301, 'archBpaper' ),
( 'archC$', 1301, 1734, 'archCpaper' ),
( 'archD$', 1734, 2602, 'archDpaper' ),
( 'archE$', 2602, 3469, 'archEpaper' ),
( 'flsa$|flse$', 614, 940, 'flsapaper' ),
( 'halfletter$', 397, 614, 'halfletterpaper' ),
( 'ledger$', 1229, 795, 'ledgerpaper' ),
( 'legal$', 614, 1012, 'legalpaper' ),
( 'letter$', 614, 795, 'letterpaper' ),
( 'note$', 542, 723, 'notepaper' )
]
found=0
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
if ( not found ):
sys.exit('ExitBadPaper',size)
#
# set Text Height
#
def setTextHeight(this,size,requester):
m=re.match('([0-9][.0-9]*)(cm|mm|pt|$)',size)
if( m ):
if ( m.group(2) == 'cm' ):
this.__set('textheight',\
float(m.group(1)) * 72.27/2.54, requester )
elif ( m.group(2) == 'mm' ):
this.__set('textheight',\
float(m.group(1)) * 72.27/25.4, requester )
elif ( m.group(2) == 'pt' ):
this.__set('textheight', float(m.group(1)), requester )
elif ( m.group(2) == '' ):
this.__set('textheight', float(m.group(1)), requester )
else:
sys.exit('ExitBadHeight', m.group(2))
else:
sys.exit('ExitBadHeight', size)
#
# set Text Width
#
def setLineWidth(this,size,requester):
m=re.match('([0-9][.0-9]*)(cm|mm|pt|$)',size)
if( m ):
if ( m.group(2) == 'cm' ):
this.__set('linewidth', \
float(m.group(1)) * 72.27/2.54, requester )
elif ( m.group(2) == 'mm' ):
this.__set('linewidth', \
float(m.group(1)) * 72.27/25.4, requester )
elif ( m.group(2) == 'pt' ):
this.__set('linewidth', float(m.group(1)), requester )
elif ( m.group(2) == '' ):
this.__set('linewidth', float(m.group(1)), requester )
else:
sys.exit('ExitBadWidth', m.group(2))
else:
sys.exit('ExitBadWidth', size)
#
# Set Orientation
#
def setOrientation(this,orient,requester):
if ( orient == 'landscape' or orient == 'portrait' ):
this.__set('orientation', orient, requester )
else:
sys.exit('ExitBadOrient', orient)
#
# Set Language
#
def setLanguage(this,lang,requester):
this.__set('language', '\\usepackage[%s]{babel}' % (lang), requester )
#
# Append Include
#
def setInclude(this,inc, requester):
tmp = this.get('include')
tmp.append(inc)
this.__set('include', tmp, requester )
#
# Set debug flag
#
def setDebug(this,requester):
this.__set('debug',1,requester)
#
# Clear debug flag
#
def clearDebug(this, requester):
this.__set('debug',0,requester)
#
# Set Keeplilypond flag
#
def setKeeplilypond(this, requester):
this.__set('keeplilypond',1,requester)
#
# Clear Keeplilypond flag
#
def clearKeeplilypond(this, requester):
this.__set('keeplilypond',0,requester)
#
# Set Keeply2dvi flag
#
def setKeeply2dvi(this, requester):
this.__set('keeply2dvi',1,requester)
#
# Clear Keeply2dvi flag
#
def clearKeeply2dvi(this, requester):
this.__set('keeply2dvi',0,requester)
#
# Set No page number flag
#
def setNonumber(this, requester):
this.__set('pagenumber','\\pagestyle{empty}',requester)
#
# Clear No page number flag
#
def clearNonumber(this, requester):
this.__set('pagenumber','%',requester)
#
# Set separate flag
#
def setSeparate(this, requester):
this.__set('separate',1,requester)
#
# Clear separate flag
#
def clearSeparate(this, requester):
this.__set('separate',0,requester)
#
# Set output directory name
#
def setOutput(this,out,requester):
this.__set('output',out,requester)
#
# Set latex header name
#
def setHeader(this,head, requester):
this.__set('header',head,requester)
#
# Set Dependencies flag to generate makefile dependencies
#
def setDependencies(this, requester):
this.__set('dependencies',1,requester)
#
# Clear Dependencies flag
#
def clearDependencies(this, requester):
this.__set('dependencies',0,requester)
#
# Set tmp directory
#
def setTmp(this,dir, requester):
this.__set('tmp',dir,requester)
#
# Set mudela source file name
#
def setFilename(this,file, requester):
this.__set('filename',file,requester)
#
# Set title commands
#
def setTitles(this,titles, requester):
this.__set('titles',titles,requester)
def addLilyOutputFiles(this,file,requester):
tmp = this.get('lilyOutputFiles')
tmp.append(file)
this.__set('lilyOutputFiles',tmp,requester)
def printProps(this):
for key in this.__data.keys():
print "%s <%s>:<%s>" % (key,this.get(key),
this.__roverrideTable[this.__data[key][1]])
def getLilyopts():
if( len(Props.get('include')) > 0 ):
inc = '-I ' + string.join(Props.get('include'),os.pathsep)
else:
inc = ''
if ( Props.get('dependencies') ):
dep=' -d'
else:
dep=''
return inc + dep
def writeLilylog(contents):
if ( Props.get('keeplilypond') ):
file='lilylog.' + str(os.getpid())
output = Props.get('output')
if ( output != '' ):
file = os.path.join( output, file )
try:
fd = open( file, 'w' )
except:
sys.exit('ExitNoWrite', file)
fd.write(contents)
fd.close()
def getTeXFile(contents):
m = re.search('^TeX output to (.+)\.tex', contents,re.M)
if ( m ):
return ( m.group(1)+'.tex' )
else:
sys.exit('ExitNoTeXName')
def program_id ():
return name + ' ' + version;
def mailaddress():
try:
return os.environ['MAILADDRESS']
except KeyError:
return '(address unknown)'
def identify ():
sys.stderr.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'
' -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'
)
def main():
"""Generate dvi files from lilypond source/output"""
infile = Input()
outfile = TeXOutput()
texInputFiles=[]
Props.rcfile()
(options, files) = getopt.getopt (sys.argv[1:],
'DF:H:I:KLNW:dhkl:o:p:s',
['debug', 'headers=', 'Height=',
'include=', 'keeplilypond', 'landscape',
'nonumber', 'Width=', 'dependencies',
'help', 'keeply2dvi', 'language=',
'output=', 'papersize=', 'separate'])
for opt in options:
o = opt[0]
a = opt[1]
if o == '--debug' or o == '-D':
Props.setDebug('commandline')
elif o == '--headers' or o == '-F':
Props.setHeader(a,'commandline')
elif o == '--include' or o == '-I':
Props.setInclude(a,'commandline')
elif o == '--Height' or o == '-H':
Props.setTextHeight(a,'commandline')
elif o == '--keeplilypond' or o == '-K':
Props.setKeeplilypond('commandline')
elif o == '--landscape' or o == '-L':
Props.setOrientation('landscape','commandline')
elif o == '--nonumber' or o == '-N':
Props.setNonumber('commandline')
elif o == '--Width' or o == '-W':
Props.setLineWidth(a,'commandline')
elif o == '--dependencies' or o == '-d':
Props.setDependencies('commandline')
elif o == '--help' or o == '-h':
help()
return 0
elif o == '--keeply2dvi' or o == '-k':
Props.setKeeply2dvi('commandline')
elif o == '--language' or o == '-l':
Props.setLanguage(a,'commandline')
elif o == '--output' or o == '-o':
Props.setOutput(a,'commandline')
elif o == '--papersize' or o == '-p':
Props.setPaperZize(a,'commandline')
elif o == '--separate' or o == '-s':
Props.setSeparate('commandline')
if( len(files) ):
for file in files:
infile.open(file)
type = infile.type()
infile.close()
if ( type == 'source' ):
cmd = 'lilypond %s %s 2>&1' % (getLilyopts(), file)
fd = os.popen( cmd , 'r' )
log = fd.read()
stat = fd.close()
print log
if( stat ):
sys.exit('ExitBadLily', cmd )
texFile=getTeXFile(log)
writeLilylog(log)
Props.addLilyOutputFiles(texFile,'program')
texInputFiles.append(texFile)
else:
texInputFiles.append(file)
firstfile=1
for file in texInputFiles:
infile.open(file)
infile.setVars() # first pass set variables
infile.close()
Props.printProps()
if ( firstfile ):
outfile.start(file)
else:
outfile.next()
outfile.write("""\
\\input{%s}
""" % (file))
if( Props.get('separate') ):
outfile.end()
else:
firstfile=0
if( not Props.get('separate') ):
outfile.end()
else:
help()
sys.exit('ExitBadArgs','No files specified')
#
# Exit values
#
ExitTable = {
'ExitInterupt' : ['Ouch!', 1 ],
'ExitBadArgs' : ['Wrong number of arguments', 2 ],
'ExitNotFound' : ['File not found', 3 ],
'ExitBadPaper' : ['Unknown papersize', 4 ],
'ExitBadHeight' : ['Invalid Height specification', 5 ],
'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 ],
'ExitBadLatex' : ['Latex failed', 11 ],
'ExitUnknown' : ['Unknown Exit Code', 20 ],
}
def cleanup():
lilyfiles = []
tmpfiles = []
if ( not Props.get('keeplilypond') ):
lilyfiles = Props.get('lilyOutputFiles')
if ( not Props.get('keeply2dvi') ):
tmpfiles = glob.glob('*.' + str(os.getpid()) + '.*' )
for file in lilyfiles + tmpfiles:
if ( os.path.isfile(file) ):
os.remove(file)
try:
identify()
Props = Properties()
main()
except KeyboardInterrupt:
print ExitTable['ExitInterupt'][0]
cleanup()
sys.exit(ExitTable['ExitInterupt'][1])
except SystemExit, errno:
if ( ExitTable.has_key(errno.args[0]) ):
msg = ExitTable[errno.args[0]]
else:
msg = ExitTable['ExitUnknown']
if ( len(errno.args) > 1 ):
sys.stderr.write( '%s: %s: %s\n' % (name, msg[0], errno.args[1]))
else:
sys.stderr.write( '%s %s\n' % (name, msg[0]))
cleanup()
sys.exit(msg[1])
else:
cleanup()