From 751eeb0fd239befa637cb5f785ceb2f41116037c Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 4 Mar 2022 12:02:35 -0500 Subject: [PATCH 1/6] Add protex --- CHANGELOG.md | 2 + latex/FindProtex.cmake | 5 +- latex/UseProTeX.cmake | 4 +- latex/protex | 1828 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1836 insertions(+), 3 deletions(-) create mode 100755 latex/protex diff --git a/CHANGELOG.md b/CHANGELOG.md index 669b58f6..0890c2fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed ### Added +- Add `protex` script + ## [3.10.0] - 2022-02-04 ### Added diff --git a/latex/FindProtex.cmake b/latex/FindProtex.cmake index b50f6251..e6ab098f 100644 --- a/latex/FindProtex.cmake +++ b/latex/FindProtex.cmake @@ -1,10 +1,11 @@ -set (protex_exe ${CMAKE_SOURCE_DIRECTORY}/config/protex) +set (protex_exe ${CMAKE_CURRENT_SOURCE_DIR}/protex) set (protex_flags -g -b -f) +function(protex src) get_filename_component (base ${src} NAME_WE) add_custom_command (OUTPUT ${base}.tex COMMAND ${protex_exe} ${protex_flags} -f ${src} > ${base}.tex DEPENDS ${src} - COMMENT "[protex] Building documentatino for ${src}" + COMMENT "[protex] Building documentation for ${src}" ) endfunction (protex src) diff --git a/latex/UseProTeX.cmake b/latex/UseProTeX.cmake index d64b590a..80d2da17 100644 --- a/latex/UseProTeX.cmake +++ b/latex/UseProTeX.cmake @@ -1 +1,3 @@ -set (protex_exe ${CMAKE_SOURCE_DIR}/config/protex) +message(STATUS "In UseProTeX CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}") +message(STATUS "In UseProTeX ESMA_CMAKE_DIR: ${ESMA_CMAKE_DIR}") +set (protex_exe ${ESMA_CMAKE_DIR}/protex) diff --git a/latex/protex b/latex/protex new file mode 100755 index 00000000..ca1c00b4 --- /dev/null +++ b/latex/protex @@ -0,0 +1,1828 @@ +#!/usr/bin/perl +# +# +#BOP +# +# !ROUTINE: ProTeX v. 2.00 - Translates DAO Prologues to LaTeX +# +# !INTERFACE: +# protex [-hbgACFS] ] [+-nlsxf] [src_file(s)] +# +# !DESCRIPTION: +# Perl filter to produce a \LaTeX compatible document +# from a DAO Fortran source code with standard Pro\TeX +# prologues. If source files are not specified it +# reads from stdin; output is always to stdout. +# +# \noindent +# {\bf Command Line Switches:} \vspace{0.2cm} +# +# \begin{center} +# \begin{tabular}{|c|l|} \hline \hline +# -h & Help mode: list command line options \\ \hline +# -b & Bare mode, meaning no preamble, etc. \\ \hline +# -i & internal mode: omit prologues marked !BOPI \\ \hline +# -g & Use GEOS style. +# -M & Use MAPL style (??) +# -E & Use ESMF style +# +/-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 \hline +# \end{tabular} +# \end{center} +# +# The options can appear in any order. The options, -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 +# +# +# !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. +# +# 30Jul2012 P. Chakraborty +# 1. Added BOS/EOS to list states (from spec calls) +# as a table instead of makebox'es which do not play +# well with latex2html +# 2. Modified EOR/BOR: please see description below +# 3. Section heading 'CODE' is not bold anymore +# 4. Added indexing of subroutines/functions (!IROUTINE:) +# 5. Added !IDESCRIPTION: (same as !DESCRIPTION:, except +# that the word 'DESCRIPTION' does not appear on top +# 08Apr2013 R. Todling Add graphicx to packages used +# +#EOP + +# !BOS/!EOS +# To document the spec calls for Import/Export/Internal states, these calls +# need to be enclosed between !BOS and !EOS. Also the spec call should look like +# call MAPL_AddExportSpec(gc, & +# SHORT_NAME = 'KE', & +# LONG_NAME = 'vertically_integrated_kinetic_energy', & +# UNITS = 'J m-2', & +# DIMS = MAPL_DimsHorzOnly, & +# VLOCATION = MAPL_VLocationNone, & +# RC = STATUS) +# Multiple arguments (e.g. UNITS and DIMS) in one line would lead to errors. +# The state variables are listed in a table, instead of makebox-es which do not +# play nice with latex2html. +# +# !BOR/EOR +# The resource items are listed in a table instead of makebox-es which do not +# play nice with latex2html. +# To document the resources fully, the call to MAPL_GetResource(...) needs to +# be enclosed between !BOR and !EOR. For complete documentation, protex needs +# two lines: the first comment line starting with the keyword !RESOURCE_ITEM: +# followed by the actual call to MAPL_GetResource(...) (in that order). e.g. +# +# !BOR +# !RESOURCE_ITEM: K :: Value of isothermal temperature on coldstart +# call MAPL_GetResource ( MAPL, T0, 'T0:', default=300., RC=STATUS ) +# !EOR +# +# From the !RESOURCE_ITEM line, protex reads the unit (K) and the description +# (Value of isothermal temperature on coldstart). From the call line, protex +# reads the name (label) and its default value. The call line should NOT be +# continued to the next line(s). + +#---------------------------------------------------------------------------- + +# Keep this if you don't know what it does... +# ------------------------------------------- +$[ = 1; # set array base to 1 +$, = ' '; # set output field separator +$\ = "\n"; # set output record separator + +# Set valid options lists +# ----------------------- + +$GlobOptions = 'hbgM'; # Global options (i.e for all files) +$LangOptions = 'ACFS'; # Options for setting programming languages +$SwOptions = 'flinsx'; # Options that can change for each input + +# file +$RegOptions = "$GlobOptions$LangOptions"; + +# Scan for global options until first first +# file is processed. + +# Scan for global options +# ----------------------- +$NFiles = 0; +Arg: +foreach $arg (@ARGV) { + $option = &CheckOpts( $arg, $RegOptions, $SwOptions ) + 1; + if ($option) { + $rc = &GetOpts( $arg, $GlobOptions ); + next Arg; + } + else { + $NFiles++; + } +} + +# If all input arguments are options, then assume the +# filename, "-", for the standard input +# -------------------------------------------------- +if ( $NFiles == 0 ) { push( @ARGV, "-" ); } + +# Implement help option +# --------------------- +if ($opt_h) { + &print_help(); + exit(); +} + +# Optional Prologue Keywords +# -------------------------- +@keys = ( + "!INTERFACE:", + "!USES:", + "!PUBLIC TYPES:", + "!PRIVATE TYPES:", + "!PUBLIC MEMBER FUNCTIONS:", + "!PRIVATE MEMBER FUNCTIONS:", + "!METHOD OVERLOADING:", + "!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 +# ---------------------------- +$intro = 0; # doing introduction? +$prologue = 0; # doing prologue? +$first = 1; # first prologue? +$source = 0; # source code mode? +$verb = 0; # verbatim mode? +$tpage = 0; # title page? +$begdoc = 0; # has \begin{document} been written? +$inspec = 0; # are we processing state specs +$initem = 0; # are we processing state specs item +$resource = 0; # are we processing resources +$inresource = 0; # are we in a resource item +$do_code = 0; # produce a code section in MAPL; Stubbed for now. +$table = 0; # doing a latex table + +# Initial LaTeX stuff +# ------------------- +&print_notice(); +&print_preamble(); # \documentclass, text dimensions, etc. +&print_macros(); # short-hand LaTeX macros + +# Main loop -- for each command-line argument +# ------------------------------------------- +ARG: +foreach $arg (@ARGV) { + + # Scan for non-global command-line options + # ---------------------------------------- + $option = &CheckOpts( $arg, $RegOptions, $SwOptions, "quiet" ) + 1; + if ($option) { + &GetOpts( $arg, $SwOptions ); + &SetOpt( $arg, $LangOptions ); + next ARG; + } + + $is_mapl = $opt_g || $opt_M; + + # Determine the type of code, set corresponding search strings + # ------------------------------------------------------------ + # if ( $opt_F ) { # FORTRAN + $comment_string = '!'; # ------- + $boi_string = '!BOI'; + $eoi_string = '!EOI'; + $bop_string = '!BOP'; + $eop_string = '!EOP'; + $bopi_string = '!BOPI'; + $eopi_string = '!EOPI'; + $boc_string = '!BOC'; + $eoc_string = '!EOC'; + $boe_string = '!BOE'; + $eoe_string = '!EOE'; + $bor_string = '!BOR'; + $eor_string = '!EOR'; + $bos_string = '!BOS'; # begin state (import/export/internal) + $eos_string = '!EOS'; # end state + $bot_string = '!BOT'; + $eot_string = '!EOT'; + $boltfd_string = '!BOLTFD'; + $eoltfd_string = '!EOLTFD'; + $boltcfd_string = '!BOLTCFD'; + $eoltcfd_string = '!EOLTCFD'; + + #} + + if ($opt_A) { # ADA + $comment_string = '--'; # --- + $boi_string = '--BOI'; + $eoi_string = '--EOI'; + $bop_string = '--BOP'; + $eop_string = '--EOP'; + $bopi_string = '--BOPI'; + $eopi_string = '--EOPI'; + $boc_string = '--BOC'; + $eoc_string = '--EOC'; + $boe_string = '--BOE'; + $eoe_string = '--EOE'; + } + + if ($opt_C) { + $comment_string = '//'; # C + $boi_string = '//BOI'; # - + $eoi_string = '//EOI'; + $bop_string = '//BOP'; + $eop_string = '//EOP'; + $bopi_string = '//BOPI'; + $eopi_string = '//EOPI'; + $boc_string = '//BOC'; + $eoc_string = '//EOC'; + $boe_string = '//BOE'; + $eoe_string = '//EOE'; + } + + if ($opt_S) { # Script + $comment_string = '#'; # ------ + $boi_string = '#BOI'; + $eoi_string = '#EOI'; + $bop_string = '#BOP'; + $eop_string = '#EOP'; + $bopi_string = '#BOPI'; + $eopi_string = '#EOPI'; + $boc_string = '#BOC'; + $eoc_string = '#EOC'; + $boe_string = '#BOE'; + $eoe_string = '#EOE'; + } + + # Set file name parameters + # ------------------------ + $InputFile = $arg; + @all_path_components = split( /\//, $InputFile ); + $FileBaseName = pop(@all_path_components); + $FileBaseName =~ s/_/\\_/g; + if ( $InputFile eq "-" ) { $FileBaseName = "Standard Input"; } + + # Set date + # -------- + $Date = `date`; + + # Open current file + # ----------------- + open( InputFile, "$InputFile" ) + or print STDERR "Unable to open $InputFile: $!"; + + # Print page header + # ----------------- + if ($is_mapl) { + $shname = " "; + $lnname = " "; + $units = " "; + $dims = " "; + $child = " "; + $locs = " "; + } + else { + printf "\n\\markboth{Left}{Source File: %s, Date: %s}\n\n", $FileBaseName, $Date; + } + + LINE: + + # Inner loop --- for processing each line of the input file + # --------------------------------------------------------- + while () { + chop; # strip record separator + + # add a space around '=', needed for parsing addspec calls + s/=/\ =\ /g; + + next LINE if /^\#/; # skip CPP directives + + # eliminate/replace keywordEnforcer arguments from API + s/keywordEnforcer, //g; + s/^[! \t]*type\(ESMF_KeywordEnforcer\), optional:: keywordEnforcer.*$/-- The following arguments require argument keyword syntax (e.g. rc=rc). --/g; + + # !PARAMETERS: really mean !ARGUMENTS: + # ------------------------------------ + # s/!PARAMETERS:/!ARGUMENTS:/g; + + # begin pc + # if($in_resource) { + # @Fld = split(',', $_, 9999); + # } else { + # @Fld = split(' ', $_, 9999); + # } + # end pc + + # if($initem){ + # @Fld = split(',', $_, 9999); + # } else { + # @Fld = split(' ', $_, 9999); + # } + + @Fld = split( ' ', $_, 9999 ); + + # end pc + + # Straight quote + # -------------- + if ( ( $Fld[1] eq '!QUOTE:' ) || ( $is_mapl && ( $Fld[1] eq '!MQUOTE:' ) ) ) { + for ( $i = 2 ; $i <= $#Fld ; $i++ ) { + printf '%s ', $Fld[$i]; + } + print " "; + next LINE; + } + + if ( $Fld[1] eq $bor_string ) { + print "\\emph{RESOURCES:}\\\\"; + print "\\newline"; + + print "\\texttt{"; + print "\\begin{longtable}{p{1in} | p{3in} p{1in} p{0.5in}}"; + print "\\hline"; + print "{\\sf \\sf Name} & {Description} & {\\sf \\sf Units} & {\\sf \\sf Default}\\\\"; + print "\\hline\\\\"; + print "\\endhead"; + + $resource = 1; + next LINE; + } + + if ( $Fld[1] eq $eor_string ) { + if ($resource) { + print "\\end{longtable}"; + print "}"; # closes \texttt{ + $resource = 0; + } + next LINE; + } + + if ( $Fld[1] eq $bos_string ) { + print "\\emph{STATES:}\\\\"; + print "\\newline"; + print "The following is a list of \\texttt{Import}, \\texttt{Export} and"; + print "\\texttt{Internal} states (second column specifies the type):"; + print "\\texttt{"; + print "\\begin{longtable}{p{1in} | p{0.2in} p{0.8in} p{0.3in} p{0.6in} p{2.4in}}"; + print "\\hline"; + print "{\\sf \\sf Short Name} & {\\sf \\sf Type} & {\\sf \\sf Units} & {\\sf \\sf Dims} & {\\sf \\sf Vert Loc} & {\\sf \\sf Long name}\\\\"; + print "\\hline\\\\"; + print "\\endhead"; + + $inspec = 1; + $initem = 0; + next LINE; + } + + if ( $Fld[1] eq $eos_string ) { + if ($inspec) { + &beg_item(); + print "\\end{longtable}"; + print "}"; # closes \texttt{ + $inspec = 0; + } + next LINE; + } + + # Handle optional Title Page and Introduction + # ------------------------------------------- + if ( $Fld[1] eq $boi_string ) { + print ' '; + $intro = 1; + next LINE; + } + + if ( $Fld[2] eq '!TITLE:' ) { + if ($intro) { + shift @Fld; + shift @Fld; + @title = @Fld; + $tpage = 1; + next LINE; + } + } + + if ( $Fld[2] eq '!AUTHORS:' ) { + if ($intro) { + shift @Fld; + shift @Fld; + @author = @Fld; + $tpage = 1; + next LINE; + } + } + + if ( $Fld[2] eq '!AFFILIATION:' ) { + if ($intro) { + shift @Fld; + shift @Fld; + @affiliation = @Fld; + $tpage = 1; + next LINE; + } + } + + if ( $Fld[2] eq '!DATE:' ) { + if ($intro) { + shift @Fld; + shift @Fld; + @date = @Fld; + $tpage = 1; + next LINE; + } + } + + if ( $Fld[2] eq '!INTRODUCTION:' ) { + if ($intro) { + &do_beg(); + print ' '; + print '%..............................................'; + shift @Fld; + shift @Fld; + if ($is_mapl) { + print "\\part{\\Large @Fld}"; + } + else { + print "\\section{@Fld}"; + } + next LINE; + } + } + + # End of introduction + # ------------------- + if ( $Fld[1] eq $eoi_string ) { + print ' '; + print '%/////////////////////////////////////////////////////////////'; + print "\\newpage"; + $intro = 0; + next LINE; + } + + # Beginning of latex table + # --------------------- + if ( $Fld[1] eq $bot_string ) { + print " "; + print "%/////////////////////////////////////////////////////////////"; + shift @Fld; + $_ = join( '|', @Fld ); + print "\\begin{tabular}{|$_|}"; + $table = 1; + $tableline = 0; + $tableelement = 0; + next LINE; + } # end if + + # End of latex table + # ------------------- + if ( $Fld[1] eq $eot_string ) { + print "\\hline"; + print "\\end{tabular}"; + print "%/////////////////////////////////////////////////////////////"; + print " "; + $table = 0; + next LINE; + } # end if + + # Beginning of fd latex longtable + # --------------------- + if ( $Fld[1] eq $boltfd_string ) { + print " "; + print "%/////////////////////////////////////////////////////////////"; + shift @Fld; + $_ = join( '|', @Fld ); + print "\\begin{longtable}{|$_|}"; + $fdtable = 1; + $tableline = 0; + $tableelement = 0; + next LINE; + } # end if + + # End of fd latex longtable + # ------------------- + if ( $Fld[1] eq $eoltfd_string ) { + print "\\hline"; + print "\\end{longtable}"; + print "%/////////////////////////////////////////////////////////////"; + print " "; + $fdtable = 0; + next LINE; + } # end if + + # Beginning of fd latex longtable contents + # --------------------- + if ( $Fld[1] eq $boltcfd_string ) { + if ( !$tableline && $tableelement ) { printf "\\\\"; } + if ( !$tableline ) { printf " \\hline \\hline\n\n"; } + print " "; + $tableelement = 0; + $tableline++; + next LINE; + } # end if + + # End of fd latex longtable contents + # ------------------- + if ( $Fld[1] eq $eoltcfd_string ) { + next LINE; + } # end if + + # Beginning of prologue + # --------------------- + if ( $Fld[1] eq $bop_string ) { + if ($source) { &do_eoc(); } + print ' '; + print '%/////////////////////////////////////////////////////////////'; + &do_beg(); + if ( $first == 0 && $opt_n == 0 ) { + ### print "\\newpage"; + print " "; + print "\\mbox{}\\hrulefill\\ "; + print " "; + } + else { + unless ( $opt_b || $is_mapl ) { + print "\\section{Routine/Function Prologues} \\label{app:ProLogues}"; + } + } + + $first = 0; + $prologue = 1; + $verb = 0; + $source = 0; + $resource = 0; + $inspec = 0; + $inresource = 0; + &set_missing(); # no required keyword yet + next LINE; + } + + # Beginning of internal prologue + # ------------------------------ + if ( $Fld[1] eq $bopi_string ) { + if ($opt_i) { $prologue = 0; } + else { + if ($source) { &do_eoc(); } + print ' '; + print '%/////////////////////////////////////////////////////////////'; + &do_beg(); + if ( $first == 0 && $opt_n == 0 ) { + ### print "\\newpage"; + print " "; + print "\\mbox{}\\hrulefill\\"; + print " "; + } + else { + unless ( $opt_b || $is_mapl ) { + print "\\section{Routine/Function Prologues} \\label{app:ProLogues}"; + } + } + $first = 0; + $prologue = 1; + $verb = 0; + $source = 0; + $resource = 0; + $inspec = 0; + $inresource = 0; + &set_missing(); # no required keyword yet + next LINE; + } + } + + # A new subroutine/function + # ------------------------- + if ( $Fld[2] eq '!ROUTINE:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + unless ($opt_f) { printf "\\subsubsection{%s (Source File: %s)}\n\n", $_, $FileBaseName; } + else { printf "\\subsubsection{%s }\n\n", $_; } + $have_name = 1; + $not_first = 1; + next LINE; + } + } + + # A new Module + # ------------ + if ( $Fld[2] eq '!PROGRAM:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + if ($is_mapl) { + printf "\\section [%s] {Program %s }\n\n", $_, $_; + } + else { + unless ($opt_f) { printf "\\subsection{Fortran: Main Program %s (Source File: %s)}\n\n", $_, $FileBaseName; } + else { printf "\\subsection{Fortran: Main Program %s }\n\n", $_; } + } # endif + + $have_name = 1; + $have_intf = 1; # fake it, it does not need one. + $not_first = 1; + next LINE; + } + } + + # A new Module + # ------------ + if ( $Fld[2] eq '!MODULE:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + if ($is_mapl) { printf "\\section [%s] {Module %s }\n\n", $_, $_; } + else { + unless ($opt_f) { + printf "\\subsection{Fortran: Module Interface %s (Source File: %s)}\n\n", $_, $FileBaseName; + } + else { + printf "\\subsection{Fortran: Module Interface %s }\n\n", $_; + } + } # endif + + $have_name = 1; + $have_intf = 1; # fake it, it does not need one. + $not_first = 1; + next LINE; + } + } + + # A new include file + # ------------------ + if ( $Fld[2] eq '!INCLUDE:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + unless ($opt_f) { printf "\\subsubsection{Include File %s (Source File: %s)}\n\n", $_, $FileBaseName; } + else { printf "\\subsubsection{Include File %s }\n\n", $_; } + $have_name = 1; + $have_intf = 1; # fake it, it does not need one. + $not_first = 1; + next LINE; + } + } + + # Anchor + # ---------------------------------- + if ( $Fld[2] eq '!ANCHOR:' ) { # HTML anchor + if ($prologue) { + printf("\\label{$Fld[3]}\n"); + next LINE; + } # end if + } # end if + + # A new INTERNAL subroutine/function + # ---------------------------------- + if ( $Fld[2] eq '!IROUTINE:' ) { # Internal routine + if ($prologue) { + shift @Fld; + shift @Fld; + $Generic_name = $Fld[0]; # For overloads: padded + $generic_name = $Fld[0]; # For overloads: not padded + $internal_name = $Fld[0]; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + + if ($is_mapl) { + + #ams @words = split "-", $_; + #ams printf "\\subsection [$words[1]] {$_}\n\n"; + $Fld[0] =~ s/_/\\_/g; # Replace "_" with "\_" + printf "\\subsection [$_] {$_\\index{$Fld[0]}}\n\n"; + } + else { + ### @words = split " ", $_; + ### printf "\\subsubsection [$words[1]] {$_}\n\n"; + $Fld[0] =~ s/_/\\_/g; # Replace "_" with "\_" + printf "\\subsection [$_] {$_\\index{$Fld[0]}}\n\n"; + } + $have_name = 1; + next LINE; + } + } + + # A new OVERLOADED subroutine/function + # ----------------------------------- + if ( $Fld[2] eq '!IIROUTINE:' ) { # Internal routine + if ($prologue) { + shift @Fld; + shift @Fld; + $internal_name = $Fld[0]; + $Generic_name = $generic_name; # padded copy + for ( $i = length($generic_name) ; $i < length($internal_name) ; $i++ ) { $Generic_name = $Generic_name . " "; } + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + @words = split " ", $_; + shift @words; + shift @words; + printf "\\subsubsection [@words] {@words}\n\n"; + $have_name = 1; + next LINE; + } + } + + # A new CONTAINED subroutine/function + # ---------------------------------- + if ( $Fld[2] eq '!CROUTINE:' ) { # Contained routine + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + @words = split " ", $_; + printf "\\subsubsection [$words[1]] {$_}\n\n"; + $have_name = 1; + next LINE; + } + } + + # A new CLASS + # ------------ + if ( $Fld[2] eq '!CLASS:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + unless ($opt_f) { printf "\\subsection{C++: Class Interface %s (Source File: %s)}\n\n", $_, $FileBaseName; } + else { printf "\\subsection{C++: Class Interface %s }\n\n", $_; } + $have_name = 1; + $have_intf = 1; # fake it, it does not need one. + $not_first = 1; + next LINE; + } + } + + # A new Method + # ------------------------- + if ( $Fld[2] eq '!METHOD:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + unless ($opt_f) { + printf "\\subsubsection{%s (Source File: %s)}\n\n", $_, $FileBaseName; + } + else { + printf "\\subsubsection{%s }\n\n", $_; + } + $have_name = 1; + $not_first = 1; + next LINE; + } + } + + # A new function + # ------------------------- + if ( $Fld[2] eq '!FUNCTION:' ) { + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + $name_is = $_; + s/_/\\_/g; # Replace "_" with "\_" + if ( $opt_n && $not_first ) { printf "\\newpage\n"; } + unless ($opt_f) { + printf "\\subsubsection{%s (Source File: %s)}\n\n", $_, $FileBaseName; + } + else { printf "\\subsubsection{%s }\n\n", $_; } + $have_name = 1; + $not_first = 1; + next LINE; + } + } + + # Status + # ---------------------------------- + if ( $Fld[2] eq '!STATUS:' ) { # Internal routine + if ($prologue) { + shift @Fld; + shift @Fld; + $_ = join( ' ', @Fld ); + if ($verb) { + printf "\\end{verbatim}"; + $verb = 0; + } + printf "\n{\\sf STATUS:}"; + next LINE; + } # end if + } # end if + + # Description: what follows will be regular LaTeX (no verbatim) + # ------------------------------------------------------------- + if ( /!DESCRIPTION:/ || /!DESIGN ISSUES:/ ) { + if ($prologue) { + if ($verb) { + printf "\\end{verbatim}"; + printf "\n{\\sf \\sf DESCRIPTION:\\ }\n\n" + if (/!DESCRIPTION:/); + printf "\n{\\sf \\sf DESIGN ISSUES:\\ }\n\n" + if (/!DESIGN/); + $verb = 0; + } + else { + printf "\n{\\sf \\sf DESCRIPTION:\\ }\n\n" + if (/!DESCRIPTION:/); + printf "\n{\\sf \\sf DESIGN ISSUES:\\ }\n\n" + if (/!DESIGN ISSUES:/); + } + if ($opt_x) { + printf "\\begin{verbatim} "; + $verb = 1; + $first_verb = 1; + } + else { + for ( $i = 3 ; $i <= $#Fld ; $i++ ) { + printf '%s ', $Fld[$i]; + } + } + ### print " "; + $have_desc = 1; + next LINE; + } + } + + # !IDESCRIPTION: Same as !DESCRIPTION, except that the word + # 'DESCRIPTION' does not appear on top + # --------------------------------------------------------- + if (/!IDESCRIPTION:/) { + if ($prologue) { + if ($verb) { + printf "\\end{verbatim}"; + $verb = 0; + } + if ($opt_x) { + printf "\\begin{verbatim} "; + $verb = 1; + $first_verb = 1; + } + else { + for ( $i = 3 ; $i <= $#Fld ; $i++ ) { + printf '%s ', $Fld[$i]; + } + } + ### print " "; + $have_desc = 1; + next LINE; + } + } + + # Handle optional keywords (these will appear as verbatim) + # -------------------------------------------------------- + if ($prologue) { + KEY: foreach $key (@keys) { + if (/$key/) { + $doing_interface = 0; + if ($verb) { + printf "\\end{verbatim}"; + $verb = 0; + } + $k = sprintf( '%s', $key ); + $ln = length($k); + $_ = $key; + + if ($is_mapl) { + if ( /USES/ + || /INPUT/ + || /OUTPUT/ + || /PARAMETERS/ + || /VALUE/ + || /ARGUMENTS/ ) + { + printf "{\\em %s}\n", substr( $k, 2, $ln - 1 ); # italics + } + else { + printf "{\\sf %s}\n", substr( $k, 2, $ln - 1 ); # san serif + } + } + else { + if ( /USES/ + || /INPUT/ + || /OUTPUT/ + || /PARAMETERS/ + || /VALUE/ + || /ARGUMENTS/ ) + { + printf "{\\em %s}\n", substr( $k, 2, $ln - 1 ); # italics + } + else { + printf "{\\sf %s}\n", substr( $k, 2, $ln - 1 ); # san serif + } + } + + printf "\\begin{verbatim} "; + $verb = 1; + $first_verb = 1; + if ( $key eq "!INTERFACE:" ) { + $have_intf = 1; + $doing_interface = 1; + } + if ( $key eq "!CALLING SEQUENCE:" ) { $have_intf = 1; } + if ( $key eq "!REVISION HISTORY:" ) { $have_hist = 1; } + next LINE; + } + } + } + + # End of prologue + # --------------- + if ( $Fld[1] eq $eop_string ) { + if ($verb) { + print "\\end{verbatim}"; + $verb = 0; + } + $prologue = 0; + + if ($opt_l) { + $Fld[1] = $boc_string; + } + else { next LINE; } + } + + unless ($opt_s) { + + # End of Internal Prologue + # ------------------------ + if ( $Fld[1] eq $eopi_string ) { + if ($verb) { + print "\\end{verbatim}"; + $verb = 0; + } + + $prologue = 0; + if ($opt_l) { + $Fld[1] = $boc_string; + } + else { next LINE; } + } + + # + # Beginning of source code section + # -------------------------------- + if ( $Fld[1] eq $boc_string ) { + print ' '; + print '%/////////////////////////////////////////////////////////////'; + $first = 0; + $prologue = 0; + $source = 1; + $verb = 0; + ### printf "\\subsubsection*{CONTENTS:}\n\n", $Fld[3]; + ###printf "{\\sf CONTENTS:}"; + unless ($opt_s) { + printf "\n{\\em CODE:}\n"; + + # printf "\n\\begin{verbatim}\n"; + printf "\\begin{verbatim}\n"; + $verb = 1; + } + next LINE; + } + + # End of source code + # ------------------ + if ( $Fld[1] eq $eoc_string ) { + &do_eoc(); + $prologue = 0; + next LINE; + } + + # Beginning of example prologue + # ----------------------------- + if ( $Fld[1] eq $boe_string ) { + if ($source) { &do_eoc(); } + print ' '; + print '%/////////////////////////////////////////////////////////////'; + $first = 0; + $prologue = 1; + $verb = 0; + $source = 0; + next LINE; + } + + # End of example prologue + # ----------------------- + if ( $Fld[1] eq $eoe_string ) { + if ($verb) { + print "\\end{verbatim}"; + $verb = 0; + } # end if + $prologue = 0; + if ($opt_l) { + $Fld[1] = $boc_string; + } + else { next LINE; } + } + } # end unless($opt_s) + + # Prologue or Introduction, print regular line (except for !) + # ----------------------------------------------------------- + if ( $prologue || $intro ) { + if ( $verb && $#Fld == 1 && ( $Fld[1] eq $comment_string ) ) { + next LINE; # to eliminate excessive blanks + } + if ($is_mapl) { + if ( $verb && $#Fld == 2 && ( $Fld[1] eq 'implicit' ) ) { + next LINE; + } + if ( $verb && $#Fld == 1 && ( $Fld[1] eq 'private' ) ) { + next LINE; + } + if ( $verb && $#Fld == 1 && ( $Fld[1] eq 'contains' ) ) { + next LINE; + } + } # endif(is_mapl) + if ( $Fld[2] eq "\\ev" ) { # special handling + $_ = $comment_string . " \\end{verbatim}"; + } + s/^$comment_string/ /; # replace comment string with blank + + unless ($first_verb) { printf "\n "; } + if ($doing_interface) { s/$internal_name/$Generic_name/; } + printf '%s', $_; + $first_verb = 0; + next LINE; + } # end if($prologue||$intro) + + # Resources + # --------- + if ( $resource && $is_mapl ) { + $in_rsrcs = 0; + if ( ( $Fld[1] eq "!RESOURCE_ITEM:" ) or ( $Fld[2] eq "!RESOURCE_ITEM:" ) ) { + &prc_rsrcs_1(); + } + if ( ( uc $Fld[1] eq "CALL" ) and ( uc substr( $Fld[2], 6, 11 ) eq "GETRESOURCE" ) ) { + &prc_rsrcs_2(); + $in_rsrcs = 1; + } + if ($in_rsrcs) { + &prnt_rsrcs(); + $in_rsrcs = 0; + } + next LINE; + } + + # State specs + # ----------- + if ( $inspec && is_mapl ) { + if ( $Fld[1] eq "call" ) { + &beg_item(); + + # IM/EX/IN? + # for some (?) reason, we have everything shifted by 1 + # hence substr($Fld[2],9,6) instead of substr($Fld[2],8,6) + if ( lc substr( $Fld[2], 9, 6 ) eq "import" ) { $imexin = "IM"; } + elsif ( lc substr( $Fld[2], 9, 6 ) eq "export" ) { $imexin = "EX"; } + elsif ( lc substr( $Fld[2], 9, 6 ) eq "intern" ) { $imexin = "IN"; } + else { + print $Fld[2]; + print lc substr( $Fld[2], 8, 6 ); + print "A spec call without a type??"; + exit 0; + } + next LINE; + } + if ( $Fld[2] eq "=" ) { + &prc_item(); + } + } + + # Source code: print the full line + # -------------------------------- + if ($source) { + printf "%s \n", $_; + next LINE; + } + + # latex table: pick out the quotations + # ------------------------------------ + if ($table) { + s/_/\\_/g; # Replace "_" with "\_" + @Fldt = split( '"', $_, 9999 ); + if ( $Fldt[2] ) { + if ( !$tableline && !$tableelement ) { print "\\hline \\hline"; } + if ($tableelement) { printf " & "; } + else { printf " "; } + print $Fldt[2]; + $tableelement++; + } + next LINE; + } # end if + + # latex table for NUOPC Field Dictionary: pick out the quotations + # ------------------------------------ + if ($fdtable) { + s/_/\\_/g; # Replace "_" with "\_" + @Fldt = split( '"', $_, 9999 ); + if ( $Fldt[2] ) { + @Fldtt = split( ':', $Fldt[2], 9999 ); + if ( $Fldtt[2] ) { + if ( !$tableline && !$tableelement ) { print "\\hline \\hline"; } + if ($tableelement) { printf " & "; } + else { printf " "; } + print $Fldtt[2]; + $tableelement++; + } + else { + print "\\\\ \\hline"; + $tableelement = 0; + } + } + next LINE; + } # end if + + } # end inner loop for processing each line of the input file + # --------------------------------------------------------- + +} # end main loop for each command-line argument + # -------------------------------------------- +print $_; +if ($source) { &do_eoc(); } +print '%...............................................................'; + +# see comment above where these are originally set. +if ($opt_E) { + print "\\setlength{\\parskip}{\\oldparskip}"; + print "\\setlength{\\parindent}{\\oldparindent}"; + print "\\setlength{\\baselineskip}{\\oldbaselineskip}"; +} + +unless ($opt_b) { + print "\\end{document}"; +} #end unless + +#---------------------------------------------------------------------- + +sub CheckOpts { + + # Checks options against a given list. Outputs error message + # for any invalid option. + # + # Usage: + # $rc = &CheckOpts ( options, valid_reg_options, + # valid_sw_options, + # quiet_mode ) + # + # character: options - 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. + # character: valid_reg_options - list of valid regular options. + # (i.e. options that are associated only + # eith negative sign.) + # character: valid_sw_options - list 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. + # integer: rc - return code + # = -1 if the arguement, options, is + # not recognized as a list of options + # = 0 if all options are valid. + # > 0 for the number of invalid options. + # + local ( $options, $valid_reg_options, $valid_sw_options, $quiet_mode ) = @_; + + if ( $options eq "+" || $options eq "-" ) { return -1 } + + local (@Options) = split( / */, $options ); + if ( $Options[$[] ne "-" && $Options[$[] ne "+" ) { return -1; } + + local ( $option, $option_sign, $valid_list, $pos ); + local ($errs) = 0; + foreach $option (@Options) { + if ( $option eq "-" || $option eq "+" ) { $option_sign = $option; } + else { + if ( $option_sign eq "-" ) { + $valid_list = $valid_reg_options . $valid_sw_options; + } + else { $valid_list = $valid_sw_options; } + $pos = index( $valid_list, $option ); + if ( $pos < $[ + && $quiet_mode ) + { + $errs++; + print STDERR "Invalid option: $option_sign$option \n"; + } + } + } # end foreach + return $errs; +} #end sub GetOpts + +sub GetOpts { + + # Gets options. If an option is valid, then opt_[option] is + # set to 0 or 1 as a side effect if the option is preceeded by + # a positive or negative sign. + # + # Usage: + # $rc = &GetOpts ( options, valid_options ) + # + # character: options - 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. + # character: valid_options - list of valid options (e.g. dfhx) + # integer: rc - return code + # = -1 if the arguement, options, is + # not recognized as a list of options. + # = 0 otherwise + + local ( $options, $valid_options ) = @_; + + if ( $options eq "+" || $options eq "-" ) { return -1 } + + local (@Options) = split( / */, $options ); + if ( $Options[$[] ne "-" && $Options[$[] ne "+" ) { return -1; } + + local ( $option, $option_sign ); + + foreach $option (@Options) { + + if ( $option eq "-" + || $option eq "+" ) + { + $option_sign = $option; + } + + else { + if ( index( $valid_options, $option ) >= $[ ) { + if ( $option_sign eq "-" ) { ${"opt_$option"} = 1; } + if ( $option_sign eq "+" ) { ${"opt_$option"} = 0; } + } + } + } # end foreach + + return 0; +} #end sub GetOpts + +sub SetOpt { + + # Sets option flags. For the last input option that is in a + # list, the flag opt_[option] is set to 1 as a side effect. + # For all other options in the list, opt_[option] is set to 0. + # + # Usage: + # $rc = &SetOpt ( options, valid_options ) + # + # character: options - 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. + # character: valid_options - list of valid options (e.g. def ) + # integer: rc - return code + # = -1 if the arguement, options, is + # not recognized as a list of options. + # = 0 otherwise + # Note: For the examples provided for the input arguments, + # $opt_d = 0, $opt_e = 0, and $opt_f = 1, since the + # input option, -f, was the last in the argument, + # option. + + local ( $options, $valid_options ) = @_; + + if ( $options eq "+" || $options eq "-" ) { return -1 } + + local (@Options) = split( / */, $options ); + local (@ValidOptions) = split( / */, $valid_options ); + if ( $Options[$[] ne "-" && $Options[$[] ne "+" ) { return -1; } + + local ( $option, $option_sign ); + + foreach $option (@Options) { + if ( $option ne "-" + && $option ne "+" ) + { + + if ( index( $valid_options, $option ) >= $[ ) { + foreach $valid_option (@ValidOptions) { + ${"opt_$valid_option"} = 0; + } + ${"opt_$option"} = 1; + } + } + } # end foreach + + return 0; +} #end sub SetOpt + +sub print_help { + print "Usage: protex [-hbACFS] [+-nlsxf] [src_file(s)]"; + print " "; + print " Options:"; + print " -h Help mode: list command line options"; + print " -b Bare mode, meaning no preamble, etc."; + print " -i internal mode: omit prologues marked !BOPI"; + print " -g Use GEOS style."; + print " +-n New Page for each subsection (wastes paper)"; + print " +-l Listing mode, default is prologues only"; + print " +-s Shut-up mode, i.e., ignore any code from BOC to EOC"; + print " +-x No LaTeX mode, i.e., put !DESCRIPTION: in verbatim mode"; + print " +-f No source file info"; + print " -A Ada code"; + print " -C C++ code"; + print " -F F90 code"; + print " -S Shell script"; + print " "; + print " The options can appear in any order. The options, -h and -b,"; + print " affect the input from all files listed on command-line input."; + print " Each of the remaining options effects only the input from the"; + print " files listed after the option and prior to any overriding"; + print " option. The plus sign turns off the option."; +} + +sub print_notice { + print "% **** IMPORTANT NOTICE *****"; + print "% This LaTeX file has been automatically produced by ProTeX v. 1.1"; + print "% Any changes made to this file will likely be lost next time"; + print "% this file is regenerated from its source. Send questions "; + print "% to Arlindo da Silva, dasilva\@gsfc.nasa.gov"; + print " "; +} # sub print_notice + +sub print_preamble { + unless ($opt_b) { + print "%------------------------ PREAMBLE --------------------------"; + print "\\documentclass[11pt]{article}"; + print "\\usepackage{amsmath}"; + print "\\usepackage{epsfig}"; + print "\\usepackage{graphicx}"; + print "\\usepackage{fancyhdr}"; + if ( $opt_E ) { + print "\\usepackage{hangcaption}"; + } else { + print "\\usepackage{caption}"; + } + # long tables for spec calls and resource items + print "\\usepackage{longtable}"; + + print "\\textheight 9in"; + print "\\topmargin 0pt"; + print "\\headsep 1cm"; + print "\\headheight 0pt"; + print "\\textwidth 6in"; + print "\\oddsidemargin 0in"; + print "\\evensidemargin 0in"; + print "\\marginparpush 0pt"; + print "\\pagestyle{myheadings}"; + print "\\markboth{}{}"; + + print "%-------------------------------------------------------------"; + } # end unless + + # 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 + + if ( $opt_E ) { + print "\\setlength{\\oldparskip}{\\parskip}"; + print "\\setlength{\\parskip}{1.5ex}"; + print "\\setlength{\\oldparindent}{\\parindent}"; + } + print "\\setlength{\\parindent}{0pt}"; + + if ( $opt_E ) { + print "\\setlength{\\oldbaselineskip}{\\baselineskip}"; + print "\\setlength{\\baselineskip}{11pt}"; + } + +} # end sub print_preamble + +sub print_macros { + + print " "; + print "%--------------------- SHORT-HAND MACROS ----------------------"; + print "\\def\\bv{\\begin{verbatim}}"; + print "\\def\\ev\{\\end\{verbatim}}"; + print "\\def\\be{\\begin{equation}}"; + print "\\def\\ee{\\end{equation}}"; + print "\\def\\bea{\\begin{eqnarray}}"; + print "\\def\\eea{\\end{eqnarray}}"; + print "\\def\\bi{\\begin{itemize}}"; + print "\\def\\ei{\\end{itemize}}"; + print "\\def\\bn{\\begin{enumerate}}"; + print "\\def\\en{\\end{enumerate}}"; + print "\\def\\bd{\\begin{description}}"; + print "\\def\\ed{\\end{description}}"; + print "\\def\\({\\left (}"; + print "\\def\\){\\right )}"; + print "\\def\\[{\\left [}"; + print "\\def\\]{\\right ]}"; + print "\\def\\<{\\left \\langle}"; + print "\\def\\>{\\right \\rangle}"; + print "\\def\\cI{{\\cal I}}"; + print "\\def\\diag{\\mathop{\\rm diag}}"; + print "\\def\\tr{\\mathop{\\rm tr}}"; + print "%-------------------------------------------------------------"; + +} # end sub print_macros + +sub do_beg { + unless ($opt_b) { + if ( $begdoc == 0 ) { + if ($tpage) { + print "\\title{@title}"; + print "\\author{{\\sc @author}\\\\ {\\em @affiliation}}"; + print "\\date{@date}"; + } + print "\\begin{document}"; + if ($tpage) { + print "\\maketitle"; + print "\\thispagestyle{fancy}"; + print "\\renewcommand{\\headrulewidth}{0pt}"; + } + print "\\tableofcontents"; + print "\\newpage"; + $begdoc = 1; + } + } +} # end sub do_beg + +sub do_eoc { + if ($verb) { + print "\\end{verbatim}"; + $verb = 0; + } + $source = 0; +} # end sub do_eoc + +sub set_missing { + $have_name = 0; # have routine name? + $have_desc = 0; # have description? + $have_intf = 0; # have interface? + $have_hist = 0; # have revision history? + $name_is = "UNKNOWN"; +} # end sub set_missing + +sub check_if_all_there { + $have_name + || die "ProTeX: invalid prologue, missing !ROUTINE: or !IROUTINE: in <$name_is>"; + + $have_desc + || die "ProTeX: invalid prologue, missing !DESCRIPTION: in <$name_is>"; + + $have_intf + || die "ProTeX: invalid prologue, missing !INTERFACE: in <$name_is>"; + + $have_hist + || die "ProTeX: invalid prologue, missing !REVISION HISTORY: in <$name_is>"; +} # end sub check_if_all_there + +sub hed_item { + printf "\n{ \\bf \\sf \n"; + printf "\\makebox[1.1 in][l]{Short Name } \n"; + printf "\\makebox[.9 in][l]{Units } \n"; + printf "\\makebox[.7 in][l]{Dims } \n"; + printf "\\makebox[.7 in][l]{Vert Loc } \n"; + printf "\\makebox[4. in][l]{Long Name } \n"; + printf "} \n \n"; +} + +sub beg_item { + if ($initem) { + + # short name + # if ($shname eq " "){ + # print "ERROR"; + # exit; + # } + if ($intv) { + print "\$\\overline{\\rm $shname}\$ \&"; + } + else { + print "$shname \&"; + } + + # type (IM/EX/IN) + if ( $imexin ne " " ) { print "$imexin \&"; } + + # units + if ( $units ne " " ) { print "$units \&"; } + else { print "\&"; } + + # dims + if ( $dims ne " " ) { + if ( $dims eq 'GEOS\_DIMSHORZONLY' ) { print "xy \&"; } + if ( $dims eq 'GEOS\_DIMSHORZVERT' ) { print "xyz \&"; } + if ( $dims eq 'GEOS\_DIMSVERTONLY' ) { print "z \&"; } + if ( $dims eq 'GEOS\_DIMSTILEONLY' ) { print "tile \&"; } + if ( $dims eq 'GEOS\_DIMSTILETILE' ) { print "TileTile \&"; } + if ( $dims eq 'GEOS\_DIMSCATCHONLY' ) { print "tile \&"; } + if ( $dims eq 'MAPL\_DIMSHORZONLY' ) { print "xy \&"; } + if ( $dims eq 'MAPL\_DIMSHORZVERT' ) { print "xyz \&"; } + if ( $dims eq 'MAPL\_DIMSVERTONLY' ) { print "z \&"; } + if ( $dims eq 'MAPL\_DIMSTILEONLY' ) { print "tile \&"; } + if ( $dims eq 'MAPL\_DIMSTILETILE' ) { print "TileTile \&"; } + if ( $dims eq 'MAPL\_DIMSCATCHONLY' ) { print "tile \&"; } + } + else { print "\&"; } + + # vlocation + if ( $locs ne " " ) { + if ( $locs eq 'GEOS\_VLOCATIONCENTER' ) { print "Center \&"; } + if ( $locs eq 'GEOS\_VLOCATIONEDGE' ) { print "Edge \&"; } + if ( $locs eq 'GEOS\_VLOCATIONNONE' ) { print "None \&"; } + if ( $locs eq 'MAPL\_VLOCATIONCENTER' ) { print "Center \&"; } + if ( $locs eq 'MAPL\_VLOCATIONEDGE' ) { print "Edge \&"; } + if ( $locs eq 'MAPL\_VLOCATIONNONE' ) { print "None \&"; } + } + else { print "\&"; } + + # # child id + # if($child ne " ") { + # printf "\\makebox[4 in][l]{Promoted from child %s}\\newline\n", $child; + # } + # else{print "\&";} + + # long name + if ( $lnname ne " " ) { + printf "$lnname \\\\"; + } + else { print "\\\\"; } + } + + $initem = 1; + $shname = " "; + $lnname = " "; + $units = " "; + $dims = " "; + $child = " "; + $locs = " "; + $imexin = " "; + $intv = 0; +} + +sub prc_units { + s/\+1//g; + s/([a-zA-Z])\+([1-9][0-9]*)/{\1}\$^{\2}\$/g; + s/\-([1-9][0-9]*)/\$^{-\1}\$/g; +} + +sub clean { + + # clean value + s/_/\\_/g; + s/\'//g; + s/\"//g; + s/,//g; + s/&//g; +} + +sub prc_item { + + # Attribute name is the first field + $name = uc( $Fld[1] ); + @value = @Fld; + shift(@value); + shift(@value); + + # units + $_ = join( ' ', @value ); + &clean(); + if ( $name eq "UNITS" ) { &prc_units(); } + if ( $name eq "UNITS" ) { $units = $_; } + + if ( $name ne "UNITS" ) { s/ //g; } + + # rest of the fields + $_ = $Fld[3]; + &clean(); + if ( $name eq "CHILD_ID" ) { $child = $_; } + if ( $name eq "SHORT_NAME" ) { $shname = $_; } #print $shname; print "shname";} + if ( $name eq "LONG_NAME" ) { s/\_/ /g; $lnname = $_; } + if ( $name eq "DIMS" ) { $dims = uc($_); } + if ( $name eq "VLOCATION" ) { $locs = uc($_); } + if ( $name eq "AVERAGING_INTERVAL" ) { $intv = 1; } +} + +sub prnt_rsrcs { + + # name + if ( $rsrc_name ne " " ) { print "$rsrc_name \&"; } + else { + print "no name!"; + exit 0; + } + + # description + if ( $description ne " " ) { print "$description \&"; } + else { print "\&"; } + + # unit + if ( $unit ne " " ) { print "$unit \&"; } + else { print "\&"; } + + # default + if ( $default ne " " ) { print "$default \\\\"; } + else { print "\\\\"; } + + $rsrc_name = " "; + $description = " "; + $unit = " "; + $default = " "; +} + +sub prc_rsrcs_1 { + $unit = " "; + $description = " "; + + @value = @Fld; + if ( $value[2] eq "!RESOURCE_ITEM:" ) { shift(@value); } + + $_ = join( ' ', @value ); + @value = split( ':', $_ ); + + $_ = $value[2]; + &prc_units(); + $unit = $_; + + $description = $value[4]; + $description =~ s/^\s+//; # ltrim + $description =~ s/\s+$//; # rtrim +} + +sub prc_rsrcs_2 { + $rsrc_name = " "; + $default = " "; + + # get rsrc name and its default value + $_ = split( ',', $_ ); + + # trim $_[3] + $_[3] =~ s/^\s+//; # ltrim + $_[3] =~ s/\s+$//; # rtrim + if ( lc substr( $_[3], 1, 5 ) eq "label" ) { + @namesplt = split( '=', $_[3] ); + $rsrc_name = $namesplt[2]; + } + else { $rsrc_name = $_[3]; } + + # replace _ by \_ + $rsrc_name =~ s/_/\\_/g; + + if ( $_[4] ) { + @defsplt = split( '=', $_[4] ); + $defsplt[1] =~ s/^\s+//; # ltrim + $defsplt[1] =~ s/\s+$//; # rtrim + if ( $defsplt[1] eq "default" ) { $default = $defsplt[2]; } + } + + # replace _ by \_ + $default =~ s/_/\\_/g; +} + +sub prc_resource1 { + @value = @Fld; + shift(@value); + shift(@value); + $_ = join( ' ', @value ); + + @value = split( ':', $_ ); + + $_ = $value[1]; + &prc_units(); + $units = $_; + $comment = $value[3]; + + $in_resource = 1; +} + +sub prc_resource2 { + @Tmp = split( '=', $Fld[3] ); + $_ = $Tmp[$#Tmp]; + s/\'//g; + s/\"//g; + s/ //g; + s/_/\\_/g; + $name = $_; + + $default = "none"; + if ( $#Fld >= 4 ) { + @Tmp = split( '=', $Fld[4] ); + if ( uc( $Tmp[1] ) ne "RC" ) { + $_ = $Tmp[$#Tmp]; + s/ //g; + s/_/\\_/g; + $default = $_; + } + } + printf "\\makebox[1.0 in][l]{\\bf %s } \n", $name; + printf "\\makebox[3.5 in][l]{\\bf %s } \n", $comment; + printf "\\makebox[1.0 in][l]{\\bf %s } \n", $units; + printf "\\makebox[1.0 in][l]{\\bf %s } \n", $default; + printf "\\newline \n"; + + $in_resource = 0; +} From ab8306812c3699acded50f9cb8d4961b0efff4fb Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 4 Mar 2022 12:13:01 -0500 Subject: [PATCH 2/6] Update to latest version of UseLATEX --- latex/{UseLatex.cmake => UseLATEX.cmake} | 718 +++++++++++++++++++---- latex/esma_latex.cmake | 10 +- 2 files changed, 612 insertions(+), 116 deletions(-) rename latex/{UseLatex.cmake => UseLATEX.cmake} (68%) diff --git a/latex/UseLatex.cmake b/latex/UseLATEX.cmake similarity index 68% rename from latex/UseLatex.cmake rename to latex/UseLATEX.cmake index 1df4baf0..85d32e8b 100644 --- a/latex/UseLatex.cmake +++ b/latex/UseLATEX.cmake @@ -1,6 +1,6 @@ # File: UseLATEX.cmake # CMAKE commands to actually use the LaTeX compiler -# Version: 2.3.0 +# Version: 2.7.2 # Author: Kenneth Moreland # # Copyright 2004, 2015 Sandia Corporation. @@ -42,17 +42,18 @@ # add_latex_document( # [BIBFILES ] # [INPUTS ] -# [IMAGE_DIRS] -# [IMAGES] -# [CONFIGURE] -# [DEPENDS] -# [MULTIBIB_NEWCITES] +# [IMAGE_DIRS ] +# [IMAGES ] +# [CONFIGURE ] +# [DEPENDS ] +# [MULTIBIB_NEWCITES ] # [USE_BIBLATEX] # [USE_INDEX] # [INDEX_NAMES ] # [USE_GLOSSARY] [USE_NOMENCL] # [FORCE_PDF] [FORCE_DVI] [FORCE_HTML] -# [TARGET_NAME] +# [TARGET_NAME ] +# [INCLUDE_DIRECTORIES ] # [EXCLUDE_FROM_ALL] # [EXCLUDE_FROM_DEFAULTS]) # Adds targets that compile . The latex output is placed @@ -61,15 +62,15 @@ # so all input files are copied from the source directory to the # output directory. This includes the target tex file, any tex file # listed with the INPUTS option, the bibliography files listed with -# the BIBFILES option, and any .cls, .bst, and .clo files found in -# the current source directory. Images found in the IMAGE_DIRS -# directories or listed by IMAGES are also copied to the output -# directory and converted to an appropriate format if necessary. Any -# tex files also listed with the CONFIGURE option are also processed -# with the CMake CONFIGURE_FILE command (with the @ONLY flag). Any -# file listed in CONFIGURE but not the target tex file or listed with -# INPUTS has no effect. DEPENDS can be used to specify generated files -# that are needed to compile the latex target. +# the BIBFILES option, and any .cls, .bst, .clo, .sty, .ist, and .fd +# files found in the current source directory. Images found in the +# IMAGE_DIRS directories or listed by IMAGES are also copied to the +# output directory and converted to an appropriate format if necessary. +# Any tex files also listed with the CONFIGURE option are also processed +# with the CMake CONFIGURE_FILE command (with the @ONLY flag). Any file +# listed in CONFIGURE but not the target tex file or listed with INPUTS +# has no effect. DEPENDS can be used to specify generated files that are +# needed to compile the latex target. # # The following targets are made. The name prefix is based off of the # base name of the tex file unless TARGET_NAME is specified. If @@ -113,8 +114,105 @@ # support the extra auxiliary files created with the \newcite command # in the multibib package. # +# INCLUDE_DIRECTORIES provides a list of directories in which LaTeX +# should look for input files. It accepts both files relative to the +# binary directory and absolute paths. +# # History: # +# 2.7.2 Add CONFIGURE_DEPENDS option when globbing files to better detect +# when files in a directory change. This only happens for CMake 3.12 +# or better. +# +# 2.7.1 Fix issues with printing log on errors when there are spaces in the +# path. (Thanks to Peter Knowles.) +# +# Ignore LaTeX warning about the font shape series value `mc'. +# +# 2.7.0 Add INCLUDE_DIRECTORIES parameters. (Thanks to Eric Dönges.) +# +# 2.6.1 Fix issue with detecting long undefined reference warnings that +# LaTeX "helpfully" split across lines (and which fowled up our +# regex). +# +# 2.6.0 Skip image conversion targets that are not used when a force option +# is given. This helps prevent errors for missing conversion programs +# that are not needed. (Thanks to Martin Wetzel.) +# +# 2.5.0 Parse biber output for warnings. +# +# For regular bibtex, you get warnings about undefined references +# when you run latex. However, when using biber, biber itself prints +# out the said warning and latex sees nothing. Thus, when using biber +# the regular output is now suppressed and the log file is scanned +# for potential issues. +# +# 2.4.9 Use biblatex.cfg file if it exists and the USE_BIBLATEX option is ON. +# +# 2.4.8 Fix synctex issue with absolute paths not being converted. +# +# 2.4.7 Fix some issues with spaces in the path of the working directory where +# LaTeX is executed. +# +# 2.4.6 Fix parse issue with older versions of CMake. +# +# 2.4.5 Fix issues with files and paths containing spaces. +# +# 2.4.4 Improve error reporting message when LaTeX fails. +# +# When LaTeX fails, delete the output file, which is invalid. +# +# Add warnings for "missing characters." These usually mean that a +# non-ASCII character is in the document and will not be printed +# correctly. +# +# 2.4.3 Check for warnings from the natbib package. When using natbib, +# warnings for missing bibliography references look different. So +# far, natbib seems to be quiet unless something is important, so +# look for all natbib warnings. (We can change this later if +# necessary.) +# +# 2.4.2 Fix an issue where new versions of ImageMagick expect the order of +# options in command line execution of magick/convert. (See, for +# example, http://www.imagemagick.org/Usage/basics/#why.) +# +# 2.4.1 Add ability to dump LaTeX log file when using batch mode. Batch +# mode suppresses most output, often including error messages. To +# make sure critical error messages get displayed, show the full log +# on failures. +# +# 2.4.0 Remove "-r 600" from the default PDFTOPS_CONVERTER_FLAGS. The -r flag +# is available from the Poppler version of pdftops, but not the Xpdf +# version. +# +# Fix an issue with the flags for the different programs not being +# properly separated. +# +# Fix an issue on windows where the = character is not allowed for +# ps2pdf arguments. +# +# Change default arguments for latex and pdflatex commands. Makes the +# output more quiet and prints out the file/line where errors occur. +# (Thanks to Nikos Koukis.) +# +# After a LaTeX build, check the log file for warnings that are +# indicative of problems with the build. +# +# Remove support for latex2html. Instead, use the htlatex program. +# This is now part of TeX Live and most other distributions. It also +# behaves much more like the other LaTeX programs. Also fixed some +# nasty issues with the htlatex arguments. +# +# 2.3.2 Declare LaTeX input files as sources for targets so that they show +# up in IDEs like QtCreator. +# +# Fix issue where main tex files in subdirectories were creating +# invalid targets for building HTML. Just disable the HTML targets in +# this case. +# +# 2.3.1 Support use of magick command instead of convert command for +# ImageMagick 7. +# # 2.3.0 Add USE_BIBLATEX option to support the biblatex package, which # requires using the program biber as a replacement for bibtex # (thanks to David Tracey). @@ -364,6 +462,68 @@ endfunction(latex_get_filename_component) ############################################################################# # Functions that perform processing during a LaTeX build. ############################################################################# +function(latex_execute_latex) + if(NOT LATEX_WORKING_DIRECTORY) + message(SEND_ERROR "Need to define LATEX_WORKING_DIRECTORY") + endif() + + if(NOT LATEX_FULL_COMMAND) + message(SEND_ERROR "Need to define LATEX_FULL_COMMAND") + endif() + + if(NOT LATEX_OUTPUT_FILE) + message(SEND_ERROR "Need to define LATEX_OUTPUT_FILE") + endif() + + if(NOT LATEX_LOG_FILE) + message(SEND_ERROR "Need to define LATEX_LOG_FILE") + endif() + + set(full_command_original "${LATEX_FULL_COMMAND}") + + # Chose the native method for parsing command arguments. Newer versions of + # CMake allow you to just use NATIVE_COMMAND. + if (CMAKE_VERSION VERSION_GREATER 3.8) + set(separate_arguments_mode NATIVE_COMMAND) + else() + if (WIN32) + set(separate_arguments_mode WINDOWS_COMMAND) + else() + set(separate_arguments_mode UNIX_COMMAND) + endif() + endif() + + # Preps variables for use in execute_process. + # Even though we expect LATEX_WORKING_DIRECTORY to have a single "argument," + # we also want to make sure that we strip out any escape characters that can + # foul up the WORKING_DIRECTORY argument. + separate_arguments(LATEX_FULL_COMMAND UNIX_COMMAND "${LATEX_FULL_COMMAND}") + separate_arguments(LATEX_WORKING_DIRECTORY_SEP UNIX_COMMAND "${LATEX_WORKING_DIRECTORY}") + + execute_process( + COMMAND ${LATEX_FULL_COMMAND} + WORKING_DIRECTORY "${LATEX_WORKING_DIRECTORY_SEP}" + RESULT_VARIABLE execute_result + OUTPUT_VARIABLE ignore + ERROR_VARIABLE ignore + ) + + if(NOT ${execute_result} EQUAL 0) + # LaTeX tends to write a file when a failure happens. Delete that file so + # that LaTeX will run again. + separate_arguments(LATEX_OUTPUT_FILE_SEP UNIX_COMMAND "${LATEX_OUTPUT_FILE}") + file(REMOVE "${LATEX_WORKING_DIRECTORY_SEP}/${LATEX_OUTPUT_FILE_SEP}") + + message("\n\nLaTeX command failed") + message("${full_command_original}") + message("Log output:") + separate_arguments(LATEX_LOG_FILE_SEP UNIX_COMMAND "${LATEX_LOG_FILE}") + file(READ "${LATEX_WORKING_DIRECTORY_SEP}/${LATEX_LOG_FILE_SEP}" log_output) + message("${log_output}") + message(FATAL_ERROR "Executed LaTeX, but LaTeX returned an error.") + endif() +endfunction(latex_execute_latex) + function(latex_makeglossaries) # This is really a bare bones port of the makeglossaries perl script into # CMake scripting. @@ -482,10 +642,10 @@ function(latex_makeglossaries) set(codepage_flags "") endif() - message("${XINDY_COMPILER} ${MAKEGLOSSARIES_COMPILER_FLAGS} ${language_flags} ${codepage_flags} -I xindy -M ${glossary_name} -t ${glossary_log} -o ${glossary_out} ${glossary_in}" + message("${XINDY_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} ${codepage_flags} -I xindy -M ${glossary_name} -t ${glossary_log} -o ${glossary_out} ${glossary_in}" ) exec_program(${XINDY_COMPILER} - ARGS ${MAKEGLOSSARIES_COMPILER_FLAGS} + ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} ${codepage_flags} -I xindy @@ -504,7 +664,7 @@ function(latex_makeglossaries) if("${xindy_output}" MATCHES "^Cannot locate xindy module for language (.+) in codepage (.+)\\.$") message("*************** Retrying xindy with default codepage.") exec_program(${XINDY_COMPILER} - ARGS ${MAKEGLOSSARIES_COMPILER_FLAGS} + ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} -I xindy -M ${glossary_name} @@ -515,8 +675,8 @@ function(latex_makeglossaries) endif() else() - message("${MAKEINDEX_COMPILER} ${MAKEGLOSSARIES_COMPILER_FLAGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}") - exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKEGLOSSARIES_COMPILER_FLAGS} + message("${MAKEINDEX_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}") + exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in} ) endif() @@ -537,7 +697,7 @@ function(latex_makenomenclature) set(nomencl_out ${LATEX_TARGET}.nls) set(nomencl_in ${LATEX_TARGET}.nlo) - exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKENOMENCLATURE_COMPILER_FLAGS} + exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKENOMENCLATURE_COMPILER_ARGS} ${nomencl_in} -s "nomencl.ist" -o ${nomencl_out} ) endfunction(latex_makenomenclature) @@ -559,6 +719,8 @@ function(latex_correct_synctex) if(NOT LATEX_BINARY_DIRECTORY) message(SEND_ERROR "Need to define LATEX_BINARY_DIRECTORY") endif() + message("${LATEX_BINARY_DIRECTORY}") + message("${LATEX_SOURCE_DIRECTORY}") set(synctex_file ${LATEX_BINARY_DIRECTORY}/${LATEX_TARGET}.synctex) set(synctex_file_gz ${synctex_file}.gz) @@ -576,13 +738,24 @@ function(latex_correct_synctex) message("Reading synctex file.") file(READ ${synctex_file} synctex_data) - message("Replacing relative with absolute paths.") - string(REGEX REPLACE - "(Input:[0-9]+:)([^/\n][^\n]*)" - "\\1${LATEX_SOURCE_DIRECTORY}/\\2" - synctex_data - "${synctex_data}" - ) + message("Replacing output paths with input paths.") + foreach(extension tex cls bst clo sty ist fd) + # Relative paths + string(REGEX REPLACE + "(Input:[0-9]+:)([^/\n][^\n]\\.${extension}*)" + "\\1${LATEX_SOURCE_DIRECTORY}/\\2" + synctex_data + "${synctex_data}" + ) + + # Absolute paths + string(REGEX REPLACE + "(Input:[0-9]+:)${LATEX_BINARY_DIRECTORY}([^\n]*\\.${extension})" + "\\1${LATEX_SOURCE_DIRECTORY}\\2" + synctex_data + "${synctex_data}" + ) + endforeach(extension) message("Writing synctex file.") file(WRITE ${synctex_file} "${synctex_data}") @@ -600,6 +773,124 @@ function(latex_correct_synctex) endfunction(latex_correct_synctex) +function(latex_check_important_warnings) + # Check for biber warnings/errors if that was run + set(bib_log_file ${LATEX_TARGET}.blg) + if(EXISTS ${bib_log_file}) + file(READ ${bib_log_file} bib_log) + if(bib_log MATCHES "INFO - This is Biber") + message("\nChecking ${bib_log_file} for Biber warnings/errors.") + + string(REGEX MATCHALL + "[A-Z]+ - [^\n]*" + biber_messages + "${bib_log}") + + set(found_error) + foreach(message ${biber_messages}) + if(NOT message MATCHES "^INFO - ") + set(found_error TRUE) + message("${message}") + endif() + endforeach(message) + + if(found_error) + latex_get_filename_component(log_file_path ${bib_log_file} ABSOLUTE) + message("\nConsult ${log_file_path} for more information on Biber output.") + else() + message("No known important Biber output found.") + endif(found_error) + else() # Biber output not in log file + message("Skipping biber checks (biber not used)") + endif() + else() # No bib log file + message("Skipping bibliography checks (not run)") + endif() + + set(log_file ${LATEX_TARGET}.log) + + message("\nChecking ${log_file} for important warnings.") + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + if(NOT EXISTS ${log_file}) + message("Could not find log file: ${log_file}") + return() + endif() + + set(found_error) + + file(READ ${log_file} log) + + # Check for declared LaTeX warnings + string(REGEX MATCHALL + "\nLaTeX Warning:[^\n]*" + latex_warnings + "${log}") + # Ignore warnings considered harmless + list(FILTER latex_warnings EXCLUDE REGEX + "LaTeX Warning: Font shape declaration has incorrect series value `mc'." + ) + if(latex_warnings) + set(found_error TRUE) + message("\nFound declared LaTeX warnings.") + foreach(warning ${latex_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for natbib warnings + string(REGEX MATCHALL + "\nPackage natbib Warning:[^\n]*" + natbib_warnings + "${log}") + if(natbib_warnings) + set(found_error TRUE) + message("\nFound natbib package warnings.") + foreach(warning ${natbib_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for overfull + string(REGEX MATCHALL + "\nOverfull[^\n]*" + overfull_warnings + "${log}") + if(overfull_warnings) + set(found_error TRUE) + message("\nFound overfull warnings. These are indicative of layout errors.") + foreach(warning ${overfull_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for invalid characters + string(REGEX MATCHALL + "\nMissing character:[^\n]*" + invalid_character_warnings + "${log}") + if(invalid_character_warnings) + set(found_error TRUE) + message("\nFound invalid character warnings. These characters are likely not printed correctly.") + foreach(warning ${invalid_character_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + if(found_error) + latex_get_filename_component(log_file_path ${log_file} ABSOLUTE) + message("\nConsult ${log_file_path} for more information on LaTeX build.") + else() + message("No known important warnings found.") + endif(found_error) +endfunction(latex_check_important_warnings) + ############################################################################# # Helper functions for establishing LaTeX build. ############################################################################# @@ -635,6 +926,12 @@ function(latex_setup_variables) DOC "The pdf to ps converter program from the Poppler package." ) + find_program(HTLATEX_COMPILER + NAMES htlatex + PATHS ${MIKTEX_BINARY_PATH} + /usr/bin + ) + mark_as_advanced( LATEX_COMPILER PDFLATEX_COMPILER @@ -646,38 +943,31 @@ function(latex_setup_variables) PS2PDF_CONVERTER PDFTOPS_CONVERTER LATEX2HTML_CONVERTER + HTLATEX_COMPILER ) latex_needit(LATEX_COMPILER latex) latex_wantit(PDFLATEX_COMPILER pdflatex) + latex_wantit(HTLATEX_COMPILER htlatex) latex_needit(BIBTEX_COMPILER bibtex) latex_wantit(BIBER_COMPILER biber) latex_needit(MAKEINDEX_COMPILER makeindex) latex_wantit(DVIPS_CONVERTER dvips) latex_wantit(PS2PDF_CONVERTER ps2pdf) latex_wantit(PDFTOPS_CONVERTER pdftops) - # MiKTeX calls latex2html htlatex - if(NOT ${LATEX2HTML_CONVERTER}) - find_program(HTLATEX_CONVERTER - NAMES htlatex - PATHS ${MIKTEX_BINARY_PATH} - /usr/bin - ) - mark_as_advanced(HTLATEX_CONVERTER) - if(HTLATEX_CONVERTER) - set(USING_HTLATEX TRUE CACHE INTERNAL "True when using MiKTeX htlatex instead of latex2html" FORCE) - set(LATEX2HTML_CONVERTER ${HTLATEX_CONVERTER} - CACHE FILEPATH "htlatex taking the place of latex2html" FORCE) - else() - set(USING_HTLATEX FALSE CACHE INTERNAL "True when using MiKTeX htlatex instead of latex2html" FORCE) - endif() - endif() - latex_wantit(LATEX2HTML_CONVERTER latex2html) - set(LATEX_COMPILER_FLAGS "-interaction=nonstopmode" + set(LATEX_COMPILER_FLAGS "-interaction=batchmode -file-line-error" CACHE STRING "Flags passed to latex.") set(PDFLATEX_COMPILER_FLAGS ${LATEX_COMPILER_FLAGS} CACHE STRING "Flags passed to pdflatex.") + set(HTLATEX_COMPILER_TEX4HT_FLAGS "html" + CACHE STRING "Options for the tex4ht.sty and *.4ht style files.") + set(HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS "" + CACHE STRING "Options for the text4ht postprocessor.") + set(HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS "" + CACHE STRING "Options for the t4ht postprocessor.") + set(HTLATEX_COMPILER_LATEX_FLAGS ${LATEX_COMPILER_FLAGS} + CACHE STRING "Flags passed from htlatex to the LaTeX compiler.") set(LATEX_SYNCTEX_FLAGS "-synctex=1" CACHE STRING "latex/pdflatex flags used to create synctex file.") set(BIBTEX_COMPILER_FLAGS "" @@ -692,15 +982,26 @@ function(latex_setup_variables) CACHE STRING "Flags passed to makenomenclature.") set(DVIPS_CONVERTER_FLAGS "-Ppdf -G0 -t letter" CACHE STRING "Flags passed to dvips.") - set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct=100 -dCompatibilityLevel=1.3 -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -dMonoImageFilter=/FlateEncode" - CACHE STRING "Flags passed to ps2pdf.") - set(PDFTOPS_CONVERTER_FLAGS -r 600 + if(NOT WIN32) + set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct=100 -dCompatibilityLevel=1.3 -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -dMonoImageFilter=/FlateEncode" + CACHE STRING "Flags passed to ps2pdf.") + else() + # Most windows ports of ghostscript utilities use .bat files for ps2pdf + # commands. bat scripts interpret "=" as a special character and separate + # those arguments. To get around this, the ghostscript utilities also + # support using "#" in place of "=". + set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct#100 -dCompatibilityLevel#1.3 -dSubsetFonts#true -dEmbedAllFonts#true -dAutoFilterColorImages#false -dAutoFilterGrayImages#false -dColorImageFilter#/FlateEncode -dGrayImageFilter#/FlateEncode -dMonoImageFilter#/FlateEncode" + CACHE STRING "Flags passed to ps2pdf.") + endif() + set(PDFTOPS_CONVERTER_FLAGS "" CACHE STRING "Flags passed to pdftops.") - set(LATEX2HTML_CONVERTER_FLAGS "" - CACHE STRING "Flags passed to latex2html.") mark_as_advanced( LATEX_COMPILER_FLAGS PDFLATEX_COMPILER_FLAGS + HTLATEX_COMPILER_TEX4HT_FLAGS + HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS + HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS + HTLATEX_COMPILER_LATEX_FLAGS LATEX_SYNCTEX_FLAGS BIBTEX_COMPILER_FLAGS BIBER_COMPILER_FLAGS @@ -710,10 +1011,17 @@ function(latex_setup_variables) DVIPS_CONVERTER_FLAGS PS2PDF_CONVERTER_FLAGS PDFTOPS_CONVERTER_FLAGS - LATEX2HTML_CONVERTER_FLAGS ) + + # Because it is easier to type, the flags variables are entered as + # space-separated strings much like you would in a shell. However, when + # using a CMake command to execute a program, it works better to hold the + # arguments in semicolon-separated lists (otherwise the whole string will + # be interpreted as a single argument). Use the separate_arguments to + # convert the space-separated strings to semicolon-separated lists. separate_arguments(LATEX_COMPILER_FLAGS) separate_arguments(PDFLATEX_COMPILER_FLAGS) + separate_arguments(HTLATEX_COMPILER_LATEX_FLAGS) separate_arguments(LATEX_SYNCTEX_FLAGS) separate_arguments(BIBTEX_COMPILER_FLAGS) separate_arguments(BIBER_COMPILER_FLAGS) @@ -723,9 +1031,27 @@ function(latex_setup_variables) separate_arguments(DVIPS_CONVERTER_FLAGS) separate_arguments(PS2PDF_CONVERTER_FLAGS) separate_arguments(PDFTOPS_CONVERTER_FLAGS) - separate_arguments(LATEX2HTML_CONVERTER_FLAGS) - find_program(IMAGEMAGICK_CONVERT convert + # Not quite done. When you call separate_arguments on a cache variable, + # the result is written to a local variable. That local variable goes + # away when this function returns (which is before any of them are used). + # So, copy these variables with local scope to cache variables with + # global scope. + set(LATEX_COMPILER_ARGS "${LATEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(PDFLATEX_COMPILER_ARGS "${PDFLATEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(HTLATEX_COMPILER_ARGS "${HTLATEX_COMPILER_LATEX_FLAGS}" CACHE INTERNAL "") + set(LATEX_SYNCTEX_ARGS "${LATEX_SYNCTEX_FLAGS}" CACHE INTERNAL "") + set(BIBTEX_COMPILER_ARGS "${BIBTEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(BIBER_COMPILER_ARGS "${BIBER_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKEINDEX_COMPILER_ARGS "${MAKEINDEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKEGLOSSARIES_COMPILER_ARGS "${MAKEGLOSSARIES_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKENOMENCLATURE_COMPILER_ARGS "${MAKENOMENCLATURE_COMPILER_FLAGS}" CACHE INTERNAL "") + set(DVIPS_CONVERTER_ARGS "${DVIPS_CONVERTER_FLAGS}" CACHE INTERNAL "") + set(PS2PDF_CONVERTER_ARGS "${PS2PDF_CONVERTER_FLAGS}" CACHE INTERNAL "") + set(PDFTOPS_CONVERTER_ARGS "${PDFTOPS_CONVERTER_FLAGS}" CACHE INTERNAL "") + + find_program(IMAGEMAGICK_CONVERT + NAMES magick convert DOC "The convert program that comes with ImageMagick (available at http://www.imagemagick.org)." ) mark_as_advanced(IMAGEMAGICK_CONVERT) @@ -864,7 +1190,7 @@ function(latex_add_convert_command if(PS2PDF_CONVERTER) set(require_imagemagick_convert FALSE) set(converter ${PS2PDF_CONVERTER}) - set(convert_flags -dEPSCrop ${PS2PDF_CONVERTER_FLAGS}) + set(convert_flags -dEPSCrop ${PS2PDF_CONVERTER_ARGS}) else() message(SEND_ERROR "Using postscript files with pdflatex requires ps2pdf for conversion.") endif() @@ -875,7 +1201,7 @@ function(latex_add_convert_command if(PDFTOPS_CONVERTER) set(require_imagemagick_convert FALSE) set(converter ${PDFTOPS_CONVERTER}) - set(convert_flags -eps ${PDFTOPS_CONVERTER_FLAGS}) + set(convert_flags -eps ${PDFTOPS_CONVERTER_ARGS}) else() message(STATUS "Consider getting pdftops from Poppler to convert PDF images to EPS images.") set(convert_flags ${flags}) @@ -888,20 +1214,27 @@ function(latex_add_convert_command if(IMAGEMAGICK_CONVERT) string(TOLOWER ${IMAGEMAGICK_CONVERT} IMAGEMAGICK_CONVERT_LOWERCASE) if(${IMAGEMAGICK_CONVERT_LOWERCASE} MATCHES "system32[/\\\\]convert\\.exe") - message(SEND_ERROR "IMAGEMAGICK_CONVERT set to Window's convert.exe for changing file systems rather than ImageMagick's convert for changing image formats. Please make sure ImageMagick is installed (available at http://www.imagemagick.org) and its convert program is used for IMAGEMAGICK_CONVERT. (It is helpful if ImageMagick's path is before the Windows system paths.)") + message(SEND_ERROR "IMAGEMAGICK_CONVERT set to Window's convert.exe for changing file systems rather than ImageMagick's convert for changing image formats. Please make sure ImageMagick is installed (available at http://www.imagemagick.org). If you have a recent version of ImageMagick (7.0 or higher), use the magick program instead of convert for IMAGEMAGICK_CONVERT.") else() set(converter ${IMAGEMAGICK_CONVERT}) + # ImageMagick requires a special order of arguments where resize and + # arguments of that nature must be placed after the input image path. + add_custom_command(OUTPUT ${output_path} + COMMAND ${converter} + ARGS ${input_path} ${convert_flags} ${output_path} + DEPENDS ${input_path} + ) endif() else() message(SEND_ERROR "Could not find convert program. Please download ImageMagick from http://www.imagemagick.org and install.") endif() + else() # Not ImageMagick convert + add_custom_command(OUTPUT ${output_path} + COMMAND ${converter} + ARGS ${convert_flags} ${input_path} ${output_path} + DEPENDS ${input_path} + ) endif() - - add_custom_command(OUTPUT ${output_path} - COMMAND ${converter} - ARGS ${convert_flags} ${input_path} ${output_path} - DEPENDS ${input_path} - ) endfunction(latex_add_convert_command) # Makes custom commands to convert a file to a particular type. @@ -921,10 +1254,15 @@ function(latex_convert_image # Check input filename for potential problems with LaTeX. latex_get_filename_component(name "${input_file}" NAME_WE) - if(name MATCHES ".*\\..*") - string(REPLACE "." "-" suggested_name "${name}") - set(suggested_name "${suggested_name}${extension}") - message(WARNING "Some LaTeX distributions have problems with image file names with multiple extensions. Consider changing ${name}${extension} to something like ${suggested_name}.") + set(suggested_name "${name}") + if(suggested_name MATCHES ".*\\..*") + string(REPLACE "." "-" suggested_name "${suggested_name}") + endif() + if(suggested_name MATCHES ".* .*") + string(REPLACE " " "-" suggested_name "${suggested_name}") + endif() + if(NOT suggested_name STREQUAL name) + message(WARNING "Some LaTeX distributions have problems with image file names with multiple extensions or spaces. Consider changing ${name}${extension} to something like ${suggested_name}${extension}.") endif() string(REGEX REPLACE "\\.[^.]*\$" ${output_extension} output_file @@ -995,19 +1333,23 @@ function(latex_process_images dvi_outputs_var pdf_outputs_var) make_directory("${path}") # Do conversions for dvi. - latex_convert_image(output_files "${file}" .eps "${convert_flags}" - "${LATEX_DVI_IMAGE_EXTENSIONS}" "${ARGN}") - list(APPEND dvi_outputs ${output_files}) + if(NOT LATEX_FORCE_PDF) + latex_convert_image(output_files "${file}" .eps "${convert_flags}" + "${LATEX_DVI_IMAGE_EXTENSIONS}" "${ARGN}") + list(APPEND dvi_outputs ${output_files}) + endif () # Do conversions for pdf. - if(is_raster) - latex_convert_image(output_files "${file}" .png "${convert_flags}" - "${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}") - list(APPEND pdf_outputs ${output_files}) - else() - latex_convert_image(output_files "${file}" .pdf "${convert_flags}" - "${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}") - list(APPEND pdf_outputs ${output_files}) + if(NOT LATEX_FORCE_DVI AND NOT LATEX_FORCE_HTML) + if(is_raster) + latex_convert_image(output_files "${file}" .png "${convert_flags}" + "${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}") + list(APPEND pdf_outputs ${output_files}) + else() + latex_convert_image(output_files "${file}" .pdf "${convert_flags}" + "${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}") + list(APPEND pdf_outputs ${output_files}) + endif() endif() else() message(WARNING "Could not find file ${CMAKE_CURRENT_SOURCE_DIR}/${file}. Are you sure you gave relative paths to IMAGES?") @@ -1019,7 +1361,11 @@ function(latex_process_images dvi_outputs_var pdf_outputs_var) endfunction(latex_process_images) function(latex_copy_globbed_files pattern dest) - file(GLOB file_list ${pattern}) + if(${CMAKE_VERSION} VERSION_LESS "3.12") + file(GLOB file_list ${pattern}) + else() + file(GLOB file_list CONFIGURE_DEPENDS ${pattern}) + endif() foreach(in_file ${file_list}) latex_get_filename_component(out_file ${in_file} NAME) configure_file(${in_file} ${dest}/${out_file} COPYONLY) @@ -1105,6 +1451,7 @@ function(parse_add_latex_arguments command latex_main_input) CONFIGURE DEPENDS INDEX_NAMES + INCLUDE_DIRECTORIES ) cmake_parse_arguments( LATEX "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -1145,24 +1492,82 @@ function(parse_add_latex_arguments command latex_main_input) endfunction(parse_add_latex_arguments) function(add_latex_targets_internal) + latex_get_output_path(output_dir) + if(LATEX_USE_SYNCTEX) - set(synctex_flags ${LATEX_SYNCTEX_FLAGS}) + set(synctex_flags ${LATEX_SYNCTEX_ARGS}) else() set(synctex_flags) endif() # The commands to run LaTeX. They are repeated multiple times. set(latex_build_command - ${LATEX_COMPILER} ${LATEX_COMPILER_FLAGS} ${synctex_flags} ${LATEX_MAIN_INPUT} + ${LATEX_COMPILER} ${LATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT} ) + if(LATEX_COMPILER_ARGS MATCHES ".*batchmode.*") + # Wrap command in script that dumps the log file on error. This makes sure + # errors can be seen. + set(latex_build_command + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=execute_latex + -D LATEX_WORKING_DIRECTORY="${output_dir}" + -D LATEX_FULL_COMMAND="${latex_build_command}" + -D LATEX_OUTPUT_FILE="${LATEX_TARGET}.dvi" + -D LATEX_LOG_FILE="${LATEX_TARGET}.log" + -P "${LATEX_USE_LATEX_LOCATION}" + ) + endif() set(pdflatex_build_command - ${PDFLATEX_COMPILER} ${PDFLATEX_COMPILER_FLAGS} -jobname=${LATEX_TARGET_NAME} ${synctex_flags} ${LATEX_MAIN_INPUT} + ${PDFLATEX_COMPILER} ${PDFLATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT} ) + if(PDFLATEX_COMPILER_ARGS MATCHES ".*batchmode.*") + # Wrap command in script that dumps the log file on error. This makes sure + # errors can be seen. + set(pdflatex_build_command + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=execute_latex + -D LATEX_WORKING_DIRECTORY="${output_dir}" + -D LATEX_FULL_COMMAND="${pdflatex_build_command}" + -D LATEX_OUTPUT_FILE="${LATEX_TARGET}.pdf" + -D LATEX_LOG_FILE="${LATEX_TARGET}.log" + -P "${LATEX_USE_LATEX_LOCATION}" + ) + endif() + + if(LATEX_INCLUDE_DIRECTORIES) + # The include directories needs to start with the build directory so + # that the copied files can be found. It also needs to end with an + # empty directory so that the standard system directories are included + # after any specified. + set(LATEX_INCLUDE_DIRECTORIES . ${LATEX_INCLUDE_DIRECTORIES} "") + + # CMake separates items in a list with a semicolon. Lists of + # directories on most systems are separated by colons, so we can do a + # simple text replace. On Windows, directories are separated by + # semicolons, but we replace them with the $ generator + # expression to make sure CMake treats it as a single string. + if(CMAKE_HOST_WIN32) + string(REPLACE ";" "$" TEXINPUTS "${LATEX_INCLUDE_DIRECTORIES}") + else() + string(REPLACE ";" ":" TEXINPUTS "${LATEX_INCLUDE_DIRECTORIES}") + endif() + + # Set the TEXINPUTS environment variable + set(latex_build_command + ${CMAKE_COMMAND} -E env TEXINPUTS=${TEXINPUTS} ${latex_build_command}) + set(pdflatex_build_command + ${CMAKE_COMMAND} -E env TEXINPUTS=${TEXINPUTS} ${pdflatex_build_command}) + endif() if(NOT LATEX_TARGET_NAME) - set(LATEX_TARGET_NAME ${LATEX_TARGET}) + # Use the main filename (minus the .tex) as the target name. Remove any + # spaces since CMake cannot have spaces in its target names. + string(REPLACE " " "_" LATEX_TARGET_NAME ${LATEX_TARGET}) endif() + # Some LaTeX commands may need to be modified (or may not work) if the main + # tex file is in a subdirectory. Make a flag for that. + get_filename_component(LATEX_MAIN_INPUT_SUBDIR ${LATEX_MAIN_INPUT} DIRECTORY) # Set up target names. set(dvi_target ${LATEX_TARGET_NAME}_dvi) @@ -1207,7 +1612,13 @@ function(add_latex_targets_internal) message(WARNING "Image directory ${CMAKE_CURRENT_SOURCE_DIR}/${dir} does not exist. Are you sure you gave relative directories to IMAGE_DIRS?") endif() foreach(extension ${LATEX_IMAGE_EXTENSIONS}) - file(GLOB files ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension}) + if(${CMAKE_VERSION} VERSION_LESS "3.12") + file(GLOB files ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension}) + else() + file(GLOB files CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension} + ) + endif() foreach(file ${files}) latex_get_filename_component(filename ${file} NAME) list(APPEND image_list ${dir}/${filename}) @@ -1242,6 +1653,8 @@ function(add_latex_targets_internal) endif() endforeach(input) + set(all_latex_sources ${LATEX_MAIN_INPUT} ${LATEX_INPUTS} ${image_list}) + if(LATEX_USE_GLOSSARY) foreach(dummy 0 1) # Repeat these commands twice. set(make_dvi_command ${make_dvi_command} @@ -1251,7 +1664,7 @@ function(add_latex_targets_internal) -D LATEX_TARGET=${LATEX_TARGET} -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} -D XINDY_COMPILER=${XINDY_COMPILER} - -D MAKEGLOSSARIES_COMPILER_FLAGS=${MAKEGLOSSARIES_COMPILER_FLAGS} + -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS} -P ${LATEX_USE_LATEX_LOCATION} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${latex_build_command} @@ -1263,7 +1676,7 @@ function(add_latex_targets_internal) -D LATEX_TARGET=${LATEX_TARGET} -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} -D XINDY_COMPILER=${XINDY_COMPILER} - -D MAKEGLOSSARIES_COMPILER_FLAGS=${MAKEGLOSSARIES_COMPILER_FLAGS} + -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS} -P ${LATEX_USE_LATEX_LOCATION} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${pdflatex_build_command} @@ -1279,7 +1692,7 @@ function(add_latex_targets_internal) -D LATEX_BUILD_COMMAND=makenomenclature -D LATEX_TARGET=${LATEX_TARGET} -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} - -D MAKENOMENCLATURE_COMPILER_FLAGS=${MAKENOMENCLATURE_COMPILER_FLAGS} + -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS} -P ${LATEX_USE_LATEX_LOCATION} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${latex_build_command} @@ -1290,7 +1703,7 @@ function(add_latex_targets_internal) -D LATEX_BUILD_COMMAND=makenomenclature -D LATEX_TARGET=${LATEX_TARGET} -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} - -D MAKENOMENCLATURE_COMPILER_FLAGS=${MAKENOMENCLATURE_COMPILER_FLAGS} + -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS} -P ${LATEX_USE_LATEX_LOCATION} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${pdflatex_build_command} @@ -1299,17 +1712,30 @@ function(add_latex_targets_internal) endif() if(LATEX_BIBFILES) + set(suppress_bib_output) if(LATEX_USE_BIBLATEX) if(NOT BIBER_COMPILER) - message(SEND_ERROR "I need the biber command.") + message(SEND_ERROR "I need the biber command.") endif() set(bib_compiler ${BIBER_COMPILER}) - set(bib_compiler_flags ${BIBER_COMPILER_FLAGS}) + set(bib_compiler_flags ${BIBER_COMPILER_ARGS}) + + if(NOT BIBER_COMPILER_ARGS MATCHES ".*-q.*") + # Only suppress bib output if the quiet option is not specified. + set(suppress_bib_output TRUE) + endif() + + if(LATEX_USE_BIBLATEX_CONFIG) + list(APPEND auxiliary_clean_files ${output_dir}/biblatex.cfg) + list(APPEND make_dvi_depends ${output_dir}/biblatex.cfg) + list(APPEND make_pdf_depends ${output_dir}/biblatex.cfg) + endif() else() set(bib_compiler ${BIBTEX_COMPILER}) - set(bib_compiler_flags ${BIBTEX_COMPILER_FLAGS}) + set(bib_compiler_flags ${BIBTEX_COMPILER_ARGS}) endif() if(LATEX_MULTIBIB_NEWCITES) + # Suppressed bib output currently not supported for multibib foreach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES}) latex_get_filename_component(multibib_target ${multibib_auxfile} NAME_WE) set(make_dvi_command ${make_dvi_command} @@ -1322,12 +1748,25 @@ function(add_latex_targets_internal) ${output_dir}/${multibib_target}.aux) endforeach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES}) else() + set(full_bib_command + ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET}) + if(suppress_bib_output) + set(full_bib_command + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=execute_latex + -D LATEX_WORKING_DIRECTORY="${output_dir}" + -D LATEX_FULL_COMMAND="${full_bib_command}" + -D LATEX_OUTPUT_FILE="${LATEX_TARGET}.bbl" + -D LATEX_LOG_FILE="${LATEX_TARGET}.blg" + -P "${LATEX_USE_LATEX_LOCATION}" + ) + endif() set(make_dvi_command ${make_dvi_command} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET}) + ${full_bib_command}) set(make_pdf_command ${make_pdf_command} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET}) + ${full_bib_command}) endif() foreach (bibfile ${LATEX_BIBFILES}) @@ -1351,12 +1790,12 @@ function(add_latex_targets_internal) COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${latex_build_command} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_FLAGS} ${idx_name}.idx) + ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx) set(make_pdf_command ${make_pdf_command} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} ${pdflatex_build_command} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_FLAGS} ${idx_name}.idx) + ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx) set(auxiliary_clean_files ${auxiliary_clean_files} ${output_dir}/${idx_name}.idx ${output_dir}/${idx_name}.ilg @@ -1414,6 +1853,22 @@ function(add_latex_targets_internal) ) endif() + # Check LaTeX output for important warnings at end of build + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=check_important_warnings + -D LATEX_TARGET=${LATEX_TARGET} + -P ${LATEX_USE_LATEX_LOCATION} + ) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=check_important_warnings + -D LATEX_TARGET=${LATEX_TARGET} + -P ${LATEX_USE_LATEX_LOCATION} + ) + # Capture the default build. string(TOLOWER "${LATEX_DEFAULT_BUILD}" default_build) @@ -1432,7 +1887,10 @@ function(add_latex_targets_internal) COMMAND ${make_pdf_command} DEPENDS ${make_pdf_depends} ) - add_custom_target(${pdf_target} DEPENDS ${output_dir}/${LATEX_TARGET}.pdf) + add_custom_target(${pdf_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.pdf + SOURCES ${all_latex_sources} + ) if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) add_dependencies(pdf ${pdf_target}) endif() @@ -1453,7 +1911,10 @@ function(add_latex_targets_internal) COMMAND ${make_dvi_command} DEPENDS ${make_dvi_depends} ) - add_custom_target(${dvi_target} DEPENDS ${output_dir}/${LATEX_TARGET}.dvi) + add_custom_target(${dvi_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.dvi + SOURCES ${all_latex_sources} + ) if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) add_dependencies(dvi ${dvi_target}) endif() @@ -1461,9 +1922,12 @@ function(add_latex_targets_internal) if(DVIPS_CONVERTER) add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.ps COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${DVIPS_CONVERTER} ${DVIPS_CONVERTER_FLAGS} -o ${LATEX_TARGET}.ps ${LATEX_TARGET}.dvi + ${DVIPS_CONVERTER} ${DVIPS_CONVERTER_ARGS} -o ${LATEX_TARGET}.ps ${LATEX_TARGET}.dvi DEPENDS ${output_dir}/${LATEX_TARGET}.dvi) - add_custom_target(${ps_target} DEPENDS ${output_dir}/${LATEX_TARGET}.ps) + add_custom_target(${ps_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.ps + SOURCES ${all_latex_sources} + ) if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) add_dependencies(ps ${ps_target}) endif() @@ -1473,7 +1937,7 @@ function(add_latex_targets_internal) # simply force a recompile every time. add_custom_target(${safepdf_target} ${CMAKE_COMMAND} -E chdir ${output_dir} - ${PS2PDF_CONVERTER} ${PS2PDF_CONVERTER_FLAGS} ${LATEX_TARGET}.ps ${LATEX_TARGET}.pdf + ${PS2PDF_CONVERTER} ${PS2PDF_CONVERTER_ARGS} ${LATEX_TARGET}.ps ${LATEX_TARGET}.pdf DEPENDS ${ps_target} ) if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) @@ -1488,19 +1952,36 @@ function(add_latex_targets_internal) set(default_build html) endif() - if(LATEX2HTML_CONVERTER) - if(USING_HTLATEX) - # htlatex places the output in a different location - set(HTML_OUTPUT "${output_dir}/${LATEX_TARGET}.html") - else() - set(HTML_OUTPUT "${output_dir}/${LATEX_TARGET}/${LATEX_TARGET}.html") - endif() + if(HTLATEX_COMPILER AND LATEX_MAIN_INPUT_SUBDIR) + message(STATUS + "Disabling HTML build for ${LATEX_TARGET_NAME}.tex because the main file is in subdirectory ${LATEX_MAIN_INPUT_SUBDIR}" + ) + # The code below to run HTML assumes that LATEX_TARGET.tex is in the + # current directory. I have tried to specify that LATEX_TARGET.tex is + # in a subdirectory. That makes the build targets correct, but the + # HTML build still fails (at least for htlatex) because files are not + # generated where expected. I am getting around the problem by simply + # disabling HTML in this case. If someone really cares, they can fix + # this, but make sure it runs on many platforms and build programs. + elseif(HTLATEX_COMPILER) + # htlatex places the output in a different location + set(HTML_OUTPUT "${output_dir}/${LATEX_TARGET}.html") add_custom_command(OUTPUT ${HTML_OUTPUT} COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} - ${LATEX2HTML_CONVERTER} ${LATEX2HTML_CONVERTER_FLAGS} ${LATEX_MAIN_INPUT} - DEPENDS ${output_dir}/${LATEX_TARGET}.tex + ${HTLATEX_COMPILER} ${LATEX_MAIN_INPUT} + "${HTLATEX_COMPILER_TEX4HT_FLAGS}" + "${HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS}" + "${HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS}" + ${HTLATEX_COMPILER_ARGS} + DEPENDS + ${output_dir}/${LATEX_TARGET}.tex + ${output_dir}/${LATEX_TARGET}.dvi + VERBATIM + ) + add_custom_target(${html_target} + DEPENDS ${HTML_OUTPUT} ${dvi_target} + SOURCES ${all_latex_sources} ) - add_custom_target(${html_target} DEPENDS ${HTML_OUTPUT} ${dvi_target}) if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) add_dependencies(html ${html_target}) endif() @@ -1555,6 +2036,11 @@ function(add_latex_document latex_main_input) latex_copy_input_file(${bib_file}) endforeach (bib_file) + if (LATEX_USE_BIBLATEX AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/biblatex.cfg) + latex_copy_input_file(biblatex.cfg) + set(LATEX_USE_BIBLATEX_CONFIG TRUE) + endif() + foreach (input ${LATEX_INPUTS}) latex_copy_input_file(${input}) endforeach(input) @@ -1577,6 +2063,11 @@ endfunction(add_latex_document) if(LATEX_BUILD_COMMAND) set(command_handled) + if("${LATEX_BUILD_COMMAND}" STREQUAL execute_latex) + latex_execute_latex() + set(command_handled TRUE) + endif() + if("${LATEX_BUILD_COMMAND}" STREQUAL makeglossaries) latex_makeglossaries() set(command_handled TRUE) @@ -1592,6 +2083,11 @@ if(LATEX_BUILD_COMMAND) set(command_handled TRUE) endif() + if("${LATEX_BUILD_COMMAND}" STREQUAL check_important_warnings) + latex_check_important_warnings() + set(command_handled TRUE) + endif() + if(NOT command_handled) message(SEND_ERROR "Unknown command: ${LATEX_BUILD_COMMAND}") endif() diff --git a/latex/esma_latex.cmake b/latex/esma_latex.cmake index e87af587..7f4e32dc 100644 --- a/latex/esma_latex.cmake +++ b/latex/esma_latex.cmake @@ -6,23 +6,23 @@ if (NOT ImageMagick_FOUND) endif () find_package(LATEX) -# These are all the bits of LaTeX that UseLatex needs. As it's confusing +# These are all the bits of LaTeX that UseLATEX needs. As it's confusing # how LATEX_FOUND from find_package(LATEX) is set, we test all the bits -# that UseLatex requires +# that UseLATEX requires # -# Also, UseLatex assumes ImageMagick is installed. While this is always +# Also, UseLATEX assumes ImageMagick is installed. While this is always # nice (and technically required to generate plots with GEOS plotting # utilities, it's not necessary to *build* if (LATEX_FOUND AND LATEX_PDFLATEX_FOUND AND LATEX_BIBTEX_FOUND AND LATEX_MAKEINDEX_FOUND AND ImageMagick_FOUND) # If they are all found, set LATEX_FOUND to TRUE... set (LATEX_FOUND TRUE) - # ...and then set up for protex and UseLatex + # ...and then set up for protex and UseLATEX include (UseProTeX) set (protex_flags -g -b -f) set (LATEX_COMPILER pdflatex) - include (UseLatex) + include (UseLATEX) else () set (LATEX_FOUND FALSE) endif () From 97e91c7244adbc6a75d3dcaac92f9b5fb2347619 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 4 Mar 2022 12:14:55 -0500 Subject: [PATCH 3/6] Update changelog and comment --- CHANGELOG.md | 3 +++ latex/esma_latex.cmake | 3 +++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0890c2fa..9eabf19f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed + +- Updated `UseLATEX` to version 2.7.2 + ### Fixed ### Removed ### Added diff --git a/latex/esma_latex.cmake b/latex/esma_latex.cmake index 7f4e32dc..383e6f26 100644 --- a/latex/esma_latex.cmake +++ b/latex/esma_latex.cmake @@ -6,6 +6,9 @@ if (NOT ImageMagick_FOUND) endif () find_package(LATEX) + +# UseLATEX is from https://gitlab.kitware.com/kmorel/UseLATEX + # These are all the bits of LaTeX that UseLATEX needs. As it's confusing # how LATEX_FOUND from find_package(LATEX) is set, we test all the bits # that UseLATEX requires From 7160ad1fb4f29877e772ac1f3d71f41b81ebe881 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 4 Mar 2022 12:42:48 -0500 Subject: [PATCH 4/6] Remove unneeded statuses --- latex/UseProTeX.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/latex/UseProTeX.cmake b/latex/UseProTeX.cmake index 80d2da17..a7033e38 100644 --- a/latex/UseProTeX.cmake +++ b/latex/UseProTeX.cmake @@ -1,3 +1,2 @@ -message(STATUS "In UseProTeX CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}") -message(STATUS "In UseProTeX ESMA_CMAKE_DIR: ${ESMA_CMAKE_DIR}") -set (protex_exe ${ESMA_CMAKE_DIR}/protex) +set (protex_exe ${CMAKE_CURRENT_LIST_DIR}/protex) +message(STATUS "Found protex: ${protex_exe}") From 5f043d9642da1d2b28ea640022a7383c99a6def5 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 20 Oct 2022 15:36:41 -0400 Subject: [PATCH 5/6] Fix changelog --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bb4d6ac..1fab96b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated `UseLATEX` to version 2.7.2 -- + ### Fixed ### Removed @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added check to `esma.cmake` to ensure `CMAKE_INSTALL_PREFIX` is writable +- Add `protex` script ## [3.18.0] - 2022-08-18 @@ -30,8 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated the CI to work with latest Baselibs - Updated the list of files ignored by CPack -- Add `protex` script - ## [3.17.0] - 2022-06-15 ### Changed From 8b3037822121182d13b04177a4100f60e4a1d722 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 20 Oct 2022 15:58:55 -0400 Subject: [PATCH 6/6] Update for newer Perl --- latex/protex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/latex/protex b/latex/protex index ca1c00b4..410fe847 100755 --- a/latex/protex +++ b/latex/protex @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # #BOP @@ -143,7 +143,7 @@ # Keep this if you don't know what it does... # ------------------------------------------- -$[ = 1; # set array base to 1 +use Array::Base (1); # set array base to 1 $, = ' '; # set output field separator $\ = "\n"; # set output record separator