#!@PYTHON@
+# vim: set noexpandtab:
+# TODO:
+# * Figure out clean set of options. Hmm, isn't it pretty ok now?
+# * add support for .lilyrc
+
+
+# This is was the idea for handling of comments:
+# Multiline comments, @ignore .. @end ignore is scanned for
+# in read_doc_file, and the chunks are marked as 'ignore', so
+# mudela-book will not touch them any more. The content of the
+# chunks are written to the output file. Also 'include' and 'input'
+# regex has to check if they are commented out.
#
-# The bugs you find are made by Tom Cato Amundsen <tomcato@xoommail.com>
-# Send patches/questions/bugreports to a mailinglist:
-# gnu-music-discuss@gnu.org
-# bug-gnu-music@gnu.org
-# help-gnu-music@gnu.org
+# Then it is scanned for 'mudela', 'mudela-file' and 'mudela-block'.
+# These three regex's has to check if they are on a commented line,
+# % for latex, @c for texinfo.
#
-# All non-english comments are NOT in swedish, they are norwegian!
-# TODO:
-# * center option (??)
-# * make mudela-book understand usepackage{geometry}
-# * check that linewidth set in \paper is not wider than actual linewidth?
-# * the following fails because mudelabook doesn't care that the
-# last } after \end{mudela} finishes the marginpar:
-# \marginpar{
-# \begin{mudela}
-# c d e f g
-# \end{mudela}}
-# * force-verbatim is maybe not that useful since latex fails with footnotes,
-# marginpars and others
-# log:
-# 0.3:
-# rewrite in Python.
-# 0.4:
-# much rewritten by new author. I think the work has been split more
-# logical between different classes.
-# 0.4.1:
-# - cleanup
-# - speedup, do all mudela parsing at the same time to avoid multiple
-# guile startup that takes some seconds on my computer
-# 0.4.2:
-# - fixed default latex fontsize, it should be 10pt not 11pt
-# - verbatim option no longer visible
-# - mudela-book produces .dvi output
-# - change to use castingalgorithm = \Gourlay instead of \Wordwrap. It gives
-# better result on small linewidths.
-# - mudela-book-doc.doc rewritten
-# 0.5:
-# - junked floating and fragment options, added eps option
-# - mudela-book will scan the mudela code to find out if it has to add
-# paper-definition and \score{\notes{...}}
-# - possible to define commands that look like this: \mudela{ c d e }
-# - don't produce .dvi output, it was a silly idea...
-# 0.5.1:
-# - removed init/mudela-book-defs.py, \mudela is defined inside mudela-book
-# - fragment and nonfragment options will override autodetection of type of
-# in mudela-block (voice contents or complete code)
-# 0.5.2:
-# - fixed verbatim option behaviour: don't show \begin{mudela} \end{mudela}
-# and show both mudela code and music
-# - veryverbatim option, same as verbatim but show \begin{mudela}
-# and \end{mudela}. (saves keystrokes in mudela-book-doc.doc)
-# - intertext="bla bla bla" option
-# - mudela-book now understand latex \begin{verbatim}
+# Then lines that are commented out with % (latex) and @c (Texinfo)
+# are put into chunks marked 'ignore'. This cannot be done before
+# searching for the mudela-blocks because % is also the comment character
+# for lilypond.
+#
+# The the rest of the rexeces are searched for. They don't have to test
+# if they are on a commented out line.
import os
+import stat
import string
import re
import getopt
import sys
+import __main__
+import operator
-outdir = 'out'
-initfile = ''
-program_version = '0.5.2'
-
-out_files = []
-
-fontsize_i2a = {11:'eleven', 13:'thirteen', 16:'sixteen',
- 20:'twenty', 26:'twentysix'}
-fontsize_pt2i = {'11pt':11, '13pt':13, '16pt':16, '20pt':20, '26pt':26}
-
-begin_mudela_re = re.compile ('^ *\\\\begin{mudela}')
-begin_verbatim_re = re.compile ('^ *\\\\begin{verbatim}')
-end_verbatim_re = re.compile ('^ *\\\\end{verbatim}')
-extract_papersize_re = re.compile('\\\\documentclass[\[, ]*(\w*)paper[\w ,]*\]\{\w*\}')
-extract_fontsize_re = re.compile('[ ,\[]*([0-9]*)pt')
-begin_mudela_opts_re = re.compile('\[[^\]]*\]')
-end_mudela_re = re.compile ('^ *\\\\end{mudela}')
-section_re = re.compile ('\\\\section')
-chapter_re = re.compile ('\\\\chapter')
-input_re = re.compile ('^\\\\input{([^}]*)')
-include_re = re.compile ('^\\\\include{([^}]*)')
-begin_document_re = re.compile ('^ *\\\\begin{document}')
-documentclass_re = re.compile('\\\\documentclass')
-twocolumn_re = re.compile('\\\\twocolumn')
-onecolumn_re = re.compile('\\\\onecolumn')
-preMudelaExample_re = re.compile('\\\\def\\\\preMudelaExample')
-postMudelaExample_re = re.compile('\\\\def\\\\postMudelaExample')
-boundingBox_re = re.compile('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)')
-intertext_re = re.compile("intertext=\"([^\"]*)\"")
-
-def file_exist_b(name):
- try:
- f = open(name)
- except IOError:
- return 0
- f.close ()
- return 1
-
-def ps_dimention(fname):
- fd = open(fname)
- lines = fd.readlines()
- for line in lines:
- s = boundingBox_re.search(line)
- if s:
- break
- return (int(s.groups()[2])-int(s.groups()[0]),
- int(s.groups()[3])-int(s.groups()[1]))
-
-
-class CompileStatus:
- pass
-class SomethingIsSeriouslyBroken:
- pass
-
-def file_mtime (name):
- return os.stat (name)[8] #mod time
-
-def need_recompile_b(infile, outfile):
- indate = file_mtime (infile)
- try:
- outdate = file_mtime (outfile)
- return indate > outdate
- except os.error:
- return 1
-#
-# executes os.system(command) if infile is newer than
-# outfile or outfile don't exist
-#
-def compile (command, workingdir, infile, outfile):
- "Test if infile is newer than outfile. If so, cd to workingdir"
- "and execute command"
- indate = file_mtime (workingdir+infile)
- try:
- outdate = file_mtime (workingdir+outfile)
- recompile = indate > outdate
-
- except os.error:
- recompile = 1
-
- if recompile:
- sys.stderr.write ('invoking `%s\'\n' % command)
- if workingdir == '':
- status = os.system (command)
- else:
- status = os.system ('cd %s; %s' %(workingdir, command))
- if status:
- raise CompileStatus
-
-class Properties:
- #
- # init
- #
- def __init__(self):
- self.__linewidth = {
- 1: {'a4':{10: 345, 11: 360, 12: 390},
- 'a5':{10: 276, 11: 276, 12: 276},
- 'b5':{10: 345, 11: 356, 12: 356},
- 'letter':{10: 345, 11: 360, 12: 390},
- 'legal': {10: 345, 11: 360, 12: 390},
- 'executive':{10: 345, 11: 360, 12: 379}},
- 2: {'a4':{10: 167, 11: 175, 12: 190},
- 'a5':{10: 133, 11: 133, 12: 133},
- 'b5':{10: 167, 11: 173, 12: 173},
- 'letter':{10: 167, 11: 175, 12: 190},
- 'legal':{10: 167, 11: 175, 12: 190},
- 'executive':{10: 167, 11: 175, 12: 184}}}
- # >0 --> force all mudela to this pt size
- self.force_mudela_fontsize = 0
- self.force_verbatim_b = 0
- self.__data = {
- 'mudela-fontsize' : {'init': 16},
- 'papersize' : {'init': 'a4'},
- 'num-column' : {'init': 1},
- 'tex-fontsize' : {'init': 10}
- }
- def clear_for_new_file(self):
- for var in self.__data.keys():
- self.__data[var] = {'init': self.__data[var]['init']}
- def clear_for_new_block(self):
- for var in self.__data.keys():
- if self.__data[var].has_key('block'):
- del self.__data[var]['block']
- def __get_variable(self, var):
- if self.__data[var].has_key('block'):
- return self.__data[var]['block']
- elif self.__data[var].has_key('file'):
- return self.__data[var]['file']
- else:
- return self.__data[var]['init']
- def setPapersize(self, size, requester):
- self.__data['papersize'][requester] = size
- def getPapersize(self):
- return self.__get_variable('papersize')
- def setMudelaFontsize(self, size, requester):
- self.__data['mudela-fontsize'][requester] = size
- def getMudelaFontsize(self):
- if self.force_mudela_fontsize:
- return self.force_mudela_fontsize
- return self.__get_variable('mudela-fontsize')
- def setTexFontsize(self, size, requester):
- self.__data['tex-fontsize'][requester] = size
- def getTexFontsize(self):
- return self.__get_variable('tex-fontsize')
- def setNumColumn(self, num, requester):
- self.__data['num-column'][requester] = num
- def getNumColumn(self):
- return self.__get_variable('num-column')
- def getLineWidth(self):
- return self.__linewidth[self.getNumColumn()][self.getPapersize()][self.getTexFontsize()]
-
-
-class Mudela_output:
- def __init__ (self, basename):
- self.basename = basename
- self.temp_filename = "%s/%s" %(outdir, 'mudela-temp.ly')
- self.file = open (self.temp_filename, 'w')
- self.__lines = []
- # 'tex' or 'eps'
- self.graphic_type = 'tex'
- self.code_type = 'unknown'
- self.code_type_override = None
- def write (self, line):
- # match only if there is nothing but whitespace before \begin HACK
- if re.search('^\s*\\\\begin{mudela}', line):
- self.scan_begin_statement(line)
- else:
- if self.code_type == 'unknown':
- if re.search('^\s*\\\\score', line) or \
- re.search('^\s*\\\\paper', line) or \
- re.search('^\s*\\\\header', line) or \
- re.search('^\s*[A-Za-z]*\s*=', line):
- self.code_type = 'ly'
- self.__lines.append(line)
- def scan_begin_statement(self, line):
- r = begin_mudela_opts_re.search(line)
- if r:
- o = r.group()[1:-1]
- optlist = re.compile('[\s,]*').split(o)
- else:
- optlist = []
- if 'fragment' in optlist:
- self.code_type_override = 'fly'
- if 'nonfragment' in optlist:
- self.code_type_override = 'ly'
- if 'eps' in optlist:
- self.graphic_type = 'eps'
- for pt in fontsize_pt2i.keys():
- if pt in optlist:
- Props.setMudelaFontsize(fontsize_pt2i[pt], 'block')
- def write_red_tape(self):
- self.file.write ('\\include \"paper%d.ly\"\n' \
- % Props.getMudelaFontsize())
-
- s = fontsize_i2a[Props.getMudelaFontsize()]
- if self.code_type == 'fly':
- linewidth_str = 'linewidth = -1.\cm;'
- else:
- linewidth_str = 'linewidth = %i.\\pt;' % Props.getLineWidth()
- self.file.write("\\paper {"
- + "\\paper_%s " % s
- + linewidth_str
- + "castingalgorithm = \Gourlay; \n}")
- #+ "castingalgorithm = \Wordwrap; indent = 2.\cm; \n}")
- if self.code_type == 'fly':
- self.file.write('\\score{\n\\notes{')
- def close (self):
- if self.code_type == 'unknown':
- self.code_type = 'fly'
- if self.code_type_override:
- self.code_type = self.code_type_override
- self.write_red_tape()
- for l in self.__lines:
- self.file.write(l)
- if self.code_type == 'fly':
- self.file.write('}}')
-
- self.file.close()
-
- inf = outdir + self.basename + '.ly'
- outf = outdir + self.basename + '.tex'
- if not os.path.isfile(inf):
- status = 1
- else:
- status = os.system ('diff -q %s %s' % (self.temp_filename, inf))
- if status:
- os.rename (self.temp_filename, inf)
- if need_recompile_b(inf, outf):
- out_files.append((self.graphic_type, inf))
- def insert_me_string(self):
- "Returns a string that can be used directly in latex."
- if self.graphic_type == 'tex':
- return ['tex', self.basename]
- elif self.graphic_type == 'eps':
- return ['eps', self.basename]
- else:
- raise SomethingIsSeriouslyBroken
-
-class Tex_output:
- def __init__ (self, name):
- self.output_fn = '%s/%s' % (outdir, name)
- self.__lines = []
- def open_verbatim (self, line, level):
- self.__lines.append('\\begin{verbatim}\n')
- if level == 2:
- s = re.sub('veryverbatim[\s,]*', '', line)
- s = re.sub('intertext=\"([^\"]*)\"[\s,]*', '', s)
- s = re.sub(',\s*\]', ']', s)
- s = re.sub('\[\]', '', s)
- self.__lines.append(s);
- def close_verbatim (self):
- self.__lines.append('\\end{verbatim}\n')
- def write (self, s):
- self.__lines.append(s)
- def create_graphics(self):
- s = ''
- g_vec = []
- for line in self.__lines:
- if type(line)==type([]):
- g_vec.append(line)
- for g in g_vec:
- if need_recompile_b(outdir+g[1]+'.ly', outdir+g[1]+'.tex'):
- s = s + ' ' + g[1]+'.ly'
- if s != '':
- e = os.system('cd %s; lilypond %s' %(outdir, s))
- if e:
- print "error: lilypond exited with value", e
- sys.exit(e)
- for g in g_vec:
- if g[0] == 'eps':
- compile('tex %s' % g[1]+'.tex', outdir, g[1]+'.tex', g[1]+'.dvi')
- compile('dvips -E -o %s %s' %(g[1]+'.eps', g[1]+'.dvi'), outdir,
- g[1]+'.dvi', g[1]+'.eps')
- def write_outfile(self):
- file = open(self.output_fn+'.latex', 'w')
- file.write('% Created by mudela-book\n')
- for line in self.__lines:
- if type(line)==type([]):
- if line[0] == 'tex':
- file.write('\\preMudelaExample\\input %s\n\postMudelaExample '\
- # TeX applies the prefix of the main source automatically.
- % (line[1]+'.tex'))
-# % (outdir+line[1]+'.tex'))
- if line[0] == 'eps':
- ps_dim = ps_dimention(outdir+line[1]+'.eps')
- file.write('\\parbox{%ipt}{\includegraphics{%s}}\n' \
- % (ps_dim[0], line[1]+'.eps'))
-# % (ps_dim[0], outdir+line[1]+'.eps'))
- else:
- file.write(line)
- file.close()
-
-class Tex_input:
- def __init__ (self, filename):
- for fn in [filename, filename+'.tex', filename+'.doc']:
- try:
- self.infile = open (fn)
- self.filename = fn
- return
- except:
- continue
- raise IOError
- def get_lines (self):
- lines = self.infile.readlines ()
- (retlines, retdeps) = ([],[self.filename])
- for line in lines:
- r_inp = input_re.search (line)
- r_inc = include_re.search (line)
-
- # Filename rules for \input :
- # input: no .tex ext
- # 1. will search for file with exact that name (tex-input.my will be found)
- # 2. will search for file with .tex ext, (tex-input.my
- # will find tex-input.my.tex)
- # input: with .tex ext
- # 1. will find exact match
-
- # Filename rules for \include :
- # 1. will only find files with name given to \include + .tex ext
- if r_inp:
- try:
- t = Tex_input (r_inp.groups()[0])
- ls = t.get_lines ()
- retlines = retlines + ls[0]
- retdeps = retdeps + ls[1]
- except:
- print "warning: can't find %s, let's hope latex will" \
- % r_inp.groups()[0]
- retlines.append (line)
- elif r_inc:
- try:
- t = Tex_input (r_inc.groups()[0]+'.tex')
- ls =t.get_lines ()
- ls[0].insert(0, '\\newpage\n')
- ls[0].append('\\newpage\n')
- retlines = retlines + ls[0]
- retdeps = retdeps + ls[1]
- except:
- print "warning: can't find %s, let's hope latex will" \
- % r_inc.groups()[0]
- retlines.append (line)
- else:
- r_mud = defined_mudela_cmd_re.search(line)
- if r_mud:
- ss = "\\\\verb(?P<xx>[^a-zA-Z])\s*\\\\%s\s*(?P=xx)" \
- % re.escape(r_mud.group()[1:])
- if re.search(ss, line):
- retlines.append(line)
- continue
- while 1:
- opts = r_mud.groups()[2]
- if opts == None:
- opts = ''
- else:
- opts = ', '+opts
- (start, rest) = string.split(line, r_mud.group(), 1)
- retlines.append(start)#+'\n')
- v = string.split(defined_mudela_cmd[r_mud.groups()[0]], '\n')
- for l in v[1:-1]:
- l = re.sub(r'\\fontoptions', opts, l)
- l = re.sub(r'\\maininput', r_mud.groups()[3], l)
- retlines.append(l)
- r_mud = defined_mudela_cmd_re.search(rest)
- if not r_mud:
- retlines.append(rest)
- break;
- line = rest
+program_version = '@TOPLEVEL_VERSION@'
+if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
+ program_version = '1.3.105.tca1'
+
+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] = float(value[:-2])
+ elif type(value) == type("") and value[-2:] == 'mm':
+ self.__dict__[name] = mm2pt(float(value[:-2]))
+ elif type(value) == type("") and value[-2:] == 'cm':
+ self.__dict__[name] = 10 * mm2pt(float(value[:-2]))
+ elif type(value) == type("") and value[-2:] == 'in':
+ self.__dict__[name] = in2pt(float(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:
+ return self.m_paperdef[self.m_papersize][self.m_landscape or self.m_geo_landscape]
+ #return self.m_paperdef[self.m_papersize][self.m_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': "\\def\postMudelaExample{}\n",
+ 'output-default-pre': "\\def\preMudelaExample{}\n",
+ 'usepackage-graphics': '\\usepackage{graphics}\n',
+ '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):
+ if __main__.format == 'texi':
+ body = re.sub ('([@{}])', '@\\1', body)
+ return get_output ('output-verbatim') % body
+
+
+re_dict = {
+ 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
+ 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
+ 'option-sep' : ', *',
+ 'header': r"\\documentclass\s*(\[.*?\])?",
+ 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
+ 'preamble-end': r'(?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' : r'(?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",
+ 'usepackage-graphics': r"\usepackage{graphics}",
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': no_match,
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
+ 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
+ },
+
+ 'texi': {
+ 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
+ 'input': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'landscape': no_match,
+ 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
+ 'verb': r"""(?P<code>@code{.*?})""",
+ 'mudela-file': '(?m)^(?!@c)(?P<match>@mudelafile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
+ 'mudela' : '(?m)^(?!@c)(?P<match>@mudela(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
+ 'mudela-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@mudela(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end mudela\s))""",
+ 'option-sep' : ', *',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
+ '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_texi_preamble (chunks):
+ # this is not bulletproof..., it checks the first 10 chunks
+ idx = 0
+ while 1:
+ if chunks[idx][0] == 'input':
+ if string.find(chunks[idx][1], "@afourpaper") != -1:
+ paperguru.m_papersize = 'a4'
+ elif string.find(chunks[idx][1], "@afourwide") != -1:
+ paperguru.m_papersize = 'a4wide'
+ elif string.find(chunks[idx][1], "@smallbook") != -1:
+ paperguru.m_papersize = 'smallbook'
+ idx = idx + 1
+ if idx == 10 or idx == len(chunks):
+ break
+
+def scan_preamble (chunks):
+ if __main__.format == 'texi':
+ scan_texi_preamble(chunks)
+ else:
+ assert __main__.format == 'latex'
+ scan_latex_preamble(chunks)
+
+
+def completize_preamble (chunks):
+ if __main__.format == 'texi':
+ return chunks
+ pre_b = post_b = graphics_b = None
+ for chunk in chunks:
+ if chunk[0] == 'preamble-end':
+ break
+ if chunk[0] == 'input':
+ m = get_re('def-pre-re').search(chunk[1])
+ if m:
+ pre_b = 1
+ if chunk[0] == 'input':
+ m = get_re('def-post-re').search(chunk[1])
+ if m:
+ post_b = 1
+ if chunk[0] == 'input':
+ m = get_re('usepackage-graphics').search(chunk[1])
+ if m:
+ graphics_b = 1
+ x = 0
+ while chunks[x][0] != 'preamble-end':
+ x = x + 1
+ if not pre_b:
+ chunks.insert(x, ('input', get_output ('output-default-pre')))
+ if not post_b:
+ chunks.insert(x, ('input', get_output ('output-default-post')))
+ if not graphics_b:
+ chunks.insert(x, ('input', get_output ('usepackage-graphics')))
+ return chunks
+
+
+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)
+ 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 chop_chunks(chunks, re_name, func, use_match=0):
+ 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:
- retlines.append (line)
+ if use_match:
+ newchunks.append (('input', str[:m.start ('match')]))
+ 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:
- return (retlines, retdeps)
-
-
-class Main_tex_input(Tex_input):
- def __init__ (self, name, outname):
-
- Tex_input.__init__ (self, name) # ugh
- self.outname = outname
- self.chapter = 0
- self.section = 0
- self.fine_count =0
- self.mudtex = Tex_output (self.outname)
- self.mudela = None
- self.deps = []
- self.verbatim = 0
- # set to 'mudela' when we are processing mudela code,
- # both verbatim and graphic-to-be
- self.mode = 'latex'
- def set_sections (self, l):
- if section_re.search (l):
- self.section = self.section + 1
- if chapter_re.search (l):
- self.section = 0
- self.chapter = self.chapter + 1
-
- def gen_basename (self):
- return '%s-%d.%d.%d' % (self.outname, self.chapter,
- self.section, self.fine_count)
- def extract_papersize_from_documentclass(self, line):
- pre = extract_papersize_re.search(line)
- if not pre:
- return None
- return pre.groups()[0]
- def extract_fontsize_from_documentclass(self, line):
- r = extract_fontsize_re.search(line)
- if r:
- return int(r.groups()[0])
- def do_it(self):
- preMudelaDef = postMudelaDef = 0
- (lines, self.deps) = self.get_lines ()
- #HACK
- latex_verbatim = 0
- for line in lines:
- if documentclass_re.search (line):
- p = self.extract_papersize_from_documentclass (line)
- if p:
- Props.setPapersize(p, 'file')
- f = self.extract_fontsize_from_documentclass (line)
- if f:
- Props.setTexFontsize (f, 'file')
- elif twocolumn_re.search (line):
- Props.setNumColumn (2, 'file')
- elif onecolumn_re.search (line):
- Props.setNumColumn (1, 'file')
- elif preMudelaExample_re.search (line):
- preMudelaDef = 1
- elif postMudelaExample_re.search (line):
- postMudelaDef = 1
- elif begin_verbatim_re.search (line):
- latex_verbatim = 1
- elif end_verbatim_re.search (line):
- latex_verbatim = 0
- elif begin_document_re.search (line):
- if not preMudelaDef:
- self.mudtex.write ('\\def\\preMudelaExample{}\n')
- if not postMudelaDef:
- self.mudtex.write ('\\def\\postMudelaExample{}\n')
- elif begin_mudela_re.search (line) and not latex_verbatim:
- Props.clear_for_new_block()
- if __debug__:
- if self.mode == 'mudela':
- raise AssertionError
- self.mode = 'mudela'
- r = begin_mudela_opts_re.search (line)
- if r:
- o = r.group()[1:][:-1]
- optlist = re.compile('[ ,]*').split(o)
- m = intertext_re.search(r.group())
- if m:
- self.intertext = m.groups()[0]
- else:
- self.intertext = None
- else:
- optlist = []
- if ('veryverbatim' in optlist):
- self.verbatim = 2
- elif ('verbatim' in optlist) or (Props.force_verbatim_b):
- self.verbatim = 1
- else:
- self.verbatim = 0
- if self.verbatim:
- self.mudtex.open_verbatim (line, self.verbatim)
- self.mudela = Mudela_output (self.gen_basename ())
- self.mudela.write (line)
- continue
- elif end_mudela_re.search (line) and not latex_verbatim:
- if __debug__:
- if self.mode != 'mudela':
- raise AssertionError
-
- if self.verbatim:
- if self.verbatim == 2:
- self.mudtex.write (line)
- self.mudtex.close_verbatim ()
- self.mudela.close ()
- if self.verbatim and self.intertext:
- self.mudtex.write(self.intertext)
- self.mudtex.write (self.mudela.insert_me_string())
- del self.mudela
- self.mudela = None
- self.fine_count = self.fine_count + 1
- self.mode = 'latex'
- continue
-
- if self.mode == 'mudela':
- self.mudela.write (line)
- if self.verbatim:
- self.mudtex.write (line)
- else:
- self.mudtex.write (line)
- self.set_sections(line)
- self.mudtex.create_graphics()
- self.mudtex.write_outfile()
- del self.mudtex
+ 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'
+ else:
+ __main__.format = 'latex'
+ if __main__.format == 'texi':
+ __main__.paperguru = TexiPaper()
+ else:
+ __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)
+ chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
+ #ugh fix input
+ chunks = chop_chunks(chunks, 'include', do_include_file, 1)
+ chunks = chop_chunks(chunks, 'input', do_input_file, 1)
+ 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, ... ]
+
+ """
+ (type, body, opts) = 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]
+ 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)
+ def f(base, ext1, ext2):
+ a = os.path.isfile(base + ext2)
+ if (os.path.isfile(base + ext1) and
+ os.path.isfile(base + ext2) and
+ os.stat(base+ext1)[stat.ST_MTIME] >
+ os.stat(base+ext2)[stat.ST_MTIME]) or \
+ not os.path.isfile(base + ext2):
+ return 1
+ todo = []
+ if 'tex' in needed_filetypes and f(outname, '.ly', '.tex'):
+ todo.append('tex')
+ if 'eps' in needed_filetypes and f(outname, '.tex', '.eps'):
+ todo.append('eps')
+ if 'png' in needed_filetypes and f(outname, '.eps', '.png'):
+ todo.append('png')
+ newbody = ''
+ if 'verbatim' in opts:
+ newbody = output_verbatim (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)
+ if g_outdir:
+ fn = os.path.join(g_outdir, fn)
+ 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
+ sys.stdout.write("""Usage: mudela-book [options] FILE\n
Generate hybrid LaTeX input from Latex + mudela
-Options:\n
- -h, --help print this help
- -d, --outdir=DIR directory to put generated files
- -o, --outname=FILE prefix for filenames
- --default-mudela-fontsize=??pt default fontsize for music
- --force-mudela-fontsize=??pt force fontsize for all inline mudela
- --force-verbatim make all mudela verbatim\n
- --dependencies write dependencies
- --init mudela-book initfile
- """
- )
- sys.exit (0)
-
-
-def write_deps (fn, out, deps):
- out_fn = outdir + '/' + fn
- print '`writing `%s\'\n\'' % out_fn
-
- f = open (out_fn, 'w')
- f.write ('%s: %s\n'% (outdir + '/' + out + '.dvi',
- reduce (lambda x,y: x + ' '+ y, deps)))
+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 bug-gnu-music@gnu.org.
+
+Written by Tom Cato Amundsen <tca@gnu.org> and
+Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""")
+
+ 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.stderr.write ('This is %s version %s\n' % ('mudela-book', program_version))
-
-def main():
- global outdir, initfile, defined_mudela_cmd, defined_mudela_cmd_re
- outname = ''
- try:
- (options, files) = getopt.getopt(
- sys.argv[1:], 'hd:o:', ['outdir=', 'outname=',
- 'default-mudela-fontsize=',
- 'force-mudela-fontsize=',
- 'help', 'dependencies',
- 'force-verbatim', 'init='])
- except getopt.error, msg:
- print "error:", msg
- sys.exit(1)
-
- do_deps = 0
- for opt in options:
+ 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 = chop_chunks(chunks, 'mudela', make_mudela, 1)
+ chunks = chop_chunks(chunks, 'mudela-file', make_mudela_file, 1)
+ chunks = chop_chunks(chunks, 'mudela-block', make_mudela_block, 1)
+ chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
+ chunks = 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
+ x = 0
+ chunks = completize_preamble (chunks)
+ 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 == '--outname' or o == '-o':
- if len(files) > 1:
- #HACK
- print "Mudela-book is confused by --outname on multiple files"
- sys.exit(1)
- outname = a
- if o == '--outdir' or o == '-d':
- outdir = a
- if o == '--help' or o == '-h':
- help ()
- if o == '--dependencies':
- do_deps = 1
- if o == '--default-mudela-fontsize':
- if not fontsize_pt2i.has_key(a):
- print "Error: illegal fontsize:", a
- print " accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt"
- sys.exit()
- Props.setMudelaFontsize(fontsize_pt2i[a], 'init')
- if o == '--force-mudela-fontsize':
- if not fontsize_pt2i.has_key(a):
- print "Error: illegal fontsize:", a
- print " accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt"
- sys.exit()
- Props.force_mudela_fontsize = fontsize_pt2i[a]
- if o == '--force-verbatim':
- Props.force_verbatim_b = 1
- if o == '--init':
- initfile = a
- if outdir[-1:] != '/':
- outdir = outdir + '/'
-
- defined_mudela_cmd = {'mudela': r"""
-\begin{mudela}[eps \fontoptions]
- \maininput
-\end{mudela}
-"""}
- if initfile != '':
- f = open(initfile)
- s = f.read()
- f.close()
- d = eval(s)
- for i in d.keys():
- defined_mudela_cmd[i] = d[i]
- del d
- c = defined_mudela_cmd.keys()[0]
- for x in defined_mudela_cmd.keys()[1:]:
- c = c + '|'+x
- defined_mudela_cmd_re = re.compile("\\\\(%s)(\[(\d*pt)\])*{([^}]*)}" %c)
-
- if not os.path.isdir(outdir):
- os.system('mkdir %s' % outdir)
-
- for input_filename in files:
- Props.clear_for_new_file()
- if outname:
- my_outname = outname
- else:
- my_outname = os.path.basename(os.path.splitext(input_filename)[0])
- my_depname = my_outname + '.dep'
- inp = Main_tex_input (input_filename, my_outname)
- inp.do_it ()
-# os.system('latex %s/%s.latex' % (outdir, my_outname))
- if do_deps:
- write_deps (my_depname, my_outname, inp.deps)
+
+ 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()
-Props = Properties()
-main()
+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