#!/bin/awk -f ############################################################################# # Pre-processor engine for SASweave - creates a SAS input file # -- Also need to load a setup file with the following functions: # fileStart() put(text) beginText() endText() setupGraph() setupsgGraph() closeodsgraphics() # Changing these functions allows this engine to be used for both # tangling and weaving. # # Copyright (C) 2006 Russell V. Lenth - University of Iowa # Revised: 2007.06.01 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## ### Function to combine lines when the current one ends with "&" ### Results are stored in "combined" function combineLines() { combined = $0 while ((p = index(combined, "&")) > 0) { combined = substr(combined, 1, p-1) getline combined = combined $0 } } ### Function to find stuff in braces starting at position pos ### and save contents in a variable named contents. ### Set pos equal to desired starting position before calling function getBraces () { newpos = index(substr(combined,pos),"{") # firstleft bracket if (newpos > 0) { p = index(substr(combined, newpos+pos), "}") if (!p) { print "Warning in", infile ": Closing brace expected in line", NR contents = substr(combined, newpos+1) } else { contents = substr(combined, newpos+pos, p-1) } pos += newpos + p } else { contents = "" } } ### Function used to parse codefmt and outfmt function getfmt (optstg, eq1, rest) { eq1 = index(optstg, "=") rest = substr(optstg, eq1 + 1) # everything after 1st "=" gsub(";", ",", rest) return rest } ### Function to parse an option list and set up variables accordingly ### Call this with an array of "key=value" pairs function parseOptions(optlist) { for (i=1; i in optlist; i++) { split (optlist[i], opt, "=") split(opt[1], op, " ") option = op[1] # option name sans whitespace if (op[2] == "+") option = option "+" ### for codefmt += ... and outfmt += ... split(opt[2], op, " ") value = op[1] # option value sans whitespace if (option=="echo") echo = (value ~ /^T/ || value == "") if (option=="hide") hide = (value ~ /^T/ || value == "") if (option=="eval") eval = (value ~ /^T/ || value == "") if (option=="split") splitChunks = (value ~ /^T/ || value == "") if (option=="prefix.string") prefixStg = value if (option=="results") hide = (value == "hide") #~~ Deprecated fontsize options ~~~~~~~~~~~~~~~~~~~ if (option=="inputsize") codefmt = codefmt "," "fontsize=" value if (option=="outputsize") outfmt = outfmt "," "fontsize=" value #~~ Shorthand for font-size spec in codefmt and outfmt if (option=="codesize") codefmt = codefmt "," "fontsize=" value if (option=="outsize") outfmt = outfmt "," "fontsize=" value #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (option=="codefmt") codefmt = getfmt(optlist[i]) if (option=="outfmt") outfmt = getfmt(optlist[i]) if (option=="codefmt+") codefmt = codefmt "," getfmt(optlist[i]) if (option=="outfmt+") outfmt = outfmt "," getfmt(optlist[i]) if (option=="squeeze") squeeze = (value ~ /^T/ || value == "") if (option=="prompt") prompt = opt[2] # (preserve whitespace) if (option=="ls") { ls = value lschanged = 1 } if (option=="fig") { ### fig could be unspec, TRUE, FALSE, or a number fig = (value ~ /^T/ || value == "") if (value - 1 >= 0) fig = value # (get -1 if value is a string) } if (option=="sgfig") { ### sgfig could be unspec, TRUE, FALSE, or a number sgfig = (value ~ /^T/ || value == "") if (value - 1 >= 0) sgfig = value # (get -1 if value is a string) } if (option=="figdir") figdir = infigdir = value if (option=="infigdir") infigdir = value if (option=="width") width = value if (option=="hsize") hsize = value if (option=="vsize") vsize = value if (option=="striptitle") striptitle = (value ~ /^T/ || value == "") #~~ Added by KK to chop out poc title for ods graphics ~~~~~~ if (option=="odsstriptitle") odsstriptitle = (value ~ /^T/ || value == "") if (option=="plotname") plotname = value if (option=="label") label = chunklab = value if (option=="showref") showref = (value ~ /^T/ || value == "") } } ### Reset to default options. function resetOptions() { # First do system defaults... echo = 1 # echo input lines hide = 0 # hide output lines eval = 1 # evaluate included SAS code label = "lastchunk" # Label for code reuse splitChunks = 0 # Split weave output into different files prefixStg = base # root name of output file ### codesize = "\\small" # DEPRECATED - font size for input lines ### outsize = "\\small" # DEPRECATED - font size for output lines codefmt = "" outfmt = "" squeeze = 1 # Strip extra blank lines from output prompt = "SAS> " # prompt to display for SAS input lines ls = 80 # length of output lines (LS option in SAS) fig = 0 # Generate a figure sgfig = 0 # Generate an sg figure figdir = "." # directory to put a figure infigdir = "." # directory for included figures width = .6 # Width of figure as a multiplier of \linewidth hsize = 4; # size in inches for GOPTIONS stmt vsize = 4; striptitle = 1; # trim off top 30pt of plots odsstriptitle = 0 # added by kk to chop title of ods plots plotname = "" # macro to save a plot (instead of displaying it) showref = 0 # Include reused chunks in listing # Now process any defaults that have been specified parseOptions(defaults) # Set up default filename suffix for the next code chunk chunklab = sprintf("swv-%03d",chunkno+1) } ### Check for any options in current \begin{SAScode} statement function doOptions() { resetOptions() chunkno++ combineLines() pos = 10 getBraces() if (contents) { split(contents, optlist, ",") parseOptions(optlist) } if (!eval) hide=1 # always hide output when we don't evaluate the code! } ### Check IML status of the current SAS code and set IMLactive = 1 if ### IML is active at the end of the chunk function checkIMLstatus() { split(sascode, opt, "\n") for (i=1; i in opt; i++) { split(opt[i], op, " ") key = tolower(op[1]) if (key == "proc") IMLactive = (tolower(op[2]) == "iml" || tolower(op[2])=="iml;") if (key == "quit" || key == "quit;") IMLactive = 0 if (key == "data" || key == "data;") IMLactive = 0 #for testing: print IMLactive ": " opt[i] } } BEGIN { print "Creating .sas file ..." sas = 0 # flag for whether it is text or SAS code IMLactive = 0; infile = ARGV[1] hasSASpkg = 0 # flags for package loads in preamble dot = index(infile,".") base = substr(infile,1,dot-1) sasfile = base ".sas" ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" resetOptions() fileStart(); } /\\usepackage/ { if ($0 ~ /SasWeave}/) hasSASpkg = 1 else if ($0 ~ /Sweave}/) hasSpkg = 1 } /^\\SASweaveOpts{/ { combineLines() pos = 10 getBraces() if (defaultstg) defaultstg = defaultstg "," contents else defaultstg = contents split(defaultstg, defaults, ",") next } /^\\begin{SAScode}/ { doOptions() if (splitChunks && (echo || !hide)) { divertName = prefixStg "-" chunklab ".tex" put("\\input{" divertName "}") put("-----SASweaveDIVERT " divertName) put("%") } if (echo) { put("\\begin{SASinput}[" codefmt "]") } sascode = "" sas = 1 next } /^\\end{SAScode}/ { sas = 0 if (echo) { put("\\end{SASinput}") } if (!hide) { put("\\begin{SASoutput}[" outfmt "]") put("-----SASweaveSQUEEZE " squeeze) } endText(); if (fig) { setupGraph() } if (sgfig) { setupsgGraph() } if (eval) { print sascode >> sasfile checkIMLstatus() } if (label) savedchunks[label] = sascode beginText(); if (sgfig) { print "ods pdf close; ods graphics off;" >> sasfile } if (!hide) { put("\\end{SASoutput}") } if (eval) for (figidx=1; figidx<=fig; figidx++) { stmt = "\\includegraphics[width=" width "\\linewidth,viewport=" viewpt ",clip,page=" figidx "]{" upfn "}" if (plotname) { if (figidx<2) put("\\gdef" plotname "{" stmt "}") put("\\gdef" plotname substr(ABC,figidx,1) "{" stmt "}") } else put(stmt) } if (eval) for (figidx=1; figidx<=sgfig; figidx++) { stmt = "\\includegraphics[width=" width "\\linewidth,viewport=" viewpt ",clip,page=" figidx "]{" upfn "}" if (plotname) { if (figidx<2) put("\\gdef" plotname "{" stmt "}") put("\\gdef" plotname substr(ABC,figidx,1) "{" stmt "}") } else put(stmt) } if (splitChunks && (echo || !hide)) { put("-----SASweaveREVERT") put("%") } next } sas==0 { if ($0 ~ /\\begin{document}/) { if (!hasSASpkg) put("\\usepackage{SasWeave}") } put($0) } sas==1 { if ($1 ~ /\\SAScoderef/) { combineLines() pos = 10 getBraces() chunk = savedchunks[contents] getBraces() for (i=1; contents!=""; i++) { gsub("#"i, contents, chunk) getBraces() } sascode = sascode chunk "\n" sr = showref if (substr($1,12,1) == "*") sr = 1 # starred form if (echo && sr) { lf = index (chunk, "\n") for (pos=1; lf > 0; pos=pos+lf) { lf = index(substr(chunk, pos), "\n") if (lf > 1) put(prompt substr(chunk, pos, lf-1)) } } } else { if (echo) put(prompt $0) sascode = sascode $0 "\n" } } END { if (!panic) print "SAS file " sasfile " has been successfully created." }