]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
patch::: 1.3.154.jcn1
[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
21 '''
22 TODO:
23
24   * figure out which set of command line options should make ly2dvi:
25
26       na: create tex only?  
27       na: create latex only? 
28       na: create tex and latex
29       default: create dvi only
30       na: create tex, latex and dvi
31       -P: create dvi and ps
32       na: * create ps only
33
34      etc.
35
36      for foo.ly, rename ly2dvi.dir to out-ly2dvi, foo.ly2dvi, foo.dir ?
37      
38   * move versatile taglines, 
39   
40      \header {
41         beginfooter=\mutopiaPD
42         endfooter=\tagline  -> 'lily was here <version>'
43      }
44
45      lilytagline (->lily was here), usertagline, copyright etc.
46
47   * head/header tagline/endfooter
48
49   * dvi from lilypond .tex output?  This is hairy, because we create dvi
50     from lilypond .tex *and* header output.
51
52   * multiple \score blocks?
53   
54 '''
55
56
57 import os
58 import stat
59 import string
60 import re
61 import getopt
62 import sys
63 import shutil
64 import __main__
65 import operator
66 import tempfile
67
68 datadir = '@datadir@'
69 sys.path.append (datadir + '/python')
70 try:
71         import gettext
72         gettext.bindtextdomain ('lilypond', '@localedir@')
73         gettext.textdomain('lilypond')
74         _ = gettext.gettext
75 except:
76         def _ (s):
77                 return s
78
79
80 layout_fields = ['title', 'subtitle', 'subsubtitle', 'footer', 'head',
81           'composer', 'arranger', 'instrument', 'opus', 'piece', 'metre',
82           'meter', 'poet']
83
84
85 # init to empty; values here take precedence over values in the file
86
87 ## TODO: change name.
88 extra_init = {
89         'language' : [],
90         'latexheaders' : [],
91         'latexpackages' :  ['geometry'],
92         'latexoptions' : [],
93         'papersize' : [],
94         'pagenumber' : [1],
95         'textheight' : [], 
96         'linewidth' : [],
97         'orientation' : []
98 }
99
100 extra_fields = extra_init.keys ()
101
102 fields = layout_fields + extra_fields
103 program_name = 'ly2dvi'
104 help_summary = _ ("Generate .dvi with LaTeX for LilyPond")
105
106 include_path = ['.']
107 lily_p = 1
108 paper_p = 1
109 cache_pks_p = 1
110
111 PK_PATTERN='feta.*\.[0-9]+pk'
112
113 output_name = ''
114 targets = {
115         'DVI' : 0,
116         'LATEX' : 0,
117         'MIDI' : 0,
118         'TEX' : 0,
119         }
120
121 track_dependencies_p = 0
122 dependency_files = []
123
124
125 # lily_py.py -- options and stuff
126
127 # source file of the GNU LilyPond music typesetter
128
129 # BEGIN Library for these?
130 # cut-n-paste from ly2dvi
131
132 program_version = '@TOPLEVEL_VERSION@'
133 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
134         program_version = '1.3.148'
135
136
137 original_dir = os.getcwd ()
138 temp_dir = '%s.dir' % program_name
139 keep_temp_dir_p = 0
140 verbose_p = 0
141
142 #
143 # Try to cater for bad installations of LilyPond, that have
144 # broken TeX setup.  Just hope this doesn't hurt good TeX
145 # setups.  Maybe we should check if kpsewhich can find
146 # feta16.{afm,mf,tex,tfm}, and only set env upon failure.
147 #
148 environment = {
149         'MFINPUTS' : ':' + datadir + '/mf',
150         'TEXINPUTS': ':' + datadir + '/tex:' + datadir + '/ps',
151         'TFMFONTS' : ':' + datadir + '/tfm',
152         'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
153         'GS_LIB' : datadir + '/ps',
154 }
155
156 def setup_environment ():
157         for key in environment.keys ():
158                 val = environment[key]
159                 if os.environ.has_key (key):
160                         val = os.environ[key] + os.pathsep + val 
161                 os.environ[key] = val
162
163 def identify ():
164         sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
165
166 def warranty ():
167         identify ()
168         sys.stdout.write ('\n')
169         sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001'))
170         sys.stdout.write ('\n')
171         sys.stdout.write ('  Han-Wen Nienhuys')
172         sys.stdout.write ('  Jan Nieuwenhuizen')
173         sys.stdout.write ('\n')
174         sys.stdout.write (_ (r'''
175 Distributed under terms of the GNU General Public License. It comes with
176 NO WARRANTY.'''))
177         sys.stdout.write ('\n')
178
179 if ( os.name == 'posix' ):
180         errorport=sys.stderr
181 else:
182         errorport=sys.stdout
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 donn't 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 ( os.name != 'posix' ):
298                 cmd = re.sub (r'''\\''', r'''\\\\\\''', cmd)
299                 cmd = "sh -c \'%s\'" % cmd
300         if verbose_p:
301                 progress (_ ("Invoking `%s\'") % cmd)
302         st = os.system (cmd)
303         if st:
304                 name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
305                 msg = name + ': ' + _ ("command exited with value %d") % st
306                 if ignore_error:
307                         warning (msg + ' ' + _ ("(ignored)") + ' ')
308                 else:
309                         error (msg)
310
311         return st
312
313
314 def cleanup_temp ():
315         if not keep_temp_dir_p:
316                 if verbose_p:
317                         progress (_ ("Cleaning %s...") % temp_dir)
318                 shutil.rmtree (temp_dir)
319
320
321 #what a name.
322 def set_setting (dict, key, val):
323         try:
324                 val = string.atof (val)
325         except ValueError:
326                 #warning (_ ("invalid value: %s") % `val`)
327                 pass
328
329         try:
330                 dict[key].append (val)
331         except KeyError:
332                 warning (_ ("no such setting: %s") % `key`)
333                 dict[key] = [val]
334
335
336 def strip_extension (f, ext):
337         (p, e) = os.path.splitext (f)
338         if e == ext:
339                 e = ''
340         return p + e
341
342 # END Library
343
344 option_definitions = [
345         ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")),
346         ('', 'h', 'help', _ ("this help")),
347         (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
348         ('', 'k', 'keep', _ ("keep all output, and name the directory %s.dir") % program_name),
349         ('', '', 'no-lily', _ ("don't run LilyPond")),
350         ('', 'm', 'no-paper', _ ("produce MIDI output only")),
351         (_ ("FILE"), 'o', 'output', _ ("write ouput to FILE")),
352         # why capital P?
353         ('', 'P', 'postscript', _ ("generate PostScript output")),
354         (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
355         ('', 'V', 'verbose', _ ("verbose")),
356         ('', 'v', 'version', _ ("print version number")),
357         ('', 'w', 'warranty', _ ("show warranty and copyright")),
358         ]
359
360 def run_lilypond (files, outbase, dep_prefix):
361         opts = ''
362 #       opts = opts + '--output=%s.tex' % outbase
363         opts = opts + ' ' + string.join (map (lambda x : '-I ' + x,
364                                               include_path))
365         if paper_p:
366                 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
367                                                       fields))
368         else:
369                 opts = opts + ' --no-paper'
370                 
371         if track_dependencies_p:
372                 opts = opts + " --dependencies"
373                 if dep_prefix:
374                         opts = opts + ' --dep-prefix=%s' % dep_prefix
375
376         fs = string.join (files)
377
378         if not verbose_p:
379                 progress ( _("Running %s...") % 'LilyPond')
380                 # cmd = cmd + ' 1> /dev/null 2> /dev/null'
381         else:
382                 opts = opts + ' --verbose'
383         
384         system ('lilypond %s %s ' % (opts, fs))
385
386 def analyse_lilypond_output (filename, extra):
387         
388         # urg
389         '''Grep FILENAME for interesting stuff, and
390         put relevant info into EXTRA.'''
391         filename = filename+'.tex'
392         progress (_ ("Analyzing %s...") % filename)
393         s = open (filename).read ()
394
395         # search only the first 10k
396         s = s[:10240]
397         for x in ('textheight', 'linewidth', 'papersize', 'orientation'):
398                 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
399                 if m:
400                         set_setting (extra, x, m.group (1))
401
402 def find_tex_files_for_base (base, extra):
403
404         """
405         Find the \header fields dumped from BASE.
406         """
407         
408         headerfiles = {}
409         for f in layout_fields:
410                 if os.path.exists (base + '.' + f):
411                         headerfiles[f] = base+'.'+f
412
413         if os.path.exists (base  +'.dep'):
414                 dependency_files.append (base + '.dep')
415
416         for f in extra_fields:
417                 if os.path.exists (base + '.' + f):
418                         extra[f].append (open (base + '.' + f).read ())
419         
420         return (base  +'.tex',headerfiles)
421          
422
423 def find_tex_files (files, extra):
424         """
425         Find all .tex files whose prefixes start with some name in FILES. 
426
427         """
428         
429         tfiles = []
430         
431         for f in files:
432                 x = 0
433                 while 1:
434                         fname = os.path.basename (f)
435                         fname = strip_extension (fname, '.ly')
436                         if x:
437                                 fname = fname + '-%d' % x
438
439                         if os.path.exists (fname + '.tex'):
440                                 tfiles.append (find_tex_files_for_base (fname, extra))
441                                 analyse_lilypond_output (fname, extra)
442                         else:
443                                 break
444
445                         x = x + 1
446         if not x:
447                 fstr = string.join (files, ', ')
448                 warning (_ ("no lilypond output found for %s") % fstr)
449         return tfiles
450
451 def one_latex_definition (defn, first):
452         s = '\n'
453         for (k,v) in defn[1].items ():
454                 val = open (v).read ()
455                 if (string.strip (val)):
456                         s = s + r'''\def\lilypond%s{%s}''' % (k, val)
457                 else:
458                         s = s + r'''\let\lilypond%s\relax''' % k
459                 s = s + '\n'
460
461         if first:
462                 s = s + '\\def\\mustmakelilypondtitle{}\n'
463         else:
464                 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
465                 
466         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.
467         return s
468
469
470 ly_paper_to_latexpaper =  {
471         'a4' : 'a4paper',
472         'letter' : 'letterpaper', 
473 }
474
475 def global_latex_definition (tfiles, extra):
476
477         '''construct preamble from EXTRA, dump Latex stuff for each
478 lily output file in TFILES after that, and return the Latex file constructed.  '''
479
480
481         s = ""
482         s = s + '% generation tag\n'
483
484         options = ''
485
486         if extra['papersize']:
487                 try:
488                         options = '%s' % ly_paper_to_latexpaper[extra['papersize'][0]]
489                 except KeyError:
490                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
491                         pass
492
493         if extra['latexoptions']:
494                 options = options + ',' + extra['latexoptions'][-1]
495
496         s = s + '\\documentclass[%s]{article}\n' % options
497
498         if extra['language']:
499                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
500
501
502         s = s + '\\usepackage{%s}\n' \
503                 % string.join (extra['latexpackages'], ',')
504
505         if extra['latexheaders']:
506                 s = s + '\\include{%s}\n' \
507                         % string.join (extra['latexheaders'], '}\n\\include{')
508
509         textheight = ''
510         if extra['textheight']:
511                 textheight = ',textheight=%fpt' % extra['textheight'][0]
512
513         orientation = 'portrait'
514         if extra['orientation']:
515                 orientation = extra['orientation'][0]
516
517         # set sane geometry width (a4-width) for linewidth = -1.
518         maxlw = max (extra['linewidth'] + [-1])
519         if maxlw < 0:
520                 # who the hell is 597 ?
521                 linewidth = '597'
522         else:
523                 linewidth = maxlw
524         s = s + '\geometry{width=%spt%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
525
526         if extra['latexoptions']:
527                 s = s + '\geometry{twosideshift=4mm}\n'
528
529         s = s + r'''
530 \usepackage[latin1]{inputenc}
531 \input{titledefs}
532 \makeatletter
533 \renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\thefooter}}%
534 \renewcommand{\@evenfoot}{\parbox{\textwidth}{\mbox{}\thefooter}}%
535 '''
536         
537         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
538                 s = s + r'''
539 \renewcommand{\@evenhead}{\hbox to\textwidth{\textbf{\thepage}\hfill{\small\theheader}}}
540 \renewcommand{\@oddhead}{\hbox to \textwidth{{\small\theheader}\hfill\textbf{\thepage}}}
541 '''
542         else:
543                 s = s + '\\pagestyle{empty}\n'
544
545         s = s + '\\makeatother\n'
546         s = s + '\\begin{document}\n'
547
548
549         first = 1
550         for t in tfiles:
551                 s = s + one_latex_definition (t, first)
552                 first = 0
553
554         s = s + r'''
555 %% I do not see why we want to clobber the footer here
556 %% \vfill\hfill\parbox{\textwidth}{\mbox{}\makelilypondtagline}
557 %% Well, maybe you don't submit music to mutopia?
558 %% I would not object to this kind of change, but I don't know how
559 %% to get the last mutopia tagline right (ie: no footer on last page)
560 %% Please check that mutopia footers and endfooter are OK before changing
561 %% this again. -- jcn
562 % the \mbox{} helps latex if people do stupid things in tagline
563 \makeatletter
564 \if@twoside
565   \ifodd\thepage
566    \renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\makelilypondtagline}}%
567   \else
568    \renewcommand{\@evenfoot}{\parbox{\textwidth}{\mbox{}\makelilypondtagline}}%
569   \fi
570  \else
571   \renewcommand{\@thefoot}{\parbox{\textwidth}{\mbox{}\makelilypondtagline}}%
572 \fi
573 \makeatother
574 '''
575         s = s + '\\end{document}'
576
577         return s
578
579 def run_latex (files, outbase, extra):
580
581         """Construct latex file, for FILES and EXTRA, dump it into
582 OUTBASE.latex. Run LaTeX on it.
583
584 RETURN VALUE
585
586 None
587         """
588         latex_fn = outbase + '.latex'
589         
590         wfs = find_tex_files (files, extra)
591         s = global_latex_definition (wfs, extra)
592
593         f = open (latex_fn, 'w')
594         f.write (s)
595         f.close ()
596
597         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
598
599         if not verbose_p and os.name == 'posix':
600                 progress ( _("Running %s...") % 'LaTeX')
601                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
602
603         system (cmd)
604
605 def run_dvips (outbase, extra):
606
607
608         """Run dvips using the correct options taken from EXTRA,
609 leaving a PS file in OUTBASE.ps
610
611 RETURN VALUE
612
613 None.
614 """
615         opts = ''
616         if extra['papersize']:
617                 opts = opts + ' -t%s' % extra['papersize'][0]
618
619         if extra['orientation'] and extra['orientation'][0] == 'landscape':
620                 opts = opts + ' -tlandscape'
621
622         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
623         
624         if not verbose_p and os.name == 'posix':
625                 progress ( _("Running %s...") % 'dvips')
626                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
627                 
628         system (cmd)
629
630 def generate_dependency_file (depfile, outname):
631         df = open (depfile, 'w')
632         df.write (outname + ':' )
633         
634         for d in dependency_files:
635                 s = open (d).read ()
636                 s = re.sub ('#[^\n]*\n', '', s)
637                 s = re.sub (r'\\\n', ' ', s)
638                 m = re.search ('.*:(.*)\n', s)
639
640                 # ugh. Different targets?
641                 if m:
642                         df.write ( m.group (1)  + ' ' )
643
644         df.write ('\n')
645         df.close ();
646
647 (sh, long) = getopt_args (__main__.option_definitions)
648 try:
649         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
650 except getopt.error, s: 
651         errorport.write ("\nerror: getopt says `%s\'\n\n" % s)
652         help ()
653         sys.exit (2)
654         
655 for opt in options:     
656         o = opt[0]
657         a = opt[1]
658
659         if 0:
660                 pass
661         elif o == '--help' or o == '-h':
662                 help ()
663                 sys.exit (0)
664         elif o == '--include' or o == '-I':
665                 include_path.append (a)
666         elif o == '--postscript' or o == '-P':
667                 targets['PS'] = 0
668         elif o == '--keep' or o == '-k':
669                 keep_temp_dir_p = 1
670         elif o == '--no-lily':
671                 lily_p = 0
672         elif o == '--no-paper' or o == '-m':
673                 targets = {}
674                 targets['MIDI'] = 0
675                 paper_p = 0
676         elif o == '--output' or o == '-o':
677                 output_name = a
678         elif o == '--set' or o == '-s':
679                 ss = string.split (a, '=')
680                 set_setting (extra_init, ss[0], ss[1])
681         elif o == '--dependencies' or o == '-d':
682                 track_dependencies_p = 1
683         elif o == '--verbose' or o == '-V':
684                 verbose_p = 1
685         elif o == '--version' or o == '-v':
686                 identify ()
687                 sys.exit (0)
688         elif o == '--warranty' or o == '-w':
689                 status = system ('lilypond -w', ignore_error = 1)
690                 if status:
691                         warranty ()
692
693                 sys.exit (0)
694
695
696 def cp_to_dir (pattern, dir):
697         "Copy files matching re PATTERN from cwd to DIR"
698         # Duh.  Python style portable: cp *.EXT OUTDIR
699         # system ('cp *.%s %s' % (ext, outdir), 1)
700         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
701         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
702
703 # Python < 1.5.2 compatibility
704 #
705 # On most platforms, this is equivalent to
706 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
707 if os.path.__dict__.has_key ('abspath'):
708         abspath = os.path.abspath
709 else:
710         def abspath (path):
711                 return os.path.normpath (os.path.join (os.getcwd (), path))
712
713 if os.__dict__.has_key ('makedirs'):
714         makedirs = os.makedirs
715 else:
716         def makedirs (dir, mode=0777):
717                 system ('mkdir -p %s' % dir)
718
719 def mkdir_p (dir, mode=0777):
720         if not os.path.isdir (dir):
721                 makedirs (dir, mode)
722
723 include_path = map (abspath, include_path)
724
725 original_output = output_name
726
727 if files and files[0] != '-':
728
729         files = map (lambda x: strip_extension (x, '.ly'), files)
730
731         if not output_name:
732                 output_name = os.path.basename (files[0])
733
734         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
735                 output_name = strip_extension (output_name, i)
736
737         files = map (abspath, files) 
738
739         if os.path.dirname (output_name) != '.':
740                 dep_prefix = os.path.dirname (output_name)
741         else:
742                 dep_prefix = 0
743
744         reldir = os.path.dirname (output_name)
745         
746         (outdir, outbase) = os.path.split (abspath (output_name))
747         if outdir != '.' and (track_dependencies_p or targets.keys ()):
748                 mkdir_p (outdir, 0777)
749
750         setup_environment ()
751         tmpdir = setup_temp ()
752         if cache_pks_p :
753                 os.chdir (outdir)
754                 cp_to_dir (PK_PATTERN, tmpdir)
755
756         os.chdir (tmpdir)
757         
758         extra = extra_init
759         
760         if lily_p:
761 ##              try:
762                         run_lilypond (files, outbase, dep_prefix)
763 ## #            except:
764 ##                      # TODO: friendly message about LilyPond setup/failing?
765 ##                      #
766 ##                      # TODO: lilypond should fail with different
767 ##                      # error codes for:
768 ##                      #   - guile setup/startup failure
769 ##                      #   - font setup failure
770 ##                      #   - init.ly setup failure
771 ##                      #   - parse error in .ly
772 ##                      #   - unexpected: assert/core dump
773 ## #                    targets = {}
774
775         if targets.has_key ('DVI') or targets.has_key ('PS'):
776 #               try:
777                         run_latex (files, outbase, extra)
778                         # unless: add --tex, or --latex?
779                         del targets['TEX']
780                         del targets['LATEX']
781 #               except Foobar:
782 #                       # TODO: friendly message about TeX/LaTeX setup,
783 #                       # trying to run tex/latex by hand
784 #                       if targets.has_key ('DVI'):
785 #                               del targets['DVI']
786 #                       if targets.has_key ('PS'):
787 #                               del targets['PS']
788
789         # TODO: does dvips ever fail?
790         if targets.has_key ('PS'):
791                 run_dvips (outbase, extra)
792
793         # add DEP to targets?
794         if track_dependencies_p:
795                 depfile = os.path.join (outdir, outbase + '.dep')
796                 generate_dependency_file (depfile, depfile)
797                 if os.path.isfile (depfile):
798                         progress (_ ("dependencies output to `%s'...") % depfile)
799
800         for i in targets.keys ():
801                 ext = string.lower (i)
802                 cp_to_dir ('.*\.%s$' % ext, outdir)
803                 outname = outbase + '.' + string.lower (i)
804                 abs = os.path.join (outdir, outname)
805                 if reldir != '.':
806                         outname = os.path.join (reldir, outname)
807                 if os.path.isfile (abs):
808                         progress (_ ("%s output to `%s'...") % (i, outname))
809                 elif verbose_p:
810                         warning (_ ("can't find file: `%s'") % outname)
811                         
812                 if cache_pks_p:
813                         cp_to_dir (PK_PATTERN, outdir)
814                 
815         os.chdir (original_dir)
816         cleanup_temp ()
817         
818 else:
819         # FIXME
820         help ()
821         errorport.write ("ly2dvi: " + _ ("error: ") + _ ("no files specified on command line.") + '\n')
822         sys.exit (2)
823
824
825