#!/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])