I added support for the geometry package today. All options
supported by the geometry package should work, but I'm sure
there are plenty of ways to confuse mudela-book. Please
report any problems to this list.
landscape package is gone in this version, but you
can get landscape with
\usepackage[landscape]{geometry}
Also, commenting out mudela-blocks like this
%\begin{mudela}
% BLABLA
%\end{mudela}
should work as expected.
Attached a testversion of mudela-book.
--
Tom Cato Amundsen <[EMAIL PROTECTED]>
GNU Solfege - free eartraining, http://www.gnu.org/software/solfege/
#!@PYTHON@
# vim: set noexpandtab:
# TODO:
# * Figure out clean set of options.
# * add support for .lilyrc
# * %\def\preMudelaExample should be ignored by mudela-book because
# it is commented out
# * if you run mudela-book once with --no-pictures, and then again
# without the option, then the pngs will not be created. You have
# to delete the generated .ly files and rerun mudela-book.
# * kontroller hvordan det skannes etter preMudelaExample i preamble
# det ser ut til at \usepackage{graphics} legges til bare hvis
# preMudelaExample ikke finnes.
# * add suppoert for @c comments. Check that preamble scanning works after this.
# * in LaTeX, commenting out blocks like this
# %\begin{mudela}
# %c d e
# %\end{mudela} works as expected.
# * \usepackage{landscape} is gone. Convince me it is really neede to get it back.
# * We are calculating more of the linewidths, for example 2 col from 1 col.
import os
import stat
import string
import re
import getopt
import sys
import __main__
import operator
program_version = '@TOPLEVEL_VERSION@'
if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
program_version = '1.3.85'
include_path = [os.getcwd()]
g_dep_prefix = ''
g_outdir = ''
g_force_mudela_fontsize = 0
g_read_lys = 0
g_do_pictures = 1
g_num_cols = 1
format = ''
g_run_lilypond = 1
no_match = 'a\ba'
default_music_fontsize = 16
default_text_fontsize = 12
class LatexPaper:
def __init__(self):
self.m_paperdef = {
# the dimentions are from geometry.sty
'a0paper': (mm2pt(841), mm2pt(1189)),
'a1paper': (mm2pt(595), mm2pt(841)),
'a2paper': (mm2pt(420), mm2pt(595)),
'a3paper': (mm2pt(297), mm2pt(420)),
'a4paper': (mm2pt(210), mm2pt(297)),
'a5paper': (mm2pt(149), mm2pt(210)),
'b0paper': (mm2pt(1000), mm2pt(1414)),
'b1paper': (mm2pt(707), mm2pt(1000)),
'b2paper': (mm2pt(500), mm2pt(707)),
'b3paper': (mm2pt(353), mm2pt(500)),
'b4paper': (mm2pt(250), mm2pt(353)),
'b5paper': (mm2pt(176), mm2pt(250)),
'letterpaper': (in2pt(8.5), in2pt(11)),
'legalpaper': (in2pt(8.5), in2pt(14)),
'executivepaper': (in2pt(7.25), in2pt(10.5))}
self.m_use_geometry = None
self.m_papersize = 'letterpaper'
self.m_fontsize = 10
self.m_num_cols = 1
self.m_landscape = 0
self.m_geo_landscape = 0
self.m_geo_width = None
self.m_geo_textwidth = None
self.m_geo_lmargin = None
self.m_geo_rmargin = None
self.m_geo_includemp = None
self.m_geo_marginparwidth = {10: 57, 11: 50, 12: 35}
self.m_geo_marginparsep = {10: 11, 11: 10, 12: 10}
self.m_geo_x_marginparwidth = None
self.m_geo_x_marginparsep = None
self.__body = None
def set_geo_option(self, name, value):
if name == 'body' or name == 'text':
if type(value) == type(""):
self._set_dimen('m_geo_textwidth', value)
else:
self._set_dimen('m_geo_textwidth', value[0])
self.__body = 1
elif name == 'portrait':
self.m_geo_landscape = 0
elif name == 'reversemp' or name == 'reversemarginpar':
if self.m_geo_includemp == None:
self.m_geo_includemp = 1
elif name == 'marginparwidth' or name == 'marginpar':
self._set_dimen('m_geo_x_marginparwidth', value)
self.m_geo_includemp = 1
elif name == 'marginparsep':
self._set_dimen('m_geo_x_marginparsep', value)
self.m_geo_includemp = 1
elif name == 'scale':
if type(value) == type(""):
self.m_geo_width = self.get_paperwidth() * float(value)
else:
self.m_geo_width = self.get_paperwidth() *
float(value[0])
elif name == 'hscale':
self.m_geo_width = self.get_paperwidth() * float(value)
elif name == 'left' or name == 'lmargin':
self._set_dimen('m_geo_lmargin', value)
elif name == 'right' or name == 'rmargin':
self._set_dimen('m_geo_rmargin', value)
elif name == 'hdivide' or name == 'divide':
if value[0] not in ('*', ''):
self._set_dimen('m_geo_lmargin', value[0])
if value[1] not in ('*', ''):
self._set_dimen('m_geo_width', value[1])
if value[2] not in ('*', ''):
self._set_dimen('m_geo_rmargin', value[2])
elif name == 'hmargin':
if type(value) == type(""):
self._set_dimen('m_geo_lmargin', value)
self._set_dimen('m_geo_rmargin', value)
else:
self._set_dimen('m_geo_lmargin', value[0])
self._set_dimen('m_geo_rmargin', value[1])
elif name == 'margin':#ugh there is a bug about this option in
# the geometry documentation
if type(value) == type(""):
self._set_dimen('m_geo_lmargin', value)
self._set_dimen('m_geo_rmargin', value)
else:
self._set_dimen('m_geo_lmargin', value[0])
self._set_dimen('m_geo_rmargin', value[0])
elif name == 'total':
if type(value) == type(""):
self._set_dimen('m_geo_width', value)
else:
self._set_dimen('m_geo_width', value[0])
elif name == 'width' or name == 'totalwidth':
self._set_dimen('m_geo_width', value)
elif name == 'paper' or name == 'papername':
self.m_papersize = value
elif name[-5:] == 'paper':
self.m_papersize = name
else:
self._set_dimen('m_geo_'+name, value)
def _set_dimen(self, name, value):
if type(value) == type("") and value[-2:] == 'pt':
self.__dict__[name] = int(value[:-2])
elif type(value) == type("") and value[-2:] == 'mm':
self.__dict__[name] = mm2pt(int(value[:-2]))
elif type(value) == type("") and value[-2:] == 'cm':
self.__dict__[name] = 10 * mm2pt(int(value[:-2]))
elif type(value) == type("") and value[-2:] == 'in':
self.__dict__[name] = in2pt(int(value[:-2]))
else:
self.__dict__[name] = value
def display(self):
print "LatexPaper:\n-----------"
for v in self.__dict__.keys():
if v[:2] == 'm_':
print v, self.__dict__[v]
print "-----------"
def get_linewidth(self):
w = self._calc_linewidth()
if self.m_num_cols == 2:
return (w - 10) / 2
else:
return w
def get_paperwidth(self):
if self.m_use_geometry:
if self.m_landscape and self.m_geo_landscape:
return self.m_paperdef[self.m_papersize][0]
return self.m_paperdef[self.m_papersize][self.m_landscape or
self.m_geo_landscape]
#return self.m_paperdef[self.m_papersize][self.m_geo_landscape]
def _calc_linewidth(self):
# since geometry sometimes ignores 'includemp', this is
# more complicated than it should be
mp = 0
if self.m_geo_includemp:
if self.m_geo_x_marginparsep is not None:
mp = mp + self.m_geo_x_marginparsep
else:
mp = mp + self.m_geo_marginparsep[self.m_fontsize]
if self.m_geo_x_marginparwidth is not None:
mp = mp + self.m_geo_x_marginparwidth
else:
mp = mp + self.m_geo_marginparwidth[self.m_fontsize]
if self.__body:#ugh test if this is necessary
mp = 0
def tNone(a, b, c):
return a == None, b == None, c == None
if not self.m_use_geometry:
return latex_linewidths[self.m_papersize][self.m_fontsize]
else:
if tNone(self.m_geo_lmargin, self.m_geo_width,
self.m_geo_rmargin) == (1, 1, 1):
if self.m_geo_textwidth:
return self.m_geo_textwidth
w = self.get_paperwidth() * 0.8
return w - mp
elif tNone(self.m_geo_lmargin, self.m_geo_width,
self.m_geo_rmargin) == (0, 1, 1):
if self.m_geo_textwidth:
return self.m_geo_textwidth
return self.f1(self.m_geo_lmargin, mp)
elif tNone(self.m_geo_lmargin, self.m_geo_width,
self.m_geo_rmargin) == (1, 1, 0):
if self.m_geo_textwidth:
return self.m_geo_textwidth
return self.f1(self.m_geo_rmargin, mp)
elif tNone(self.m_geo_lmargin, self.m_geo_width,
self.m_geo_rmargin) \
in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
if self.m_geo_textwidth:
return self.m_geo_textwidth
return self.m_geo_width - mp
elif tNone(self.m_geo_lmargin, self.m_geo_width,
self.m_geo_rmargin) in ((0, 1, 0), (0, 0, 0)):
w = self.get_paperwidth() - self.m_geo_lmargin -
self.m_geo_rmargin - mp
if w < 0:
w = 0
return w
raise "Never do this!"
def f1(self, m, mp):
tmp = self.get_paperwidth() - m * 2 - mp
if tmp < 0:
tmp = 0
return tmp
def f2(self):
tmp = self.get_paperwidth() - self.m_geo_lmargin \
- self.m_geo_rmargin
if tmp < 0:
return 0
return tmp
class TexiPaper:
def __init__(self):
self.m_papersize = 'a4'
self.m_fontsize = 12
def get_linewidth(self):
return texi_linewidths[self.m_papersize][self.m_fontsize]
def mm2pt(x):
return x * 2.8452756
def in2pt(x):
return x * 72.26999
def em2pt(x, fontsize):
return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
def ex2pt(x, fontsize):
return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
# latex linewidths:
# indices are no. of columns, papersize, fontsize
# Why can't this be calculated?
latex_linewidths = {
'a4paper':{10: 345, 11: 360, 12: 390},
'a4paper-landscape': {10: 598, 11: 596, 12:592},
'a5paper':{10: 276, 11: 276, 12: 276},
'b5paper':{10: 345, 11: 356, 12: 356},
'letterpaper':{10: 345, 11: 360, 12: 390},
'letterpaper-landscape':{10: 598, 11: 596, 12:596},
'legalpaper': {10: 345, 11: 360, 12: 390},
'executivepaper':{10: 345, 11: 360, 12: 379}}
texi_linewidths = {
'a4': {12: 455},
'a4wide': {12: 470},
'smallbook': {12: 361},
'texidefault': {12: 433}}
option_definitions = [
('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed
to be in points'),
('DIM', '', 'default-mudela-fontsize', 'deprecated, use --default-music-fontsize'),
('DIM', '', 'force-music-fontsize', 'force fontsize for all inline mudela. DIM is
assumed be to in points'),
('DIM', '', 'force-mudela-fontsize', 'deprecated, use --force-music-fontsize'),
('DIR', 'I', 'include', 'include path'),
('', 'M', 'dependencies', 'write dependencies'),
('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
('', 'n', 'no-lily', 'don\'t run lilypond'),
('', '', 'no-pictures', "don\'t generate pictures"),
('', '', 'read-lys', "don't write ly files."),
('FILE', 'o', 'outname', 'filename main output file'),
('FILE', '', 'outdir', "where to place generated files"),
('', 'v', 'version', 'print version information' ),
('', 'h', 'help', 'print help'),
]
# format specific strings, ie. regex-es for input, and % strings for output
output_dict= {
'latex': {
'output-mudela-fragment' : r"""\begin[eps,singleline,%s]{mudela}
\context Staff <
\context Voice{
%s
}
>
\end{mudela}""",
'output-mudela':r"""\begin[%s]{mudela}
%s
\end{mudela}""",
'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
'output-default-post': r"""\def\postMudelaExample{}""",
'output-default-pre': r"""\def\preMudelaExample{}""",
'output-eps':
'\\noindent\\parbox{\\mudelaepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
'output-tex': '\\preMudelaExample \\input %(fn)s.tex
\\postMudelaExample\n',
'pagebreak': r'\pagebreak',
},
'texi' : {'output-mudela': """@mudela[%s]
%s
@end mudela
""",
'output-mudela-fragment': """@mudela[%s]
\context Staff\context Voice{ %s }
@end mudela """,
'pagebreak': None,
'output-verbatim': r"""@example
%s
@end example
""",
# do some tweaking: @ is needed in some ps stuff.
# override EndLilyPondOutput, since @tex is done
# in a sandbox, you can't do \input lilyponddefs at the
# top of the document.
# should also support fragment in
'output-all': r"""@tex
\catcode`\@=12
\input lilyponddefs
\def\EndLilyPondOutput{}
\input %(fn)s.tex
\catcode`\@=0
@end tex
@html
<p>
<img src=%(fn)s.png>
@end html
""",
}
}
def output_verbatim (body):#ugh .format
if __main__.format == 'texi':
body = re.sub ('([@{}])', '@\\1', body)
return get_output ('output-verbatim') % body
def output_mbverbatim (body):#ugh .format
if __main__.format == 'texi':
body = re.sub ('([@{}])', '@\\1', body)
return get_output ('output-verbatim') % body
re_dict = {
'latex': {'input': '\\\\mbinput{?([^}\t \n}]*)',
'include': '\\\\mbinclude{(?P<filename>[^}]+)}',
'option-sep' : ', *',
'header': r"""\\documentclass(\[.*?\])?""",
# ^(?m)[^%]* is here so we can comment it out
###########
'usepackage':
r"^(?m)[^%\n]*?\\usepackage\s*(?P<options>\[.*\])?\s*{(?P<packagename>.*?)}",
'geometry':
r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
###################
'preamble-end':
'(?s)^[^%]*?(?P<match>(?P<code>\\\\begin{document}))',
'verbatim': r"""(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})""",
'verb': r"""(?P<code>\\verb(?P<del>.).*?(?P=del))""",
'mudela-file':
r'(?m)^[^%\n]*?(?P<match>\\mudelafile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
'mudela' :
'(?m)^[^%\n]*?(?P<match>\\\\mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
'mudela-block':
r"""(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{mudela}(?P<code>.*?)\\end{mudela})""",
'def-post-re': r"""\\def\\postMudelaExample""",
'def-pre-re': r"""\\def\\preMudelaExample""",
'intertext': r',?\s*intertext=\".*?\"',
'ignore': r"(?m)(?P<code>^%.*$\n+)",
'numcols': r"(?P<code>\\(?P<num>one|two)column)",
},
'texi': {
'include': '@mbinclude[ \n\t]+(?P<filename>[^\t \n]*)',
'input': no_match,
'header': no_match,
'preamble-end': no_match,
'usepackage': no_match,
'landscape': no_match,
'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
'verb': r"""(?P<code>@code{.*?})""",
'mudela-file':
'(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
'mudela' : '(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
#ugh add check for @c
'mudela-block':
r"""(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end
mudela\s))""",
'option-sep' : ', *',
'intertext': r',?\s*intertext=\".*?\"',
'ignore': r"(?s)(?P<code>@ignore\s.*?@end ignore)\s",
'numcols': no_match,
}
}
for r in re_dict.keys ():
olddict = re_dict[r]
newdict = {}
for k in olddict.keys ():
newdict[k] = re.compile (olddict[k])
re_dict[r] = newdict
def uniq (list):
list.sort ()
s = list
list = []
for x in s:
if x not in list:
list.append (x)
return list
def get_output (name):
return output_dict[format][name]
def get_re (name):
return re_dict[format][name]
def bounding_box_dimensions(fname):
try:
fd = open(fname)
except IOError:
error ("Error opening `%s'" % fname)
str = fd.read ()
s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
if s:
return (int(s.group(3))-int(s.group(1)),
int(s.group(4))-int(s.group(2)))
else:
return (0,0)
def error (str):
sys.stderr.write (str + "\n Exiting ... \n\n")
raise 'Exiting.'
def compose_full_body (body, opts):
"""Construct the mudela code to send to Lilypond.
Add stuff to BODY using OPTS as options."""
music_size = default_music_fontsize
latex_size = default_text_fontsize
for o in opts:
if g_force_mudela_fontsize:
music_size = g_force_mudela_fontsize
else:
m = re.match ('([0-9]+)pt', o)
if m:
music_size = string.atoi(m.group (1))
m = re.match ('latexfontsize=([0-9]+)pt', o)
if m:
latex_size = string.atoi (m.group (1))
if re.search ('\\\\score', body):
is_fragment = 0
else:
is_fragment = 1
if 'fragment' in opts:
is_fragment = 1
if 'nonfragment' in opts:
is_fragment = 0
if is_fragment and not 'multiline' in opts:
opts.append('singleline')
if 'singleline' in opts:
l = -1.0;
else:
l = paperguru.get_linewidth()
if 'relative' in opts:#ugh only when is_fragment
body = '\\relative c { %s }' % body
if is_fragment:
body = r"""\score {
\notes { %s }
\paper { }
}""" % body
opts = uniq (opts)
optstring = string.join (opts, ' ')
optstring = re.sub ('\n', ' ', optstring)
body = r"""
%% Generated by mudela-book.py; options are %s %%ughUGH not original options
\include "paper%d.ly"
\paper { linewidth = %f \pt; }
""" % (optstring, music_size, l) + body
return body
def parse_options_string(s):
d = {}
r1 = re.compile("((\w+)={(.*?)})((,\s*)|$)")
r2 = re.compile("((\w+)=(.*?))((,\s*)|$)")
r3 = re.compile("(\w+?)((,\s*)|$)")
while s:
m = r1.match(s)
if m:
s = s[m.end():]
d[m.group(2)] = re.split(",\s*", m.group(3))
continue
m = r2.match(s)
if m:
s = s[m.end():]
d[m.group(2)] = m.group(3)
continue
m = r3.match(s)
if m:
s = s[m.end():]
d[m.group(1)] = 1
continue
print "tr�bbel:%s:" % s
return d
def scan_latex_preamble(chunks):
# first we want to scan the \documentclass line
# it should be the first non-comment line
idx = 0
while 1:
if chunks[idx][0] == 'ignore':
idx = idx + 1
continue
m = get_re ('header').match(chunks[idx][1])
options = re.split (',[\n \t]*', m.group(1)[1:-1])
for o in options:
if o == 'landscape':
paperguru.m_landscape = 1
m = re.match("(.*?)paper", o)
if m:
paperguru.m_papersize = m.group()
else:
m = re.match("(\d\d)pt", o)
if m:
paperguru.m_fontsize = int(m.group(1))
break
while chunks[idx][0] != 'preamble-end':
if chunks[idx] == 'ignore':
idx = idx + 1
continue
m = get_re ('geometry').search(chunks[idx][1])
if m:
paperguru.m_use_geometry = 1
o = parse_options_string(m.group('options'))
for k in o.keys():
paperguru.set_geo_option(k, o[k])
idx = idx + 1
def scan_preamble (chunks):
if __main__.format == 'texi':
#ugh has to be fixed when @c comments are implemented
# also the searching here is far from bullet proof.
if string.find(chunks[0][1], "@afourpaper") != -1:
paperguru.m_papersize = 'a4'
elif string.find(chunks[0][1], "@afourwide") != -1:
paperguru.m_papersize = 'a4wide'
elif string.find(chunks[0][1], "@smallbook") != -1:
paperguru.m_papersize = 'smallbook'
else:
assert __main__.format == 'latex'
scan_latex_preamble(chunks)
def completize_preamble (str):
m = get_re ('preamble-end').search( str)
if not m:
return str
preamble = str [:m.start (0)]
str = str [m.start(0):]
if not get_re('def-post-re').search (preamble):
preamble = preamble + get_output('output-default-post')
if not get_re ('def-pre-re').search( preamble):
preamble = preamble + get_output ('output-default-pre')
# UGH ! BUG!
#if re.search ('\\\\includegraphics', str) and not re.search
('usepackage{graphics}',str):
preamble = preamble + '\\usepackage{graphics}\n'
return preamble + str
read_files = []
def find_file (name):
f = None
for a in include_path:
try:
nm = os.path.join (a, name)
f = open (nm)
__main__.read_files.append (nm)
break
except IOError:
pass
if f:
return f.read ()
else:
error ("File not found `%s'\n" % name)
return ''
def do_ignore(match_object):
return [('ignore', match_object.group('code'))]
def do_preamble_end(match_object):
return [('preamble-end', match_object.group('code'))]
def make_verbatim(match_object):
return [('verbatim', match_object.group('code'))]
def make_verb(match_object):
return [('verb', match_object.group('code'))]
def do_include_file(m):
"m: MatchObject"
return [('input', get_output ('pagebreak'))] \
+ read_doc_file(m.group('filename')) \
+ [('input', get_output ('pagebreak'))]
def do_input_file(m):
return read_doc_file(m.group('filename'))
def make_mudela(m):
if m.group('options'):
options = m.group('options')
else:
options = ''
return [('input', get_output('output-mudela-fragment') %
(options, m.group('code')))]
def make_mudela_file(m):
if m.group('options'):
options = m.group('options')
else:
options = ''
return [('input', get_output('output-mudela') %
(options, find_file(m.group('filename'))))]
def make_mudela_block(m):
if m.group('options'):
options = get_re('option-sep').split (m.group('options'))
else:
options = []
options = filter(lambda s: s != '', options)
if 'mbverbatim' in options:#ugh this is ugly and only for texi format
s = m.group()
im = get_re('intertext').search(s)
if im:
s = s[:im.start()] + s[im.end():]
im = re.search('mbverbatim', s)
if im:
s = s[:im.start()] + s[im.end():]
if s[:9] == "@mudela[]":
s = "@mudela" + s[9:]
return [('mudela', m.group('code'), options, s)]
return [('mudela', m.group('code'), options)]
def do_columns(m):
if __main__.format != 'latex':
return []
if m.group('num') == 'one':
return [('numcols', m.group('code'), 1)]
if m.group('num') == 'two':
return [('numcols', m.group('code'), 2)]
def new_chop_chunks(chunks, re_name, func):
newchunks = []
for c in chunks:
if c[0] == 'input':
str = c[1]
while str:
m = get_re (re_name).search (str)
if m == None:
newchunks.append (('input', str))
str = ''
else:
print "REDICT", re_name
print m.groupdict()
newchunks.append (('input', str[:m.start ('match')]))
#newchunks.extend(func(m))
# python 1.5 compatible:
newchunks = newchunks + func(m)
str = str [m.end(0):]
else:
newchunks.append(c)
return newchunks
def chop_chunks(chunks, re_name, func):
newchunks = []
for c in chunks:
if c[0] == 'input':
str = c[1]
while str:
m = get_re (re_name).search (str)
if m == None:
newchunks.append (('input', str))
str = ''
else:
newchunks.append (('input', str[:m.start (0)]))
#newchunks.extend(func(m))
# python 1.5 compatible:
newchunks = newchunks + func(m)
str = str [m.end(0):]
else:
newchunks.append(c)
return newchunks
def read_doc_file (filename):
"""Read the input file, find verbatim chunks and do \input and \include
"""
str = ''
str = find_file(filename)
if __main__.format == '':
latex = re.search ('\\\\document', str[:200])
texinfo = re.search ('@node|@setfilename', str[:200])
if (texinfo and latex) or not (texinfo or latex):
error("error: can't determine format, please specify")
if texinfo:
__main__.format = 'texi'
__main__.paperguru = TexiPaper()
else:
__main__.format = 'latex'
__main__.paperguru = LatexPaper()
chunks = [('input', str)]
# we have to check for verbatim before doing include,
# because we don't want to include files that are mentioned
# inside a verbatim environment
chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
chunks = chop_chunks(chunks, 'verb', make_verb)
#ugh fix input
chunks = chop_chunks(chunks, 'include', do_include_file)
chunks = chop_chunks(chunks, 'input', do_input_file)
return chunks
taken_file_names = {}
def schedule_mudela_block (chunk):
"""Take the body and options from CHUNK, figure out how the
real .ly should look, and what should be left MAIN_STR (meant
for the main file). The .ly is written, and scheduled in
TODO.
Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
TODO has format [basename, extension, extension, ... ]
"""
if len(chunk) == 3:
(type, body, opts) = chunk
complete_body = None
else:# mbverbatim
(type, body, opts, complete_body) = chunk
assert type == 'mudela'
file_body = compose_full_body (body, opts)
basename = `abs(hash (file_body))`
for o in opts:
m = re.search ('filename="(.*?)"', o)
if m:
basename = m.group (1)
if not taken_file_names.has_key(basename):
taken_file_names[basename] = 0
else:
taken_file_names[basename] = taken_file_names[basename] + 1
basename = basename + "-%i" % taken_file_names[basename]
# writes the file if necessary, returns true if it was written
if not g_read_lys:
update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
needed_filetypes = ['tex']
if format == 'texi':
needed_filetypes.append('eps')
needed_filetypes.append('png')
if 'eps' in opts and not ('eps' in needed_filetypes):
needed_filetypes.append('eps')
outname = os.path.join(g_outdir, basename)
if not os.path.isfile(outname + '.tex') \
or os.stat(outname+'.ly')[stat.ST_MTIME] > \
os.stat(outname+'.tex')[stat.ST_MTIME]:
todo = needed_filetypes
else:
todo = []
newbody = ''
if 'verbatim' in opts:
newbody = output_verbatim (body)
elif 'mbverbatim' in opts:
newbody = output_mbverbatim (complete_body)
for o in opts:
m = re.search ('intertext="(.*?)"', o)
if m:
newbody = newbody + m.group (1) + "\n\n"
if format == 'latex':
if 'eps' in opts:
s = 'output-eps'
else:
s = 'output-tex'
else: # format == 'texi'
s = 'output-all'
newbody = newbody + get_output(s) % {'fn': basename }
return ('mudela', newbody, opts, todo, basename)
def process_mudela_blocks(outname, chunks):#ugh rename
newchunks = []
# Count sections/chapters.
for c in chunks:
if c[0] == 'mudela':
c = schedule_mudela_block (c)
elif c[0] == 'numcols':
paperguru.m_num_cols = c[2]
newchunks.append (c)
return newchunks
def find_eps_dims (match):
"Fill in dimensions of EPS files."
fn =match.group (1)
dims = bounding_box_dimensions (fn)
return '%ipt' % dims[0]
def system (cmd):
sys.stderr.write ("invoking `%s'\n" % cmd)
st = os.system (cmd)
if st:
error ('Error command exited with value %d\n' % st)
return st
def compile_all_files (chunks):
eps = []
tex = []
png = []
for c in chunks:
if c[0] <> 'mudela':
continue
base = c[4]
exts = c[3]
for e in exts:
if e == 'eps':
eps.append (base)
elif e == 'tex':
#ugh
if base + '.ly' not in tex:
tex.append (base + '.ly')
elif e == 'png' and g_do_pictures:
png.append (base)
d = os.getcwd()
if g_outdir:
os.chdir(g_outdir)
if tex:
lilyopts = map (lambda x: '-I ' + x, include_path)
lilyopts = string.join (lilyopts, ' ' )
texfiles = string.join (tex, ' ')
system ('lilypond %s %s' % (lilyopts, texfiles))
for e in eps:
system(r"tex '\nonstopmode \input %s'" % e)
system(r"dvips -E -o %s %s" % (e + '.eps', e))
for g in png:
cmd = r"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q
-sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
cmd = cmd % (g + '.eps', g + '.png')
system (cmd)
if g_outdir:
os.chdir(d)
def update_file (body, name):
"""
write the body if it has changed
"""
same = 0
try:
f = open (name)
fs = f.read (-1)
same = (fs == body)
except:
pass
if not same:
f = open (name , 'w')
f.write (body)
f.close ()
return not same
def getopt_args (opts):
"Construct arguments (LONG, SHORT) for getopt from list of options."
short = ''
long = []
for o in opts:
if o[1]:
short = short + o[1]
if o[0]:
short = short + ':'
if o[2]:
l = o[2]
if o[0]:
l = l + '='
long.append (l)
return (short, long)
def option_help_str (o):
"Transform one option description (4-tuple ) into neatly formatted string"
sh = ' '
if o[1]:
sh = '-%s' % o[1]
sep = ' '
if o[1] and o[2]:
sep = ','
long = ''
if o[2]:
long= '--%s' % o[2]
arg = ''
if o[0]:
if o[2]:
arg = '='
arg = arg + o[0]
return ' ' + sh + sep + long + arg
def options_help_str (opts):
"Convert a list of options into a neatly formatted string"
w = 0
strs =[]
helps = []
for o in opts:
s = option_help_str (o)
strs.append ((s, o[3]))
if len (s) > w:
w = len (s)
str = ''
for s in strs:
str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
return str
def help():
sys.stdout.write("""Usage: mudela-book [options] FILE\n
Generate hybrid LaTeX input from Latex + mudela
Options:
""")
sys.stdout.write (options_help_str (option_definitions))
sys.stdout.write (r"""Warning all output is written in the CURRENT directory
Report bugs to [EMAIL PROTECTED]
Written by Tom Cato Amundsen <[EMAIL PROTECTED]> and
Han-Wen Nienhuys <[EMAIL PROTECTED]>
""")
sys.exit (0)
def write_deps (fn, target):
sys.stdout.write('writing `%s\'\n' % os.path.join(g_outdir, fn))
f = open (os.path.join(g_outdir, fn), 'w')
f.write ('%s%s: ' % (g_dep_prefix, target))
for d in __main__.read_files:
f.write ('%s ' % d)
f.write ('\n')
f.close ()
__main__.read_files = []
def identify():
sys.stdout.write ('mudela-book (GNU LilyPond) %s\n' % program_version)
def print_version ():
identify()
sys.stdout.write (r"""Copyright 1998--1999
Distributed under terms of the GNU General Public License. It comes with
NO WARRANTY.
""")
def do_file(input_filename):
file_settings = {}
if outname:
my_outname = outname
else:
my_outname = os.path.basename(os.path.splitext(input_filename)[0])
my_depname = my_outname + '.dep'
chunks = read_doc_file(input_filename)
chunks = new_chop_chunks(chunks, 'mudela', make_mudela)
chunks = new_chop_chunks(chunks, 'mudela-file', make_mudela_file)
chunks = new_chop_chunks(chunks, 'mudela-block', make_mudela_block)
chunks = chop_chunks(chunks, 'ignore', do_ignore)
chunks = new_chop_chunks(chunks, 'preamble-end', do_preamble_end)
chunks = chop_chunks(chunks, 'numcols', do_columns)
#print "-" * 50
#for c in chunks: print "c:", c;
#sys.exit()
scan_preamble(chunks)
chunks = process_mudela_blocks(my_outname, chunks)
# Do It.
if __main__.g_run_lilypond:
compile_all_files (chunks)
newchunks = []
# finishing touch.
for c in chunks:
if c[0] == 'mudela' and 'eps' in c[2]:
body = re.sub (r"""\\mudelaepswidth{(.*?)}""",
find_eps_dims, c[1])
newchunks.append (('mudela', body))
else:
newchunks.append (c)
chunks = newchunks
if chunks and chunks[0][0] == 'input':
chunks[0] = ('input', completize_preamble (chunks[0][1]))
foutn = os.path.join(g_outdir, my_outname + '.' + format)
sys.stderr.write ("Writing `%s'\n" % foutn)
fout = open (foutn, 'w')
for c in chunks:
fout.write (c[1])
fout.close ()
if do_deps:
write_deps (my_depname, foutn)
outname = ''
try:
(sh, long) = getopt_args (__main__.option_definitions)
(options, files) = getopt.getopt(sys.argv[1:], sh, long)
except getopt.error, msg:
sys.stderr.write("error: %s" % msg)
sys.exit(1)
do_deps = 0
for opt in options:
o = opt[0]
a = opt[1]
if o == '--include' or o == '-I':
include_path.append (a)
elif o == '--version' or o == '-v':
print_version ()
sys.exit (0)
elif o == '--format' or o == '-f':
__main__.format = a
elif o == '--outname' or o == '-o':
if len(files) > 1:
#HACK
sys.stderr.write("Mudela-book is confused by --outname on
multiple files")
sys.exit(1)
outname = a
elif o == '--help' or o == '-h':
help ()
elif o == '--no-lily' or o == '-n':
__main__.g_run_lilypond = 0
elif o == '--dependencies' or o == '-M':
do_deps = 1
elif o == '--default-music-fontsize':
default_music_fontsize = string.atoi (a)
elif o == '--default-mudela-fontsize':
print "--default-mudela-fontsize is deprecated, use
--default-music-fontsize"
default_music_fontsize = string.atoi (a)
elif o == '--force-music-fontsize':
g_force_mudela_fontsize = string.atoi(a)
elif o == '--force-mudela-fontsize':
print "--force-mudela-fontsize is deprecated, use
--default-mudela-fontsize"
g_force_mudela_fontsize = string.atoi(a)
elif o == '--dep-prefix':
g_dep_prefix = a
elif o == '--no-pictures':
g_do_pictures = 0
elif o == '--read-lys':
g_read_lys = 1
elif o == '--outdir':
g_outdir = a
identify()
if g_outdir:
if os.path.isfile(g_outdir):
error ("outdir is a file: %s" % g_outdir)
if not os.path.exists(g_outdir):
os.mkdir(g_outdir)
for input_filename in files:
do_file(input_filename)
#
# Petr, ik zou willen dat ik iets zinvoller deed,
# maar wat ik kan ik doen, het verandert toch niets?
# --hwn 20/aug/99