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