diff options
Diffstat (limited to 'macros/latex/contrib/hybrid-latex/python/pypostproc.py')
-rwxr-xr-x | macros/latex/contrib/hybrid-latex/python/pypostproc.py | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/macros/latex/contrib/hybrid-latex/python/pypostproc.py b/macros/latex/contrib/hybrid-latex/python/pypostproc.py new file mode 100755 index 0000000000..11b4ae3382 --- /dev/null +++ b/macros/latex/contrib/hybrid-latex/python/pypostproc.py @@ -0,0 +1,239 @@ +#!/usr/local/bin/python3 + +import re +import sys +import os.path + +import enum + +class Type (enum.Enum): + BegTag = 1 + EndTag = 2 + PlainText = 3 + Unknown = 4 + +def empty_line (this_line): + if len(this_line) == 0: + return True + else: + return re.search ("(^ *$)",this_line) + +def get_index (this_line): + result = re.search ("tag([0-9]+)",this_line) + if result: + return int(result.group (1)) + else: + print ("> Error reading tag index on: " + this_line) + sys.exit (1) + +def get_text (this_line): + result = re.search ("tag([0-9]+)=(.*)",this_line) + if result: + return result.group (2) + else: + print ("> Error reading tag text on: " + this_line) + sys.exit (1) + +def has_tag (this_line): + return re.search (r"(tag[0-9]+=)",this_line) + +def is_beg_tag (this_line): + return re.search (r"(^beg_tag[0-9]+$)",this_line) + +def is_end_tag (this_line): + return re.search (r"(^end_tag[0-9]+$)",this_line) + +# ------------------------------------------------------------------------- +# stack operations + +stack = [] +stack_index = 0 +max_stack_index = 5 +for i in range (0,max_stack_index): # create an empty stack + stack.append(0) # using zero forces any non-tagged output to be stored in tag_output[0] + +def read_stack (index): + return stack [index] + +def push_stack (index, stack_index): + if stack_index < max_stack_index: + stack_index = stack_index + 1 + stack [stack_index] = index + return stack_index + else: + print ("> Depth of nested pyBeg/pyEnd pairs exceeded, max = "+str(max_stack_index)+", exit\n") + sys.exit (1) + +def pop_stack (index, stack_index): + if stack_index > 0: + if index == read_stack (stack_index): + stack [stack_index] = 0 + return stack_index - 1 + else: + print ("> Error with pyBeg/pyEnd pairs for tag index: "+str(index)+", exit\n") + sys.exit (1) + else: + print ("> Error with pyBeg/pyEnd pairs, check for missing pyBeg or pyEnd, exit\n") + sys.exit (1) + +def parse (this_line): + if is_beg_tag (this_line): + return Type.BegTag + elif is_end_tag (this_line): + return Type.EndTag + else: + return Type.PlainText + +def append_text (this_line, index): + tag_output[index].append(this_line.rstrip("\n")) + +def tex_macro (tex, index): + the_lines = tag_output [index] + tex.write ("\pytag{"+tag_name[index]+"}{%\n") + for i in range (0,len(the_lines)): + if not empty_line (the_lines[i]): + tex.write (the_lines[i]+"%\n") + tex.write("}\n") + +# ----------------------------------------------------------------------------- +# the main code + +import argparse + +parser = argparse.ArgumentParser(description="Post-process Python output") +parser.add_argument("-i", dest="input", metavar="source", help="LaTeX-Python source file (without .tex file extension)", required=True) +parser.add_argument("-I", dest="sty", metavar="include", help="Full path to LaTeX-Python pymacros.sty file") + +the_file_name = parser.parse_args().input +sty_file_name = parser.parse_args().sty + +# ---------------------------------------------------------------------------- +# include the Python macros in the .cdbtex file? + +if sty_file_name: + include_macros_header = True + if not os.path.isfile (sty_file_name): + print ("> could not find "+sty_file_name) + print ("> will not include Python macros") + include_macros_header = False +else: + include_macros_header = False + +# ---------------------------------------------------------------------------- +# file names + +idx_file_name = the_file_name + ".pyidx" +tex_file_name = the_file_name + ".pytex" +src_file_name = the_file_name + ".pytxt" + +# ---------------------------------------------------------------------------- +# any tag index/name pairs to read? + +if not os.path.isfile (idx_file_name): + with open(tex_file_name,"w") as tex: + tex.write ("% no Python output") + sys.exit (0) + +# ---------------------------------------------------------------------------- +# read tag index/name pairs + +tag_name = [""] # dummy entry at index = 0 +tag_done = [False] # ditto +tag_found = [False] # ditto +tag_output = [[]] # ditto +num_tag = 0 +tag_index = 0 + +with open(idx_file_name, "r") as idx: + for this_line in idx: + if has_tag (this_line): # skip any non-tag text (e.g., comments) + num_tag = num_tag + 1 # the tag index + tag_name.append (get_text (this_line)) # the tag name + tag_done.append (False) + tag_found.append (False) + tag_output.append ([]) + +# note: num_tag = number of tags declared in the Python/LaTeX source +# these tags are stored in locations 1,2,3 ... num_tag in the various arrays +# tag_output[0] will contain all non-tagged Python output. + +# ---------------------------------------------------------------------------- +# read Python output and create LaTeX macros for each tag + +if num_tag == 0: + with open(tex_file_name,"w") as tex: + tex.write ("% no Python output") +else: + + if not os.path.isfile (src_file_name): + with open(tex_file_name,"w") as tex: + tex.write ("% no Python output") + print ("> post-process: Source file " + src_file_name + " not found, exit.") + print ("> possible error during execution of Python.") + sys.exit (1) + + # ------------------------------------------------------------------------- + # read Python output + + with open(src_file_name,"r") as src: + for this_line in src: + + line_type = parse (this_line) + if line_type == Type.BegTag: + + tag_index = get_index (this_line) + tag_done [tag_index] = False + tag_found [tag_index] = True + stack_index = push_stack (tag_index,stack_index) + + elif line_type == Type.EndTag: + + tag_index = get_index (this_line) + tag_done [tag_index] = True + tag_found [tag_index] = True + stack_index = pop_stack (tag_index,stack_index) + tag_index = read_stack (stack_index) + + elif line_type == Type.PlainText: + + append_text (this_line,tag_index) + + else: + pass # should never get here + + # ----------------------------------------------------------------------- + # create the latex macros, one for each tag + + with open(tex_file_name,"w") as tex: + + if include_macros_header: + tex.write(r'% ====================================================================='+'\n') + tex.write(r'% Define Python macros so that this file may be used by other LaTeX sources.'+'\n') + tex.write(r'% To include this file in some other LaTeX source be sure to add the following'+'\n') + tex.write(r'% lines in the LaTeX preamble.'+'\n') + tex.write(r'% \input{foo.mattex}% change foo to match the name of this file.'+'\n') + tex.write(r'% ---------------------------------------------------------------------'+'\n') + tex.write(r'\makeatletter'+'\n') + with open(sty_file_name,"r") as sty: + for this_line in sty: + tex.write (this_line) + tex.write(r'\makeatother'+'\n') + tex.write(r'% ====================================================================='+'\n') + + for i in range (1,num_tag+1): + + tex_macro (tex, i) + + # ------------------------------------------------------------------------- + # report tags that didn't have matching Python output + + for i in range (1,num_tag+1): + if not tag_found [i]: + print ("> post-process: Failed to find output for tag: "+tag_name[i]) + + # ------------------------------------------------------------------------- + # report problems with un-matched beg/end pairs + + for i in range (1,num_tag+1): + if not tag_done [i]: + print ("> post-process: Something is missing for tag: "+tag_name[i]) |