]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
release: 1.5.43
[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--2002'))
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         datadir = os.environ['LILYPONDPREFIX']
268 else:
269         datadir = '@datadir@'
270
271
272 while datadir[-1] == os.sep:
273         datadir= datadir[:-1]
274
275 program_name = 'ly2dvi'
276
277 original_dir = os.getcwd ()
278 temp_dir = os.path.join (original_dir,  '%s.dir' % program_name)
279 errorport = sys.stderr
280 keep_temp_dir_p = 0
281 verbose_p = 0
282
283 try:
284         import gettext
285         gettext.bindtextdomain ('lilypond', '@localedir@')
286         gettext.textdomain ('lilypond')
287         _ = gettext.gettext
288 except:
289         def _ (s):
290                 return s
291
292 # Attempt to fix problems with limited stack size set by Python!
293 # Sets unlimited stack size. Note that the resource module only
294 # is available on UNIX.
295 try:
296        import resource
297        resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
298 except:
299        pass
300
301 help_summary = _ ("Generate .dvi with LaTeX for LilyPond")
302
303 option_definitions = [
304         ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")),
305         ('', 'h', 'help', _ ("this help")),
306         (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
307         ('', 'k', 'keep', _ ("keep all output, and name the directory %s.dir") % program_name),
308         ('', '', 'no-lily', _ ("don't run LilyPond")),
309         ('', 'm', 'no-paper', _ ("produce MIDI output only")),
310         (_ ("FILE"), 'o', 'output', _ ("write ouput to FILE")),
311         (_ ("FILE"), 'f', 'find-pfa', _ ("find pfa fonts used in FILE")),
312         # why capital P?
313         ('', 'P', 'postscript', _ ("generate PostScript output")),
314         (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
315         ('', 'V', 'verbose', _ ("verbose")),
316         ('', 'v', 'version', _ ("print version number")),
317         ('', 'w', 'warranty', _ ("show warranty and copyright")),
318         ]
319
320 layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle',
321           'footer', 'head', 'composer', 'arranger', 'instrument',
322           'opus', 'piece', 'metre', 'meter', 'poet', 'texttranslator']
323
324
325 # init to empty; values here take precedence over values in the file
326
327 ## TODO: change name.
328 extra_init = {
329         'language' : [],
330         'latexheaders' : [],
331         'latexpackages' :  ['geometry'],
332         'latexoptions' : [],
333         'papersize' : [],
334         'pagenumber' : [1],
335         'textheight' : [], 
336         'linewidth' : [],
337         'orientation' : []
338 }
339
340 extra_fields = extra_init.keys ()
341 fields = layout_fields + extra_fields
342
343 include_path = ['.']
344 lily_p = 1
345 paper_p = 1
346 cache_pks_p = 1
347
348 PK_PATTERN='feta.*\.[0-9]+pk'
349
350 output_name = ''
351 targets = {
352         'DVI' : 0,
353         'LATEX' : 0,
354         'MIDI' : 0,
355         'TEX' : 0,
356         }
357
358 track_dependencies_p = 0
359 dependency_files = []
360
361
362
363 kpse = os.popen ('kpsexpand \$TEXMF').read()
364 kpse = re.sub('[ \t\n]+$','', kpse)
365
366 environment = {
367         ## todo: prevent multiple addition.
368         'TEXMF' : "{%s,%s}" % (datadir, kpse) ,
369         'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
370         'GS_LIB' : datadir + '/ps',
371 }
372
373 # tex needs lots of memory, more than it gets by default on Debian
374 non_path_environment = {
375         'extra_mem_top' : '1000000',
376         'extra_mem_bottom' : '1000000',
377         'pool_size' : '250000',
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         for key in non_path_environment.keys ():
388                 val = non_path_environment[key]
389                 os.environ[key] = val
390
391 #what a name.
392 def set_setting (dict, key, val):
393         try:
394                 val = string.atof (val)
395         except ValueError:
396                 #warning (_ ("invalid value: %s") % `val`)
397                 pass
398
399         try:
400                 dict[key].append (val)
401         except KeyError:
402                 warning (_ ("no such setting: %s") % `key`)
403                 dict[key] = [val]
404
405
406 def print_environment ():
407         for (k,v) in os.environ.items ():
408                 sys.stderr.write ("%s=\"%s\"\n" % (k,v)) 
409
410 def run_lilypond (files, outbase, dep_prefix):
411         opts = ''
412 #       opts = opts + '--output=%s.tex' % outbase
413         opts = opts + ' ' + string.join (map (lambda x : '-I ' + x,
414                                               include_path))
415         if paper_p:
416                 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
417                                                       fields))
418         else:
419                 opts = opts + ' --no-paper'
420                 
421         if track_dependencies_p:
422                 opts = opts + " --dependencies"
423                 if dep_prefix:
424                         opts = opts + ' --dep-prefix=%s' % dep_prefix
425
426         fs = string.join (files)
427
428         if not verbose_p:
429                 # cmd = cmd + ' 1> /dev/null 2> /dev/null'
430                 progress ( _("Running %s...") % 'LilyPond')
431         else:
432                 opts = opts + ' --verbose'
433
434                 # for better debugging!
435                 print_environment ()
436         print opts, fs  
437         system ('lilypond %s %s ' % (opts, fs))
438
439 def analyse_lilypond_output (filename, extra):
440         
441         # urg
442         '''Grep FILENAME for interesting stuff, and
443         put relevant info into EXTRA.'''
444         filename = filename+'.tex'
445         progress (_ ("Analyzing %s...") % filename)
446         s = open (filename).read ()
447
448         # search only the first 10k
449         s = s[:10240]
450         for x in extra_fields:
451                 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
452                 if m:
453                         set_setting (extra, x, m.group (1))
454
455 def find_tex_files_for_base (base, extra):
456
457         """
458         Find the \header fields dumped from BASE.
459         """
460         
461         headerfiles = {}
462         for f in layout_fields:
463                 if os.path.exists (base + '.' + f):
464                         headerfiles[f] = base+'.'+f
465
466         if os.path.exists (base  +'.dep'):
467                 dependency_files.append (base + '.dep')
468
469         for f in extra_fields:
470                 if os.path.exists (base + '.' + f):
471                         extra[f].append (open (base + '.' + f).read ())
472         
473         return (base  +'.tex',headerfiles)
474          
475
476 def find_tex_files (files, extra):
477         """
478         Find all .tex files whose prefixes start with some name in FILES. 
479
480         """
481         
482         tfiles = []
483         
484         for f in files:
485                 x = 0
486                 while 1:
487                         fname = os.path.basename (f)
488                         fname = strip_extension (fname, '.ly')
489                         if x:
490                                 fname = fname + '-%d' % x
491
492                         if os.path.exists (fname + '.tex'):
493                                 tfiles.append (find_tex_files_for_base (fname, extra))
494                                 analyse_lilypond_output (fname, extra)
495                         else:
496                                 break
497
498                         x = x + 1
499         if not x:
500                 fstr = string.join (files, ', ')
501                 warning (_ ("no lilypond output found for %s") % fstr)
502         return tfiles
503
504 def one_latex_definition (defn, first):
505         s = '\n'
506         for (k,v) in defn[1].items ():
507                 val = open (v).read ()
508                 if (string.strip (val)):
509                         s = s + r'''\def\lilypond%s{%s}''' % (k, val)
510                 else:
511                         s = s + r'''\let\lilypond%s\relax''' % k
512                 s = s + '\n'
513
514         if first:
515                 s = s + '\\def\\mustmakelilypondtitle{}\n'
516         else:
517                 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
518                 
519         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.
520         return s
521
522
523 ly_paper_to_latexpaper =  {
524         'a4' : 'a4paper',
525         'letter' : 'letterpaper', 
526 }
527
528 def global_latex_definition (tfiles, extra):
529
530         '''construct preamble from EXTRA, dump Latex stuff for each
531 lily output file in TFILES after that, and return the Latex file constructed.  '''
532
533
534         s = ""
535         s = s + '% generation tag\n'
536
537         options = ''
538
539         if extra['papersize']:
540                 try:
541                         options = '%s' % ly_paper_to_latexpaper[extra['papersize'][0]]
542                 except KeyError:
543                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
544                         pass
545
546         if extra['latexoptions']:
547                 options = options + ',' + extra['latexoptions'][-1]
548
549         s = s + '\\documentclass[%s]{article}\n' % options
550
551         if extra['language']:
552                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
553
554
555         s = s + '\\usepackage{%s}\n' \
556                 % string.join (extra['latexpackages'], ',')
557
558         if extra['latexheaders']:
559                 s = s + '\\include{%s}\n' \
560                         % string.join (extra['latexheaders'], '}\n\\include{')
561
562         textheight = ''
563         if extra['textheight']:
564                 textheight = ',textheight=%fpt' % extra['textheight'][0]
565
566         orientation = 'portrait'
567         if extra['orientation']:
568                 orientation = extra['orientation'][0]
569
570         # set sane geometry width (a4-width) for linewidth = -1.
571         maxlw = max (extra['linewidth'] + [-1])
572         if maxlw < 0:
573                 # who the hell is 597 ?
574                 linewidth = '597'
575         else:
576                 linewidth = maxlw
577         s = s + '\geometry{width=%spt%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
578
579         if extra['latexoptions']:
580                 s = s + '\geometry{twosideshift=4mm}\n'
581
582         s = s + r'''
583 \usepackage[latin1]{inputenc}
584 \input{titledefs}
585 '''
586         
587         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
588                 s = s + '\setcounter{page}{%s}\n' % (extra['pagenumber'][-1])
589                 s = s + '\\pagestyle{plain}\n'
590         else:
591                 s = s + '\\pagestyle{empty}\n'
592
593         s = s + '\\begin{document}\n'
594         s = s + '\\thispagestyle{firstpage}\n'
595
596         first = 1
597         for t in tfiles:
598                 s = s + one_latex_definition (t, first)
599                 first = 0
600
601
602         s = s + '\\thispagestyle{lastpage}\n'
603         s = s + '\\end{document}'
604
605         return s
606
607 def run_latex (files, outbase, extra):
608
609         """Construct latex file, for FILES and EXTRA, dump it into
610 OUTBASE.latex. Run LaTeX on it.
611
612 RETURN VALUE
613
614 None
615         """
616         latex_fn = outbase + '.latex'
617         
618         wfs = find_tex_files (files, extra)
619         s = global_latex_definition (wfs, extra)
620
621         f = open (latex_fn, 'w')
622         f.write (s)
623         f.close ()
624
625         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
626
627         if not verbose_p:
628                 progress ( _("Running %s...") % 'LaTeX')
629                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
630
631         system (cmd)
632
633 def run_dvips (outbase, extra):
634
635
636         """Run dvips using the correct options taken from EXTRA,
637 leaving a PS file in OUTBASE.ps
638
639 RETURN VALUE
640
641 None.
642 """
643         opts = ''
644         if extra['papersize']:
645                 opts = opts + ' -t%s' % extra['papersize'][0]
646
647         if extra['orientation'] and extra['orientation'][0] == 'landscape':
648                 opts = opts + ' -tlandscape'
649
650         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
651         
652         if not verbose_p:
653                 progress ( _("Running %s...") % 'dvips')
654                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
655                 
656         system (cmd)
657
658 def generate_dependency_file (depfile, outname):
659         df = open (depfile, 'w')
660         df.write (outname + ':' )
661         
662         for d in dependency_files:
663                 s = open (d).read ()
664                 s = re.sub ('#[^\n]*\n', '', s)
665                 s = re.sub (r'\\\n', ' ', s)
666                 m = re.search ('.*:(.*)\n', s)
667
668                 # ugh. Different targets?
669                 if m:
670                         df.write ( m.group (1)  + ' ' )
671
672         df.write ('\n')
673         df.close ();
674
675 def find_file_in_path (path, name):
676         for d in string.split (path, os.pathsep):
677                 if name in os.listdir (d):
678                         return os.path.join (d, name)
679
680 # Added as functionality to ly2dvi, because ly2dvi may well need to do this
681 # in future too.
682 PS = '%!PS-Adobe'
683 def find_pfa_fonts (name):
684         s = open (name).read ()
685         if s[:len (PS)] != PS:
686                 # no ps header?
687                 errorport.write (_( "error: ") + _ ("not a PostScript file: `%s\'" % name))
688                 errorport.write ('\n')
689                 sys.exit (1)
690         here = 0
691         m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
692         pfa = []
693         while m:
694                 here = m.end (1)
695                 pfa.append (m.group (1))
696                 m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
697         return pfa
698
699         
700 (sh, long) = getopt_args (option_definitions)
701 try:
702         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
703 except getopt.error, s:
704         errorport.write ('\n')
705         errorport.write (_ ("error: ") + _ ("getopt says: `%s\'" % s))
706         errorport.write ('\n')
707         errorport.write ('\n')
708         help ()
709         sys.exit (2)
710         
711 for opt in options:     
712         o = opt[0]
713         a = opt[1]
714
715         if 0:
716                 pass
717         elif o == '--help' or o == '-h':
718                 help ()
719                 sys.exit (0)
720         elif o == '--find-pfa' or o == '-f':
721                 fonts = map (lambda x: x + '.pfa', find_pfa_fonts (a))
722                 files = map (lambda x:
723                              find_file_in_path (os.environ['GS_FONTPATH'], x),
724                              fonts)
725                 print string.join (files, ' ')
726                 sys.exit (0)
727         elif o == '--include' or o == '-I':
728                 include_path.append (a)
729         elif o == '--postscript' or o == '-P':
730                 targets['PS'] = 0
731         elif o == '--keep' or o == '-k':
732                 keep_temp_dir_p = 1
733         elif o == '--no-lily':
734                 lily_p = 0
735         elif o == '--no-paper' or o == '-m':
736                 targets = {}
737                 targets['MIDI'] = 0
738                 paper_p = 0
739         elif o == '--output' or o == '-o':
740                 output_name = a
741         elif o == '--set' or o == '-s':
742                 ss = string.split (a, '=')
743                 set_setting (extra_init, ss[0], ss[1])
744         elif o == '--dependencies' or o == '-d':
745                 track_dependencies_p = 1
746         elif o == '--verbose' or o == '-V':
747                 verbose_p = 1
748         elif o == '--version' or o == '-v':
749                 identify ()
750                 sys.exit (0)
751         elif o == '--warranty' or o == '-w':
752                 status = system ('lilypond -w', ignore_error = 1)
753                 if status:
754                         warranty ()
755
756                 sys.exit (0)
757
758
759 def cp_to_dir (pattern, dir):
760         "Copy files matching re PATTERN from cwd to DIR"
761         # Duh.  Python style portable: cp *.EXT OUTDIR
762         # system ('cp *.%s %s' % (ext, outdir), 1)
763         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
764         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
765
766 # Python < 1.5.2 compatibility
767 #
768 # On most platforms, this is equivalent to
769 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
770 if os.path.__dict__.has_key ('abspath'):
771         abspath = os.path.abspath
772 else:
773         def abspath (path):
774                 return os.path.normpath (os.path.join (os.getcwd (), path))
775
776 if os.__dict__.has_key ('makedirs'):
777         makedirs = os.makedirs
778 else:
779         def makedirs (dir, mode=0777):
780                 system ('mkdir -p %s' % dir)
781
782 def mkdir_p (dir, mode=0777):
783         if not os.path.isdir (dir):
784                 makedirs (dir, mode)
785
786 include_path = map (abspath, include_path)
787
788 original_output = output_name
789
790
791 if files and files[0] != '-':
792         
793         # Ugh, maybe make a setup () function
794         files = map (lambda x: strip_extension (x, '.ly'), files)
795
796         # hmmm. Wish I'd 've written comments when I wrote this.
797         # now it looks complicated.
798         
799         (outdir, outbase) = ('','')
800         if not output_name:
801                 outbase = os.path.basename (files[0])
802                 outdir = abspath('.')
803         elif output_name[-1] == os.sep:
804                 outdir = abspath (output_name)
805                 outbase = os.path.basename (files[0])
806         else:
807                 (outdir, outbase) = os.path.split (abspath (output_name))
808
809         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
810                 output_name = strip_extension (output_name, i)
811                 outbase = strip_extension (outbase, i)
812         files = map (abspath, files)
813
814         for i in files[:] + [output_name]:
815                 if string.find (i, ' ') >= 0:
816                         user_error (_ ("filename should not contain spaces: `%s'") % i)
817                         
818         if os.path.dirname (output_name) != '.':
819                 dep_prefix = os.path.dirname (output_name)
820         else:
821                 dep_prefix = 0
822
823         reldir = os.path.dirname (output_name)
824         if outdir != '.' and (track_dependencies_p or targets.keys ()):
825                 mkdir_p (outdir, 0777)
826
827         setup_environment ()
828         tmpdir = setup_temp ()
829         if cache_pks_p :
830                 os.chdir (outdir)
831                 cp_to_dir (PK_PATTERN, tmpdir)
832
833         # to be sure, add tmpdir *in front* of inclusion path.
834         #os.environ['TEXINPUTS'] =  tmpdir + ':' + os.environ['TEXINPUTS']
835         os.chdir (tmpdir)
836         
837         if lily_p:
838                 try:
839                         run_lilypond (files, outbase, dep_prefix)
840                 except:
841                         # TODO: friendly message about LilyPond setup/failing?
842                         #
843                         # TODO: lilypond should fail with different
844                         # error codes for:
845                         #   - guile setup/startup failure
846                         #   - font setup failure
847                         #   - init.ly setup failure
848                         #   - parse error in .ly
849                         #   - unexpected: assert/core dump
850                         targets = {}
851                         traceback.print_exc ()
852
853         if targets.has_key ('DVI') or targets.has_key ('PS'):
854                 try:
855                         run_latex (files, outbase, extra_init)
856                         # unless: add --tex, or --latex?
857                         del targets['TEX']
858                         del targets['LATEX']
859                 except:
860                         # TODO: friendly message about TeX/LaTeX setup,
861                         # trying to run tex/latex by hand
862                         if targets.has_key ('DVI'):
863                                 del targets['DVI']
864                         if targets.has_key ('PS'):
865                                 del targets['PS']
866                         traceback.print_exc ()
867
868         if targets.has_key ('PS'):
869                 try:
870                         run_dvips (outbase, extra_init)
871                 except: 
872                         if targets.has_key ('PS'):
873                                 del targets['PS']
874                         traceback.print_exc ()
875
876         # add DEP to targets?
877         if track_dependencies_p:
878                 depfile = os.path.join (outdir, outbase + '.dep')
879                 generate_dependency_file (depfile, depfile)
880                 if os.path.isfile (depfile):
881                         progress (_ ("dependencies output to `%s'...") % depfile)
882
883         # Hmm, if this were a function, we could call it the except: clauses
884         for i in targets.keys ():
885                 ext = string.lower (i)
886                 cp_to_dir ('.*\.%s$' % ext, outdir)
887                 outname = outbase + '.' + string.lower (i)
888                 abs = os.path.join (outdir, outname)
889                 if reldir != '.':
890                         outname = os.path.join (reldir, outname)
891                 if os.path.isfile (abs):
892                         progress (_ ("%s output to `%s'...") % (i, outname))
893                 elif verbose_p:
894                         warning (_ ("can't find file: `%s'") % outname)
895                         
896                 if cache_pks_p:
897                         cp_to_dir (PK_PATTERN, outdir)
898                 
899         os.chdir (original_dir)
900         cleanup_temp ()
901         
902 else:
903         # FIXME: read from stdin when files[0] = '-'
904         help ()
905         user_error (_ ("no files specified on command line."), 2)
906
907
908