summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/hybrid-latex/python/pypostproc.py
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/hybrid-latex/python/pypostproc.py')
-rwxr-xr-xmacros/latex/contrib/hybrid-latex/python/pypostproc.py239
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])