#!/usr/bin/env python # # Copyright 2015 Momme Butenschoen, Plymouth Marine Laboratory # # This file is part of the PyProTex module. # # PyProTex 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. # # PyProTex 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. # 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 PyProTex. If not, see . # # Address: # Plymouth Marine Laboratory # Prospect Place, The Hoe # Plymouth, PL1 3DH, UK # # Email: # momm@pml.ac.uk # # $Id: PyProTex,v15.04 $ # #BOI # # !TITLE: PyProTex # !AUTHOR: Momme Butensch\xf6n # !AFFILIATION: Plymouth Marine Laboratory # !DATE: 20 April 2015 # #EOI #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. # The 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. \\ hline # +/-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 tag 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 # 20Apr2015 M. Butenschoen Compability for python 2 and 3 in one file, # python3 specific version therefore obsolete. # #EOP #---------------------------------------------------------------------------- #BOC from __future__ import print_function 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: self.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: self.author = "{}".format(" ".join(*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: self.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) #EOC