From eb9aa7f870e8ab085ad6b644caccd5e48cb589c7 Mon Sep 17 00:00:00 2001 From: Momme Butenschoen Date: Wed, 22 Oct 2014 22:23:32 +0100 Subject: [PATCH] Added python3 version. --- py3/PyProTex.py | 1121 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1121 insertions(+) create mode 100755 py3/PyProTex.py diff --git a/py3/PyProTex.py b/py3/PyProTex.py new file mode 100755 index 0000000..9fa2332 --- /dev/null +++ b/py3/PyProTex.py @@ -0,0 +1,1121 @@ +#!/usr/bin/python3 +# +# Copyright 2014 Plymouth Marine Laboratory +# +# This file is part of the SSB-ERSEM library. +# +# SSB-ERSEM is free software: you can redistribute it and/or modify it +# under the terms of the Lesser GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SSB-ERSEM is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser +# NU General Public License for more details. +# You should have received a copy of the Lesser GNU General Public License +# along with SSB-ERSEM. If not, see . +# +# Address: +# Plymouth Marine Laboratory +# Prospect Place, The Hoe +# Plymouth, PL1 3DH, UK +# +# Email: +# ssm@pml.ac.uk +# +# $Id: PyProTex,v14.10 $ +# +#BOP +# +# !ROUTINE: PyProTex - Translates DAO Prologues to LaTeX +# +# !INTERFACE: +# PyProTex.py [-hbgACFS] ] [+-nlsxf] src_file[s] +# +# !DESCRIPTION: +# This as a python version of the protex perl tool. +# Th perl tool was developed at the Goddard Space Flight Center +# by Arlindo Da Silva, Will Sawyer, and others under no specific +# license. +# The python version was created by Momme Butenschoen at the +# Plymouth Marine Laboratory +# The adaptation is based on the version 2.0 as downloaded from +# http://acmg.seas.harvard.edu/geos/wiki_docs/protex/protex.tar.gz +# +# Python class to produce a \LaTeX compatible document +# from a DAO Fortran source code with standard Pro\TeX +# prologues. +# By default, output is directed to stdout. +# +# \noindent +# {\bf Command Line Switches:} \vspace{0.2cm} +# +# \begin{center} +# \begin{tabular}{|c|l|} \hline \hline +# -h & Human mode: descriptions only, no code information \\ +# & implies -l and -s \\ \hline +# -b & Bare mode, meaning no preamble, etc. \\ \hline +# -i & internal mode: omit prologues marked !BOPI \\ \hline +# -g & Use GEOS style. Implies -n unless overidden. +# +/-n & New Page for each subsection (wastes paper) \\ \hline +# +/-l & Listing mode, default is prologues only \\ \hline +# +/-s & Shut-up mode, i.e., ignore any code from BOC to EOC \\ \hline +# +/-x & No LaTeX mode, i.e., put !DESCRIPTION: in verbatim mode \\ \hline +# +/-f & No source file info \\ \hline +# -A & Ada code \\ \hline +# -C & C++ code \\ \hline +# -F & F90 code (default) \\ \hline +# -S & Shell script \\ \hline +# none & Print help message \\ \hline \hline +# \end{tabular} +# \end{center} +# +# The options can appear in any order. The options -g, -h and -b, affect +# the input from all files listed on command-line input. Each of the +# remaining options affects only the input from the files listed after +# the option and prior to any overriding option. The plus sign +# turns off the option. For example, the command-line input, +# \bv +# protex -bnS File1 -F File2.f +n File3.f +# \ev +# will cause the option, {\tt -n} to affect the input from the files, +# {\tt File} and {\tt File2.f}, but not from {\tt File3.f}. The +# {\tt -S} option is implemented for {\tt File1} but is overridden by +# the {\tt -F} for files {\tt File2.f} and {\tt File3.f}. +# +# +# !SEE ALSO: +# For a more detailed description of ProTeX functionality, +# DAO Prologue and other conventions, consult: +# +# Sawyer, W., and A. da Silva, 1997: ProTeX: A Sample +# Fortran 90 Source Code Documentation System. +# DAO Office Note 97-11 +# +# !AUTHOR: +# ! Momme Butensch\xf6n +# +# !REVISION HISTORY: +# +# 20Dec1995 da Silva First experimental version +# 10Nov1996 da Silva First internal release (v1.01) +# 28Jun1997 da Silva Modified so that !DESCRIPTION can appear after +# !INTERFACE, and !INPUT PARAMETERS etc. changed to italics. +# 02Jul1997 Sawyer Added shut-up mode +# 20Oct1997 Sawyer Added support for shell scripts +# 11Mar1998 Sawyer Added: file name, date in header, C, script support +# 05Aug1998 Sawyer Fixed LPChang-bug-support-for-files-with-underscores +# 10Oct1998 da Silva Introduced -f option for removing source file info +# from subsection, etc. Added help (WS). +# 06Dec1999 C. Redder Added LaTeX command "\label{sec:prologues}" just +# after the beginning of the proglogue section. +# 13Dec1999 C. Redder Increased flexbility in command-line +# interface. The options can appear in any +# order which will allow the user to implement +# options for select files. +# 01Feb1999 C. Redder Added \usepackage commands to preamble of latex +# document to include the packages amsmath, epsfig +# and hangcaption. +# 10May2000 C. Redder Revised LaTeX command "\label{sec:prologues}" +# to "\label{app:ProLogues}" +# 10/10/2002 da Silva Introduced ARGUMENTS keyword, touch ups. +# +# 15Jan2003 R. Staufer Modified table of contents to print only section headers - no descriptions +# +# 25Feb2003 R. Staufer Added BOPI/EOPI and -i (internal) switch to provide the option of omitting prologue information from output files. +# 31Mar2014 M. Butenschoen Changed heading style to use sections for modules. +# 22Oct2014 M. Butenschoen Conversion to python with consistent changes +# to use part for top-level and section for 2nd +# level. Introduced -d option. +# 22Oct2014 M. Butenschoen -h option produces human-readable +# documentation with desciptions only omitting +# any iformation on the code. +# Help string is now obtained by calling without# argument +# +#EOP +#---------------------------------------------------------------------------- + + +from sys import argv,stderr,stdout +from time import localtime,strftime +from re import sub +from re import split as rsplit + + +#---------------------------------------------------------------------- + +class PyProTex: + + def __init__(self,Choices): + """Initiate class object with all options and settings. + Choices: PyProTex options as list of input strings in.""" + + #Option Classes + self.GlobOptions=["h","b","g"] + self.LangOptions=["A","C","F","S"] + self.SwOptions=["f","l","i","n","s","x"] + self.RegOptions=self.GlobOptions+self.LangOptions + #Default Options + self.opt={} + self.opt["h"]=0 + self.opt["b"]=0 + self.opt["g"]=0 + self.opt["f"]=0 + self.opt["l"]=0 + self.opt["i"]=0 + self.opt["n"]=0 + self.opt["s"]=0 + self.opt["x"]=0 + self.opt["A"]=0 + self.opt["C"]=0 + self.opt["S"]=0 + self.opt["F"]=1 #Default file format is fortran + + # Optional Prologue Keywords + # -------------------------- + self.keys = [ "!INTERFACE:", + "!USES:", + "!PUBLIC TYPES:", + "!PRIVATE TYPES:", + "!PUBLIC MEMBER FUNCTIONS:", + "!PRIVATE MEMBER FUNCTIONS:", + "!PUBLIC DATA MEMBERS:", + "!PARAMETERS:", + "!ARGUMENTS:", + "!IMPORT STATE:", + "!EXPORT STATE:", + "!INTERNAL STATE:", + "!DEFINED PARAMETERS:", + "!INPUT PARAMETERS:", + "!INPUT/OUTPUT PARAMETERS:", + "!OUTPUT PARAMETERS:", + "!RETURN VALUE:", + "!REVISION HISTORY:", + "!BUGS:", + "!SEE ALSO:", + "!SYSTEM ROUTINES:", + "!FILES USED:", + "!REMARKS:", + "!TO DO:", + "!CALLING SEQUENCE:", + "!AUTHOR:", + "!CALLED FROM:", + "!LOCAL VARIABLES:" ] + + # Initialize these for clarity + # ---------------------------- + self.intro = 0 # doing introduction? + self.prologue = 0 # doing prologue? + self.first = 1 # first prologue? + self.source = 0 # source code mode? + self.verb = 0 # verbatim mode? + self.tpage = 0 # title page? + self.begdoc = 0 # has \begin{document} been written? + self.descr_verb = 0 # descriptions in LaTeX mode + self.inspec = 0 # are we processing state specs (GEOS) + self.initem = 0 # are we processing state specs item (GEOS) + self.skip = 0 # don't skip + + # Set for global options + # ----------------------- + + for choice in Choices: + option = self.CheckOpts (choice,) + if option: + rc=self.GetOpts(choice,self.GlobOptions) + else: + print("Invalid option string: {}".format(choice),file=stderr) + self.print_help(dest=stderr) + + # g option requires n option + # --------------------- + + if self.opt["g"]: self.opt["n"]=1 + + # Set for non-global options + # ----------------------- + for choice in Choices: + option = self.CheckOpts(choice,quiet_mode=1)+1 + if option: + self.GetOpts(choice,self.SwOptions) + self.SetLanguage(choice) + + # d option implies s option and no l option + # --------------------- + + if self.opt["g"]: + self.opt["s"]=1 + self.opt["l"]=0 + + # Determine the type of code, set corresponding search strings + # ------------------------------------------------------------ + # DEFAULT: FORTRAN + if self.opt["A"]: # ADA + self.comment_string = '--' + self.boi_string = '--BOI' + self.eoi_string = '--EOI' + self.bop_string = '--BOP' + self.eop_string = '--EOP' + self.bopi_string = '--BOPI' + self.eopi_string = '--EOPI' + self.boc_string = '--BOC' + self.eoc_string = '--EOC' + self.boe_string = '--BOE' + self.eoe_string = '--EOE' + elif self.opt["C"]: # C + self.comment_string = '//' + self.boi_string = '//BOI' + self.eoi_string = '//EOI' + self.bop_string = '//BOP' + self.eop_string = '//EOP' + self.bopi_string = '//BOPI' + self.eopi_string = '//EOPI' + self.boc_string = '//BOC' + self.eoc_string = '//EOC' + self.boe_string = '//BOE' + self.eoe_string = '//EOE' + elif self.opt["S"]: # Script + self.comment_string = '#' + self.boi_string = '#BOI' + self.eoi_string = '#EOI' + self.bop_string = '#BOP' + self.eop_string = '#EOP' + self.bopi_string = '#BOPI' + self.eopi_string = '#EOPI' + self.boc_string = '#BOC' + self.eoc_string = '#EOC' + self.boe_string = '#BOE' + self.eoe_string = '#EOE' + else: + self.comment_string = '!' + self.boi_string = '!BOI' + self.eoi_string = '!EOI' + self.bop_string = '!BOP' + self.eop_string = '!EOP' + self.bopi_string = '!BOPI' + self.eopi_string = '!EOPI' + self.boc_string = '!BOC' + self.eoc_string = '!EOC' + self.boe_string = '!BOE' + self.eoe_string = '!EOE' + + # Set date + # -------- + self.Date = strftime("%a %b %d %T %Z",localtime()) + + # Initial LaTeX stuff + # ------------------- + self.Str="" + self.Str+=self.print_notice() # auto-generation warning + self.Str+=self.print_preamble() # \documentclass, text dimensions, etc. + self.Str+=self.print_macros() # short-hand LaTeX macros + + def __call__(self,files): + """Process all files in argument list, line by line, + compiling the documentation Tex source into the self.Str string + attribute. + files: list of input files""" + # If no file arguments are present print help string and exit + # --------------------- + + if not files: self.print_help() + + for f in files: + # Set file name parameters + # ------------------------ + self.InputFile = f + self.all_path_components = self.InputFile.split("/") + self.FileBaseName = self.all_path_components[-1].replace("_","\_") + # Open current file + # ----------------- + try: + fid=open(self.InputFile,'r') + except: + raise RunTimeError("Unable to open {}".format(self.InputFile)) + + # Print page header + # ----------------- + + if self.opt["g"]: + self.shname = " " + self.lnname = " " + self.units = " " + self.dims = " " + self.locs = " " + else: + self.Str+="\n\markboth{{Left}}{{Source File: {}, Date: {}}}\n\n".format(self.FileBaseName,self.Date) + + # Process input file line by line: + # --------------------------------------------------------- + + Lines=fid.readlines() + for line in Lines: + Record=line.rstrip("\n") #strip record separator + self._processRecord(Record) + + #close document + self.Str+="\n" + if self.source: self.do_eoc() + self.Str+="\n%...............................................................\n" + + # see comment above where these are originally set. + #print "\\setlength{\\parskip}{\\oldparskip}"; + #print "\\setlength{\\parindent}{\\oldparindent}"; + #print "\\setlength{\\baselineskip}{\\oldbaselineskip}"; + + if not self.opt["b"]: + self.Str+="\n\\end{document}" + + def _processRecord(self,Rec): + """Process a record according to its context.""" + + Fld=Rec.split(None,9999) #split line by whitespace + if len(Fld)==0: return #skip empty lines + if Fld[0] == "!QUOTE:" or (self.opt["g"] and len(Fld)>1 and Fld[1] == "!!GEOS!!"): + self.Str+="\n" + for f in Fld[1:]: + self.Str+="{} ".format(f) + return + + # Start the intro at new line and switch intro on + # ------------------------------------------- + if Fld[0] == self.boi_string: + self.Str+="\n" + self.intro = 1 + return + + # If within intro and title is given print title and switch title page on + # ------------------------------------------- + if len(Fld)>1 and Fld[1] == '!TITLE:': + if self.intro: + title = "{}".format(" ".join(*Fld[2])) + self.tpage = 1 + return + + # If within intro and author is given print title and switch title page on + # ------------------------------------------- + if len(Fld)>1 and Fld[1] == '!AUTHOR:': + if self.intro: + author = Fld[2] + self.tpage = 1 + return + + # If within intro and affiliation is given print title and set title page + # ------------------------------------------- + if len(Fld)>1 and Fld[1] == '!AFFILIATION:': + if self.intro: + affiliation = "{}".format(" ".join(*Fld[2])) + self.tpage = 1 + return + + # If within intro and date is given print date and switch title page on + # ------------------------------------------- + if len(Fld)>1 and Fld[1] == '!DATE:': + if self.intro: + self.date="{}".format(" ".join(*Fld[2])) + self.tpage = 1 + return + + # If within intro and introduction is given print introduction header and switch title page on + # ------------------------------------------- + if len(Fld)>1 and Fld[1] == '!INTRODUCTION:': + if self.intro: + self.self,do_beg() + self.Str+=" \n" + self.Str+="%..............................................\n" + if self.opt["g"]: + self.Str+="\part{{\Large {} }}\n".format(" ".join(*Fld[2:])) + else: + self.Str+="\part{{ {} }}\n".format(" ".join(*Fld[2:])) + return + + # close introduction and switch off intro + # ------------------- + + if Fld[0] == self.eoi_string: + self.Str+=" \n" + self.Str+="%/////////////////////////////////////////////////////////////\n" + self.Str+="\\newpage\n" + self.intro = 0 + return + + # Beginning of prologue : print header and + # switch on prologue + # switch off verb, source and inspec + # --------------------- + if Fld[0] == self.bop_string: + self.skip=0 + if self.source: self.do_eoc() + self.Str+=" \n" + self.Str+="%/////////////////////////////////////////////////////////////\n" + self.do_beg() + if self.first or self.opt["n"]: + if not (self.opt["b"] or self.opt["g"]): + self.Str+="\part{Routine/Function Prologues} \label{app:ProLogues}\n" + else: + self.Str+=" \n" + self.Str+="\mbox{}\hrulefill\\ \n" + self.Str+=" \n" + self.first = 0 + self.prologue = 1 + self.verb = 0 + self.source = 0 + self.inspec = 0 + self.set_missing() # initialise keyword check + return + + # Beginning of internal prologue (switchable) + # ------------------------------ + if Fld[0] == self.bopi_string: + if self.opt["i"]: + self.prologue = 0 #No internal prologue with i option + else: + if self.source: self.do_eoc() #if source is still active close it and close verbatim + self.Str+=" \n" + self.Str+="%/////////////////////////////////////////////////////////////\n" + self.do_beg() + if self.first or self.opt["n"]: + if not (self.opt["b"] or self.opt["g"]): + self.Str+="\part{Routine/Function Prologues} \label{{app:ProLogues}}\n" + else: + self.Str+=" \n" + self.Str+="\mbox{}\hrulefill\\\ \n" + self.Str+=" \n" + self.first = 0 + self.prologue = 1 + self.verb = 0 + self.source = 0 + self.inspec = 0 + self.set_missing() # initialise keyword check + return + + # A new subroutine/function + # ------------------------- + if len(Fld)>1 and Fld[1] == '!ROUTINE:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not self.first: self.Str+="\n\\newpage\n" + if self.opt["f"]: + self.Str+="\n\\section{{{} }\n\n".format(name) + else: + self.Str+="\n\section{{{} (Source: {})}\n\n".format(name, self.FileBaseName) + self.have_name = 1 + self.first = 0 + return + + # A new Module + # ------------ + if len(Fld)>1 and Fld[1] == '!MODULE:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not self.first: self.Str+="\n\\newpage\n" + if self.opt["g"]: + self.Str+="\n\section [{0}] {{Module {0} }}\n\n".format(name) + else: + if self.opt["f"]: + self.Str+="\n\section{{Module: {} }}\n\n".format(name) + else: + self.Str+="\n\section{{Module: {} (Source: {})}}\n\n".format(name,self.FileBaseName) + self.have_name = 1 + self.have_intf = 1 # fake, does not need one. + self.first = 0 + return + + # A new include file + # ------------------ + if len(Fld)>1 and Fld[1] == '!INCLUDE:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not self.first: self.Str+="\n\\newpage\n" + if self.opt["f"]: + self.Str+="\n\subsection{{Include File {} }}\n\n".format(name) + else: + self.Str+="\n\subsection{{Include File {} (Source: {})}}\n\n".format(name,self.FileBaseName) + self.have_name = 1 + self.have_intf = 1 # fake, does not need one. + self.first = 0 + return + + # A new INTERNAL subroutine/function + # ---------------------------------- + if len(Fld)>1 and Fld[1] == '!IROUTINE:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + words = name.split() + if self.opt["n"] and not self.first: self.Str+="\n\\newpage\n" + if self.opt["g"]: + self.Str+="\n\subsection {{{}}}\n\n".format(name) + else: + self.Str+="\n\subsection {{{}}}\n\n".format(name) + self.have_name = 1 + return + + # A new CONTAINED subroutine/function + # ---------------------------------- + if len(Fld)>1 and Fld[1] == '!CROUTINE:': # Contained routine + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + words = name.split() + self.Str+="\n\subsection{{{}}}\n\n".format(name) + self.have_name = 1 + return + + # A new CLASS + # ------------ + if len(Fld)>1 and Fld[1] == '!CLASS:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not first: self.Str+="\n\\newpage\n" + if self.opt["f"]: + self.Str+="\n\section{{C++: Class Interface {} }}\n\n".format( self.name_is) + else: + self.Str+="\n\section{{C++: Class Interface {} (Source: {})}}\n\n".format(self.name_is,self.FileBaseName) + self.have_name = 1 + self.have_intf = 1 # fake, does not need one. + self.first = 0 + return + + # A new Method + # ------------------------- + if len(Fld)>1 and Fld[1] == '!METHOD:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not self.first: + self.Str+="\n\\newpage\n" + if self.opt["f"]: + self.Str+="\n\subsection{{{}}}\n\n".format(name) + else: + self.Str+="\n\subsection{{{} (Source: {})}}\n\n".format(name,self.FileBaseName) + self.have_name = 1 + self.first = 0 + return + + # A new function + # ------------------------- + if len(Fld)>1 and Fld[1] == '!FUNCTION:': + if self.prologue: + self.name_is = " ".join(Fld[2:]) + name=self.name_is.replace("_","\_")# Replace "_" with "\_" + if self.opt["n"] and not self.first: self.Str+="\n\\newpage\n" + if self.opt["f"]: + self.Str+="\n\subsection{{{}}}\n\n".format(names) + else: + self.Str+="\n\subsection{{{}(Source: {})}}\n\n".format(name,self.FileBaseName) + self.have_name = 1 + self.first = 0 + return + + # Description: what follows will be regular LaTeX (no verbatim) + # ------------------------------------------------------------- + if "!DESCRIPTION:" in Rec: + if self.prologue: + self.skip=0 + # if still active close verbatim and switch off + if self.verb: + self.Str+="\n\end{verbatim}" + self.Str+="\n{{\sf \\bf DESCRIPTION:\\\ }}\n\n" + self.verb = 0 + if self.opt["x"]: #description not latex + self.Str+="\n\\begin{verbatim} " + self.verb = 1 + self.descr_verb = 1 + else: + for f in Fld[2:]: + self.Str+="\n{} ".format(f) + # self.Str+=" " + self.have_desc = 1 + return + + # Handle optional keywords (these will appear as verbatim) + # -------------------------------------------------------- + if self.prologue: + for key in self.keys: + if key in Rec: + if self.opt['h']: + self.skip=1 + return + else: + if self.verb: #switch off verbatim to create heading + self.Str+="\n\end{verbatim}\n" + self.verb = 0 + k = "{}".format(key) + ln = len(k) + Rec=key + if self.opt["g"]: + if ("/IMPORT STATE/" in key) or ("/EXPORT STATE/" in key) or ("/INTERNAL STATE/" in key): + if self.inspec: + self.beg_item() + self.Str+="\n \\bigskip \n {{\\bf {} }} \n\n".format(k[1:ln]) + self.hed_item() + self.inspec = 1 + self.initem = 0 + return + else: + self.Str+="\n{{\\bf {}}}".format(k[1:ln]) # italics + else: + if ("/USES/" in key) or ("/INPUT/" in key) or ("/OUTPUT/" in key) or ("/PARAMETERS/" in key) or ("/VALUE/" in key) or ("/ARGUMENTS/" in key): + self.Str+="\n{{\em {}}}".format(k[1:ln]) # italics + else: + self.Str+="\n{{\\sf {}}}".format(k[1:ln]) # san serif + #switch verbatim back on: + self.Str+="\n\\begin{verbatim}" + self.verb = 1 + self.descr_verb = 1 + if key == "!INTERFACE:": self.have_intf = 1 + if key == "!CALLING SEQUENCE:": self.have_intf = 1 + if key == "!REVISION HISTORY:": self.have_hist = 1 + return + + # End of prologue + # --------------- + if Fld[0] == self.eop_string: + if self.verb: #close and switch off verbatim + self.Str+="\n\end{verbatim}\n" + self.verb = 0 + if self.opt["g"] and self.inspec: + self.beg_item() + self.inspec = 0 + self.prologue = 0 #switch off prologue + if self.opt["l"]: + Fld[0] = self.boc_string + else: + return + + if not self.opt["s"]: + + # End of Internal Prologue + # ------------------------ + if Fld[0] == self.eopi_string: + if self.verb: #close and switch off verbatim + self.Str+="\n\end{verbatim}\n" + self.verb = 0 + if self.opt["g"] and self.inspec: + self.beg_item() + self.inspec = 0 + self.prologue = 0 + if self.opt["l"]: + Fld[0] = self.boc_string + else: + return + + # + # Beginning of source code section + # -------------------------------- + if Fld[0] == self.boc_string: + self.Str+=" \n" + self.Str+="%/////////////////////////////////////////////////////////////\n" + self.first = 0 + self.prologue = 0 + self.source = 1 + self.Str+="\n\\begin{verbatim}" + self.verb = 1 + return + + # End of source code + # ------------------ + if Fld[0] == self.eoc_string: + self.do_eoc() #if source is still active close it and close verbatim + + self.prologue = 0 + return + + # Beginning of example prologue + # (separated in latex source but not in output) + # ----------------------------- + if Fld[0] == self.boe_string: + if self.source: self.do_eoc() #if source is still active close it and close verbatim + self.Str+=" \n" + self.Str+="%/////////////////////////////////////////////////////////////\n" + self.first = 0 + self.prologue = 1 + self.verb = 0 + self.source = 0 + return + + # End of example prologue + # ----------------------- + if Fld[0] == self.eoe_string: + if self.verb: + self.Str+="\n\end{verbatim}\n" + self.verb = 0 + self.prologue = 0 + if self.opt["l"]: + Fld[0] = self.boc_string + else: + return + + # Prologue or Introduction, print regular line (except for !) + # ----------------------------------------------------------- + if not self.skip and (self.prologue or self.intro): + if self.verb and len(Fld)==1 and Fld[0]==self.comment_string: + return + elif(self.opt["g"]): + if self.verb and len(Fld)==2 and Fld[0]=='implicit': + return + elif self.verb and len(Fld)==1 and Fld[0] == 'private': + return + elif len(Fld)>1 and Fld[1] == "\\ev": # special handling + Rec = self.comment_string+" \end{verbatim}" + Rec=Rec.replace(self.comment_string," ") # replace comment string with blank + if self.opt["g"] and self.inspec: + if Fld[0] == "call": + self.beg_item() + return + elif len(Fld)>1 and Fld[1] == "=": + self.prc_item(Fld) + else: + self.Str+="\n{}".format(Rec) + self.descr_verb = 0 + + # Source code: print the full line + # -------------------------------- + if self.source and not self.skip: + self.Str+="\n"+Rec + return + + def __str__(self,): + return self.Str + + def CheckOpts(self,optStr,quiet_mode=0): + """Checks options against a given list. Outputs error message + for any invalid option. + + string: optStr - options to be checked. (e.g. -df+x) The + string must begin with a positive or + negative sign. If no sign appears at the + beginning or by itself, then the argument + is not recognized as a list of options. + string: valid_reg_options - string of valid regular options. + (i.e. options that are associated only + eith negative sign.) + string: valid_sw_options - string of valid switch options. + (i.e. options that can be associated with + either a positive or negative sign. + logical: quiet mode (optional) If True then print no error + messages. + Returns: integer return code + = 0 if the arguement, options, is + not recognized as a list of options + = 1 if all options are valid. + > 1 for the number of invalid options. + """ + + if ( optStr=="+" or optStr=="-" ): return -1 + Options = [c for c in optStr] #split up string in single characters + if Options[0]!="-" and Options[0]!="+": return -1 + flag = 1 + for option in Options: + if option == "-" or option == "+": + option_sign = option + else: + if option_sign == "-": + valid_options = self.RegOptions+self.SwOptions + else: + valid_options = self.SwOptions + if option not in valid_options and quiet_mode: + flag+=1 + print("Invalid option: {}{}\n".format(option_sign,option),file=stderr) + self.print_help(dest=stderr) + return flag + + def GetOpts(self,optStr,valid_options): + """Gets options. If an option is valid, then self.opt[option] is + set to 0 or 1 in relation to if the option is preceeded + by a positive or negative sign. + + string: optStr - options to be checked. (e.g. -df+x) The + list must begin with a positive or + negative sign. If no sign appears at the + beginning or by itself, then the argument + is not recognized as a list of options. + string: valid_options - list of valid options (e.g. dfhx) + Returns: integer return code + = -1 if the arguement, options, is + not recognized as a list of options. + = 0 otherwise + """ + + if optStr == "+" or optStr == "-": return -1 + Options = [c for c in optStr] #split up string in single characters + if Options[0]!="-" and Options[0]!="+": return -1 + for option in Options: + if option == "-" or option == "+": + option_sign = option + else: + if option in valid_options: + if option_sign == "-": + self.opt[option] = 1 + elif option_sign == "+": + self.opt[option] = 0 + return 0 + + def SetLanguage(self,optStr): + """Sets the language option. + The last input option that is a LanguageOption will overrule + all others, i.e. for all other language options in the list, + opt_[option] is set to 0. Other options are ignored. + + string: optStr - options to be checked. (e.g. -df+x) The + list must begin with a positive or + negative sign. If no sign appears at the + beginning or by itself, then the argument + is not recognized as a list of options. + Returns: integer return code + = -1 if the arguement, options, is + not recognized as a list of options. + = 0 otherwise + """ + + if optStr == "+" or optStr == "-": return -1 + Options = [c for c in optStr] #split up string in single characters + ValidOptions = [c for c in self.LangOptions] #split up string in single characters + for option in Options: + if option != "-" and option != "+": + if option in self.LangOptions: + for valid_option in self.LangOptions: + self.opt[valid_option]=0 + self.opt[option]=1 + return 0 + + def print_help(self,dest=stdout): + """Print help string, by default to standard output.""" + print("Usage: PyProTex.py [-hbACFS] [+-nlsxf] src_file[s]",file=dest) + print(" ",file=dest) + print(" Options:",file=dest) + print(" -h Human mode: descriptions only, no code information",file=dest) + print(" implies -l and -s",file=dest) + print(" -b Bare mode, meaning no preamble, etc.",file=dest) + print(" -d descriptions only, implies +s and -l",file=dest) + print(" +-n New Page for each subsection (wastes paper)",file=dest) + print(" +-l Listing mode, default is prologues only",file=dest) + print(" +-i drop internal prologues",file=dest) + print(" +-s Shut-up mode, i.e., ignore any code from BOC to EOC",file=dest) + print(" +-x No LaTeX mode, i.e., put !DESCRIPTION: in verbatim mode",file=dest) + print(" +-f No source file info",file=dest) + print(" -A Ada code",file=dest) + print(" -C C++ code",file=dest) + print(" -F F90 code",file=dest) + print(" -S Shell script",file=dest) + print(" ",file=dest) + print(" The options can appear in any order. The options, -h and -b,",file=dest) + print(" affect the input from all files listed on command-line input.",file=dest) + print(" Each of the remaining options effects only the input from the",file=dest) + print(" files listed after the option and prior to any overriding",file=dest) + print(" option. The plus sign turns off the option.",file=dest) + raise SystemExit() + + def print_notice(self,): + """Add auto generation disclaimer to output string.""" + Str="% **** IMPORTANT NOTICE *****" + Str+="% This LaTeX file has been automatically produced by PyProTex" + Str+="% Any changes made to this file will likely be lost next time" + Str+="% this file is regenerated from its source." + Str+=" " + return Str + + def print_preamble(self,): + """Add Latex Preamble to output string.""" + Str="" + if not self.opt["b"]: + Str+="%------------------------ PREAMBLE --------------------------\n" + Str+="\\documentclass[11pt]{article}\n" + Str+="\\usepackage{amsmath,amsfonts,mathrsfs}\n" + Str+="\\usepackage{epsfig}\n" + Str+="\\usepackage{hangcaption}\n" + Str+="\\textheight 9in\n" + Str+="\\topmargin 0pt\n" + Str+="\\headsep 1cm\n" + Str+="\\headheight 0pt\n" + Str+="\\textwidth 6in\n" + Str+="\\oddsidemargin 0in\n" + Str+="\\evensidemargin 0in\n" + Str+="\\marginparpush 0pt\n" + Str+="\\pagestyle{myheadings}\n" + Str+="\\markboth{}{}\n" + Str+="%-------------------------------------------------------------\n" + + # in your main document before you include any protex-generated files + # for the first time, if you define these three variables as length + # settings (like this:) + # \newlength{\oldparskip} + # \newlength{\oldparindent} + # \newlength{\oldbaselineskip} + # then 1) comment in all the lines below, and 2) find the 3 reset lines + # further down and comment in them as well. + # then protex will override the paragraph and skip settings during + # the source sections, but will restore the original document settings + # at the end. if someone can figure out how to check to see if a + # latex variable exists, and do a conditional section, we could make + # this fully self-contained. + # nsc feb 2003 + + #.Str+="\\setlength{\\oldparskip}{\\parskip}\n" + Str+="\\setlength{\\parskip}{0pt}\n" + #Str+="\\setlength{\\oldparindent}{\\parindent}\n" + Str+="\\setlength{\\parindent}{0pt}\n" + #Str+="\\setlength{\\oldbaselineskip}{\\baselineskip}\n" + Str+="\\setlength{\\baselineskip}{11pt}\n" + return Str + + def print_macros(self,): + """Add macro definitions to output string.""" + Str=" \n" + Str+="%--------------------- SHORT-HAND MACROS ----------------------\n" + Str+="\\def\\bv{\\begin{verbatim}}\n" + Str+="\\def\\ev{\\end{verbatim}}\n" + Str+="\\def\\be{\\begin{equation}}\n" + Str+="\\def\\ee{\\end{equation}}\n" + Str+="\\def\\bea{\\begin{eqnarray}}\n" + Str+="\\def\\eea{\\end{eqnarray}}\n" + Str+="\\def\\bi{\\begin{itemize}}\n" + Str+="\\def\\ei{\\end{itemize}}\n" + Str+="\\def\\bn{\\begin{enumerate}}\n" + Str+="\\def\\en{\\end{enumerate}}\n" + Str+="\\def\\bd{\\begin{description}}\n" + Str+="\\def\\ed{\\end{description}}\n" + Str+="\\def\\({\\left (}\n" + Str+="\\def\\){\\right )}\n" + Str+="\\def\\[{\\left [}\n" + Str+="\\def\\]{\\right ]}\n" + Str+="\\def\\<{\\left \\langle}\n" + Str+="\\def\\>{\\right \\rangle}\n" + Str+="\\def\\cI{{\\cal I}}\n" + Str+="\\def\\diag{\\mathop{\\rm diag}}\n" + Str+="\\def\\tr{\\mathop{\\rm tr}}\n" + Str+="%-------------------------------------------------------------\n" + return Str + + def do_beg(self,): + """Add title page to output string.""" + if not self.opt["b"]: + if self.begdoc == 0: + if self.tpage: + self.Str+="\n\\title{@title}\n" + self.Str+="\\author{\\sc {}}\\\\ {\\em {}}}\n".format(self.author,self.affiliation) + self.Str+="\\date{{{}}}\n".format(self.date) + self.Str+="\\begin{document}\n" + if self.tpage: + self.Str+="\\maketitle\n" + self.Str+="\\tableofcontents\n" + self.Str+="\\newpage\n" + self.begdoc = 1 + + def do_eoc(self,): + """At eoc close verbatim and set source to false.""" + self.Str+="\n" + if self.verb: + self.Str+="\end{verbatim}" + self.verb = 0 + self.source = 0 + + def set_missing(self,): + """Reset section attributes for later checking.""" + self.have_name = 0; # have routine name? + self.have_desc = 0; # have description? + self.have_intf = 0; # have interface? + self.have_hist = 0; # have revision history? + self.name_is = "UNKNOWN"; + + def check_if_all_there(self,): + """Checking for section attributes.""" + self.check_error(self.have_name,"!(I)ROUTINE:") + self.check_error(self.have_desc,"!DESCRIPTION:") + self.check_error(self.have_intf,"!INTERFACE:") + self.check_error(self.have_hist,"!REVISION HISTORY:") + + def check_error(self,flag,tag): + """Raise prologue status error flag is False.""" + if not flag: + raise RunTimeError("ProTeX: invalid prologue, missing {}: in {}".format(tag,self.name_is)) + + def hed_item(self,): + self.Str+="\\bigskip\n{{ \\bf \sf \n" + self.Str+="\makebox[.9 in][l]{{Short Name }} \n" + self.Str+="\makebox[.9 in][l]{{Units }} \n" + self.Str+="\makebox[.7 in][l]{{Dims }} \n" + self.Str+="\makebox[.7 in][l]{{Vert Loc }} \n" + self.Str+="\makebox[4. in][l]{{Long Name }} \n" + self.Str+="}} \n \n" + + def beg_item(self,): + if self.initem: + if self.intv: + self.Str+="\makebox[1.05 in][l]{{\$\overline{{\\rm \\bf {} }}\$}} \n".format(self.shname) + else: + self.Str+="\makebox[1.05 in][l]{{\\bf {} }} \n".format(self.shname) + self.Str+="\makebox[.9 in][l]{{ {} }} \n".format(units) + if self.dims != " ": + if self.dims != 'GEOS\_DIMSHORZONLY': + self.Str+="\makebox[.7 in][l]{{HorzOnly}}\n" + elif self.dims == 'GEOS\_DIMSHORZVERT': + self.Str+="\makebox[.7 in][l]{{HorzVert}}\n" + elif self.dims == 'GEOS\_DIMSVERTONLY': + self.Str+="\makebox[.7 in][l]{{VertOnly}}\n" + elif self.dims == 'GEOS\_DIMSTILEONLY': + self.Str+="\makebox[.7 in][l]{{TileOnly}}\n" + elif self.dims == 'GEOS\_DIMSTILETILE': + self.Str+="\makebox[.7 in][l]{{TileTile}}\n" + if self.locs != " ": + if(self.locs == 'GEOS\_VLOCATIONCENTER'): + self.Str+="\makebox[.7 in][l]{{Center}}\n" + elif(self.locs == 'GEOS\_VLOCATIONEDGE'): + self.Str+="\makebox[.7 in][l]{{Edge }}\n" + elif(self.locs == 'GEOS\_VLOCATIONNONE'): + self.Str+="\makebox[.7 in][l]{{None }}\n" + self.Str+="\makebox[4 in][l]{{\\small {} }}\\newline\n".format(self.lnname) + self.initem=1 + self.dims=' ' + self.locs=' ' + self.intv=0 + + def prc_units(self,Str): + #outStr=Str.replace("+1","").replace( + #s/\+1//g; + #s/([a-zA-Z])\+([1-9][0-9]*)/{\1}\$^{\2}\$/g; + #s/\-([1-9][0-9]*)/\$^{-\1}\$/g; + pass + + def prc_item(self,fld): + # Attribute name is the first field + self.name = fld[0].upper() + # Attribute value begins at the third field + value=fld + valStr = " ".join(value[2:]) + # Clean the value + valStr=valStr.replace("_","\_").replace("\'","").replace("\"","").replace(",","").replace("&","") + if self.name == "UNITS": + self.prc_units() + else: + valStr=valStr.replace(" ","") + if self.name == "SHORT_NAME": + self.shname = valStr + elif self.name == "LONG_NAME": + self.lnname = valStr + elif self.name == "UNITS": + self.units = valStr + elif self.name == "DIMS": + self.dims = valStr.upper() + elif self.name == "VLOCATION": + self.locs = valStr.upper() + elif self.name == "AVERAGING_INTERVAL": + self.intv = 1 + +if __name__=="__main__": + files=[] + opts=[] + for arg in argv[1:]: + if arg[0] not in ("+","-",): + files.append(arg) + else: + opts.append(arg) + PPTex=PyProTex(opts) #set-up with all options + PPTex(files) #translate all files + print(PPTex) -- GitLab