From 686e69ca129f9d606d40fba6f4ea1547cf8a1d7b Mon Sep 17 00:00:00 2001 From: fred Date: Tue, 26 Mar 2002 22:25:02 +0000 Subject: [PATCH] lilypond-1.2.2 --- VERSION | 2 +- scripts/mudela-book.py | 1480 +++++++++++++++++++--------------------- 2 files changed, 696 insertions(+), 786 deletions(-) diff --git a/VERSION b/VERSION index 9b18ae90d8..95a1009af5 100644 --- a/VERSION +++ b/VERSION @@ -1,7 +1,7 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=1 MINOR_VERSION=2 -PATCH_LEVEL=1 +PATCH_LEVEL=2 MY_PATCH_LEVEL= # use the above to send patches: MY_PATCH_LEVEL is always empty for a diff --git a/scripts/mudela-book.py b/scripts/mudela-book.py index 3044ea0389..0000a26aea 100644 --- a/scripts/mudela-book.py +++ b/scripts/mudela-book.py @@ -1,77 +1,4 @@ #!@PYTHON@ -# -# The bugs you find are made by Tom Cato Amundsen -# Send patches/questions/bugreports to a mailinglist: -# gnu-music-discuss@gnu.org -# bug-gnu-music@gnu.org -# help-gnu-music@gnu.org -# -# 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} -# 0.5.3: -# - bf: \mudela{ \times 2/3{...} } -# * \t in \times is not tab character and -# * dont treat the first '}' as command ending -# 0.5.4: (Mats B) -# - .fly and .sly files in \mudelafile{} are treated as standalone Lilypond. -# - Fragments, .fly and .sly files are in \relative mode. -# 0.5.5: (Mats B) -# - bf: Default fragments have linewidth=-1.0 -# - Added 'singleline' and 'multiline' options. -# 0.5.6: -# - \mudelafile{} set linewidth correct, -1 for .sly and texlinewidth for .fly -# - changes to Mudela_output -# - changed RE to search for pre/postMudelaExample to make it possible to -# comment out a definition. -# - use sys.stderr and sys.stdout instead of print -# 1.1.62 -# - junked separate versioning -# - pass -I options to lily. -# - portability stuff (os.sep). import os import string @@ -83,739 +10,722 @@ import __main__ outdir = 'out' initfile = '' program_version = '@TOPLEVEL_VERSION@' -include_path = ['.'] - -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} - -# perhaps we can do without this? - -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') -mudela_file_re = re.compile('\\\\mudelafile{([^}]+)}') -file_ext_re = re.compile('.+\\.([^.}]+$)') -preMudelaExample_re = re.compile('^\s*\\\\def\\\\preMudelaExample') -postMudelaExample_re = re.compile('^\s*\\\\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])) +cwd = os.getcwd () +include_path = [cwd] -def find_file (name): - for a in include_path: +# TODO: use splitting iso. \mudelagraphic. + +# +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 = [ + ('', 'h', 'help', 'print help'), + ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'), + ('', 'v', 'version', 'print version information' ), + ('FILE', 'o', 'outname', 'prefix for filenames'), + ('DIM', '', 'default-mudela-fontsize', 'default fontsize for music. DIM is assumed to in points'), +# ('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'), + ('DIR', 'I', 'include', 'include path'), + ('', '', 'init', 'mudela-book initfile') + ] + +format = 'latex' +no_match = 'a\ba' + +# format specific strings, ie. regex-es for input, and % strings for output +re_dict = { + 'latex': {'input': '\\\\input{?([^}\t \n}]*)', + 'include': '\\\\include{([^}]+)}', + 'include-mudela':r"""\begin%s{mudela} +%s +\end{mudela}""", + '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|mudelagraphic|twocolumn|onecolumn)', + 'quote-verbatim': r"""\begin{verbatim}%s\end{verbatim}""", + 'def-post-re': r"""\\def\\postMudelaExample""", + 'def-pre-re': r"""\\def\\preMudelaExample""", + 'default-post': r"""\def\postMudelaExample{}""", + 'default-pre': r"""\def\preMudelaExample{}""", + 'output-eps': '\\noindent\\parbox{\\mudelaepswidth{%s.eps}}{\includegraphics{%s.eps}}', + 'output-tex': '\\preMudelaExample \\input %s.tex \\postMudelaExample\n' + }, + 'texi': {'input': '@include[ \n\t]+([^\t \n]*)', + 'include': no_match, + 'include-mudela': """@mudela[%s] +%s +@end mudela +""", + '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"""[\\@](node|mudelagraphic)""", + 'quote-verbatim': r"""@example +%s +@end example""", + 'output-all': r"""@tex +\input %s.tex +@end tex +@html + +@end html +""", + } + } + + + + +def get_re (name): + return re_dict[format][name] + + +def bounding_box_dimensions(fname): try: - nm = os.path.join (a, name) - f = open (nm) - return nm + fd = open(fname) except IOError: - pass - return '' + 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)) -class CompileStatus: - pass -class SomethingIsSeriouslyBroken: - pass + m = re.match ('latexfontsize=([0-9]+)pt', o) + if m: + latex_size = string.atoi (m.group (1)) + + + if 'twocolumn' in opts: + cols = 2 + + if 'fragment' or 'singleline' in opts: + l = -1.0; + else: + l = latex_linewidths[cols][paper][latex_size] -def file_mtime (name): - return os.stat (name)[8] #mod time + if not 'nofly' in opts and not re.search ('\\\\score', body): + opts.append ('fly') + + + if 'fly' in opts: + body = r"""\score { + \notes\relative c { + %s + } + \paper { } +}""" % body + + + body = r""" +%% Generated by mudela-book.py +\include "paper%d.ly" +\paper { linewidth = %f \pt; } +""" % (music_size, l) + body + + return body -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 +# Petr, ik zou willen dat ik iets zinvoller deed, +# maar wat ik kan ik doen, het verandert toch niets? +# --hwn 20/aug/99 # -def compile (command, workingdir, infile, outfile): - "Test if infile is newer than outfile. If so, cd to workingdir" - "and execute command" - print "COMPILE!!" - 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: - """ Using only self.code_type to deside both value of linewith and - if we have to put code into \score{...} was silly. Now we use: - self.code_type: show us what need to be added. - None : init value - 'NOTES' : add \context Voice{ ... } - 'CONTEXT' : add \score{ ... } - 'COMPLETE' : jupp - self.single_line_b: 0 : linewidth=-1 1: linewith=textwidth - """ - 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 = None - self.single_line_b = 1 - self.optlist = [] - def write (self, line): - # match only if there is nothing but whitespace before \begin. - # we should not have to do this RE for every line - if re.search('^\s*\\\\begin{mudela}', line): - r = begin_mudela_opts_re.search(line) - if r: - o = r.group()[1:-1] - self.optlist = re.compile('[\s,]*').split(o) - else: - self.optlist = [] - else: # ugh this is NOT bulletproof... - if not self.code_type: - if re.search('^\s*%', line) or re.search('^\s*$', line): - pass - elif re.search('^\s*\\\\context', line): - self.code_type = 'CONTEXT' - self.single_line_b = 0 - elif re.search('^\s*\\\\score', line) or \ - re.search('^\s*\\\\paper', line) or \ - re.search('^\s*\\\\header', line) or \ - re.search('^\s*\\\\version', line) or \ - re.search('^\s*\\\\include', line) or \ - re.search('^\s*[A-Za-z]*\s*=', line): - self.code_type = 'COMPLETE' - self.single_line_b = 0 - else: - self.code_type = 'NOTES' - self.single_line_b = 1 - self.__lines.append(line) - def write_red_tape(self): - if 'eps' in self.optlist: - self.graphic_type = 'eps' - #self.single_line_b = 1 - if 'fragment' in self.optlist: - self.code_type = 'NOTES' - if 'nonfragment' in self.optlist: - self.code_type = 'COMPLETE' - if 'multiline' in self.optlist: - self.single_line_b = 0 - for pt in fontsize_pt2i.keys(): - if pt in self.optlist: - Props.setMudelaFontsize(fontsize_pt2i[pt], 'block') - self.file.write ('\\include \"paper%d.ly\"\n' \ - % Props.getMudelaFontsize()) - - s = fontsize_i2a[Props.getMudelaFontsize()] - if 'singleline' in self.optlist: - self.single_line_b = 1 - if self.single_line_b: - 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 == 'CONTEXT': - self.file.write('\\score{\n\\notes\\relative c{') - if self.code_type == 'NOTES' : - self.file.write('\\score{\n\\notes\\relative c{\\context Voice{') - def close (self): - self.write_red_tape() - for l in self.__lines: - self.file.write(l) - if self.code_type == 'CONTEXT': - self.file.write('}}') - elif self.code_type == 'NOTES': - 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) - - recompile_b = need_recompile_b(inf, outf) - if recompile_b: - out_files.append((self.graphic_type, inf)) - return recompile_b - - def insert_me_string(self): - "ugh the name of this function is wrong" - 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' - - lilyoptions = '' - for inc in __main__.include_path : - p = inc[:] - if p[0] <> os.sep and outdir: # UGH-> win32 ? - p = '..' + os.sep + p - lilyoptions = lilyoptions + " -I \"%s\"" % p + + +def read_tex_file (filename): + """Read the input file, substituting for \input, \include, \mudela{} and \mudelafile""" + str = '' + for fn in [filename, filename+'.tex', filename+'.doc']: + try: + f = open(fn) + str = f.read (-1) + except: + pass - if s != '': - cmd = 'cd %s; lilypond %s %s' %(outdir, lilyoptions, s) - sys.stderr.write ('invoking command %s' % cmd) - e = os.system(cmd) - if e: - sys.stderr.write("error: lilypond exited with value %i\n" % 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') - last_line = None - for line in self.__lines: - if type(line)==type([]): - if last_line == '\n': - file.write(r'\vspace{0.5cm}') - if line[0] == 'tex': - file.write('\\preMudelaExample \\input %s \\postMudelaExample\n'\ - % (line[1]+'.tex')) - if line[0] == 'eps': - ps_dim = ps_dimention(outdir+line[1]+'.eps') - file.write('\\noindent\\parbox{%ipt}{\includegraphics{%s}}\n' \ - % (ps_dim[0], line[1]+'.eps')) - else: - file.write(line) - if type(last_line)==type([]): - if line=='\n': - file.write(r'\vspace{0.5cm}') - last_line = line - file.close() - -# given parameter s="\mudela[some options]{CODE} some text and commands" -# it returns a tuple: -# (CODE, integer) -# where the last number is the index of the ending '}' -def extract_command(s): - start_found_b = 0 - count = 0 - start = 0 - for idx in range(len(s)): - if s[idx] == '{': - if not start_found_b: - start = idx - start_found_b = 1 - count = count + 1 - if s[idx] == '}': - count = count - 1 - if (start_found_b == 1) and (count == 0): - break - return s[start+1:idx], idx - -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: - sys.stderr.write("warning: can't find %s, let's hope latex will\n" % 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: - sys.stderr.write("warning: can't find %s, let's hope latex will" % r_inc.groups()[0]) - retlines.append (line) - else: - # This code should be rewritten, it looks terrible - r_mud = defined_mudela_cmd_re.search(line) - if r_mud: - # TODO document this - ss = "\\\\verb(?P[^a-zA-Z])\s*\\\\%s\s*(?P=xx)" \ - % re.escape(r_mud.group()[1:]) - # just append the line if the command is inside \verb|..| - if re.search(ss, line): - retlines.append(line) - continue - while 1: - opts = r_mud.groups()[2] - cmd_start_idx = r_mud.span()[0] - if cmd_start_idx > 0: - retlines.append(line[:cmd_start_idx]) - - cmd_data, rest_idx = extract_command(line[cmd_start_idx:]) - rest_idx = rest_idx + cmd_start_idx + 1 - if opts == None: - opts = '' - else: - opts = ', '+opts - - v = string.split(defined_mudela_cmd[r_mud.groups()[0]], '\n') - for l in v[1:-1]: - l = string.replace(l, '\\fontoptions', opts) - l = string.replace(l, '\\maininput', cmd_data) - retlines.append(l) - r_mud = defined_mudela_cmd_re.search(line[rest_idx:]) - if not r_mud: - rs = line[rest_idx:] - while rs[0] == " ": - rs = rs[1:] - if rs != "\n": - retlines.append(line[rest_idx:]) - break; - line = line[rest_idx:] - else: - retlines.append (line) - 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 mudela_file_re.search(line): - r = mudela_file_re.search(line) - - self.mudela = Mudela_output(self.gen_basename()) - fn = r.group (1) - full_path = find_file (fn) + + if not str: + raise IOError + + retdeps = [filename] + + def inclusion_func (match, surround): + insert = match.group (0) + try: + (insert, d) = read_tex_file (match.group(1)) + deps = deps + d + insert = surround + insert + surround + except: + sys.stderr.write("warning: can't find %s, let's hope latex will\n" % m.group(1)) + + return (insert, deps) + + def include_func (match, d = retdeps): + (s,d) = inclusion_func (match, '\\newpage ', retdeps) + retdeps = retdeps + d + return s + + str = re.sub (get_re ('input'), include_func, str) + + def input_func (match, d = retdeps): + (s,d) = inclusion_func (match, '', retdeps) + retdeps = retdeps + d + return s + + str = re.sub (get_re ('include'), input_func, str) + + return (str, retdeps) + +def scan_preamble (str): + options = [] + m = re.search (get_re ('header'), 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): + if o.match('[0-9]+pt'): + return 'latexfontsize=' + x + else: + return x + + options = map (verbose_fontsize, options) + + return options + + +def completize_preamble (str): + m = re.search (get_re ('preamble-end'), str) + if not m: + return str + + preamble = str [:m.start (0)] + str = str [m.start(0):] + + if not re.search (get_re('def-post-re'), preamble): + preamble = preamble + get_re('default-post') + if not re.search (get_re ('def-pre-re'), preamble): + preamble = preamble + get_re ('default-pre') + + if re.search ('\\\\includegraphics', str) and not re.search ('usepackage{graphics}',str): + preamble = preamble + '\\usepackage{graphics}\n' + + return preamble + str + +def find_mudela_sections (str): + """Find mudela blocks, while watching for verbatim. Returns + (STR,MUDS) with \mudelagraphic substituted for the blocks in STR, + and the blocks themselves MUDS""" + + mudelas = [] + verbblocks = [] + noverbblocks = [] + + while str: + m = re.search (get_re ('verbatim'), str) + m2 = re.search (get_re ("verb"), str) + + if m == None and m2 == None: + noverbblocks.append (str) + str = '' + break + + if m == None: + m = m2 + + if m2 and m2.start (0) < m.start (0): + m = m2 + + noverbblocks.append (str[:m.start (0)]) + verbblocks.append (m.group (0)) + str = str [m.end(0):] + + 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 r"""\begin[eps,fragment%s]{mudela} + \context Staff < + \context Voice{ + %s + } + > +\end{mudela}""" % (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: - sys.stderr.write("error: can't find file '%s'\n" % fn) - sys.exit (1) - - f = open (full_path, 'r') - lines =f.readlines () - self.mudela.write ('%% This is a copy of file %s\n' % full_path) - for x in lines: - self.mudela.write (x) - r = file_ext_re.search(fn) - if r: - if r.group(1) == 'fly': - self.mudela.optlist.append('multiline') - stat =self.mudela.close () - if stat: - sys.stdout.write("(File %s needs recompiling)\n" % full_path) - self.mudtex.write (self.mudela.insert_me_string()) - self.deps.append (full_path) - del self.mudela - self.mudela = None - self.fine_count = self.fine_count + 1 - continue - 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 + 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 = re.split (',[ \n\t]*', opts[1:-1]) + 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, ',') + if str_opts: str_opts = '[' + str_opts + ']' + + + str = "%% copied from %s" % full_path + str + return get_re ('include-mudela') % (str_opts, str) + + + def find_one_mudela_block (match,muds =mudelas): + "extract body and options from a mudela block, and append into MUDELAS" + opts = match.group (1) + if opts: + opts = opts[1:-1] + else: + opts = '' + + body = match.group (2) + optlist = re.split (', *', opts) + muds.append ((body, optlist)) + + return '\\mudelagraphic\n'# UGH. + + doneblocks = [] + for b in noverbblocks: + b = re.sub (get_re('mudela-file'), mudela_file, b) + b = re.sub (get_re('mudela'), mudela_short, b) + b = re.sub (get_re ("mudela-block"), find_one_mudela_block, b) + doneblocks.append (b) + + allblocks = [] + verbblocks.append ('') + while doneblocks: + allblocks = allblocks + doneblocks[0:1] + verbblocks[0:1] + verbblocks = verbblocks[1:] + doneblocks =doneblocks[1:] + + str = string.join (allblocks,'') + + return (str, mudelas) + + +def eps_file_cs (base): + if format == 'latex': + return + els + +def tex_file_cs (base): + return + + + + +def make_files (str, mudelas, filename): + (chapter, section, count) = (0,0,0) + total = 0 + done = '' + + # number them. + numbering = [] + current_opts = [] + while str: + m = re.search (get_re ('interesting-cs'), 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': + current_opts.append ('twocolumn') + elif g == 'onecolumn': + try: + current_opts.remove ('twocolumn') + except IndexError: + pass + if g == 'mudelagraphic': + numbering.append ((chapter, section, count, current_opts[:])) + count = count + 1 + elif g == 'chapter': + (chapter, section, count) = (chapter + 1, 0, 0) + elif g == 'section' or g == 'node': + (section, count) = (section + 1, 0) + + + todo = [] + str = done + + + done = '' + while str: + m = re.search ('\\\\mudelagraphic', str) + if not m: + done = done + str; + str = '' + break + + done = done + str[:m.start(0)] + str = str[m.end(0):] + (c1,c2,c3, file_opts) = numbering[0] + (body, opts) = mudelas[0] + numbering = numbering[1:] + mudelas = mudelas[1:] + + opts = opts + file_opts + + base = '%s-%d.%d.%d' % (filename, c1, c2,c3) + if 'verbatim' in opts: + done = done + get_re ('quote-verbatim') % body + + + body = compose_full_body (body, opts) + updated = update_file (body, base + '.ly') + def is_updated (extension, t = todo): + for x in t: + if t[0] == extension: + return 1 + return 0 + + if not os.path.isfile (base + '.tex') or updated: + todo.append (('tex', base, opts)) + updated = 1 + + for o in opts: + m = re.search ('intertext="(.*?)"', o) + if m: + done = done + m.group (1) + + if format == 'texi': + opts.append ('png') + + if 'png' in opts: + opts.append ('eps') + + if 'eps' in opts and (is_updated ('tex') or + not os.path.isfile (base + '.eps')): + todo.append (('eps', base, opts)) + + if 'png' in opts and (is_updated ('eps') or + not os.path.isfile (base + '.png')): + todo.append (('png', base, opts)) + + if format == 'latex': + if 'eps' in opts : + done = done + get_re ('output-eps') % (base, base ) + else: + done = done + get_re ('output-tex') % base + elif format == 'texi': + done = done + get_re ('output-all') % (base, base) + + + compile_all_files (todo) + + def find_eps_dims (match): + "Fill in dimensions of EPS files." + fn =match.group (1) + dims = bounding_box_dimensions (fn) + + return '%ipt' % dims[0] + + done = re.sub (r"""\\mudelaepswidth{(.*?)}""", find_eps_dims, done) + + return done + +def system (cmd): + sys.stderr.write ("invoking `%s'\n" % cmd) + st = os.system (cmd) + if st: + sys.stderr.write ('Error command exited with value %d\n' % st) + return st + +def compile_all_files ( list): + eps = [] + tex = [] + gif = [] + for l in list: + if l[0] == 'eps': + eps.append (l[1]) + elif l[0] == 'tex': + tex.append (l[1] + '.ly') + elif l[0] == 'png': + gif.append (l[1]) + + if tex: + lilyopts = map (lambda x: '-I ' + x, include_path) + texfiles = string.join (tex, ' ') + lilyopts = string.join (lilyopts, ' ' ) + 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 gif: + 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) + + +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): + "Transform 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 - --include include path - --init mudela-book initfile - """ - ) - sys.exit (0) - - -def write_deps (fn, out, deps): - out_fn = os.path.join (outdir, fn) - - sys.stdout.write('writing `%s\'\n' % out_fn) +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 and +Han-Wen Nienhuys +""") + + 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') - target = re.sub (os.sep + os.sep, os.sep, os.path.join (outdir, out + '.latex')) - f.write ('%s: %s\n'% (target, - 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 ('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 outdir, initfile, defined_mudela_cmd, defined_mudela_cmd_re - outname = '' - try: - (options, files) = getopt.getopt( - sys.argv[1:], 'hd:o:I:', ['outdir=', 'outname=', - 'default-mudela-fontsize=', - 'force-mudela-fontsize=', - 'help', 'dependencies', 'include=', - 'force-verbatim', 'init=']) - 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 == '--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 == '--dependencies': - do_deps = 1 - elif o == '--default-mudela-fontsize': - if not fontsize_pt2i.has_key(a): - sys.stderr.write("Error: invalid fontsize: %s" % a) - sys.stderr.write(" accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt") - sys.exit() - Props.setMudelaFontsize(fontsize_pt2i[a], 'init') - elif o == '--force-mudela-fontsize': - if not fontsize_pt2i.has_key(a): - sys.stderr.write("Error: invalid fontsize: %s" % a) - sys.stderr.write(" accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt") - sys.exit() - Props.force_mudela_fontsize = fontsize_pt2i[a] - elif o == '--force-verbatim': - Props.force_verbatim_b = 1 - elif o == '--init': - initfile = a - if outdir[-1:] != os.sep: - outdir = outdir + os.sep - - # r""" ... """ means: leave escape seqs alone. - defined_mudela_cmd = {'mudela': r""" -\begin{mudela}[eps, singleline \fontoptions] - \context Staff < - \context Voice{ - \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 = string.join (defined_mudela_cmd.keys(), '|') - - 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 () - if do_deps: - write_deps (my_depname, my_outname, inp.deps) - -identify() -Props = Properties() + 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 == '--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' + + (input, deps) = read_tex_file (input_filename) + (input, muds) = find_mudela_sections (input) + output = make_files (input, muds, my_outname) + output = completize_preamble (output) + + foutn = my_outname + '.' + format + sys.stderr.write ("Writing `%s'\n" % foutn) + fout = open (foutn, 'w') + + fout.write (output) + fout.close () + + if do_deps: + write_deps (my_depname, my_outname, deps) + main() -- 2.39.5