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