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