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