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