2 # run lily, setup LaTeX input.
4 """ TODO: --dependencies
20 layout_fields = ['title', 'subtitle', 'subsubtitle', 'footer', 'head',
21 'composer', 'arranger', 'instrument', 'opus', 'piece', 'metre',
25 # init to empty; values here take precedence over values in the file
29 'latexpackages' : ['geometry'],
37 extra_fields = extra_init.keys ()
39 fields = layout_fields + extra_fields
40 original_dir = os.getcwd ()
46 track_dependencies_p = 0
51 program_version = '@TOPLEVEL_VERSION@'
52 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
53 program_version = '1.3.134'
58 option_definitions = [
59 ('', 'h', 'help', 'print help'),
60 ('KEY=VAL', 's', 'set', 'change global setting KEY to VAL'),
61 ('', 'P', 'postscript', 'Generate PostScript output'),
62 ('', 'k', 'keep', 'Keep all output, and name the directory ly2dvi.dir'),
63 ('', '', 'no-lily', 'Don\'t run lilypond'),
64 ('', 'v', 'version', "Print version and copyright info"),
65 ('DIR', '', 'outdir', 'Dump all final output into DIR'),
66 ('', 'd', 'dependencies', 'Dump all final output into DIR'),
72 sys.stdout.write ('ly2dvi (GNU LilyPond) %s\n' % program_version)
76 sys.stdout.write (r"""Copyright 1998--1999
77 Distributed under terms of the GNU General Public License. It comes with
83 """Make the progress messages stand out between lilypond stuff"""
84 sys.stderr.write ('*** ' + s+ '\n')
93 Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
98 for a in include_path:
100 nm = os.path.join (a, name)
102 __main__.read_files.append (nm)
107 sys.stderr.write ("Reading `%s'\n" % nm)
108 return (f.read (), nm)
110 error ("File not found `%s'\n" % name)
116 def getopt_args (opts):
117 "Construct arguments (LONG, SHORT) for getopt from list of options."
132 def option_help_str (o):
133 "Transform one option description (4-tuple ) into neatly formatted string"
151 return ' ' + sh + sep + long + arg
154 def options_help_str (opts):
155 "Convert a list of options into a neatly formatted string"
161 s = option_help_str (o)
162 strs.append ((s, o[3]))
168 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
172 sys.stdout.write("""Usage: lyvi [options] FILE\n
173 Generate .dvi with LaTeX for lilypond
176 sys.stdout.write (options_help_str (option_definitions))
177 sys.stdout.write (r"""Warning all output is written in the CURRENT directory
181 Report bugs to bug-gnu-music@gnu.org.
184 Han-Wen Nienhuys <hanwen@cs.uu.nl>
192 temp_dir = 'ly2dvi.dir'
193 if not keep_temp_dir:
194 temp_dir = tempfile.mktemp ('ly2dvi')
202 # try not to gen/search MF stuff in temp dir
205 fp = ':' + os.environ['TFMFONTS']
210 os.environ['TFMFONTS'] = original_dir + fp
213 progress ('Temp directory is `%s\'\n' % temp_dir)
216 def system (cmd, ignore_error = 0):
217 sys.stderr.write ("invoking `%s\'\n" % cmd)
220 msg = ('Error command exited with value %d' % st)
222 sys.stderr.write (msg + ' (ignored)\n')
229 if not keep_temp_dir:
230 progress ('Cleaning up `%s\'' % temp_dir)
231 system ('rm -rf %s' % temp_dir)
234 def run_lilypond (files):
236 opts = opts + ' ' + string.join (map (lambda x : '-I ' + x, include_path))
237 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x, fields))
239 if track_dependencies_p:
240 opts = opts + " --dependencies "
242 fs = string.join (files)
244 system ('lilypond %s %s ' % (opts, fs))
247 def set_setting (dict, key, val):
249 val = string.atof (val)
254 dict[key].append (val)
259 def analyse_lilypond_output (filename, extra):
260 """Grep FILENAME for interesting stuff, and
261 put relevant info into EXTRA."""
262 filename = filename+'.tex'
263 progress ("Analyzing `%s'" % filename)
264 s = open (filename).read ()
266 # search only the first 10k
268 for x in ('textheight', 'linewidth', 'papersizename', 'orientation'):
269 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
271 set_setting (extra, x, m.group (1))
273 def find_tex_files_for_base (base, extra):
275 for f in layout_fields:
276 if os.path.exists (base + '.' + f):
277 headerfiles[f] = base+'.'+f
279 if os.path.exists (base +'.dep'):
280 dependency_files.append (base + '.dep')
282 for f in extra_fields:
283 if os.path.exists (base + '.' + f):
284 extra[f].append (open (base + '.' + f).read ())
286 return (base +'.tex',headerfiles)
289 def find_tex_files (files, extra):
294 fname = os.path.basename (f)
295 fname = os.path.splitext (fname)[0]
297 fname = fname + '-%d' % x
299 if os.path.exists (fname + '.tex'):
300 tfiles.append (find_tex_files_for_base (fname, extra))
301 analyse_lilypond_output (fname, extra)
308 def one_latex_definition (defn, first):
310 for (k,v) in defn[1].items ():
311 s = r"""\def\the%s{%s}""" % (k,open (v).read ())
314 s = s + '\\def\\mustmakelilypondtitle{}\n'
316 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
318 s = s + '\\input %s' % defn[0]
322 ly_paper_to_latexpaper = {
327 def global_latex_definition (tfiles, extra):
328 """construct preamble from EXTRA,
329 dump lily output files after that, and return result.
334 s = s + '% generation tag\n'
338 if extra['papersizename']:
339 paper = '[%s]' % ly_paper_to_latexpaper[extra['papersizename'][0]]
340 s = s + '\\documentclass%s{article}\n' % paper
342 if extra['language']:
343 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
346 s = s + '\\usepackage{%s}\n' \
347 % string.join (extra['latexpackages'], ',')
349 s = s + string.join (extra['latexheaders'], ' ')
352 if extra['textheight']:
353 textheight = ',textheight=%fpt' % extra['textheight'][0]
355 orientation = 'portrait'
356 if extra['orientation']:
357 orientation = extra['orientation'][0]
359 s = s + '\geometry{width=%spt%s,headheight=2mm,headsep=0pt,footskip=2mm,%s}\n' % (extra['linewidth'][0], textheight, orientation)
362 \usepackage[latin1]{inputenc}
365 \renewcommand{\@oddfoot}{\parbox{\textwidth}{\mbox{}\thefooter}}%%
367 if extra['pagenumber'] and extra['pagenumber'][-1]:
369 \renewcommand{\@oddhead}{\parbox{\textwidth}%%
370 {\mbox{}\small\theheader\hfill\textbf{\thepage}}}%%"""
372 s = s + '\\pagestyle{empty}'
374 s = s + '\\begin{document}'
378 s = s + one_latex_definition (t, first)
381 s = s + '\\end{document}'
385 def do_files (fs, extra):
387 """process the list of filenames in FS, using standard settings in EXTRA.
392 wfs = find_tex_files (fs, extra)
393 s = global_latex_definition (wfs, extra)
395 latex_file ='ly2dvi.out'
396 f = open (latex_file + '.tex', 'w')
401 system ('latex %s' % latex_file)
402 return latex_file + '.dvi'
404 def generate_postscript (dvi_name, extra):
405 """Run dvips on DVI_NAME, optionally doing -t landscape"""
408 if extra['papersizename']:
409 opts = opts + ' -t %s' % extra['papersizename'][0]
411 if extra['orientation'] and extra['orientation'][0] == 'landscape':
412 opts = opts + ' -t landscape'
414 ps_name = re.sub (r'\.dvi', r'.ps', dvi_name)
415 system ('dvips %s -o %s %s' % (opts, ps_name, dvi_name))
421 def generate_dependency_file (depfile, outname):
422 df = open (depfile, 'w')
423 df.write (outname + ':' )
425 for d in dependency_files:
427 s = re.sub ('#[^\n]*\n', '', s)
428 s = re.sub (r'\\\n', ' ', s)
429 m = re.search ('.*:(.*)\n', s)
431 # ugh. Different targets?
433 df.write ( m.group (1) + ' ' )
438 (sh, long) = getopt_args (__main__.option_definitions)
439 (options, files) = getopt.getopt(sys.argv[1:], sh, long)
446 elif o == '--help' or o == '-h':
448 elif o == '--include' or o == '-I':
449 include_path.append (a)
450 elif o == '--postscript' or o == '-P':
452 elif o == '--keep' or o == '-k':
454 elif o == '--no-lily':
456 elif o == '--outdir':
458 elif o == '--set' or o == '-s':
459 ss = string.split (a, '=')
460 set_setting (extra_init, ss[0], ss[1])
461 elif o == '--dependencies' or o == '-d':
462 track_dependencies_p = 1
463 elif o == '--version' or o == '-v':
467 include_path = map (os.path.abspath, include_path)
468 files = map (os.path.abspath, files)
469 outdir = os.path.abspath (outdir)
471 def strip_ly_suffix (f):
472 (p, e) =os.path.splitext (f)
477 files = map (strip_ly_suffix, files)
483 dvi_name = do_files (files, extra)
486 ps_name = generate_postscript (dvi_name, extra)
490 base = os.path.basename (files[0])
504 dest = os.path.join (outdir, dest)
505 system ('cp \"%s\" \"%s\"' % (srcname, dest ))
506 system ('cp *.midi %s' % outdir, ignore_error = 1)
508 depfile = os.path.join (outdir, base + '.dep')
510 if track_dependencies_p:
511 generate_dependency_file (depfile, dest)
515 # most insteresting info last
516 progress ("Dependency file left in `%s'" % depfile)
517 progress ("%s file left in `%s'" % (type, dest))