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