#!@PYTHON@
-# All non-english comments are NOT in swedish, they are norwegian!
-
-# TODO: center option (??)
-# * clean up handling of filename of inputfile
-# * steal Props class from ly2dvi?
-# * \onecolumn, \twocolumn
-# * fontsize change with commandline parameters
-# * the verbatim option should not be visible in the created latex file
-# * what the h.. does castingalgorithm do/mean???
-# * compile all regular expressions
-# * the following fails because mudelabook doesn't care that the
-# last } after \end{mudela} finishes the marginpar:
-# \marginpar{
-# \begin{mudela}[fragment]
-# c d e f g
-# \end{mudela}}
-# * Command line parameter that force all inline mudela to be verbatim, and
-# one that forces all to be printed
-# 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.
-#
import os
import string
import re
import getopt
import sys
-import regsub
+import __main__
outdir = 'out'
-program_version = '0.4'
-default_paper_size_global = 'a4'
-default_mudela_fontsize = '16pt'
-force_mudela_fontsize_b = 0
-
-fontsize_i2a = {11:'eleven', 13:'thirteen', 16:'sixteen', 20:'twenty', 26:'twentysix'}
-fontsize_pt2i = {'11pt':11, '13pt':13, '16pt':16, '20pt':20, '26pt':26}
-
-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()
- reg = re.compile('%%BoundingBox: ([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)')
- for line in lines:
- s = reg.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
-
-def file_mtime (name):
- return os.stat (name)[8] #mod time
-#
-# executes os.system(command) if infile is newer than
-# outfile or outfile don't exist
+initfile = ''
+program_version = '@TOPLEVEL_VERSION@'
+
+cwd = os.getcwd ()
+include_path = [cwd]
+
+# TODO: Figure out clean set of options.
+
+# BUG: does not handle \verb|\begin{verbatim}\end{verbatim}| correctly.
+# Should make a joint RE for \verb and \begin, \end{verbatim}
#
-def compile (command, workingdir, infile, outfile):
- indate = file_mtime (workingdir+infile)
- try:
- outdate = file_mtime (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 PaperDef:
- __onecolumn_linewidth = {
- 'a4':{'10pt': 345, '11pt': 360, '12pt':390},
- 'a5':{'10pt': 276, '11pt': 276, '12pt':276},
- 'b5':{'10pt': 345, '11pt': 356, '12pt':356},
- 'letter':{'10pt': 345, '11pt': 360, '12pt':390},
- 'legal':{'10pt': 345, '11pt': 360, '12pt':390},
- 'executive':{'10pt': 345, '11pt': 360, '12pt':379}
- }
- __twocolumn_linewidth = {
- 'a4':{'10pt': 167, '11pt': 175, '12pt':190},
- 'a5':{'10pt': 133, '11pt': 133, '12pt':133},
- 'b5':{'10pt': 167, '11pt': 173, '12pt':173},
- 'letter':{'10pt': 167, '11pt': 175, '12pt':190},
- 'legal':{'10pt': 167, '11pt': 175, '12pt':190},
- 'executive':{'10pt': 167, '11pt': 175, '12pt':184}
- }
- __numcolumn = 1
- __fontsize = '11pt'
- #
- # init
- #
- def __init__(self):
- self.__papersize = default_paper_size_global
- def set_papersize (self, p):
- if not self.__onecolumn_linewidth.has_key(p):
- print "warning:unsupported papersize", p, \
- "will use", default_paper_size_global
- self.__papersize = default_paper_size_global
- else:
- self.__papersize = p
- def set_fontsize(self, pt):
- self.__fontsize = pt
- def get_linewidth (self):
- if self.__numcolumn == 1:
- return self.__onecolumn_linewidth[self.__papersize][self.__fontsize]
- else:
- return self.__twocolumn_linewidth[self.__papersize][self.__fontsize]
- def onecolumn (slef):
- self.__numcolumn = 1
- def twocolumn (self):
- self.__numcolumn = 2
-
-
-class Mudela_output:
- def __init__ (self, basename):
- self.basename = basename
- # it's an integer!
- self.feta_pt_size = fontsize_pt2i[default_mudela_fontsize]
- self.temp_filename = "%s/%s" %(outdir, 'mudela-temp.ly')
- self.file = open (self.temp_filename, 'w')
- # 'tex' or 'eps'
- self.graphic_type = 'tex'
- self.fragment = 0
- def write (self, line):
- # match only if there is nothing but whitespace before \begin
- if re.search('^\s*\\\\begin{mudela}', line):
- self.scan_begin_statement(line)
- self.write_red_tape()
- else:
- self.file.write (line)
- def scan_begin_statement(self, line):
- r = begin_mudela_opts_re.search(line)
- if r:
- o = r.group()[1:][:-1]
- optlist = re.compile('[ ,]*').split(o)
- else:
- optlist = []
- if 'floating' in optlist:
- self.graphic_type = 'eps'
- else:
- self.graphic_type = 'tex'
- if 'fragment' in optlist:
- self.fragment = 1
- else:
- self.fragment = 0
- for pt in fontsize_pt2i.keys():
- if pt in optlist:
- self.feta_pt_size = fontsize_pt2i[pt]
- def write_red_tape(self):
- self.file.write ('\\include \"paper%d.ly\"\n' % self.feta_pt_size)
- s = fontsize_i2a[self.feta_pt_size]
- if self.fragment:
- self.file.write("default_paper = \\paper {"
- + "\\paper_%s\n linewidth = -1.\\pt;" % s
- + "castingalgorithm = \Wordwrap; indent = 2.\cm; \n}")
- self.file.write("\\score{\n\\notes") #HACK
- else:
- self.file.write ("default_paper = \\paper {"
- + "\\paper_%s\n linewidth = %i.\\pt;" % \
- (s, Paper.get_linewidth()) \
- + "castingalgorithm = \Wordwrap; indent = 2.\cm;\n}")
- def close (self):
- if self.fragment:
- self.file.write ('\\paper { \\default_paper; } }\n')
- self.file.close ()
-
- inf = self.basename + '.ly'
- outf = self.basename + '.tex'
- if not file_exist_b (inf):
- status = 1
- else:
- status = os.system ('diff -q %s %s' % (self.temp_filename, inf))
-
- if status:
- os.rename (self.temp_filename, inf)
- compile ('lilypond -o %s %s;'% (self.basename, inf), '', inf, outf)
- if self.graphic_type == 'eps':
- bname = self.basename[string.rfind(self.basename, '/')+1:]
- tex_name = bname+'.tex'
- dvi_name = bname+'.dvi'
- eps_name = bname+'.eps'
- compile ('tex %s' % tex_name, outdir, tex_name, dvi_name)
- compile ('dvips -E -o %s %s' % (eps_name, dvi_name), outdir, dvi_name, eps_name)
- def insert_me_string(self):
- "Returns a string that can be used directly in latex."
- if self.graphic_type == 'tex':
- return '\\preMudelaExample\\input %s\n\postMudelaExample\n' % self.basename
- elif self.graphic_type == 'eps':
- ps_dim = ps_dimention('%s.eps' % self.basename)
- return '\\parbox{%ipt}{\includegraphics{%s.eps}}' % (ps_dim[0], self.basename)
- else:
- print "Unsupported graphic type '%s'" % self.graphic_type
- sys.exit(1)
-
-class Tex_output:
- def __init__ (self, name):
- self.output_fn = '%s/%s' % (outdir, name)
- self.file = open (self.output_fn , 'w')
- def open_mudela (self, basename):
- self.mudela_basename = basename
- def open_verbatim (self):
- self.file.write ('\\begin{verbatim}\n')
- def close_verbatim (self):
- self.file.write ('\\end{verbatim}\n')
- def write (self, s):
- self.file.write (s)
-
-begin_mudela_re = re.compile ('^ *\\\\begin{mudela}')
-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')
-
-class Tex_input:
- def __init__ (self,name):
- # HACK
- if (name[-4:] != '.tex') and (name[-4:] != '.doc'):
- name = name + '.tex'
- self.filename = name
- self.infile = open (name)
+
+default_music_fontsize = 16
+default_text_fontsize = 12
+
+# latex linewidths:
+# indices are no. of columns, papersize, fontsize
+# Why can't this be calculated?
+latex_linewidths = {
+ 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}}}
+
+
+options = [
+ ('DIM', '', 'default-mudela-fontsize', 'default fontsize for music. DIM is assumed to in points'),
+ ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
+ ('', 'h', 'help', 'print help'),
+ ('DIR', 'I', 'include', 'include path'),
+ ('', '', 'init', 'mudela-book initfile'),
+# ('DIM', '', 'force-mudela-fontsize', 'force fontsize for all inline mudela. DIM is assumed to in points'),
+ ('', '', 'force-verbatim', 'make all mudela verbatim'),
+ ('', 'M', 'dependencies', 'write dependencies'),
+ ('', 'n', 'no-lily', 'don\'t run lilypond'),
+ ('FILE', 'o', 'outname', 'prefix for filenames'),
+ ('', 'v', 'version', 'print version information' )
+ ]
+
+format = ''
+run_lilypond = 1
+use_hash = 1
+no_match = 'a\ba'
+
+# format specific strings, ie. regex-es for input, and % strings for output
+output_dict= {
+ 'latex': {
+ 'output-mudela-fragment' : r"""\begin[eps,fragment%s]{mudela}
+ \context Staff <
+ \context Voice{
+ %s
+ }
+ >
+\end{mudela}""",
+ 'output-mudela':r"""\begin[%s]{mudela}
+%s
+\end{mudela}""",
+ 'output-verbatim': r"""\begin{verbatim}%s\end{verbatim}""",
+ 'output-default-post': r"""\def\postMudelaExample{}""",
+ 'output-default-pre': r"""\def\preMudelaExample{}""",
+ 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%s.eps}}{\includegraphics{%s.eps}}',
+ 'output-tex': '\\preMudelaExample \\input %s.tex \\postMudelaExample\n'
+ },
+ 'texi' : {'output-mudela': """@mudela[%s]
+%s
+@end mudela
+""",
+ '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.
+ 'output-all': r"""@tex
+\catcode`\@=12
+\input lilyponddefs
+\def\EndLilyPondOutput{}
+\input %s.tex
+\catcode`\@=0
+@end tex
+@html
+<img src=%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': '\\\\input{?([^}\t \n}]*)',
+ 'include': '\\\\include{([^}]+)}',
+
+ 'comma-sep' : ', *',
+ 'header': r"""\\documentclass(\[.*?\])?""",
+ 'preamble-end': '\\\\begin{document}',
+ 'verbatim': r"""(?s)\\begin{verbatim}(.*?)\\end{verbatim}""",
+ 'verb': r"""\\verb(.)(.*?)\1""",
+ 'mudela-file': '\\\\mudelafile(\[[^\\]]+\])?{([^}]+)}',
+ 'mudela' : '\\\\mudela(\[.*?\])?{(.*?)}',
+ 'mudela-block': r"""(?s)\\begin(\[.*?\])?{mudela}(.*?)\\end{mudela}""",
+ 'interesting-cs': '\\\\(chapter|section|twocolumn|onecolumn)',
+ 'def-post-re': r"""\\def\\postMudelaExample""",
+ 'def-pre-re': r"""\\def\\preMudelaExample""",
+ },
+ 'texi': {'input': '@include[ \n\t]+([^\t \n]*)',
+ 'include': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'verbatim': r"""(?s)@example(.*?)@end example$""",
+ 'verb': r"""@code{(.*?)}""",
+ 'mudela-file': '@mudelafile(\[[^\\]]+\])?{([^}]+)}',
+ 'mudela' : '@mudela(\[.*?\])?{(.*?)}',
+ 'mudela-block': r"""(?s)@mudela(\[.*?\])?(.*?)@end mudela""",
+ 'interesting-cs': r"""[\\@](chapter|section)""",
+ 'comma-sep' : ', *',
+ }
+ }
+
+
+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 (-1)
+ 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 find_file (name):
+ for a in include_path:
+ try:
+ nm = os.path.join (a, name)
+ f = open (nm)
+ return nm
+ except IOError:
+ pass
+ return ''
+
+def error (str):
+ sys.stderr.write (str + "\n Exiting ... \n\n")
+ raise 'Exiting.'
+
+
+def compose_full_body (body, opts):
+ "Construct the text of an input file: add stuff to BODY using OPTS as options."
+ paper = 'a4'
+ music_size = default_music_fontsize
+ latex_size = default_text_fontsize
+
+ cols = 1
+ for o in opts:
+ m = re.search ('^(.*)paper$', o)
+ if m:
+ paper = m.group (1)
+
+
+ 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 'twocolumn' in opts:
+ cols = 2
+
+
+ # urg: breaks on \include of full score
+ # Use nofly option if you want to \include full score.
+ if 'nofly' not in opts and not re.search ('\\\\score', body):
+ opts.append ('fragment')
+
+ if 'fragment' in opts and 'nosingleline' not in opts:
+ opts.append ('singleline')
+
+ if 'singleline' in opts:
+ l = -1.0;
+ else:
+ l = latex_linewidths[cols][paper][latex_size]
+
+
+ if 'relative' in opts:
+ body = '\\relative c { %s }' % body
+
+
+ if 'fragment' in opts:
+ 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
+\include "paper%d.ly"
+\paper { linewidth = %f \pt; }
+""" % (optstring, music_size, l) + body
+
+ return body
+
+def find_inclusion_chunks (regex, surround, str):
+ chunks = []
+ while str:
+ m = regex.search (str)
+
+ if m == None:
+ chunks.append (('input', str))
+ str = ''
+ break
+
+ chunks.append (('input', str[: m.start (0)]))
+ chunks.append (('input', surround))
+ chunks = chunks + read_doc_file (m.group (1))
+ chunks.append (('input', surround))
+
+ str = str [m.end (0):]
+ return chunks
+
+def find_include_chunks (str):
+ return find_inclusion_chunks (get_re ('include'), '\\newpage', str)
+
+def find_input_chunks (str):
+ return find_inclusion_chunks (get_re ('input'), '', str)
+
+def read_doc_file (filename):
+ """Read the input file, substituting for \input, \include, \mudela{} and \mudelafile"""
+ str = ''
+ for ext in ['', '.tex', '.doc', '.tely']:
+ try:
+ f = open(filename+ ext)
+ str = f.read (-1)
+ except:
+ pass
+
+
+ if not str:
+ error ("File not found `%s'\n" % filename)
+
+ retdeps = [filename]
+
+ if __main__.format == '':
+ latex = re.search ('\\\\document', str[:200])
+ texinfo = re.search ('@node', 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'
+
+ chunks = [('input', str)]
+
+ for func in (find_verbatim_chunks, find_verb_chunks, find_include_chunks, find_input_chunks):
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'input':
+ ch = func (c[1])
+ newchunks = newchunks + ch
+ else:
+ newchunks.append (c)
+ chunks = newchunks
+
+ return chunks
+
+
+
+def scan_preamble (str):
+ options = []
+ m = get_re ('header').search( str)
+
+ # should extract paper & fontsz.
+ if m and m.group (1):
+ options = options + re.split (',[\n \t]*', m.group(1)[1:-1])
+
+ def verbose_fontsize ( x):
+ # o ??
+ #if o.match('[0-9]+pt'):
+ if re.match('[0-9]+pt', x):
+ return 'latexfontsize=' + x
+ else:
+ return x
+
+ options = map (verbose_fontsize, options)
+
+ return options
+
+
+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
+
+def find_verbatim_chunks (str):
+ """Chop STR into a list of tagged chunks, ie. tuples of form
+ (TYPE_STR, CONTENT_STR), where TYPE_STR is one of 'input' and 'verbatim'
+ """
+
+ chunks = []
+ while str:
+ m = get_re ('verbatim').search( str)
+ if m == None:
+ chunks.append( ('input', str))
+ str = ''
+ else:
+ chunks.append (('input', str[:m.start (0)]))
+ chunks.append (('verbatim', m.group (0)))
+
+ str = str [m.end(0):]
+
+ return chunks
+
+def find_verb_chunks (str):
+
+ chunks = []
+ while str:
+ m = get_re ("verb").search(str)
+ if m == None:
+ chunks.append (('input', str))
+ str = ''
+ else:
+ chunks.append (('input', str[:m.start (0)]))
+ chunks.append (('verbatim', m.group (0)))
+ str = str [m.end(0):]
+
+ return chunks
+
+
+
+def find_mudela_shorthand_chunks (str):
+ return [('input', find_mudela_shorthands(str))]
+
+def find_mudela_shorthands (b):
+ def mudela_short (match):
+ "Find \mudela{}, and substitute appropriate \begin / \end blocks."
+ opts = match.group (1)
+ if opts:
+ opts = ',' + opts[1:-1]
+ else:
+ opts = ''
+ return get_output ('output-mudela-fragment') % (opts, match.group (2))
+
+ def mudela_file (match):
+ "Find \mudelafile, and substitute appropriate \begin / \end blocks."
+ d = [] #, d = retdeps
+ full_path = find_file (match.group (2))
+ if not full_path:
+ error("error: can't find file `%s'\n" % match.group(2))
+
+ d.append (full_path)
+ f = open (full_path)
+ str = f.read (-1)
+ opts = match.group (1)
+ if opts:
+ opts = opts[1:-1]
+ opts = re.split (',[ \n\t]*', opts)
+ else:
+ opts = []
+
+ if re.search ('.fly$', full_path):
+ opts.append ('fly')
+ elif re.search ('.sly$', full_path):
+ opts = opts + [ 'fly','fragment']
+ elif re.search ('.ly$', full_path):
+ opts .append ('nofly')
+
+ str_opts = string.join (opts, ',')
+
+ str = ("%% copied from file `%s'\n" % full_path) + str
+ return get_output ('output-mudela') % (str_opts, str)
+
+ b = get_re('mudela-file').sub (mudela_file, b)
+ b = get_re('mudela').sub (mudela_short, b)
+ return b
+
+def find_mudela_chunks (str):
+ """Find mudela blocks, while watching for verbatim. Returns
+ (STR,MUDS) with substituted for the blocks in STR,
+ and the blocks themselves MUDS"""
+
+ chunks = []
+ while str:
+ m = get_re ("mudela-block").search( str)
+ if not m:
+ chunks.append (('input', str))
+ str = ''
+ break
+
+ chunks.append (('input', str[:m.start (0)]))
+
+ opts = m.group (1)
+ if opts:
+ opts = opts[1:-1]
+ else:
+ opts = ''
+ optlist = get_re('comma-sep').split (opts)
+
+ body = m.group (2)
+ chunks.append (('mudela', body, optlist))
+
+ str = str [m.end (0):]
+
+ return chunks
+
+
+
+def advance_counters (counter, opts, str):
+ """Advance chap/sect counters,
+ revise OPTS. Return the new counter tuple"""
+
+ (chapter, section, count) = counter
+ done = ''
+ while str:
+ m = get_re ('interesting-cs').search(str)
+ if not m:
+ done = done + str
+ str = ''
+ break
+
+ done = done + str[:m.end (0)]
+ str = str[m.end(0):]
+ g = m.group (1)
+
+ if g == 'twocolumn':
+ opts.append ('twocolumn')
+ elif g == 'onecolumn':
+ try:
+ current_opts.remove ('twocolumn')
+ except IndexError:
+ pass
+ elif g == 'chapter':
+ (chapter, section, count) = (chapter + 1, 0, 0)
+ elif g == 'section':
+ (section, count) = (section + 1, 0)
+
+
+ return (chapter, section, count)
+
+
+def schedule_mudela_block (base, chunk, extra_opts):
+ """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'
+ opts = opts + extra_opts
+
+ newbody = ''
+ if 'verbatim' in opts:
+ newbody = output_verbatim (body)
+
+ file_body = compose_full_body (body, opts)
+ basename = base
+ if __main__.use_hash:
+ basename = `hash (file_body)`
+ updated = update_file (file_body, basename + '.ly')
+ todo = [basename] # UGH.
+
+ if not os.path.isfile (basename + '.tex') or updated:
+ todo.append ('tex')
+ updated = 1
+
+ for o in opts:
+ m = re.search ('intertext="(.*?)"', o)
+ if m:
+ newbody = newbody + m.group (1)
+
+ if format == 'texi':
+ opts.append ('png')
+
+ if 'png' in opts:
+ opts.append ('eps')
+
+ if 'eps' in opts and ('tex' in todo or
+ not os.path.isfile (basename + '.eps')):
+ todo.append ('eps')
+
+ if 'png' in opts and ('eps' in todo or
+ not os.path.isfile (basename + '.png')):
+ todo.append ('png')
+
+ if format == 'latex':
+ if 'eps' in opts :
+ newbody = newbody + get_output ('output-eps') % (basename, basename)
+ else:
+ newbody = newbody + get_output ('output-tex') % basename
+
+ elif format == 'texi':
+ newbody = newbody + get_output ('output-all') % (basename, basename)
+
+ return ('mudela', newbody, opts, todo, base)
+
+
+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 print_chunks (ch):
+ for c in ch:
+ print '-->%s\n%s' % (c[0], c[1])
+ if len (c) > 2:
+ print '==>%s' % list (c[2:])
+ print foo
+
+
+def transform_input_file (in_filename, out_filename):
+ """Read the input, and deliver a list of chunks
+ ready for writing.
+ """
+
+ chunks = read_doc_file (in_filename)
+
+ #. Process \mudela and \mudelafile.
+ for func in [find_mudela_shorthand_chunks,
+ find_mudela_chunks]:
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'input':
+ newchunks = newchunks + func (c[1])
+ else:
+ newchunks.append (c)
+ chunks = newchunks
+
+ opts = []
+ if chunks:
+ opts = scan_preamble (chunks[0][1])
+
+ (chap,sect,count) = (0,0,0)
+ newchunks = []
+ # Count sections/chapters.
+ for c in chunks:
+ if c[0] == 'input':
+ (chap,sect,count) = advance_counters((chap,sect,count), opts, c[1])
+ elif c[0] == 'mudela':
+ base = '%s-%d.%d.%d' % (out_filename, chap, sect, count)
+ count = count + 1
+ c = schedule_mudela_block (base, c, opts)
+
+ newchunks.append (c)
+
+ chunks = newchunks
+ newchunks = []
+
+ # Do It.
+ if __main__.run_lilypond:
+ compile_all_files (chunks)
- def get_lines (self):
- lines = self.infile.readlines ()
- (retlines, retdeps) = ([],[self.filename])
- for line in lines:
- r = input_re.search (line)
- ri = include_re.search (line)
- if r:
- t = Tex_input (r.groups()[0])
- ls =t.get_lines ()
- retlines = retlines + ls[0]
- retdeps = retdeps + ls[1]
- elif ri:
- t = Tex_input (ri.groups()[0])
- ls =t.get_lines ()
- ls[0].insert(0, '\\newpage')
- ls[0].append('\\newpage')
- retlines = retlines + ls[0]
- retdeps = retdeps + ls[1]
- else:
- retlines.append (line)
- return (retlines, retdeps)
-
-
-class Main_tex_input(Tex_input):
- def __init__ (self, name, outname):
+ # 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
- 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/%s-%d.%d.%d' % (outdir, self.outname,self.chapter,self.section,self.fine_count)
-
- def extract_papersize_from_documentclass(self, line):
- pre = re.search('\\\\documentclass[\[, ]*(\w*)paper[\w ,]*\]\{\w*\}', line)
- if not pre:
- return default_paper_size_global
- return pre.groups()[0]
- def extract_fontsize_from_documentclass(self, line):
- if re.search('\\\\documentclass\[[^\]]*\]\{[^\}]*\}', line):
- r = re.search('[ ,\[]*([0-9]*pt)', line)
- if r:
- return r.groups()[0]
- return '10pt'
- def do_it(self):
- (lines, self.deps) = self.get_lines ()
- for line in lines:
- if documentclass_re.search (line):
- Paper.set_papersize (self.extract_papersize_from_documentclass (line) )
- Paper.set_fontsize (self.extract_fontsize_from_documentclass (line) )
- elif twocolumn_re.search (line):
- Paper.twocolumn ()
- elif onecolumn_re.search (line):
- Paper.onecolumn ()
- elif begin_document_re.search (line):
- self.mudtex.write ('\\def\\preMudelaExample{}\n')
- self.mudtex.write ('\\def\\postMudelaExample{}\n')
- elif begin_mudela_re.search (line):
- 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)
- else:
- optlist = []
- if 'verbatim' in optlist:
- self.verbatim = 1
- self.mudtex.open_verbatim ()
- else:
- self.verbatim = 0
- self.mudela = Mudela_output (self.gen_basename ())
-
- elif end_mudela_re.search (line):
- if __debug__:
- if self.mode != 'mudela':
- raise AssertionError
- if self.mudela:
- self.mudela.close ()
- self.mudtex.write (self.mudela.insert_me_string())
- del self.mudela
- self.mudela = None
- self.fine_count = self.fine_count + 1
- else:
- self.mudtex.write (line)
- self.mudtex.close_verbatim ()
- self.mode = 'latex'
- continue
-
- if self.mode == 'mudela' and not self.verbatim:
- self.mudela.write (line)
- else:
- self.mudtex.write (line)
- self.set_sections(line)
- del self.mudtex
+ if chunks and chunks[0][0] == 'input':
+ chunks[0] = ('input', completize_preamble (chunks[0][1]))
+
+ return chunks
+
+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 = []
+ hash_dict = {}
+
+ for c in chunks:
+ if c[0] <> 'mudela':
+ continue
+ base = c[3][0]
+ exts = c[3][1:]
+ for e in exts:
+ if e == 'eps':
+ eps.append (base)
+ elif e == 'tex':
+ tex.append (base + '.ly')
+ elif e == 'png':
+ png.append (base)
+
+ if __main__.use_hash:
+ hash_dict[c[4]] = c[3][0]
+
+ 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:
+ cmd = r"""tex %s; dvips -E -o %s %s""" % \
+ (e, e + '.eps', e)
+ system (cmd)
+
+ 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 __main__.use_hash:
+ name = ''
+ last_name = ''
+ f = 0
+ ks = hash_dict.keys ()
+ ks.sort ()
+ for i in ks:
+ name = re.sub ("(.*)-[0-9]+\.[0-9]+\.[0-9]+", "\\1", i)
+ name = name + '.mix'
+ if name != last_name:
+ if last_name:
+ f.close ()
+ f = open (name, 'w')
+ last_name = name
+ f.write ("%s:%s\n" % (i, hash_dict[i]))
+
+
+def update_file (body, name):
+ 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:\n"
- + " -h, --help print this help\n"
- + " -d, --outdir=DIR directory to put generated files\n"
- + " -o, --outname=FILE prefix for filenames\n"
- + " --mudela-fontsize=??pt default fontsize when no parameter for \\begin{mudela}\n"
- + " --force-mudela-fontsize=??pt force fontsize for all inline mudela\n"
- )
- sys.exit (0)
-
-
-def write_deps (fn, out, deps):
- out_fn = outdir + '/' + fn
- print '\`writing \`%s\'\n\'' % out_fn
+ sys.stdout.write("""Usage: mudela-book [options] FILE\n
+Generate hybrid LaTeX input from Latex + mudela
+Options:
+""")
+ sys.stdout.write (options_help_str (options))
+ 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 <tomcato@xoommail.com> and
+Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""")
+
+ sys.exit (0)
+
+
+def write_deps (fn, target, deps):
+ sys.stdout.write('writing `%s\'\n' % fn)
+
+ f = open (fn, 'w')
- f = open (out_fn, 'w')
- f.write ('%s: %s\n'% (outdir + '/' + out + '.dvi',
- reduce (lambda x,y: x + ' '+ y, deps)))
+ target = target + '.latex'
+ f.write ('%s: %s\n'% (target, string.join (deps, ' ')))
f.close ()
+
def identify():
- sys.stderr.write('*** Lokal versjon av mudela-book ***\n')
- sys.stderr.write ('This is %s version %s\n' % ('mudela-book', program_version))
+ 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 main():
- global default_mudela_fontsize, outdir
- outname = ''
- try:
- (options, files) = getopt.getopt(
- sys.argv[1:], 'hd:o:', ['outdir=', 'outname=', 'mudela-fontsize=',
- 'force-mudela-fontsize=', 'help', 'dependencies'])
- except getopt.error, msg:
- print "error:", msg
- sys.exit(1)
-
- do_deps = 0
- for opt in options:
- o = opt[0]
- a = opt[1]
- if o == '--outname' or o == '-o':
- 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 == '--mudela-fontsize':
- default_mudela_fontsize = a
- if o == '--force-mudela-fontsize':
- default_mudela_fontsize = a
- force_mudela_fontsize_b = 1
-
- if outdir[-1:] != '/':
- outdir = outdir + '/'
-
- if not file_exist_b(outdir):
- os.system('mkdir %s' % outdir)
-
- if not fontsize_pt2i.has_key(default_mudela_fontsize):
- print "warning: fontsize %s is not supported using 16pt" % default_mudela_fontsize
- default_mudela_fontsize = '16pt'
-
- for f in files:
- my_outname = outname
- if not my_outname:
- my_outname = regsub.sub ('\\(.*\\)\\.doc', '\\1', f)
-
- my_depname = my_outname + '.dep'
-
- inp = Main_tex_input (f, my_outname)
- inp.do_it ()
-
- if do_deps:
- write_deps (my_depname, my_outname, inp.deps)
-
-
-
-identify()
-Paper = PaperDef()
+ global outdir, initfile, defined_mudela_cmd, defined_mudela_cmd_re
+ outname = ''
+ try:
+ (sh, long) = getopt_args (__main__.options)
+ (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':
+ print_version ()
+ sys.exit (0)
+
+ elif o == '--format' or o == '-o':
+ __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 == '--outdir' or o == '-d':
+ outdir = a
+ elif o == '--help' or o == '-h':
+ help ()
+ elif o == '--no-lily' or o == '-n':
+ __main__.run_lilypond = 0
+ elif o == '--dependencies':
+ do_deps = 1
+ elif o == '--default-mudela-fontsize':
+ default_music_fontsize = string.atoi (a)
+ elif o == '--init':
+ initfile = a
+
+ identify()
+
+ for input_filename in files:
+ 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 = transform_input_file (input_filename, my_outname)
+
+ foutn = 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, my_outname, deps)
+ sys.stderr.write ("--dependencies broken")
+
main()
+
+
+
+#
+# Petr, ik zou willen dat ik iets zinvoller deed,
+# maar wat ik kan ik doen, het verandert toch niets?
+# --hwn 20/aug/99