]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
1e9a7329b32ac968d6c4c6cea4085434977d5a8a
[lilypond.git] / scripts / ly2dvi.py
1 #!@PYTHON@
2 # Run lilypond, latex, dvips.
3 #
4 # This is the third incarnation of ly2dvi.
5 #
6 # Earlier incarnations of ly2dvi were written by
7 # Jeffrey B. Reed<daboys@austin.rr.com> (Python version)
8 # Jan Arne Fagertun <Jan.A.Fagertun@@energy.sintef.no> (Bourne shell script)
9 #
10
11
12
13 # TODO: should allow to set a central pk cache directory from the command line.
14 # TODO: should allow to switch off pk cache.
15 #
16
17
18 # Note: gettext work best if we use ' for docstrings and "
19 #       for gettextable strings.
20 #       --> DO NOT USE """ for docstrings.
21
22 '''
23 TODO:
24
25   * figure out which set of command line options should make ly2dvi:
26
27       na: create tex only?  
28       na: create latex only? 
29       na: create tex and latex
30       default: create dvi only
31       na: create tex, latex and dvi
32       -P: create dvi and ps
33       na: * create ps only
34
35      etc.
36
37      for foo.ly, rename ly2dvi.dir to out-ly2dvi, foo.ly2dvi, foo.dir ?
38      
39   * move versatile taglines, 
40   
41      \header {
42         beginfooter=\mutopiaPD
43         endfooter=\tagline  -> 'lily was here <version>'
44      }
45
46      lilytagline (->lily was here), usertagline, copyright etc.
47
48   * head/header tagline/endfooter
49
50   * dvi from lilypond .tex output?  This is hairy, because we create dvi
51     from lilypond .tex *and* header output.
52
53   * multiple \score blocks?
54   
55 '''
56
57
58 import os
59 import stat
60 import string
61 import re
62 import getopt
63 import sys
64 import shutil
65 import __main__
66 import operator
67 import tempfile
68 import traceback
69
70 datadir = '@datadir@'
71 sys.path.append (datadir + '/python')
72 try:
73         import gettext
74         gettext.bindtextdomain ('lilypond', '@localedir@')
75         gettext.textdomain('lilypond')
76         _ = gettext.gettext
77 except:
78         def _ (s):
79                 return s
80
81
82 layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle',
83           'footer', 'head', 'composer', 'arranger', 'instrument',
84           'opus', 'piece', 'metre', 'meter', 'poet', 'texttranslator']
85
86
87 # init to empty; values here take precedence over values in the file
88
89 ## TODO: change name.
90 extra_init = {
91         'language' : [],
92         'latexheaders' : [],
93         'latexpackages' :  ['geometry'],
94         'latexoptions' : [],
95         'papersize' : [],
96         'pagenumber' : [1],
97         'textheight' : [], 
98         'linewidth' : [],
99         'orientation' : []
100 }
101
102 extra_fields = extra_init.keys ()
103
104 fields = layout_fields + extra_fields
105 program_name = 'ly2dvi'
106 help_summary = _ ("Generate .dvi with LaTeX for LilyPond")
107
108 include_path = ['.']
109 lily_p = 1
110 paper_p = 1
111 cache_pks_p = 1
112
113 PK_PATTERN='feta.*\.[0-9]+pk'
114
115 output_name = ''
116 targets = {
117         'DVI' : 0,
118         'LATEX' : 0,
119         'MIDI' : 0,
120         'TEX' : 0,
121         }
122
123 track_dependencies_p = 0
124 dependency_files = []
125
126
127 # lily_py.py -- options and stuff
128
129 # source file of the GNU LilyPond music typesetter
130
131 # BEGIN Library for these?
132 # cut-n-paste from ly2dvi
133
134 program_version = '@TOPLEVEL_VERSION@'
135 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
136         program_version = '1.3.148'
137
138
139 original_dir = os.getcwd ()
140 temp_dir = os.path.join (original_dir,  '%s.dir' % program_name)
141
142 keep_temp_dir_p = 0
143 verbose_p = 0
144
145 #
146 # Try to cater for bad installations of LilyPond, that have
147 # broken TeX setup.  Just hope this doesn't hurt good TeX
148 # setups.  Maybe we should check if kpsewhich can find
149 # feta16.{afm,mf,tex,tfm}, and only set env upon failure.
150 #
151 environment = {
152         'MFINPUTS' : datadir + '/mf' + ':',
153         'TEXINPUTS': datadir + '/tex:' + datadir + '/ps' + ':',
154         'TFMFONTS' : datadir + '/tfm' + ':',
155         'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
156         'GS_LIB' : datadir + '/ps',
157 }
158
159 def setup_environment ():
160         for key in environment.keys ():
161                 val = environment[key]
162                 if os.environ.has_key (key):
163                         val = os.environ[key] + os.pathsep + val 
164                 os.environ[key] = val
165
166 def identify ():
167         sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
168
169 def warranty ():
170         identify ()
171         sys.stdout.write ('\n')
172         sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001'))
173         sys.stdout.write ('\n')
174         sys.stdout.write ('  Han-Wen Nienhuys')
175         sys.stdout.write ('  Jan Nieuwenhuizen')
176         sys.stdout.write ('\n')
177         sys.stdout.write (_ (r'''
178 Distributed under terms of the GNU General Public License. It comes with
179 NO WARRANTY.'''))
180         sys.stdout.write ('\n')
181
182 if ( os.name == 'posix' ):
183         errorport=sys.stderr
184 else:
185         errorport=sys.stdout
186
187 def progress (s):
188         errorport.write (s + '\n')
189
190 def warning (s):
191         progress (_ ("warning: ") + s)
192                 
193 def error (s):
194
195
196         '''Report the error S.  Exit by raising an exception. Please
197         do not abuse by trying to catch this error. If you do not want
198         a stack trace, write to the output directly.
199
200         RETURN VALUE
201
202         None
203         
204         '''
205         
206         progress (_ ("error: ") + s)
207         raise _ ("Exiting ... ")
208
209 def getopt_args (opts):
210         '''Construct arguments (LONG, SHORT) for getopt from  list of options.'''
211         short = ''
212         long = []
213         for o in opts:
214                 if o[1]:
215                         short = short + o[1]
216                         if o[0]:
217                                 short = short + ':'
218                 if o[2]:
219                         l = o[2]
220                         if o[0]:
221                                 l = l + '='
222                         long.append (l)
223         return (short, long)
224
225 def option_help_str (o):
226         '''Transform one option description (4-tuple ) into neatly formatted string'''
227         sh = '  '       
228         if o[1]:
229                 sh = '-%s' % o[1]
230
231         sep = ' '
232         if o[1] and o[2]:
233                 sep = ','
234                 
235         long = ''
236         if o[2]:
237                 long= '--%s' % o[2]
238
239         arg = ''
240         if o[0]:
241                 if o[2]:
242                         arg = '='
243                 arg = arg + o[0]
244         return '  ' + sh + sep + long + arg
245
246
247 def options_help_str (opts):
248         '''Convert a list of options into a neatly formatted string'''
249         w = 0
250         strs =[]
251         helps = []
252
253         for o in opts:
254                 s = option_help_str (o)
255                 strs.append ((s, o[3]))
256                 if len (s) > w:
257                         w = len (s)
258
259         str = ''
260         for s in strs:
261                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
262         return str
263
264 def help ():
265         ls = [(_ ("Usage: %s [OPTION]... FILE") % program_name),
266                 ('\n\n'),
267                 (help_summary),
268                 ('\n\n'),
269                 (_ ("Options:")),
270                 ('\n'),
271                 (options_help_str (option_definitions)),
272                 ('\n\n'),
273                 (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org'),
274                 ('\n')]
275         map (sys.stdout.write, ls)
276         
277 def setup_temp ():
278         """
279         Create a temporary directory, and return its name. 
280         """
281         global temp_dir
282         if not keep_temp_dir_p:
283                 temp_dir = tempfile.mktemp (program_name)
284         try:
285                 os.mkdir (temp_dir, 0777)
286         except OSError:
287                 pass
288
289         return temp_dir
290
291
292 def system (cmd, ignore_error = 0):
293         """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero.
294
295         RETURN VALUE
296
297         Exit status of CMD
298         """
299         
300         if ( os.name != 'posix' ):
301                 cmd = re.sub (r'''\\''', r'''\\\\\\''', cmd)
302                 cmd = "sh -c \'%s\'" % cmd
303
304                 
305         if verbose_p:
306                 progress (_ ("Invoking `%s\'") % cmd)
307         st = os.system (cmd)
308         if st:
309                 name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
310                 msg = name + ': ' + _ ("command exited with value %d") % st
311                 if ignore_error:
312                         warning (msg + ' ' + _ ("(ignored)") + ' ')
313                 else:
314                         error (msg)
315
316         return st
317
318
319 def cleanup_temp ():
320         if not keep_temp_dir_p:
321                 if verbose_p:
322                         progress (_ ("Cleaning %s...") % temp_dir)
323                 shutil.rmtree (temp_dir)
324
325
326 #what a name.
327 def set_setting (dict, key, val):
328         try:
329                 val = string.atof (val)
330         except ValueError:
331                 #warning (_ ("invalid value: %s") % `val`)
332                 pass
333
334         try:
335                 dict[key].append (val)
336         except KeyError:
337                 warning (_ ("no such setting: %s") % `key`)
338                 dict[key] = [val]
339
340
341 def strip_extension (f, ext):
342         (p, e) = os.path.splitext (f)
343         if e == ext:
344                 e = ''
345         return p + e
346
347 # END Library
348
349 option_definitions = [
350         ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")),
351         ('', 'h', 'help', _ ("this help")),
352         (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
353         ('', 'k', 'keep', _ ("keep all output, and name the directory %s.dir") % program_name),
354         ('', '', 'no-lily', _ ("don't run LilyPond")),
355         ('', 'm', 'no-paper', _ ("produce MIDI output only")),
356         (_ ("FILE"), 'o', 'output', _ ("write ouput to FILE")),
357         (_ ("FILE"), 'f', 'find-pfa', _ ("find pfa fonts used in FILE")),
358         # why capital P?
359         ('', 'P', 'postscript', _ ("generate PostScript output")),
360         (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
361         ('', 'V', 'verbose', _ ("verbose")),
362         ('', 'v', 'version', _ ("print version number")),
363         ('', 'w', 'warranty', _ ("show warranty and copyright")),
364         ]
365
366 def run_lilypond (files, outbase, dep_prefix):
367         opts = ''
368 #       opts = opts + '--output=%s.tex' % outbase
369         opts = opts + ' ' + string.join (map (lambda x : '-I ' + x,
370                                               include_path))
371         if paper_p:
372                 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
373                                                       fields))
374         else:
375                 opts = opts + ' --no-paper'
376                 
377         if track_dependencies_p:
378                 opts = opts + " --dependencies"
379                 if dep_prefix:
380                         opts = opts + ' --dep-prefix=%s' % dep_prefix
381
382         fs = string.join (files)
383
384         if not verbose_p:
385                 progress ( _("Running %s...") % 'LilyPond')
386                 # cmd = cmd + ' 1> /dev/null 2> /dev/null'
387         else:
388                 opts = opts + ' --verbose'
389         
390         system ('lilypond %s %s ' % (opts, fs))
391
392 def analyse_lilypond_output (filename, extra):
393         
394         # urg
395         '''Grep FILENAME for interesting stuff, and
396         put relevant info into EXTRA.'''
397         filename = filename+'.tex'
398         progress (_ ("Analyzing %s...") % filename)
399         s = open (filename).read ()
400
401         # search only the first 10k
402         s = s[:10240]
403         for x in ('textheight', 'linewidth', 'papersize', 'orientation'):
404                 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
405                 if m:
406                         set_setting (extra, x, m.group (1))
407
408 def find_tex_files_for_base (base, extra):
409
410         """
411         Find the \header fields dumped from BASE.
412         """
413         
414         headerfiles = {}
415         for f in layout_fields:
416                 if os.path.exists (base + '.' + f):
417                         headerfiles[f] = base+'.'+f
418
419         if os.path.exists (base  +'.dep'):
420                 dependency_files.append (base + '.dep')
421
422         for f in extra_fields:
423                 if os.path.exists (base + '.' + f):
424                         extra[f].append (open (base + '.' + f).read ())
425         
426         return (base  +'.tex',headerfiles)
427          
428
429 def find_tex_files (files, extra):
430         """
431         Find all .tex files whose prefixes start with some name in FILES. 
432
433         """
434         
435         tfiles = []
436         
437         for f in files:
438                 x = 0
439                 while 1:
440                         fname = os.path.basename (f)
441                         fname = strip_extension (fname, '.ly')
442                         if x:
443                                 fname = fname + '-%d' % x
444
445                         if os.path.exists (fname + '.tex'):
446                                 tfiles.append (find_tex_files_for_base (fname, extra))
447                                 analyse_lilypond_output (fname, extra)
448                         else:
449                                 break
450
451                         x = x + 1
452         if not x:
453                 fstr = string.join (files, ', ')
454                 warning (_ ("no lilypond output found for %s") % fstr)
455         return tfiles
456
457 def one_latex_definition (defn, first):
458         s = '\n'
459         for (k,v) in defn[1].items ():
460                 val = open (v).read ()
461                 if (string.strip (val)):
462                         s = s + r'''\def\lilypond%s{%s}''' % (k, val)
463                 else:
464                         s = s + r'''\let\lilypond%s\relax''' % k
465                 s = s + '\n'
466
467         if first:
468                 s = s + '\\def\\mustmakelilypondtitle{}\n'
469         else:
470                 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
471                 
472         s = s + '\\input %s\n' % defn[0] # The final \n seems important here. It ensures that the footers and taglines end up on the right page.
473         return s
474
475
476 ly_paper_to_latexpaper =  {
477         'a4' : 'a4paper',
478         'letter' : 'letterpaper', 
479 }
480
481 def global_latex_definition (tfiles, extra):
482
483         '''construct preamble from EXTRA, dump Latex stuff for each
484 lily output file in TFILES after that, and return the Latex file constructed.  '''
485
486
487         s = ""
488         s = s + '% generation tag\n'
489
490         options = ''
491
492         if extra['papersize']:
493                 try:
494                         options = '%s' % ly_paper_to_latexpaper[extra['papersize'][0]]
495                 except KeyError:
496                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
497                         pass
498
499         if extra['latexoptions']:
500                 options = options + ',' + extra['latexoptions'][-1]
501
502         s = s + '\\documentclass[%s]{article}\n' % options
503
504         if extra['language']:
505                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
506
507
508         s = s + '\\usepackage{%s}\n' \
509                 % string.join (extra['latexpackages'], ',')
510
511         if extra['latexheaders']:
512                 s = s + '\\include{%s}\n' \
513                         % string.join (extra['latexheaders'], '}\n\\include{')
514
515         textheight = ''
516         if extra['textheight']:
517                 textheight = ',textheight=%fpt' % extra['textheight'][0]
518
519         orientation = 'portrait'
520         if extra['orientation']:
521                 orientation = extra['orientation'][0]
522
523         # set sane geometry width (a4-width) for linewidth = -1.
524         maxlw = max (extra['linewidth'] + [-1])
525         if maxlw < 0:
526                 # who the hell is 597 ?
527                 linewidth = '597'
528         else:
529                 linewidth = maxlw
530         s = s + '\geometry{width=%spt%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
531
532         if extra['latexoptions']:
533                 s = s + '\geometry{twosideshift=4mm}\n'
534
535         s = s + r'''
536 \usepackage[latin1]{inputenc}
537 \input{titledefs}
538 '''
539         
540         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
541                 s = s + '\\pagestyle{plain}\n'
542         else:
543                 s = s + '\\pagestyle{empty}\n'
544
545         s = s + '\\begin{document}\n'
546         s = s + '\\thispagestyle{firstpage}\n'
547
548         first = 1
549         for t in tfiles:
550                 s = s + one_latex_definition (t, first)
551                 first = 0
552
553
554         s = s + '\\thispagestyle{lastpage}\n'
555         s = s + '\\end{document}'
556
557         return s
558
559 def run_latex (files, outbase, extra):
560
561         """Construct latex file, for FILES and EXTRA, dump it into
562 OUTBASE.latex. Run LaTeX on it.
563
564 RETURN VALUE
565
566 None
567         """
568         latex_fn = outbase + '.latex'
569         
570         wfs = find_tex_files (files, extra)
571         s = global_latex_definition (wfs, extra)
572
573         f = open (latex_fn, 'w')
574         f.write (s)
575         f.close ()
576
577         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
578
579         if not verbose_p and os.name == 'posix':
580                 progress ( _("Running %s...") % 'LaTeX')
581                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
582
583         system (cmd)
584
585 def run_dvips (outbase, extra):
586
587
588         """Run dvips using the correct options taken from EXTRA,
589 leaving a PS file in OUTBASE.ps
590
591 RETURN VALUE
592
593 None.
594 """
595         opts = ''
596         if extra['papersize']:
597                 opts = opts + ' -t%s' % extra['papersize'][0]
598
599         if extra['orientation'] and extra['orientation'][0] == 'landscape':
600                 opts = opts + ' -tlandscape'
601
602         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
603         
604         if not verbose_p and os.name == 'posix':
605                 progress ( _("Running %s...") % 'dvips')
606                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
607                 
608         system (cmd)
609
610 def generate_dependency_file (depfile, outname):
611         df = open (depfile, 'w')
612         df.write (outname + ':' )
613         
614         for d in dependency_files:
615                 s = open (d).read ()
616                 s = re.sub ('#[^\n]*\n', '', s)
617                 s = re.sub (r'\\\n', ' ', s)
618                 m = re.search ('.*:(.*)\n', s)
619
620                 # ugh. Different targets?
621                 if m:
622                         df.write ( m.group (1)  + ' ' )
623
624         df.write ('\n')
625         df.close ();
626
627 def find_file_in_path (path, name):
628         for d in string.split (path, os.pathsep):
629                 if name in os.listdir (d):
630                         return os.path.join (d, name)
631
632 # Added as functionality to ly2dvi, because ly2dvi may well need to do this
633 # in future too.
634 PS = '%!PS-Adobe'
635 def find_pfa_fonts (name):
636         s = open (name).read ()
637         if s[:len (PS)] != PS:
638                 # no ps header?
639                 errorport.write (_( "error: ") + _ ("not a PostScript file: `%s\'" % name))
640                 errorport.write ('\n')
641                 sys.exit (1)
642         here = 0
643         m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
644         pfa = []
645         while m:
646                 here = m.end (1)
647                 pfa.append (m.group (1))
648                 m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
649         return pfa
650
651         
652 (sh, long) = getopt_args (__main__.option_definitions)
653 try:
654         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
655 except getopt.error, s:
656         errorport.write ('\n')
657         errorport.write (_( "error: ") + _ ("getopt says: `%s\'" % s))
658         errorport.write ('\n')
659         errorport.write ('\n')
660         help ()
661         sys.exit (2)
662         
663 for opt in options:     
664         o = opt[0]
665         a = opt[1]
666
667         if 0:
668                 pass
669         elif o == '--help' or o == '-h':
670                 help ()
671                 sys.exit (0)
672         elif o == '--find-pfa' or o == '-f':
673                 fonts = map (lambda x: x + '.pfa', find_pfa_fonts (a))
674                 files = map (lambda x:
675                              find_file_in_path (os.environ['GS_FONTPATH'], x),
676                              fonts)
677                 print string.join (files, ' ')
678                 sys.exit (0)
679         elif o == '--include' or o == '-I':
680                 include_path.append (a)
681         elif o == '--postscript' or o == '-P':
682                 targets['PS'] = 0
683         elif o == '--keep' or o == '-k':
684                 keep_temp_dir_p = 1
685         elif o == '--no-lily':
686                 lily_p = 0
687         elif o == '--no-paper' or o == '-m':
688                 targets = {}
689                 targets['MIDI'] = 0
690                 paper_p = 0
691         elif o == '--output' or o == '-o':
692                 output_name = a
693         elif o == '--set' or o == '-s':
694                 ss = string.split (a, '=')
695                 set_setting (extra_init, ss[0], ss[1])
696         elif o == '--dependencies' or o == '-d':
697                 track_dependencies_p = 1
698         elif o == '--verbose' or o == '-V':
699                 verbose_p = 1
700         elif o == '--version' or o == '-v':
701                 identify ()
702                 sys.exit (0)
703         elif o == '--warranty' or o == '-w':
704                 status = system ('lilypond -w', ignore_error = 1)
705                 if status:
706                         warranty ()
707
708                 sys.exit (0)
709
710
711 def cp_to_dir (pattern, dir):
712         "Copy files matching re PATTERN from cwd to DIR"
713         # Duh.  Python style portable: cp *.EXT OUTDIR
714         # system ('cp *.%s %s' % (ext, outdir), 1)
715         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
716         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
717
718 # Python < 1.5.2 compatibility
719 #
720 # On most platforms, this is equivalent to
721 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
722 if os.path.__dict__.has_key ('abspath'):
723         abspath = os.path.abspath
724 else:
725         def abspath (path):
726                 return os.path.normpath (os.path.join (os.getcwd (), path))
727
728 if os.__dict__.has_key ('makedirs'):
729         makedirs = os.makedirs
730 else:
731         def makedirs (dir, mode=0777):
732                 system ('mkdir -p %s' % dir)
733
734 def mkdir_p (dir, mode=0777):
735         if not os.path.isdir (dir):
736                 makedirs (dir, mode)
737
738 include_path = map (abspath, include_path)
739
740 original_output = output_name
741
742
743 if files and files[0] != '-':
744
745         # Ugh, maybe make a setup () function
746         files = map (lambda x: strip_extension (x, '.ly'), files)
747
748         (outdir, outbase) = ('','')
749         if not output_name:
750                 outbase = os.path.basename (files[0])
751                 outdir = abspath('.')
752         elif output_name[-1] == os.sep:
753                 outdir = abspath (output_name)
754                 outbase = os.path.basename (files[0])
755         else:
756                 (outdir, outbase) = os.path.split (abspath (output_name))
757
758         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
759                 output_name = strip_extension (output_name, i)
760
761         files = map (abspath, files) 
762
763         if os.path.dirname (output_name) != '.':
764                 dep_prefix = os.path.dirname (output_name)
765         else:
766                 dep_prefix = 0
767
768         reldir = os.path.dirname (output_name)
769         if outdir != '.' and (track_dependencies_p or targets.keys ()):
770                 mkdir_p (outdir, 0777)
771
772         setup_environment ()
773         tmpdir = setup_temp ()
774         if cache_pks_p :
775                 os.chdir (outdir)
776                 cp_to_dir (PK_PATTERN, tmpdir)
777
778         os.chdir (tmpdir)
779         
780         if lily_p:
781                 try:
782                         run_lilypond (files, outbase, dep_prefix)
783                 except:
784                         # TODO: friendly message about LilyPond setup/failing?
785                         #
786                         # TODO: lilypond should fail with different
787                         # error codes for:
788                         #   - guile setup/startup failure
789                         #   - font setup failure
790                         #   - init.ly setup failure
791                         #   - parse error in .ly
792                         #   - unexpected: assert/core dump
793                         targets = {}
794                         traceback.print_exc ()
795
796         if targets.has_key ('DVI') or targets.has_key ('PS'):
797                 try:
798                         run_latex (files, outbase, extra_init)
799                         # unless: add --tex, or --latex?
800                         del targets['TEX']
801                         del targets['LATEX']
802                 except:
803                         # TODO: friendly message about TeX/LaTeX setup,
804                         # trying to run tex/latex by hand
805                         if targets.has_key ('DVI'):
806                                 del targets['DVI']
807                         if targets.has_key ('PS'):
808                                 del targets['PS']
809                         traceback.print_exc ()
810
811         if targets.has_key ('PS'):
812                 try:
813                         run_dvips (outbase, extra_init)
814                 except: 
815                         if targets.has_key ('PS'):
816                                 del targets['PS']
817                         traceback.print_exc ()
818
819         # add DEP to targets?
820         if track_dependencies_p:
821                 depfile = os.path.join (outdir, outbase + '.dep')
822                 generate_dependency_file (depfile, depfile)
823                 if os.path.isfile (depfile):
824                         progress (_ ("dependencies output to `%s'...") % depfile)
825
826         # Hmm, if this were a function, we could call it the except: clauses
827         for i in targets.keys ():
828                 ext = string.lower (i)
829                 cp_to_dir ('.*\.%s$' % ext, outdir)
830                 outname = outbase + '.' + string.lower (i)
831                 abs = os.path.join (outdir, outname)
832                 if reldir != '.':
833                         outname = os.path.join (reldir, outname)
834                 if os.path.isfile (abs):
835                         progress (_ ("%s output to `%s'...") % (i, outname))
836                 elif verbose_p:
837                         warning (_ ("can't find file: `%s'") % outname)
838                         
839                 if cache_pks_p:
840                         cp_to_dir (PK_PATTERN, outdir)
841                 
842         os.chdir (original_dir)
843         cleanup_temp ()
844         
845 else:
846         # FIXME: read from stdin when files[0] = '-'
847         help ()
848         errorport.write ("ly2dvi: " + _ ("error: ") + _ ("no files specified on command line.") + '\n')
849         sys.exit (2)
850
851
852