]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
patch::: 1.5.6.jcn2
[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 errorport=sys.stderr
183
184 def progress (s):
185         errorport.write (s + '\n')
186
187 def warning (s):
188         progress (_ ("warning: ") + s)
189                 
190 def error (s):
191
192
193         '''Report the error S.  Exit by raising an exception. Please
194         do not abuse by trying to catch this error. If you do not want
195         a stack trace, write to the output directly.
196
197         RETURN VALUE
198
199         None
200         
201         '''
202         
203         progress (_ ("error: ") + s)
204         raise _ ("Exiting ... ")
205
206 def getopt_args (opts):
207         '''Construct arguments (LONG, SHORT) for getopt from  list of options.'''
208         short = ''
209         long = []
210         for o in opts:
211                 if o[1]:
212                         short = short + o[1]
213                         if o[0]:
214                                 short = short + ':'
215                 if o[2]:
216                         l = o[2]
217                         if o[0]:
218                                 l = l + '='
219                         long.append (l)
220         return (short, long)
221
222 def option_help_str (o):
223         '''Transform one option description (4-tuple ) into neatly formatted string'''
224         sh = '  '       
225         if o[1]:
226                 sh = '-%s' % o[1]
227
228         sep = ' '
229         if o[1] and o[2]:
230                 sep = ','
231                 
232         long = ''
233         if o[2]:
234                 long= '--%s' % o[2]
235
236         arg = ''
237         if o[0]:
238                 if o[2]:
239                         arg = '='
240                 arg = arg + o[0]
241         return '  ' + sh + sep + long + arg
242
243
244 def options_help_str (opts):
245         '''Convert a list of options into a neatly formatted string'''
246         w = 0
247         strs =[]
248         helps = []
249
250         for o in opts:
251                 s = option_help_str (o)
252                 strs.append ((s, o[3]))
253                 if len (s) > w:
254                         w = len (s)
255
256         str = ''
257         for s in strs:
258                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
259         return str
260
261 def help ():
262         ls = [(_ ("Usage: %s [OPTION]... FILE") % program_name),
263                 ('\n\n'),
264                 (help_summary),
265                 ('\n\n'),
266                 (_ ("Options:")),
267                 ('\n'),
268                 (options_help_str (option_definitions)),
269                 ('\n\n'),
270                 (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org'),
271                 ('\n')]
272         map (sys.stdout.write, ls)
273         
274 def setup_temp ():
275         """
276         Create a temporary directory, and return its name. 
277         """
278         global temp_dir
279         if not keep_temp_dir_p:
280                 temp_dir = tempfile.mktemp (program_name)
281         try:
282                 os.mkdir (temp_dir, 0777)
283         except OSError:
284                 pass
285
286         return temp_dir
287
288
289 def system (cmd, ignore_error = 0):
290         """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero.
291
292         RETURN VALUE
293
294         Exit status of CMD
295         """
296         
297         if verbose_p:
298                 progress (_ ("Invoking `%s\'") % cmd)
299         st = os.system (cmd)
300         if st:
301                 name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
302                 msg = name + ': ' + _ ("command exited with value %d") % st
303                 if ignore_error:
304                         warning (msg + ' ' + _ ("(ignored)") + ' ')
305                 else:
306                         error (msg)
307
308         return st
309
310
311 def cleanup_temp ():
312         if not keep_temp_dir_p:
313                 if verbose_p:
314                         progress (_ ("Cleaning %s...") % temp_dir)
315                 shutil.rmtree (temp_dir)
316
317
318 #what a name.
319 def set_setting (dict, key, val):
320         try:
321                 val = string.atof (val)
322         except ValueError:
323                 #warning (_ ("invalid value: %s") % `val`)
324                 pass
325
326         try:
327                 dict[key].append (val)
328         except KeyError:
329                 warning (_ ("no such setting: %s") % `key`)
330                 dict[key] = [val]
331
332
333 def strip_extension (f, ext):
334         (p, e) = os.path.splitext (f)
335         if e == ext:
336                 e = ''
337         return p + e
338
339 # END Library
340
341 option_definitions = [
342         ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")),
343         ('', 'h', 'help', _ ("this help")),
344         (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
345         ('', 'k', 'keep', _ ("keep all output, and name the directory %s.dir") % program_name),
346         ('', '', 'no-lily', _ ("don't run LilyPond")),
347         ('', 'm', 'no-paper', _ ("produce MIDI output only")),
348         (_ ("FILE"), 'o', 'output', _ ("write ouput to FILE")),
349         (_ ("FILE"), 'f', 'find-pfa', _ ("find pfa fonts used in FILE")),
350         # why capital P?
351         ('', 'P', 'postscript', _ ("generate PostScript output")),
352         (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
353         ('', 'V', 'verbose', _ ("verbose")),
354         ('', 'v', 'version', _ ("print version number")),
355         ('', 'w', 'warranty', _ ("show warranty and copyright")),
356         ]
357
358 def run_lilypond (files, outbase, dep_prefix):
359         opts = ''
360 #       opts = opts + '--output=%s.tex' % outbase
361         opts = opts + ' ' + string.join (map (lambda x : '-I ' + x,
362                                               include_path))
363         if paper_p:
364                 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
365                                                       fields))
366         else:
367                 opts = opts + ' --no-paper'
368                 
369         if track_dependencies_p:
370                 opts = opts + " --dependencies"
371                 if dep_prefix:
372                         opts = opts + ' --dep-prefix=%s' % dep_prefix
373
374         fs = string.join (files)
375
376         if not verbose_p:
377                 progress ( _("Running %s...") % 'LilyPond')
378                 # cmd = cmd + ' 1> /dev/null 2> /dev/null'
379         else:
380                 opts = opts + ' --verbose'
381         
382         system ('lilypond %s %s ' % (opts, fs))
383
384 def analyse_lilypond_output (filename, extra):
385         
386         # urg
387         '''Grep FILENAME for interesting stuff, and
388         put relevant info into EXTRA.'''
389         filename = filename+'.tex'
390         progress (_ ("Analyzing %s...") % filename)
391         s = open (filename).read ()
392
393         # search only the first 10k
394         s = s[:10240]
395         for x in ('textheight', 'linewidth', 'papersize', 'orientation'):
396                 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
397                 if m:
398                         set_setting (extra, x, m.group (1))
399
400 def find_tex_files_for_base (base, extra):
401
402         """
403         Find the \header fields dumped from BASE.
404         """
405         
406         headerfiles = {}
407         for f in layout_fields:
408                 if os.path.exists (base + '.' + f):
409                         headerfiles[f] = base+'.'+f
410
411         if os.path.exists (base  +'.dep'):
412                 dependency_files.append (base + '.dep')
413
414         for f in extra_fields:
415                 if os.path.exists (base + '.' + f):
416                         extra[f].append (open (base + '.' + f).read ())
417         
418         return (base  +'.tex',headerfiles)
419          
420
421 def find_tex_files (files, extra):
422         """
423         Find all .tex files whose prefixes start with some name in FILES. 
424
425         """
426         
427         tfiles = []
428         
429         for f in files:
430                 x = 0
431                 while 1:
432                         fname = os.path.basename (f)
433                         fname = strip_extension (fname, '.ly')
434                         if x:
435                                 fname = fname + '-%d' % x
436
437                         if os.path.exists (fname + '.tex'):
438                                 tfiles.append (find_tex_files_for_base (fname, extra))
439                                 analyse_lilypond_output (fname, extra)
440                         else:
441                                 break
442
443                         x = x + 1
444         if not x:
445                 fstr = string.join (files, ', ')
446                 warning (_ ("no lilypond output found for %s") % fstr)
447         return tfiles
448
449 def one_latex_definition (defn, first):
450         s = '\n'
451         for (k,v) in defn[1].items ():
452                 val = open (v).read ()
453                 if (string.strip (val)):
454                         s = s + r'''\def\lilypond%s{%s}''' % (k, val)
455                 else:
456                         s = s + r'''\let\lilypond%s\relax''' % k
457                 s = s + '\n'
458
459         if first:
460                 s = s + '\\def\\mustmakelilypondtitle{}\n'
461         else:
462                 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
463                 
464         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.
465         return s
466
467
468 ly_paper_to_latexpaper =  {
469         'a4' : 'a4paper',
470         'letter' : 'letterpaper', 
471 }
472
473 def global_latex_definition (tfiles, extra):
474
475         '''construct preamble from EXTRA, dump Latex stuff for each
476 lily output file in TFILES after that, and return the Latex file constructed.  '''
477
478
479         s = ""
480         s = s + '% generation tag\n'
481
482         options = ''
483
484         if extra['papersize']:
485                 try:
486                         options = '%s' % ly_paper_to_latexpaper[extra['papersize'][0]]
487                 except KeyError:
488                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
489                         pass
490
491         if extra['latexoptions']:
492                 options = options + ',' + extra['latexoptions'][-1]
493
494         s = s + '\\documentclass[%s]{article}\n' % options
495
496         if extra['language']:
497                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
498
499
500         s = s + '\\usepackage{%s}\n' \
501                 % string.join (extra['latexpackages'], ',')
502
503         if extra['latexheaders']:
504                 s = s + '\\include{%s}\n' \
505                         % string.join (extra['latexheaders'], '}\n\\include{')
506
507         textheight = ''
508         if extra['textheight']:
509                 textheight = ',textheight=%fpt' % extra['textheight'][0]
510
511         orientation = 'portrait'
512         if extra['orientation']:
513                 orientation = extra['orientation'][0]
514
515         # set sane geometry width (a4-width) for linewidth = -1.
516         maxlw = max (extra['linewidth'] + [-1])
517         if maxlw < 0:
518                 # who the hell is 597 ?
519                 linewidth = '597'
520         else:
521                 linewidth = maxlw
522         s = s + '\geometry{width=%spt%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
523
524         if extra['latexoptions']:
525                 s = s + '\geometry{twosideshift=4mm}\n'
526
527         s = s + r'''
528 \usepackage[latin1]{inputenc}
529 \input{titledefs}
530 '''
531         
532         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
533                 s = s + '\setcounter{page}{%s}\n' % (extra['pagenumber'][-1])
534                 s = s + '\\pagestyle{plain}\n'
535         else:
536                 s = s + '\\pagestyle{empty}\n'
537
538         s = s + '\\begin{document}\n'
539         s = s + '\\thispagestyle{firstpage}\n'
540
541         first = 1
542         for t in tfiles:
543                 s = s + one_latex_definition (t, first)
544                 first = 0
545
546
547         s = s + '\\thispagestyle{lastpage}\n'
548         s = s + '\\end{document}'
549
550         return s
551
552 def run_latex (files, outbase, extra):
553
554         """Construct latex file, for FILES and EXTRA, dump it into
555 OUTBASE.latex. Run LaTeX on it.
556
557 RETURN VALUE
558
559 None
560         """
561         latex_fn = outbase + '.latex'
562         
563         wfs = find_tex_files (files, extra)
564         s = global_latex_definition (wfs, extra)
565
566         f = open (latex_fn, 'w')
567         f.write (s)
568         f.close ()
569
570         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
571
572         if not verbose_p:
573                 progress ( _("Running %s...") % 'LaTeX')
574                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
575
576         system (cmd)
577
578 def run_dvips (outbase, extra):
579
580
581         """Run dvips using the correct options taken from EXTRA,
582 leaving a PS file in OUTBASE.ps
583
584 RETURN VALUE
585
586 None.
587 """
588         opts = ''
589         if extra['papersize']:
590                 opts = opts + ' -t%s' % extra['papersize'][0]
591
592         if extra['orientation'] and extra['orientation'][0] == 'landscape':
593                 opts = opts + ' -tlandscape'
594
595         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
596         
597         if not verbose_p:
598                 progress ( _("Running %s...") % 'dvips')
599                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
600                 
601         system (cmd)
602
603 def generate_dependency_file (depfile, outname):
604         df = open (depfile, 'w')
605         df.write (outname + ':' )
606         
607         for d in dependency_files:
608                 s = open (d).read ()
609                 s = re.sub ('#[^\n]*\n', '', s)
610                 s = re.sub (r'\\\n', ' ', s)
611                 m = re.search ('.*:(.*)\n', s)
612
613                 # ugh. Different targets?
614                 if m:
615                         df.write ( m.group (1)  + ' ' )
616
617         df.write ('\n')
618         df.close ();
619
620 def find_file_in_path (path, name):
621         for d in string.split (path, os.pathsep):
622                 if name in os.listdir (d):
623                         return os.path.join (d, name)
624
625 # Added as functionality to ly2dvi, because ly2dvi may well need to do this
626 # in future too.
627 PS = '%!PS-Adobe'
628 def find_pfa_fonts (name):
629         s = open (name).read ()
630         if s[:len (PS)] != PS:
631                 # no ps header?
632                 errorport.write (_( "error: ") + _ ("not a PostScript file: `%s\'" % name))
633                 errorport.write ('\n')
634                 sys.exit (1)
635         here = 0
636         m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
637         pfa = []
638         while m:
639                 here = m.end (1)
640                 pfa.append (m.group (1))
641                 m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
642         return pfa
643
644         
645 (sh, long) = getopt_args (__main__.option_definitions)
646 try:
647         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
648 except getopt.error, s:
649         errorport.write ('\n')
650         errorport.write (_( "error: ") + _ ("getopt says: `%s\'" % s))
651         errorport.write ('\n')
652         errorport.write ('\n')
653         help ()
654         sys.exit (2)
655         
656 for opt in options:     
657         o = opt[0]
658         a = opt[1]
659
660         if 0:
661                 pass
662         elif o == '--help' or o == '-h':
663                 help ()
664                 sys.exit (0)
665         elif o == '--find-pfa' or o == '-f':
666                 fonts = map (lambda x: x + '.pfa', find_pfa_fonts (a))
667                 files = map (lambda x:
668                              find_file_in_path (os.environ['GS_FONTPATH'], x),
669                              fonts)
670                 print string.join (files, ' ')
671                 sys.exit (0)
672         elif o == '--include' or o == '-I':
673                 include_path.append (a)
674         elif o == '--postscript' or o == '-P':
675                 targets['PS'] = 0
676         elif o == '--keep' or o == '-k':
677                 keep_temp_dir_p = 1
678         elif o == '--no-lily':
679                 lily_p = 0
680         elif o == '--no-paper' or o == '-m':
681                 targets = {}
682                 targets['MIDI'] = 0
683                 paper_p = 0
684         elif o == '--output' or o == '-o':
685                 output_name = a
686         elif o == '--set' or o == '-s':
687                 ss = string.split (a, '=')
688                 set_setting (extra_init, ss[0], ss[1])
689         elif o == '--dependencies' or o == '-d':
690                 track_dependencies_p = 1
691         elif o == '--verbose' or o == '-V':
692                 verbose_p = 1
693         elif o == '--version' or o == '-v':
694                 identify ()
695                 sys.exit (0)
696         elif o == '--warranty' or o == '-w':
697                 status = system ('lilypond -w', ignore_error = 1)
698                 if status:
699                         warranty ()
700
701                 sys.exit (0)
702
703
704 def cp_to_dir (pattern, dir):
705         "Copy files matching re PATTERN from cwd to DIR"
706         # Duh.  Python style portable: cp *.EXT OUTDIR
707         # system ('cp *.%s %s' % (ext, outdir), 1)
708         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
709         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
710
711 # Python < 1.5.2 compatibility
712 #
713 # On most platforms, this is equivalent to
714 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
715 if os.path.__dict__.has_key ('abspath'):
716         abspath = os.path.abspath
717 else:
718         def abspath (path):
719                 return os.path.normpath (os.path.join (os.getcwd (), path))
720
721 if os.__dict__.has_key ('makedirs'):
722         makedirs = os.makedirs
723 else:
724         def makedirs (dir, mode=0777):
725                 system ('mkdir -p %s' % dir)
726
727 def mkdir_p (dir, mode=0777):
728         if not os.path.isdir (dir):
729                 makedirs (dir, mode)
730
731 include_path = map (abspath, include_path)
732
733 original_output = output_name
734
735
736 if files and files[0] != '-':
737
738         # Ugh, maybe make a setup () function
739         files = map (lambda x: strip_extension (x, '.ly'), files)
740
741         (outdir, outbase) = ('','')
742         if not output_name:
743                 outbase = os.path.basename (files[0])
744                 outdir = abspath('.')
745         elif output_name[-1] == os.sep:
746                 outdir = abspath (output_name)
747                 outbase = os.path.basename (files[0])
748         else:
749                 (outdir, outbase) = os.path.split (abspath (output_name))
750
751         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
752                 output_name = strip_extension (output_name, i)
753
754         files = map (abspath, files) 
755
756         if os.path.dirname (output_name) != '.':
757                 dep_prefix = os.path.dirname (output_name)
758         else:
759                 dep_prefix = 0
760
761         reldir = os.path.dirname (output_name)
762         if outdir != '.' and (track_dependencies_p or targets.keys ()):
763                 mkdir_p (outdir, 0777)
764
765         setup_environment ()
766         tmpdir = setup_temp ()
767         if cache_pks_p :
768                 os.chdir (outdir)
769                 cp_to_dir (PK_PATTERN, tmpdir)
770
771         os.chdir (tmpdir)
772         
773         if lily_p:
774                 try:
775                         run_lilypond (files, outbase, dep_prefix)
776                 except:
777                         # TODO: friendly message about LilyPond setup/failing?
778                         #
779                         # TODO: lilypond should fail with different
780                         # error codes for:
781                         #   - guile setup/startup failure
782                         #   - font setup failure
783                         #   - init.ly setup failure
784                         #   - parse error in .ly
785                         #   - unexpected: assert/core dump
786                         targets = {}
787                         traceback.print_exc ()
788
789         if targets.has_key ('DVI') or targets.has_key ('PS'):
790                 try:
791                         run_latex (files, outbase, extra_init)
792                         # unless: add --tex, or --latex?
793                         del targets['TEX']
794                         del targets['LATEX']
795                 except:
796                         # TODO: friendly message about TeX/LaTeX setup,
797                         # trying to run tex/latex by hand
798                         if targets.has_key ('DVI'):
799                                 del targets['DVI']
800                         if targets.has_key ('PS'):
801                                 del targets['PS']
802                         traceback.print_exc ()
803
804         if targets.has_key ('PS'):
805                 try:
806                         run_dvips (outbase, extra_init)
807                 except: 
808                         if targets.has_key ('PS'):
809                                 del targets['PS']
810                         traceback.print_exc ()
811
812         # add DEP to targets?
813         if track_dependencies_p:
814                 depfile = os.path.join (outdir, outbase + '.dep')
815                 generate_dependency_file (depfile, depfile)
816                 if os.path.isfile (depfile):
817                         progress (_ ("dependencies output to `%s'...") % depfile)
818
819         # Hmm, if this were a function, we could call it the except: clauses
820         for i in targets.keys ():
821                 ext = string.lower (i)
822                 cp_to_dir ('.*\.%s$' % ext, outdir)
823                 outname = outbase + '.' + string.lower (i)
824                 abs = os.path.join (outdir, outname)
825                 if reldir != '.':
826                         outname = os.path.join (reldir, outname)
827                 if os.path.isfile (abs):
828                         progress (_ ("%s output to `%s'...") % (i, outname))
829                 elif verbose_p:
830                         warning (_ ("can't find file: `%s'") % outname)
831                         
832                 if cache_pks_p:
833                         cp_to_dir (PK_PATTERN, outdir)
834                 
835         os.chdir (original_dir)
836         cleanup_temp ()
837         
838 else:
839         # FIXME: read from stdin when files[0] = '-'
840         help ()
841         errorport.write ("ly2dvi: " + _ ("error: ") + _ ("no files specified on command line.") + '\n')
842         sys.exit (2)
843
844
845