lilypond-1.1.40
[lilypond.git] / scripts / ly2dvi.py
blob417533310a2018798daf48c5e3a0fa9fd7d93644
1 #!@PYTHON@
3 """
4 =======================================================================
5 LilyPond to dvi converter
7 Features include Title information, paper size specification, and image
8 orientation.
10 Usage: ly2dvi.py [OPTION]... [FILE]...
11 Input: LilyPond source or LilyPond generated TeX files
12 Output: DVI file
13 =======================================================================
14 """
16 name = 'ly2dvi'
17 version = '0.0.11'
18 errorlog = ''
20 import sys
21 import os
22 import getopt
23 import re
24 import string
25 import time
26 import glob
29 class Input:
30 """
31 This class handles all ly2dvi.py input file methods
33 Public methods:
35 __init__() Constructor
36 open(file) Open a .ly file or .tex file using lilyinclude path
37 close() Close current file
38 type() Determine file type .ly (input) or .tex (output)
39 setVars() Set title definitions found in .tex (output) file
40 """
43 # Constructors
46 def __init__(this):
47 this.__fd = None
50 # open
52 def open(this,file):
53 """
54 open file and set private class variable __fd. The search
55 sequence is: current directory followed by the directories
56 found in include property list. Each directory is searched
57 for file, file.ly, file.sly and file.fly.
59 input: file filename
60 output: void
61 error: ExitNotFound Exception
62 """
64 for i in [''] + Props.get('include')[0:]:
65 ifile = os.path.join(i,file)
66 for j in ['','.ly','.fly', 'sly']:
67 jfile = ifile+j
68 try:
69 this.__fd = open( jfile, 'r' )
70 return
71 except:
72 pass
73 sys.exit('ExitNotFound', file)
77 # close
79 def close(this):
80 """
81 close file object __fd
83 input: void
84 output: void
85 error: None
86 """
87 this.__fd.close()
91 # type
93 def type(this):
94 """
95 Determine input file type. LilyPond source is 'input' type
96 and LilyPond generated TeX file is 'output' type
98 input: void
99 output: 'input' | 'output'
100 error: None
103 firstline = this.__fd.readline()
104 this.__fd.seek(0)
105 if re.match('%created by: GNU LilyPond [0-9]+[.0-9]+',firstline ):
106 return 'output'
107 else:
108 return 'source'
112 # setVars
114 def setVars(this):
116 Search for properties in the current input file and set the
117 appropriate values. The supported properties names are in
118 local variable varTable along with the property list
119 titledefs.
121 input: void
122 output: None
123 error: None
126 varTable = [
127 # regexp set method
128 # ------ ----------
129 ( 'language', Props.setLanguage ),
130 ( 'latexheaders', Props.setHeader ),
131 ( 'orientation', Props.setOrientation ),
132 ( 'paperpapersize', Props.setPaperZize ),
133 ( 'papertextheight', Props.setTextHeight ),
134 ( 'paperlinewidth', Props.setLineWidth ),
135 ( 'filename', Props.setFilename ),
138 titles={}
139 for line in this.__fd.readlines():
140 m=re.match('\\\\def\\\\mudela([\w]+){(.*)}',line)
141 if m:
142 for var in varTable:
143 if m.group(1) == var[0]:
144 var[1](m.group(2),'file')
145 break
146 for var in Props.get('titledefs'):
147 if m.group(1) == var:
148 titles[var]=m.group(2)
149 break
150 Props.setTitles(titles,'file')
151 this.__fd.seek(0)
155 class TeXOutput:
157 This class handles all ly2dvi.py output file methods
159 private methods:
160 __mudelaDefs(opt) Send title info to output file
162 Public methods:
163 __init__() Constructor
164 write(str) Write a string to output file
165 start(file) Start the latex file
166 next() Process next output file
167 end() Finish latex file and run latex
171 # constructor
173 def __init__(this):
174 this.__fd = None
175 this.__base = ''
176 this.__outfile = ''
179 # __medelaDefs
181 def __mudelaDefs(this,opt):
183 Write titles to output
185 input: opt Supports header and subheader output
186 output: None
187 error: None
190 titles = Props.get('titles')
191 for key in titles.keys():
192 this.write('%s\\mudela%s{%s}%%\n' % (opt,key,titles[key]))
195 # write
197 def write(this,str):
199 Write str to current output file
201 input: str String to write
202 output: None
203 error: None
206 this.__fd.write(str)
209 # start
211 def start(this,file):
213 Start LaTeX file. Calculates the horizontal and vertical
214 margin using pagewidth, pageheight, linewidth, and textheight.
215 Creates temporary output filename and opens it for write.
216 Sends the LaTeX header information to output. Lastly sends
217 the title information to output.
219 input: file output file name
220 output: None
221 error: None
224 now=time.asctime(time.localtime(time.time()))
225 linewidth = Props.get('linewidth')
226 textheight = Props.get('textheight')
228 if Props.get('orientation') == 'landscape':
229 pagewidth = Props.get('pageheight')
230 pageheight = Props.get('pagewidth')
231 else:
232 pageheight = Props.get('pageheight')
233 pagewidth = Props.get('pagewidth')
235 horizontalMarginArg = ( (pagewidth - linewidth)/2 )
236 verticalMarginArg = ( (pageheight - textheight)/2 )
238 top="""\
239 %% Creator: %s
240 %% Automatically generated from %s, %s
242 \\documentclass[%s]{article}
245 \\usepackage{geometry}
246 \\usepackage[latin1]{inputenc}
247 %%\\usepackage[T1]{fontenc}
249 %%\\addtolength{\\oddsidemargin}{-1cm}
250 %%\\addtolength{\\topmargin}{-1cm}
251 %%\\setlength{\\textwidth}{%s}
252 %%\\setlength{\\textheight}{%s}
253 \\geometry{width=%spt, left=%spt, height=%spt, top=%spt}
254 \\input lilyponddefs
255 \\input titledefs
257 \\begin{document}
258 """ % ( program_id(), Props.get('filename'), now, Props.get('papersize'),
259 Props.get('language'), Props.get('pagenumber'), linewidth, textheight,
260 linewidth, horizontalMarginArg, textheight, verticalMarginArg,
261 Props.get('header') )
263 pathcomp = os.path.splitext(file)
264 this.__base = pathcomp[0]
265 this.__outfile = '%s.%d%s' % (pathcomp[0], os.getpid(), pathcomp[1])
266 try:
267 this.__fd = open(this.__outfile,"w")
268 except:
269 sys.exit('ExitNoWrite', this.__outfile)
270 this.write(top)
271 this.__mudelaDefs('')
272 this.write("""\
273 \\cmrtwenty% ugh
274 \\makelilytitle
275 """)
278 # next
280 def next(this):
282 Write LaTeX subheader information to support more than one
283 score in a document. Lastly send current title information to
284 output.
286 input: None
287 output: None
288 error: None
291 this.write("""\
292 \\def\\theopus{}%
293 \\def\\thepiece{}%
294 \\def\\mudelaopus{}%
295 \\def\\mudelapiece{}%
296 """)
297 this.__mudelaDefs("\\def")
298 this.write("""\
299 \\def\\theopus{\\mudelaopus}% ugh
300 \\def\\thepiece{\\mudelapiece}%
301 \\makelilypiecetitle
302 """)
306 # end
308 def end(this):
310 Close output file and run latex on it.
312 input: None
313 output: None
314 error: ExitBadLatex Exception
317 outfile=this.__base + '.dvi'
318 if Props.get('output') != '':
319 outfile = os.path.join(Props.get('output'), outfile )
321 this.write("""\
322 \\vfill\\hfill{\\mudelatagline}
323 \\end{document}
324 """)
325 this.__fd.close()
326 if ( os.name == 'posix' ):
327 stat = os.system('latex \'\\nonstopmode \\input %s\'' %
328 (this.__outfile))
329 else: # Windows shells don't eat the single quotes
330 stat = os.system('latex \\nonstopmode \\input %s' %
331 (this.__outfile))
332 if stat:
333 sys.exit('ExitBadLatex')
334 if os.path.isfile(outfile):
335 os.remove(outfile)
336 os.rename(this.__base + '.' + str(os.getpid()) + '.dvi', outfile)
337 sys.stderr.write( '\n' + program_id() + ': dvi file name is %s\n\n'
338 % (outfile))
340 if Props.get('postscript'):
341 psoutfile=this.__base + '.ps'
342 if Props.get('output') != '':
343 psoutfile = os.path.join(Props.get('output'), psoutfile )
344 stat = os.system('dvips -o %s %s' % (psoutfile,outfile))
345 if stat:
346 sys.exit('ExitBadPostscript')
351 class Properties:
353 This class handles all ly2dvi.py property manipulation
355 Public methods:
357 __init__() Constructor
358 set<property> methods
361 def __init__(this):
364 # Following is the order of priority for property assignment. The
365 # list is organized from lowest to highest priority. Each
366 # assignment is overridden by the next requester in the list.
368 # Requester Description
369 # --------- -----------
370 # init Initial default values
371 # file The values found in the lilypond generated TeX files
372 # environment Envrionment variables LILYINCLUDE, LILYPONDPREFIX
373 # rcfile $LILYPONDPREFIX/.lilyrc
374 # rcfile $HOME/.lilyrc
375 # rcfile ./.lilyrc
376 # commandline command line arguments
378 this.__overrideTable = {
379 'init' : 0,
380 'file' : 1,
381 'environment' : 2,
382 'rcfile' : 3,
383 'commandline' : 4,
384 'program' : 5
387 this.__roverrideTable = {} # reverse lookup used for debug
388 for i in this.__overrideTable.items():
389 this.__roverrideTable[i[1]]=i[0]
391 this.__data = {
392 'pagewidth' : [597, this.__overrideTable['init']],
393 'pageheight' : [845, this.__overrideTable['init']],
394 'papersize' : ['a4paper', this.__overrideTable['init']],
395 'textheight' : [0, this.__overrideTable['init']],
396 'linewidth' : [500, this.__overrideTable['init']],
397 'orientation' : ['portrait', this.__overrideTable['init']],
398 'language' : ['%', this.__overrideTable['init']],
399 'include' : [[], this.__overrideTable['init']],
400 'debug' : [0, this.__overrideTable['init']],
401 'keeplilypond' : [0, this.__overrideTable['init']],
402 'keeply2dvi' : [0, this.__overrideTable['init']],
403 'pagenumber' : ['%', this.__overrideTable['init']],
404 'separate' : [0, this.__overrideTable['init']],
405 'output' : ['', this.__overrideTable['init']],
406 'header' : ['%', this.__overrideTable['init']],
407 'dependencies' : [0, this.__overrideTable['init']],
408 'root' : ['', this.__overrideTable['init']],
409 'tmp' : ['d:\tmp', this.__overrideTable['init']],
410 'filename' : ['', this.__overrideTable['init']],
411 'titledefs' : [[], this.__overrideTable['init']],
412 'titles' : [{}, this.__overrideTable['init']],
413 'lilyOutputFiles' : [[], this.__overrideTable['init']],
414 'postscript' : [0, this.__overrideTable['init']],
418 # Try to set root and HOME first before calling rcfile
420 if os.environ.has_key('LILYPONDPREFIX'):
421 this.setRoot(os.environ['LILYPONDPREFIX'], 'environment')
422 else:
423 p=os.path.split(sys.argv[0])
424 p=os.path.split(p[0])
425 # bit silly. for ly2dvi, overrules compiled-in datadir...
426 # how to do this better (without running lily, of course?
427 this.setRoot(os.path.join(p[0],'share','lilypond'), 'init')
429 if not os.environ.has_key('HOME'):
430 if os.environ.has_key('HOMEDRIVE') and \
431 os.environ.has_key('HOMEPATH'):
432 os.environ['HOME'] = os.environ['HOMEDRIVE'] + \
433 os.environ['HOMEPATH']
434 else:
435 os.environ['HOME'] = os.curdir
437 this.rcfile() # Read initialization file(s)
439 if os.environ.has_key('LILYINCLUDE'):
440 tmp=this.get('include')
441 for s in string.split(os.environ['LILYINCLUDE'],os.pathsep):
442 tmp.append(s)
443 this.__set('include', tmp, 'environment')
446 t= os.pathsep
447 if os.environ.has_key ('TEXINPUTS'):
448 t = os.environ['TEXINPUTS'] + os.pathsep
449 os.environ['TEXINPUTS'] = t + \
450 os.path.join(this.get('root'), 'tex' ) + \
451 os.pathsep + os.path.join(this.get('root'), 'ps' )
453 t=''
454 if os.environ.has_key ('MFINPUTS'):
455 t = os.environ['MFINPUTS'] + os.pathsep
456 os.environ['MFINPUTS'] = t + os.path.join(this.get('root'), 'mf' )
458 if os.environ.has_key('TMP'):
459 this.__set('tmp',os.environ['TMP'],'environment')
462 fd=this.get_texfile_path ('titledefs.tex')
463 mudefs=[]
465 for line in fd.readlines():
466 m=re.match('\\\\newcommand\*{\\\\mudela([\w]+)}',line)
467 if m:
468 mudefs.append(m.group(1))
469 fd.close
470 this.__set('titledefs', mudefs, 'init')
473 # __set
475 def __set(this,var,value,requester):
477 All of the set methods call this to set a property. If the value
478 was last set by a requestor of lesser priority the new value is
479 assigned, else the old value has priority and is unchanged.
482 if this.__overrideTable[requester] < this.__data[var][1]:
483 return 0
484 else:
485 this.__data[var] = [value, this.__overrideTable[requester]]
488 # get
490 def get(this,var):
492 All of the get methods call this to get a property value. List
493 variable types are return by value to facilitate an append operation.
496 if var == 'include' or var == 'lilyOutputFiles':
497 return this.__data[var][0][0:] # return a copy not a ref
498 else:
499 return this.__data[var][0]
502 # get_texfile_path
504 def get_texfile_path (this, var):
506 locate and open titledefs.tex file
509 if os.name == 'nt':
510 path = os.path.join(this.get('root'), 'tex', var)
511 else:
512 path =''
513 cmd =('kpsewhich tex %s %s' % (var,errorlog))
514 pipe = os.popen (cmd, 'r')
515 path = pipe.readline ()[:-1] # chop off \n
516 return_status = pipe.close()
517 if return_status and not path:
518 path = os.path.join(this.get('root'), 'tex', var)
519 fd = open(path, 'r')
520 return fd
524 # Read rc file
526 def rcfile(this):
528 Read initialization file(s)
530 varTable = [
531 # name set method
532 # ---- ----------
533 ( 'DEBUG', this.setDebug ),
534 ( 'DEPENDENCIES', this.setDependencies ),
535 ( 'KEEPLILYPOND', this.setKeeplilypond ),
536 ( 'KEEPLY2DVI', this.setKeeply2dvi ),
537 ( 'LANGUAGE', this.setLanguage ),
538 ( 'LATEXHF', this.setHeader ),
539 ( 'LILYINCLUDE', this.setInclude ),
540 ( 'LILYPONDPREFIX', this.setRoot ),
541 ( 'NONUMBER', this.setNonumber ),
542 ( 'ORIENTATION', this.setOrientation ),
543 ( 'OUTPUTDIR', this.setOutput ),
544 ( 'PAPERSIZE', this.setPaperZize ),
545 ( 'PHEIGHT', this.setTextHeight ),
546 ( 'POSTSCRIPT', this.setPostscript ),
547 ( 'PWIDTH', this.setLineWidth ),
548 ( 'SEPARATE', this.setSeparate ),
549 ( 'TMP', this.setTmp ),
552 if ( os.name == 'posix' ):
553 dotFilename='.lilyrc'
554 else: # Windows apps like edit choke on .lilyrc
555 dotFilename='_lilyrc'
557 for d in [os.path.join(this.get('root'),'ly'), \
558 os.environ['HOME'], os.curdir ]:
559 file=os.path.join(d,dotFilename)
560 try:
561 fd = open( file, 'r' )
562 except:
563 continue
565 for line in fd.readlines():
566 if re.match('#.*',line):
567 continue
568 m=re.search('([\w]+)=(.*)',line)
569 if m:
570 for var in varTable:
571 if m.group(1) == var[0]:
572 var[1](m.group(2),'rcfile')
573 break
574 fd.close
577 # setPaperZize
579 def setPaperZize(this,size,requester):
581 Set paper size properties
584 paperTable = [
585 # regex width height name
586 # ----- ----- ------ ----
587 ( 'a0.*', 2389, 3381, 'a0paper' ),
588 ( 'a1$|a1p.*', 1690, 2389, 'a1paper' ),
589 ( 'a2.*', 1194, 1690, 'a2paper' ),
590 ( 'a3.*', 845, 1194, 'a3paper' ),
591 ( 'a4.*', 597, 845, 'a4paper' ),
592 ( 'a5.*', 423, 597, 'a5paper' ),
593 ( 'a6.*', 298, 423, 'a6paper' ),
594 ( 'a7.*', 211, 298, 'a7paper' ),
595 ( 'a8.*', 305, 211, 'a8paper' ),
596 ( 'a9.*', 105, 305, 'a9paper' ),
597 ( 'a10.*', 74, 105, 'a10paper' ),
598 ( 'b0.*', 2847, 4023, 'b0paper' ),
599 ( 'b1.*', 2012, 2847, 'b1paper' ),
600 ( 'b2.*', 1423, 2012, 'b2paper' ),
601 ( 'b3.*', 1006, 1423, 'b3paper' ),
602 ( 'b4.*', 712, 1006, 'b4paper' ),
603 ( 'b5.*', 503, 712, 'b5paper' ),
604 ( 'archA$', 650, 867, 'archApaper' ),
605 ( 'archB$', 867, 1301, 'archBpaper' ),
606 ( 'archC$', 1301, 1734, 'archCpaper' ),
607 ( 'archD$', 1734, 2602, 'archDpaper' ),
608 ( 'archE$', 2602, 3469, 'archEpaper' ),
609 ( 'flsa$|flse$', 614, 940, 'flsapaper' ),
610 ( 'halfletter$', 397, 614, 'halfletterpaper' ),
611 ( 'ledger$', 1229, 795, 'ledgerpaper' ),
612 ( 'legal$', 614, 1012, 'legalpaper' ),
613 ( 'letter$', 614, 795, 'letterpaper' ),
614 ( 'note$', 542, 723, 'notepaper' )
617 found=0
618 for paper in paperTable:
619 if re.match(paper[0],size):
620 found=1
621 this.__set('pagewidth',paper[1],requester)
622 this.__set('pageheight',paper[2],requester)
623 this.__set('papersize',paper[3],requester)
624 break
626 if not found:
627 sys.exit('ExitBadPaper',size)
630 # setTextHeight
632 def setTextHeight(this,size,requester):
634 Set textheight property
637 m=re.match('([0-9][.0-9]*)(cm|mm|pt|$)',size)
638 if m:
639 if m.group(2) == 'cm':
640 this.__set('textheight',\
641 float(m.group(1)) * 72.27/2.54, requester )
642 elif m.group(2) == 'mm':
643 this.__set('textheight',\
644 float(m.group(1)) * 72.27/25.4, requester )
645 elif m.group(2) == 'pt':
646 this.__set('textheight', float(m.group(1)), requester )
647 elif m.group(2) == '':
648 this.__set('textheight', float(m.group(1)), requester )
649 else:
650 sys.exit('ExitBadHeight', m.group(2))
651 else:
652 sys.exit('ExitBadHeight', size)
655 # setLineWidth
657 def setLineWidth(this,size,requester):
659 Set linewidth propery
662 m=re.match('([0-9][.0-9]*)(cm|mm|pt|$)',size)
663 if m:
664 if m.group(2) == 'cm':
665 this.__set('linewidth', \
666 float(m.group(1)) * 72.27/2.54, requester )
667 elif m.group(2) == 'mm':
668 this.__set('linewidth', \
669 float(m.group(1)) * 72.27/25.4, requester )
670 elif m.group(2) == 'pt':
671 this.__set('linewidth', float(m.group(1)), requester )
672 elif m.group(2) == '':
673 this.__set('linewidth', float(m.group(1)), requester )
674 else:
675 sys.exit('ExitBadWidth', m.group(2))
676 else:
677 sys.stderr.write ('ly2dvi: warning: ignoring linewidth: ' + size + '\n')
680 # setOrientation
682 def setOrientation(this,orient,requester):
684 Set orientation property
687 if orient == 'landscape' or orient == 'portrait':
688 this.__set('orientation', orient, requester )
689 else:
690 sys.exit('ExitBadOrient', orient)
693 # setLanguage
695 def setLanguage(this,lang,requester):
697 Set language property
700 this.__set('language', '\\usepackage[%s]{babel}' % (lang), requester )
703 # setInclude
705 def setInclude(this,inc, requester):
707 Append an include path
710 tmp = this.get('include')
711 tmp.append(inc)
712 this.__set('include', tmp, requester )
715 # setDebug
717 def setDebug(this,value,requester):
719 Set or Clear debug flag
722 if int(value) == 1:
723 this.__set('debug',1,requester)
724 else:
725 this.__set('debug',0,requester)
728 # setKeeplilypond
730 def setKeeplilypond(this, value, requester):
732 Set or Clear keeplilypond flag
735 if int(value) == 1:
736 this.__set('keeplilypond',1,requester)
737 else:
738 this.__set('keeplilypond',0,requester)
741 # setKeeply2dvi
743 def setKeeply2dvi(this, value, requester):
745 Set or Clear keeply2dvi flag
748 if int(value) == 1:
749 this.__set('keeply2dvi',1,requester)
750 else:
751 this.__set('keeply2dvi',0,requester)
754 # setNonumber
756 def setNonumber(this, value, requester):
758 Set nonumber flag
761 if int(value) == 1:
762 this.__set('pagenumber',1,requester)
763 else:
764 this.__set('pagenumber',0,requester)
767 # setSeparate
769 def setSeparate(this, value, requester):
771 Set or Clear separate flag
774 if int(value) == 1:
775 this.__set('separate',1,requester)
776 else:
777 this.__set('separate',0,requester)
780 # Set output directory name
782 def setOutput(this,out,requester):
783 this.__set('output',out,requester)
786 # Set latex header name
788 def setHeader(this,head, requester):
789 this.__set('header',head,requester)
792 # Set or Clear Dependencies flag to generate makefile dependencies
794 def setDependencies(this, requester):
796 Set or Clear dependencies flag
799 if int(value) == 1:
800 this.__set('dependencies',1,requester)
801 else:
802 this.__set('dependencies',0,requester)
805 # Set tmp directory
807 def setTmp(this,dir, requester):
808 this.__set('tmp',dir,requester)
811 # Set mudela source file name
813 def setFilename(this,file, requester):
814 this.__set('filename',file,requester)
817 # Set title commands
819 def setTitles(this,titles, requester):
820 this.__set('titles',titles,requester)
823 # Set title commands
825 def addLilyOutputFiles(this,filelist,requester):
827 Add a to the lily output list
830 tmp = this.get('lilyOutputFiles')
831 tmp = tmp + filelist
832 this.__set('lilyOutputFiles',tmp,requester)
835 # Set/Clear postscript flag
837 def setPostscript(this,value,requester):
839 Set postscript flag
842 if int(value) == 1:
843 this.__set('postscript',1,requester)
844 else:
845 this.__set('postscript',0,requester)
848 # Set root
850 def setRoot(this,path, requester):
852 Set lilypond root directory
855 os.environ['LILYPONDPREFIX'] = path
856 this.__set('root',path,requester)
859 # printProps
861 def printProps(this):
863 Print properties
866 for key in this.__data.keys():
867 print "%s <%s>:<%s>" % (key,this.get(key),
868 this.__roverrideTable[this.__data[key][1]])
873 # Misc functions
876 def getLilyopts():
877 inc = ''
878 if len(Props.get('include')) > 0:
879 inc = string.join (map (lambda x: '-I "%s"' % x, Props.get('include')))
880 else:
882 if Props.get('dependencies'):
883 dep=' -d'
884 else:
885 dep=''
886 return inc + dep
887 return inc
889 def writeLilylog(contents):
890 if Props.get('keeplilypond'):
891 file='lilylog.' + str(os.getpid())
892 output = Props.get('output')
893 if output != '':
894 file = os.path.join( output, file )
895 try:
896 fd = open( file, 'w' )
897 except:
898 sys.exit('ExitNoWrite', file)
899 fd.write(contents)
900 fd.close()
902 def getTeXFile(contents):
903 texfiles=[]
904 for line in string.split(contents,'\n'):
905 m = re.search('^Paper output to (.+)\.\.\.', line)
906 if m:
907 texfiles.append(m.group(1))
909 if texfiles == []:
910 sys.exit('ExitNoTeXName')
911 else:
912 return texfiles
914 def program_id ():
915 return name + ' ' + version;
918 def mailaddress():
919 try:
920 return os.environ['MAILADDRESS']
921 except KeyError:
922 return '(address unknown)'
925 def identify ():
926 sys.stderr.write (program_id () + '\n')
928 def help ():
929 sys.stderr.write (
930 'Generate dvi file from mudela or lilypond output\n'
931 'Usage: ' + name + ' [OPTION]... [FILE]...\n'
932 '\n'
933 'Options:\n'
934 ' -D,--debug increase verbosity\n'
935 ' -F,--headers= name of additional LaTeX headers file\n'
936 ' -H,--Height= set paper height (points) (see manual page)\n'
937 ' -I,--include=DIR add DIR to LilyPond\'s search path\n'
938 ' -K,--keeplilypond keep lilypond output files\n'
939 ' -L,--landscape set landscape orientation\n'
940 ' -N,--nonumber switch off page numbering\n'
941 ' -O,--orientation= set orientation (obsolete - use -L instead)\n'
942 ' -P,--postscript generate postscript file\n'
943 ' -W,--Width= set paper width (points) (see manual page)\n'
944 ' -d,--dependencies tell lilypond make a dependencies file\n'
945 ' -h,--help this help text\n'
946 ' -k,--keeply2dvi keep ly2dvi output files\n'
947 ' -l,--language= give LaTeX language (babel)\n'
948 ' -o,--output= set output directory\n'
949 ' -p,--papersize= give LaTeX papersize (eg. a4)\n'
950 ' -s,--separate run all files separately through LaTeX\n'
951 '\n'
952 'files may be (a mix of) input to or output from lilypond(1)\n'
958 # main
961 def main():
962 """Generate dvi files from lilypond source/output"""
964 infile = Input()
965 outfile = TeXOutput()
966 texInputFiles=[]
968 (options, files) = getopt.getopt (sys.argv[1:],
969 'DF:H:I:KLNPW:dhkl:o:p:s',
970 ['debug', 'headers=', 'Height=',
971 'include=', 'keeplilypond', 'landscape',
972 'nonumber', 'Width=', 'dependencies',
973 'help', 'keeply2dvi', 'language=',
974 'output=', 'papersize=', 'separate',
975 'postscript'])
976 for opt in options:
977 o = opt[0]
978 a = opt[1]
979 if o == '--debug' or o == '-D':
980 Props.setDebug(1,'commandline')
981 elif o == '--headers' or o == '-F':
982 Props.setHeader(a,'commandline')
983 elif o == '--include' or o == '-I':
984 Props.setInclude(a,'commandline')
985 elif o == '--Height' or o == '-H':
986 Props.setTextHeight(a,'commandline')
987 elif o == '--keeplilypond' or o == '-K':
988 Props.setKeeplilypond(1,'commandline')
989 elif o == '--landscape' or o == '-L':
990 Props.setOrientation('landscape','commandline')
991 elif o == '--nonumber' or o == '-N':
992 Props.setNonumber('commandline')
993 elif o == '--Width' or o == '-W':
994 Props.setLineWidth(a,'commandline')
995 elif o == '--dependencies' or o == '-d':
996 Props.setDependencies(1,'commandline')
997 elif o == '--help' or o == '-h':
998 help()
999 return 0
1000 elif o == '--keeply2dvi' or o == '-k':
1001 Props.setKeeply2dvi(1,'commandline')
1002 elif o == '--language' or o == '-l':
1003 Props.setLanguage(a,'commandline')
1004 elif o == '--output' or o == '-o':
1005 Props.setOutput(a,'commandline')
1006 elif o == '--papersize' or o == '-p':
1007 Props.setPaperZize(a,'commandline')
1008 elif o == '--separate' or o == '-s':
1009 Props.setSeparate(1,'commandline')
1010 elif o == '--postscript' or o == '-P':
1011 Props.setPostscript(1,'commandline')
1013 if len(files):
1014 for file in files:
1015 infile.open(file)
1016 type = infile.type()
1017 infile.close()
1018 if type == 'source':
1019 if os.environ.has_key('OS') and \
1020 os.environ['OS'] == 'Windows_95':
1021 cmd = 'ash -c "lilypond %s %s 2>&1"' %(getLilyopts(), file)
1022 else:
1023 cmd = 'lilypond %s %s 2>&1' % (getLilyopts(), file)
1024 sys.stderr.write ('executing: %s\n'% cmd)
1026 fd = os.popen(cmd , 'r')
1027 log = ''
1029 s = fd.readline()
1030 while len(s) > 0:
1031 sys.stderr.write (s)
1032 sys.stderr.flush ()
1033 log = log + s
1034 s = fd.readline ()
1035 if 0:
1036 s = fd.read (1)
1037 while len(s) > 0:
1038 sys.stderr.write (s)
1039 sys.stderr.flush ()
1040 s = fd.read (1)
1041 log = log + s
1042 stat = fd.close()
1043 if stat:
1044 sys.exit('ExitBadLily', cmd )
1045 texFiles=getTeXFile(log)
1046 writeLilylog(log)
1047 Props.addLilyOutputFiles(texFiles,'program')
1048 texInputFiles = texInputFiles + texFiles
1049 else:
1050 texInputFiles.append(file)
1052 firstfile=1
1053 for file in texInputFiles:
1054 infile.open(file)
1055 infile.setVars() # first pass set variables
1056 infile.close()
1057 if Props.get('debug'):
1058 Props.printProps()
1059 if firstfile:
1060 outfile.start(file)
1061 else:
1062 outfile.next()
1063 outfile.write("""\
1064 \\input{%s}
1065 """ % (file))
1066 if Props.get('separate'):
1067 outfile.end()
1068 else:
1069 firstfile=0
1070 if not Props.get('separate'):
1071 outfile.end()
1072 else:
1073 help()
1074 sys.exit('ExitBadArgs','No files specified')
1077 # Exit values
1079 ExitTable = {
1080 'ExitInterupt' : ['Ouch!', 1 ],
1081 'ExitBadArgs' : ['Wrong number of arguments', 2 ],
1082 'ExitNotFound' : ['File not found', 3 ],
1083 'ExitBadPaper' : ['Unknown papersize', 4 ],
1084 'ExitBadHeight' : ['Invalid Height specification', 5 ],
1085 'ExitBadWidth' : ['Invalid Width specification', 6 ],
1086 'ExitBadOrient' : ['Invalid Orientation specification', 7 ],
1087 'ExitNoWrite' : ['Permission denied', 8 ],
1088 'ExitNoTeXName' : ['hmm, I could not find an output file name', 9 ],
1089 'ExitBadLily' : ['Lilypond failed', 10 ],
1090 'ExitBadLatex' : ['Latex failed', 11 ],
1091 'ExitBadPostscript' : ['Postscript failed', 12 ],
1092 'ExitUnknown' : ['Unknown Exit Code', 20 ],
1095 def cleanup():
1096 lilyfiles = []
1097 tmpfiles = []
1098 if not Props.get('keeplilypond'):
1099 lilyfiles = Props.get('lilyOutputFiles')
1100 if not Props.get('keeply2dvi'):
1101 tmpfiles = glob.glob('*.' + str(os.getpid()) + '.*' )
1102 for file in lilyfiles + tmpfiles:
1103 if os.path.isfile(file):
1104 os.remove(file)
1107 identify()
1108 Props = Properties()
1110 try:
1111 main()
1113 except KeyboardInterrupt:
1114 print ExitTable['ExitInterupt'][0]
1115 cleanup()
1116 sys.exit(ExitTable['ExitInterupt'][1])
1118 except SystemExit, errno:
1119 if ExitTable.has_key(errno.args[0]):
1120 msg = ExitTable[errno.args[0]]
1121 else:
1122 msg = ExitTable['ExitUnknown']
1123 if len(errno.args) > 1:
1124 sys.stderr.write( '%s: %s: %s\n' % (name, msg[0], errno.args[1]))
1125 else:
1126 sys.stderr.write( '%s %s\n' % (name, msg[0]))
1127 if Props.get('debug'):
1128 Props.printProps()
1129 cleanup()
1130 sys.exit(msg[1])
1131 else:
1132 cleanup()