]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
''
[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 #TODO: should set textheight (enlarge) depending on papersize. 
541
542 def global_latex_definition (tfiles, extra):
543         '''construct preamble from EXTRA, dump Latex stuff for each
544 lily output file in TFILES after that, and return the Latex file constructed.  '''
545
546
547         s = ""
548         s = s + '% generation tag\n'
549
550         options = ''
551
552
553         if extra['papersize']:
554                 try:
555                         options = ly_paper_to_latexpaper[extra['papersize'][0]]
556                 except KeyError:
557                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
558                         pass
559
560         if extra['latexoptions']:
561                 options = options + ',' + extra['latexoptions'][-1]
562
563         s = s + '\\documentclass[%s]{article}\n' % options
564
565         if extra['language']:
566                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
567
568
569         s = s + '\\usepackage{%s}\n' \
570                 % string.join (extra['latexpackages'], ',')
571
572         if extra['latexheaders']:
573                 s = s + '\\include{%s}\n' \
574                         % string.join (extra['latexheaders'], '}\n\\include{')
575
576         unit = extra['unit'][-1]
577
578         textheight = ''
579         if extra['textheight']:
580                 textheight = ',textheight=%f%s' % (extra['textheight'][0], unit)
581
582         orientation = 'portrait'
583         if extra['orientation']:
584                 orientation = extra['orientation'][0]
585
586         # set sane geometry width (a4-width) for linewidth = -1.
587         maxlw = max (extra['linewidth'] + [-1])
588         if maxlw < 0:
589                 # who the hell is 597 ?
590                 linewidth = '597pt'
591         else:
592                 linewidth = '%d%s' % (maxlw, unit)
593         s = s + '\geometry{width=%s%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
594
595         if extra['latexoptions']:
596                 s = s + '\geometry{twosideshift=4mm}\n'
597
598         s = s + r'''
599 \usepackage[latin1]{inputenc}
600 \input{titledefs}
601 '''
602         
603         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
604                 s = s + '\setcounter{page}{%s}\n' % (extra['pagenumber'][-1])
605                 s = s + '\\pagestyle{plain}\n'
606         else:
607                 s = s + '\\pagestyle{empty}\n'
608
609         s = s + '\\begin{document}\n'
610         s = s + '\\thispagestyle{firstpage}\n'
611
612         first = 1
613         for t in tfiles:
614                 s = s + one_latex_definition (t, first)
615                 first = 0
616
617
618         s = s + '\\thispagestyle{lastpage}\n'
619         s = s + '\\end{document}'
620
621         return s
622
623 def run_latex (files, outbase, extra):
624
625         """Construct latex file, for FILES and EXTRA, dump it into
626 OUTBASE.latex. Run LaTeX on it.
627
628 RETURN VALUE
629
630 None
631         """
632         latex_fn = outbase + '.latex'
633         
634         wfs = find_tex_files (files, extra)
635         s = global_latex_definition (wfs, extra)
636
637         f = open (latex_fn, 'w')
638         f.write (s)
639         f.close ()
640
641         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
642
643         if not verbose_p:
644                 progress ( _("Running %s...") % 'LaTeX')
645                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
646
647         system (cmd)
648
649 def run_dvips (outbase, extra):
650
651
652         """Run dvips using the correct options taken from EXTRA,
653 leaving a PS file in OUTBASE.ps
654
655 RETURN VALUE
656
657 None.
658 """
659         opts = ''
660         if extra['papersize']:
661                 opts = opts + ' -t%s' % extra['papersize'][0]
662
663         if extra['orientation'] and extra['orientation'][0] == 'landscape':
664                 opts = opts + ' -tlandscape'
665
666         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
667         
668         if not verbose_p:
669                 progress ( _("Running %s...") % 'dvips')
670                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
671                 
672         system (cmd)
673
674 def generate_dependency_file (depfile, outname):
675         df = open (depfile, 'w')
676         df.write (outname + ':' )
677         
678         for d in dependency_files:
679                 s = open (d).read ()
680                 s = re.sub ('#[^\n]*\n', '', s)
681                 s = re.sub (r'\\\n', ' ', s)
682                 m = re.search ('.*:(.*)\n', s)
683
684                 # ugh. Different targets?
685                 if m:
686                         df.write ( m.group (1)  + ' ' )
687
688         df.write ('\n')
689         df.close ();
690
691 def find_file_in_path (path, name):
692         for d in string.split (path, os.pathsep):
693                 if name in os.listdir (d):
694                         return os.path.join (d, name)
695
696 # Added as functionality to ly2dvi, because ly2dvi may well need to do this
697 # in future too.
698 PS = '%!PS-Adobe'
699 def find_pfa_fonts (name):
700         s = open (name).read ()
701         if s[:len (PS)] != PS:
702                 # no ps header?
703                 errorport.write (_( "error: ") + _ ("not a PostScript file: `%s\'" % name))
704                 errorport.write ('\n')
705                 sys.exit (1)
706         here = 0
707         m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
708         pfa = []
709         while m:
710                 here = m.end (1)
711                 pfa.append (m.group (1))
712                 m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
713         return pfa
714
715         
716 (sh, long) = getopt_args (option_definitions)
717 try:
718         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
719 except getopt.error, s:
720         errorport.write ('\n')
721         errorport.write (_ ("error: ") + _ ("getopt says: `%s\'" % s))
722         errorport.write ('\n')
723         errorport.write ('\n')
724         help ()
725         sys.exit (2)
726         
727 for opt in options:     
728         o = opt[0]
729         a = opt[1]
730
731         if 0:
732                 pass
733         elif o == '--help' or o == '-h':
734                 help ()
735                 sys.exit (0)
736         elif o == '--find-pfa' or o == '-f':
737                 fonts = map (lambda x: x + '.pfa', find_pfa_fonts (a))
738                 files = map (lambda x:
739                              find_file_in_path (os.environ['GS_FONTPATH'], x),
740                              fonts)
741                 print string.join (files, ' ')
742                 sys.exit (0)
743         elif o == '--include' or o == '-I':
744                 include_path.append (a)
745         elif o == '--postscript' or o == '-P':
746                 targets['PS'] = 0
747         elif o == '--keep' or o == '-k':
748                 keep_temp_dir_p = 1
749         elif o == '--no-lily':
750                 lily_p = 0
751         elif o == '--no-paper' or o == '-m':
752                 targets = {}
753                 targets['MIDI'] = 0
754                 paper_p = 0
755         elif o == '--output' or o == '-o':
756                 output_name = a
757         elif o == '--set' or o == '-s':
758                 ss = string.split (a, '=')
759                 set_setting (extra_init, ss[0], ss[1])
760         elif o == '--dependencies' or o == '-d':
761                 track_dependencies_p = 1
762         elif o == '--verbose' or o == '-V':
763                 verbose_p = 1
764         elif o == '--version' or o == '-v':
765                 identify ()
766                 sys.exit (0)
767         elif o == '--warranty' or o == '-w':
768                 status = system ('lilypond -w', ignore_error = 1)
769                 if status:
770                         warranty ()
771
772                 sys.exit (0)
773
774
775 def cp_to_dir (pattern, dir):
776         "Copy files matching re PATTERN from cwd to DIR"
777         # Duh.  Python style portable: cp *.EXT OUTDIR
778         # system ('cp *.%s %s' % (ext, outdir), 1)
779         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
780         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
781
782 # Python < 1.5.2 compatibility
783 #
784 # On most platforms, this is equivalent to
785 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
786 if os.path.__dict__.has_key ('abspath'):
787         abspath = os.path.abspath
788 else:
789         def abspath (path):
790                 return os.path.normpath (os.path.join (os.getcwd (), path))
791
792 if os.__dict__.has_key ('makedirs'):
793         makedirs = os.makedirs
794 else:
795         def makedirs (dir, mode=0777):
796                 system ('mkdir -p %s' % dir)
797
798 def mkdir_p (dir, mode=0777):
799         if not os.path.isdir (dir):
800                 makedirs (dir, mode)
801
802 include_path = map (abspath, include_path)
803
804 original_output = output_name
805
806
807 if files and files[0] != '-':
808         
809         # Ugh, maybe make a setup () function
810         files = map (lambda x: strip_extension (x, '.ly'), files)
811
812         # hmmm. Wish I'd 've written comments when I wrote this.
813         # now it looks complicated.
814         
815         (outdir, outbase) = ('','')
816         if not output_name:
817                 outbase = os.path.basename (files[0])
818                 outdir = abspath('.')
819         elif output_name[-1] == os.sep:
820                 outdir = abspath (output_name)
821                 outbase = os.path.basename (files[0])
822         else:
823                 (outdir, outbase) = os.path.split (abspath (output_name))
824
825         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
826                 output_name = strip_extension (output_name, i)
827                 outbase = strip_extension (outbase, i)
828         files = map (abspath, files)
829
830         for i in files[:] + [output_name]:
831                 if string.find (i, ' ') >= 0:
832                         user_error (_ ("filename should not contain spaces: `%s'") % i)
833                         
834         if os.path.dirname (output_name) != '.':
835                 dep_prefix = os.path.dirname (output_name)
836         else:
837                 dep_prefix = 0
838
839         reldir = os.path.dirname (output_name)
840         if outdir != '.' and (track_dependencies_p or targets.keys ()):
841                 mkdir_p (outdir, 0777)
842
843         setup_environment ()
844         tmpdir = setup_temp ()
845
846         # to be sure, add tmpdir *in front* of inclusion path.
847         #os.environ['TEXINPUTS'] =  tmpdir + ':' + os.environ['TEXINPUTS']
848         os.chdir (tmpdir)
849         
850         if lily_p:
851                 try:
852                         run_lilypond (files, outbase, dep_prefix)
853                 except:
854                         # TODO: friendly message about LilyPond setup/failing?
855                         #
856                         # TODO: lilypond should fail with different
857                         # error codes for:
858                         #   - guile setup/startup failure
859                         #   - font setup failure
860                         #   - init.ly setup failure
861                         #   - parse error in .ly
862                         #   - unexpected: assert/core dump
863                         targets = {}
864                         traceback.print_exc ()
865
866         if targets.has_key ('DVI') or targets.has_key ('PS'):
867                 try:
868                         run_latex (files, outbase, extra_init)
869                         # unless: add --tex, or --latex?
870                         del targets['TEX']
871                         del targets['LATEX']
872                 except:
873                         # TODO: friendly message about TeX/LaTeX setup,
874                         # trying to run tex/latex by hand
875                         if targets.has_key ('DVI'):
876                                 del targets['DVI']
877                         if targets.has_key ('PS'):
878                                 del targets['PS']
879                         traceback.print_exc ()
880
881         if targets.has_key ('PS'):
882                 try:
883                         run_dvips (outbase, extra_init)
884                 except: 
885                         if targets.has_key ('PS'):
886                                 del targets['PS']
887                         traceback.print_exc ()
888
889         # add DEP to targets?
890         if track_dependencies_p:
891                 depfile = os.path.join (outdir, outbase + '.dep')
892                 generate_dependency_file (depfile, depfile)
893                 if os.path.isfile (depfile):
894                         progress (_ ("dependencies output to `%s'...") % depfile)
895
896         # Hmm, if this were a function, we could call it the except: clauses
897         for i in targets.keys ():
898                 ext = string.lower (i)
899                 cp_to_dir ('.*\.%s$' % ext, outdir)
900                 outname = outbase + '.' + string.lower (i)
901                 abs = os.path.join (outdir, outname)
902                 if reldir != '.':
903                         outname = os.path.join (reldir, outname)
904                 if os.path.isfile (abs):
905                         progress (_ ("%s output to `%s'...") % (i, outname))
906                 elif verbose_p:
907                         warning (_ ("can't find file: `%s'") % outname)
908                         
909         os.chdir (original_dir)
910         cleanup_temp ()
911         
912 else:
913         # FIXME: read from stdin when files[0] = '-'
914         help ()
915         user_error (_ ("no files specified on command line."), 2)
916
917
918