]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
release: 1.3.154
[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' % defn[0]
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,headsep=0pt,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 \renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\makelilypondtagline}}%
565 \makeatother
566 '''
567         s = s + '\\end{document}'
568
569         return s
570
571 def run_latex (files, outbase, extra):
572
573         """Construct latex file, for FILES and EXTRA, dump it into
574 OUTBASE.latex. Run LaTeX on it.
575
576 RETURN VALUE
577
578 None
579         """
580         latex_fn = outbase + '.latex'
581         
582         wfs = find_tex_files (files, extra)
583         s = global_latex_definition (wfs, extra)
584
585         f = open (latex_fn, 'w')
586         f.write (s)
587         f.close ()
588
589         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
590
591         if not verbose_p and os.name == 'posix':
592                 progress ( _("Running %s...") % 'LaTeX')
593                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
594
595         system (cmd)
596
597 def run_dvips (outbase, extra):
598
599
600         """Run dvips using the correct options taken from EXTRA,
601 leaving a PS file in OUTBASE.ps
602
603 RETURN VALUE
604
605 None.
606 """
607         opts = ''
608         if extra['papersize']:
609                 opts = opts + ' -t%s' % extra['papersize'][0]
610
611         if extra['orientation'] and extra['orientation'][0] == 'landscape':
612                 opts = opts + ' -tlandscape'
613
614         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
615         
616         if not verbose_p and os.name == 'posix':
617                 progress ( _("Running %s...") % 'dvips')
618                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
619                 
620         system (cmd)
621
622 def generate_dependency_file (depfile, outname):
623         df = open (depfile, 'w')
624         df.write (outname + ':' )
625         
626         for d in dependency_files:
627                 s = open (d).read ()
628                 s = re.sub ('#[^\n]*\n', '', s)
629                 s = re.sub (r'\\\n', ' ', s)
630                 m = re.search ('.*:(.*)\n', s)
631
632                 # ugh. Different targets?
633                 if m:
634                         df.write ( m.group (1)  + ' ' )
635
636         df.write ('\n')
637         df.close ();
638
639 (sh, long) = getopt_args (__main__.option_definitions)
640 try:
641         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
642 except getopt.error, s: 
643         errorport.write ("\nerror: getopt says `%s\'\n\n" % s)
644         help ()
645         sys.exit (2)
646         
647 for opt in options:     
648         o = opt[0]
649         a = opt[1]
650
651         if 0:
652                 pass
653         elif o == '--help' or o == '-h':
654                 help ()
655                 sys.exit (0)
656         elif o == '--include' or o == '-I':
657                 include_path.append (a)
658         elif o == '--postscript' or o == '-P':
659                 targets['PS'] = 0
660         elif o == '--keep' or o == '-k':
661                 keep_temp_dir_p = 1
662         elif o == '--no-lily':
663                 lily_p = 0
664         elif o == '--no-paper' or o == '-m':
665                 targets = {}
666                 targets['MIDI'] = 0
667                 paper_p = 0
668         elif o == '--output' or o == '-o':
669                 output_name = a
670         elif o == '--set' or o == '-s':
671                 ss = string.split (a, '=')
672                 set_setting (extra_init, ss[0], ss[1])
673         elif o == '--dependencies' or o == '-d':
674                 track_dependencies_p = 1
675         elif o == '--verbose' or o == '-V':
676                 verbose_p = 1
677         elif o == '--version' or o == '-v':
678                 identify ()
679                 sys.exit (0)
680         elif o == '--warranty' or o == '-w':
681                 status = system ('lilypond -w', ignore_error = 1)
682                 if status:
683                         warranty ()
684
685                 sys.exit (0)
686
687
688 def cp_to_dir (pattern, dir):
689         "Copy files matching re PATTERN from cwd to DIR"
690         # Duh.  Python style portable: cp *.EXT OUTDIR
691         # system ('cp *.%s %s' % (ext, outdir), 1)
692         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
693         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
694
695 # Python < 1.5.2 compatibility
696 #
697 # On most platforms, this is equivalent to
698 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
699 if os.path.__dict__.has_key ('abspath'):
700         abspath = os.path.abspath
701 else:
702         def abspath (path):
703                 return os.path.normpath (os.path.join (os.getcwd (), path))
704
705 if os.__dict__.has_key ('makedirs'):
706         makedirs = os.makedirs
707 else:
708         def makedirs (dir, mode=0777):
709                 system ('mkdir -p %s' % dir)
710
711 def mkdir_p (dir, mode=0777):
712         if not os.path.isdir (dir):
713                 makedirs (dir, mode)
714
715 include_path = map (abspath, include_path)
716
717 original_output = output_name
718
719 if files and files[0] != '-':
720
721         files = map (lambda x: strip_extension (x, '.ly'), files)
722
723         if not output_name:
724                 output_name = os.path.basename (files[0])
725
726         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
727                 output_name = strip_extension (output_name, i)
728
729         files = map (abspath, files) 
730
731         if os.path.dirname (output_name) != '.':
732                 dep_prefix = os.path.dirname (output_name)
733         else:
734                 dep_prefix = 0
735
736         reldir = os.path.dirname (output_name)
737         
738         (outdir, outbase) = os.path.split (abspath (output_name))
739         if outdir != '.' and (track_dependencies_p or targets.keys ()):
740                 mkdir_p (outdir, 0777)
741
742         setup_environment ()
743         tmpdir = setup_temp ()
744         if cache_pks_p :
745                 os.chdir (outdir)
746                 cp_to_dir (PK_PATTERN, tmpdir)
747
748         os.chdir (tmpdir)
749         
750         extra = extra_init
751         
752         if lily_p:
753 ##              try:
754                         run_lilypond (files, outbase, dep_prefix)
755 ## #            except:
756 ##                      # TODO: friendly message about LilyPond setup/failing?
757 ##                      #
758 ##                      # TODO: lilypond should fail with different
759 ##                      # error codes for:
760 ##                      #   - guile setup/startup failure
761 ##                      #   - font setup failure
762 ##                      #   - init.ly setup failure
763 ##                      #   - parse error in .ly
764 ##                      #   - unexpected: assert/core dump
765 ## #                    targets = {}
766
767         if targets.has_key ('DVI') or targets.has_key ('PS'):
768 #               try:
769                         run_latex (files, outbase, extra)
770                         # unless: add --tex, or --latex?
771                         del targets['TEX']
772                         del targets['LATEX']
773 #               except Foobar:
774 #                       # TODO: friendly message about TeX/LaTeX setup,
775 #                       # trying to run tex/latex by hand
776 #                       if targets.has_key ('DVI'):
777 #                               del targets['DVI']
778 #                       if targets.has_key ('PS'):
779 #                               del targets['PS']
780
781         # TODO: does dvips ever fail?
782         if targets.has_key ('PS'):
783                 run_dvips (outbase, extra)
784
785         # add DEP to targets?
786         if track_dependencies_p:
787                 depfile = os.path.join (outdir, outbase + '.dep')
788                 generate_dependency_file (depfile, depfile)
789                 if os.path.isfile (depfile):
790                         progress (_ ("dependencies output to `%s'...") % depfile)
791
792         for i in targets.keys ():
793                 ext = string.lower (i)
794                 cp_to_dir ('.*\.%s$' % ext, outdir)
795                 outname = outbase + '.' + string.lower (i)
796                 abs = os.path.join (outdir, outname)
797                 if reldir != '.':
798                         outname = os.path.join (reldir, outname)
799                 if os.path.isfile (abs):
800                         progress (_ ("%s output to `%s'...") % (i, outname))
801                 elif verbose_p:
802                         warning (_ ("can't find file: `%s'") % outname)
803                         
804                 if cache_pks_p:
805                         cp_to_dir (PK_PATTERN, outdir)
806                 
807         os.chdir (original_dir)
808         cleanup_temp ()
809         
810 else:
811         # FIXME
812         help ()
813         errorport.write ("ly2dvi: " + _ ("error: ") + _ ("no files specified on command line.") + '\n')
814         sys.exit (2)
815
816
817