diff --git a/LICENSE b/LICENSE index f8b699e..b1b1d3e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,44 @@ +---------------------------------------------------------------- +statrep.dtx +statrep_macros.sas +statrep_tagset.sas +statrepmanual.tex + +Copyright (c) 2015 SAS Institute Inc. +Copyright (c) 2026 Martial Phélippé-Guinvarc'h + +This work may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either version 1.3c +of this license or (at your option) any later version. +The latest version of this license is in + http://www.latex-project.org/lppl.txt +and version 1.3c or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +This work has the LPPL maintenance status 'maintained'. + +The Current Maintainer of this work is Martial Phélippé-Guinvarc'h. +Contact: Martial dot Phelippe-GuinvarcH at univ-lemans dot fr + +The original version was developed by Tim Arnold (SAS Institute). +This is an independent update and is not officially supported +by SAS Institute Inc. + +This work consists of the files: + statrep.dtx + statrep_macros.sas + statrep_tagset.sas + statrepmanual.tex + quickstart.tex +and the derived files: + statrep.ins + statrep.sty + longfigure.sty + statrep.cfg + statrep.pdf + statrepmanual.pdf + +---------------------------------------------------------------- The LaTeX Project Public License =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- diff --git a/Quickstart/quickstart.pdf b/Quickstart/quickstart.pdf new file mode 100644 index 0000000..18161bd Binary files /dev/null and b/Quickstart/quickstart.pdf differ diff --git a/supplement/quickstart.tex b/Quickstart/quickstart.tex similarity index 85% rename from supplement/quickstart.tex rename to Quickstart/quickstart.tex index 4cf527f..765ebe8 100644 --- a/supplement/quickstart.tex +++ b/Quickstart/quickstart.tex @@ -1,13 +1,16 @@ \documentclass{article} -\usepackage{statrep} +\usepackage{../statrep} \usepackage{parskip,xspace} \newcommand*{\Statrep}{\mbox{\textsf{StatRep}}\xspace} \newcommand*{\Code}[1]{\texttt{\textbf{#1}}} \newcommand*{\cs}[1]{\texttt{\textbf{\textbackslash#1}}} \setcounter{secnumdepth}{0} \title{Example and Tutorial for the \Statrep Package} -\author{Tim Arnold and Warren F. Kuhfeld\\SAS Institute Inc., Cary, NC} -\date{April 25, 2012} +\author{Martial Phélippé-Guinvarc'h\\Le Mans Université\\\texttt{martial.phelippe-guinvarch@univ-lemans.fr}\\ +\smallskip +{\small Based on the original work by Tim Arnold and Warren F. Kuhfeld (SAS Institute Inc. 2015)}} +%\author{Tim Arnold and Warren F. Kuhfeld\\SAS Institute Inc., Cary, NC} +\date{April 28, 2026} \begin{document} \maketitle \section{Introduction} @@ -71,8 +74,11 @@ \section{Step 1: Create Your \LaTeX\ Document} red 104 red 91 red 132 red 78 red 107 red 101 red 92 ; + \end{Datastep} + + The purpose of the \Code{Sascode} environment is to generate output. The statements in the following \Code{Sascode} environment perform an analysis that uses the ANOVA procedure (PROC ANOVA). @@ -83,6 +89,24 @@ \section{Step 1: Create Your \LaTeX\ Document} In this example, all output that is generated by the analysis is stored in the ODS document \Code{wineA}. +\begin{Sascode}[store=quickstart] +PROC SQL NOPRINT; +SELECT MEAN(VisitLength) +INTO :MeanOfVisitLength +FROM Wine; +QUIT; + +PROC PRINT DATA=WINE(OBS=3); +RUN; + +%STATREPMACROVAR(MeanOfVisitLength) +\end{Sascode} + +\Listing[store=quickstart, +dest=latex, +caption={Proc print, with a mean \textbackslash MeanOfVisitLength= \MeanOfVisitLength }]{quickstart} + + ...descriptive text that introduces the analysis... \begin{Sascode}[store=wineA] @@ -102,7 +126,7 @@ \section{Step 1: Create Your \LaTeX\ Document} The \cs{Listing} tag selects three output tables from the \Code{wineA} ODS document: \Code{ClassLevels}, \Code{NObs}, and \Code{OverallANOVA} -\Listing[store=wineA, +\Listing[store=wineA,fontsize=small, objects=ClassLevels NObs OverallANOVA, caption={Analysis of Variance for Visit Length}]{tsta} @@ -142,7 +166,10 @@ \section{Step 3: Execute the SAS Program} By default, tabular output files are created in the `lst' subdirectory and graphic output files are created in the `png' subdirectory. -\section{Step 4: Recompile Your \LaTeX\ Document} +The file \texttt{quickstart\_VarSAStoTex.tex} is automatically generated +by the SAS program and contains \verb|\def| commands of the form +\verb|\def\MacroName{value}|. These definitions are loaded at compile time +and can be used directly in the \LaTeX\ document.\section{Step 4: Recompile Your \LaTeX\ Document} The last step is to recompile your document with pdf\LaTeX. As in the first compilation, you can use a \LaTeX-aware editor such diff --git a/Quickstart/quickstart_VarSAStoTex.tex b/Quickstart/quickstart_VarSAStoTex.tex new file mode 100644 index 0000000..0a30e48 --- /dev/null +++ b/Quickstart/quickstart_VarSAStoTex.tex @@ -0,0 +1 @@ +\def \MeanOfVisitLength { 96,28} diff --git a/Quickstart/sas.sty b/Quickstart/sas.sty new file mode 100644 index 0000000..427580c --- /dev/null +++ b/Quickstart/sas.sty @@ -0,0 +1,1003 @@ + +\RequirePackage[T1]{fontenc} +\RequirePackage{times} +\RequirePackage{fancyvrb} +\RequirePackage{array} +\RequirePackage{graphicx} + +\newbox\sas@fig +\newlength\sas@figwidth + +\newif\ifsas@color +\sas@colorfalse + +\DeclareOption{color}{\sas@colortrue} +\ProcessOptions + +\def\sasSaftercaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbatch{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbeforecaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbody{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbodydate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbycontentfolder{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSbyline{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbylinecontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScell{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentfolder{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasScontentitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasScontentproclabel{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontents{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentsdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontenttitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontinued{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdata{% + \footnotesize% + \sffamily% +} +\def\sasSdataemphasis{% + \footnotesize% + \sffamily% +} +\def\sasSdataemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% +} +\def\sasSdataempty{% + \footnotesize% + \sffamily% +} +\def\sasSdatafixed{% + \footnotesize% + \ttfamily% +} +\def\sasSdatastrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdatastrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdocument{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorcontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorcontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSextendedpage{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalcontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalcontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfolderaction{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSfooter{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooteremphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooteremphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSframe{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSgraph{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheader{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderemphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheadersandfooters{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheadingb{% + \sffamily% +} +\def\sasSheadingc{% + \sffamily% +} +\def\sasSheadingd{% + \sffamily% +} +\def\sasSheadinge{% + \sffamily% +} +\def\sasSheadingf{% + \sffamily% +} +\def\sasSheadingg{% + \sffamily% +} +\def\sasSindex{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSindexaction{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSindexitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSindexprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSindextitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlayoutcontainer{% +} +\def\sasSlayoutregion{% +} +\def\sasSlinecontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlist{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSliste{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlisth{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlisti{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistiteme{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemh{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemi{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnote{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotebanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotecontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotecontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSoutput{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpageno{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpages{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSpagesproclabel{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagestitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSparagraph{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSparskip{% + \footnotesize% + \bfseries% + \sffamily% +} +\def\sasSprepage{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSproctitle{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSproctitlefixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooter{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooteremphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooteremphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheader{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderemphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooter{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfootere{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterh{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooteri{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitle{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleba{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlec{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitled{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlee{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlef{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleg{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleh{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlei{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlej{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystitleandfootercontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasStable{% +} +\def\sasStitleandnotecontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasStitlesandfooters{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSusertext{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarnbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarncontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarncontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +% Set cell padding +\renewcommand{\arraystretch}{1.3} + +% Headings +\newcommand{\sasheading}[3][c]{{% + \if#1r\flushright\else\if#1l\flushleft\else\centering\fi\fi% + {\csname sasS#2\endcsname #3}\mbox{}\\[0.1\baselineskip]% + \if#1r\endflushright\else\if#1l\endflushleft\else\fi\fi% +}} + +\newcommand{\sasbyline}[2][c]{\sasheading[#1]{byline}{#2}} +\newcommand{\sassystemtitle}[2][c]{\sasheading[#1]{systemtitle}{#2}} +\newcommand{\sassystemfooter}[2][c]{\sasheading[#1]{systemfooter}{#2}} +\newcommand{\sasproctitle}[2][c]{\sasheading[#1]{proctitle}{#2}} +\newcommand{\sascaption}[2][l]{\marginpar[#1]{\fbox{\parbox{0.7in}{\sasScaption{#2}}}}} + +% Declare new verbatim type +\DefineVerbatimEnvironment{sasverbatim}{BVerbatim}% + {fontsize=\footnotesize, + commandchars=\\\{\}, + formatcom=\sasSbatch} + +% Declare new column types +\newcolumntype{S}[2]{>{\csname sasS#1\endcsname}#2} +\newcolumntype{d}{r} + +% Set warning box style +\newlength\notewidth +\setlength\notewidth{4in} +\newcommand*{\saswarn}[2][c]{\sasmsg{warn}{#1}{#2}} +\newcommand*{\saserror}[2][c]{\sasmsg{error}{#1}{#2}} +\newcommand*{\sasnote}[2][c]{\sasmsg{note}{#1}{#2}} +\newcommand*{\sasfatal}[2][c]{\sasmsg{fatal}{#1}{#2}} +\newcommand*{\sasmsg}[3]{% + \ifsas@color\let\columncolor\undefined\fi% + \begin{center}% + \begin{tabular}{ll}\hline% + \multicolumn{1}{|S{#1banner}{p{0.7in}}|}{#1} & % + \multicolumn{1}{|S{#1content}{p{\notewidth}}|}{#3{\newline}}\\\hline% + \end{tabular}% + \end{center}% + \ifsas@color\let\columncolor\sascolumncolor\fi% +} + +\ifsas@color\RequirePackage{colortbl}\fi + +% Hack colortbl to allow \columncolor in macros +\let\CT@extract@org\CT@extract +\def\CT@extract{\futurelet\CT@NEXT\CT@extract@next} +\def\CT@extract@next{% + \ifx\CT@NEXT\csname + \@ReturnAfterFi{% + \expandafter\expandafter\expandafter + }% + \fi + \CT@extract@org +} +\long\def\@ReturnAfterFi#1\fi{\fi#1} + +\ifsas@color + + \newcommand{\foreground}[1]{\color[rgb]{#1}} + \newcommand{\sascolumncolor}[2][]{} + \let\columncolor\sascolumncolor + \newcommand{\documentforeground}[1]{\AtBeginDocument{\color[rgb]{#1}}} + \newcommand{\documentbackground}[1]{\AtBeginDocument{\pagecolor[rgb]{#1}}} + \def\sastable{\let\columncolor\undefined\tabular} + \def\endsastable{\endtabular\let\columncolor\sascolumncolor} + \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular} + \def\endstackedcell{\endtabular\egroup} + +\else + + \providecommand{\foreground}[1]{} + \providecommand{\color}[2][]{} + \newcommand{\sascolumncolor}[2][]{} + \let\columncolor\sascolumncolor + \newcommand{\documentforeground}[1]{} + \newcommand{\documentbackground}[1]{} + \def\sastable{\tabular} + \def\endsastable{\endtabular} + \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular} + \def\endstackedcell{\endtabular\egroup} + +\fi + +%\let\sasgraph\includegraphics +% Scale graphics so they always fit on the page +\newcommand\sasgraph[2][]{% + \savebox{\sas@fig}{\includegraphics[#1]{#2}}% + \settowidth{\sas@figwidth}{\usebox{\sas@fig}}% + \ifthenelse{\lengthtest{\sas@figwidth > \textwidth}}{% + \resizebox{0.95\textwidth}{!}{\usebox{\sas@fig}}}{% + \usebox{\sas@fig}} +} + diff --git a/supplement/statrep_macros.sas b/Quickstart/statrep_macros.sas similarity index 90% rename from supplement/statrep_macros.sas rename to Quickstart/statrep_macros.sas index 3681c4b..cd0ebe7 100644 --- a/supplement/statrep_macros.sas +++ b/Quickstart/statrep_macros.sas @@ -1,4 +1,4 @@ - /*---------------------------------------------*/ + /*---------------------------------------------*/ /* The WRITE macro displays one or more pieces */ /* of output (tables, notes, graphs, and so */ /* on) that were captured into an ODS document */ @@ -347,7 +347,7 @@ proc document name=&store; run; quit; %if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; -ods listing; +ods listing ; data _null_; call symputx('ls', getoption('ls'), 'L'); @@ -568,7 +568,7 @@ data _ads_doclist(drop=i p); English German Spanish French Italian Batch Batch Batch Traitement par lots Batch Crosstab Kreuztabelle TablaCruzada Table a double entr*e Campi incr. - Dir Dir Dir Rép. Dir + Dir Dir Dir R�p. Dir File file Archivo Fichier File Graph Grafik Gr*fico Graphique Grafico Note Hinweis Nota Note Nota @@ -945,13 +945,15 @@ options source &savenote; %end; %else %do; %if %index(&dest, listing) %then %do; - ods listing file="&listingdir/_tmp"; - %end; + FILENAME LISTTMP "&listingdir/_tmp" ENCODING="&SASencodingTex."; + ODS LISTING FILE=LISTTMP ; + %end; %if %index(&dest, latex) %then %do; ods tagsets.statrep style=&latexstyle file="&latexdir/&fname&jh..tex" (notop nobot) stylesheet="&rootdir/sas.sty" - newfile=output ; + newfile=output + encoding="&SASencodingTex."; %end; %end; %if not %index(&flow, notes) %then %do; options nonotes; %end; @@ -984,13 +986,15 @@ options source &savenote; kl + 1; call symputx('kl', kl, 'L'); put 'Note: Writing Listing file : ' fn; + filename outlst "&listingdir/&fname..lst" encoding="&SASEncodingTex."; end; - file x filevar=fn nopad; + file outlst nopad ; l = length(line); put line $varying. l; if _error_ then call symputx('error', '1', 'L'); run; - %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + filename outlst clear; + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; options &savenote; %end; %end; @@ -1391,7 +1395,8 @@ data _null_; rc = fdelete('__f'); run; %let __ls = %sysfunc(getoption(ls)); options nostimer nosource2 nosource; -proc printto log="&listingdir/__tmp" new; run; +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +proc printto log=LOGTMP new ; run; %mend; @@ -1415,8 +1420,10 @@ proc printto log=log; run; options stimer source2 source; +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +FILENAME LOGOUT "&listingdir/&__fname..lst" ENCODING='UTF-8'; data _null_; - infile "&listingdir/__tmp" lrecl=%eval(&__ls+4) pad; + infile LOGTMP lrecl=%eval(&__ls+4) pad; input line $char&__ls..; if anycntrl(line) = 0; %if &store %then %do; @@ -1427,7 +1434,7 @@ data _null_; compress(line, ' 0123456789') =: '+'); %end; if ⦥ - file "&listingdir/&__fname..lst" lrecl=%eval(&__ls+4); + file LOGOUT lrecl=%eval(&__ls+4); put line $char&__ls..; run; @@ -1521,3 +1528,194 @@ given extension to insure the directory exists and is empty of output files.; %mend cleandir; +proc format; + /* Format pour nombres < 100000 */ + picture STATREPS + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPR + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour nombres >= 100000 */ + picture STATREPL + 1000000000-high='000~000~000~009,99' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009,99' (decsep="," dig3sep=" ") + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009,99' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPK + 1000000000-high='000~000~000~009' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009' (decsep="," dig3sep=" ") + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour pourcentages/petits nombres */ + picture STATREPC + other='0~009,9900' (mult=1000000); + + /* Format date dd/mm/yyyy */ + picture STATREPD + low-high='%0d/%0m/%Y' (datatype=date); +run; +%macro STATREPResults(variable,format); + filename outtex "&SAStoTexname" encoding="utf-8" mod; + file outtex termstr=nl mod; + put "\def\&variable{" &variable &format '}'; +%mend; + +%macro STATREPAllResults(); + array _all _numeric_; + filename outtex "&SAStoTexname" encoding="utf-8" ; + file outtex termstr=nl mod; + + do over _all; + a = vname(_all); + fmt = vformat(_all); + + /* Test si variable de type date (format date appliqué) */ + if index(upcase(fmt),'DATE') or index(upcase(fmt),'DDMMYY') or + index(upcase(fmt),'MMDDYY') or index(upcase(fmt),'YYMMDD') or + index(upcase(fmt),'EURDFDD') or index(upcase(fmt),'NLDATE') or + (_all >= 0 and _all < 100000 and mod(_all,1)=0 and + vformat(_all) in ('BEST','F','') and a ne '') then do; + /* Vérification additionnelle : valeur dans la plage des dates SAS */ + if _all >= -109572 and _all <= 157377 then do; + put '\def\' a '{' _all STATREPD. '}'; + end; + else do; + /* Ce n'est pas une date, traiter comme nombre normal */ + if abs(_all) >= 100000 then + put '\def\' a '{' _all STATREPL. '}'; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + /* Sinon traiter comme nombre normal */ + else do; + if abs(_all) >= 100000 then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPK. '}'; + else + put '\def\' a '{' _all STATREPL. '}'; + end; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPR. '}'; + else + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + end; +DROP A FMT; +%mend; + +%MACRO STATREPMACROVAR(variable); +DATA _NULL_; +&variable = &&&variable; +%STATREPALLRESULTS() +;RUN; +%MEND; + + +PROC IML; +START STATREPFormatValue(value, varName); + ligne = ""; + + IF value = . THEN RETURN(ligne); + + IF value >= -109572 & value <= 157377 & MOD(value,1)=0 + & INDEX(UPCASE(varName),'DATE')>0 THEN + ligne = STRIP(PUTN(value, 'STATREPD.')); + + ELSE IF ABS(value) >= 100000 THEN DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPK.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPL.')); + END; + + ELSE IF ABS(value) < 1 THEN + ligne = STRIP(PUTN(value, 'STATREPC.')); + + ELSE DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPR.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPS.')); + END; + + RETURN(ligne); +FINISH; + +START STATREPResult(variable); + varName = PARENTNAME("variable"); + n = NROW(variable); + p = NCOL(variable); + v=variable; +IF p=1 & n>1 THEN DO; V=v`;p=n; n=1; END; + latex = ""; + +DO i = 1 TO n; + row = ""; + DO j = 1 TO p; + cell = STATREPFormatValue(v[i,j], varName); + IF cell ^= "" THEN DO; + IF j > 1 THEN row = row + " & "; + row = row + cell; + END; + END; + IF i > 1 THEN latex = latex + " \\ "; + latex = latex + row; +END; +IF n=1 & p=1 THEN + ligne = "\def\" + STRIP(varName) + " {" + latex + "}"; + +ELSE DO; + tabspec = "*{" + STRIP(CHAR(p)) + "}{c}"; + ligne = "\def\" + STRIP(varName) + + " {\begin{center}\begin{tabular}{" + + tabspec + "}" + + latex + + "\end{tabular}\end{center}}"; +END; + +EDIT WORK._STATREP_TEMP_; +APPEND FROM ligne; +CLOSE WORK._STATREP_TEMP_; +FINISH; + +STORE MODULE=( STATREPResult STATREPFormatValue ); +QUIT; + + +DATA WORK._STATREP_TEMP_; +LENGTH LIGNE $256; +STOP; +RUN; +QUIT; + +%MACRO STATREPIMLWrite(); +DATA _NULL_; + SET WORK._STATREP_TEMP_; + FILENAME outtex "&SAStoTexname" ENCODING="utf-8"; + FILE outtex TERMSTR=NL MOD; + PUT LIGNE; +RUN; + +%MEND STATREPIMLWrite; diff --git a/supplement/statrep_tagset.sas b/Quickstart/statrep_tagset.sas similarity index 99% rename from supplement/statrep_tagset.sas rename to Quickstart/statrep_tagset.sas index 819157c..147a64a 100644 --- a/supplement/statrep_tagset.sas +++ b/Quickstart/statrep_tagset.sas @@ -1,3 +1,4 @@ +ODS PATH WORK.TEMPLAT(UPDATE) SASHELP.TMPLMST(READ); proc template; define style styles.StatRep; parent = styles.statistical; diff --git a/README b/README new file mode 100644 index 0000000..a67f332 --- /dev/null +++ b/README @@ -0,0 +1,214 @@ +ABOUT + +The StatRep package is a LaTeX package that provides two environments and +two tags that work together to display your SAS code and results and to +generate the SAS program that produces those results. The two environments +(Datastep and Sascode) display SAS code. The two tags (Listing and Graphic) +display SAS output. + +The generated SAS program includes calls to macros that use the SAS +Output Delivery System (ODS) document to capture the output as external files. +These SAS macros are included in this package (statrep_macros.sas). + +The package is available in two locations: + + * http://support.sas.com/StatRepPackage - Obsolet + * https://github.com/MartialP-G/StatRep + * http://mirror.ctan.org/macros/latex/contrib/statrep/ + +The distribution(statrep.zip) consists of the following files: + README.txt (this file) + statrep_macros.sas SAS macro file + statrep_tagset.sas SAS tagset and style for LaTeX tabular output + statrepmanual.pdf StatRep Package User's Guide (pdf) + statrepmanual.tex StatRep Package User's Guide (source) + quickstart.tex Example and tutorial LaTeX file + statrep.dtx Package source file + statrep.ins Install file (for MikTeX Users) + +INSTALL + +Unzip the file statrep.zip to a temporary directory and +perform the following steps: + +Step 1: Install the StatRep SAS Macros + + Copy the file statrep_macros.sas to a local directory. If you have a + folder where you keep your personal set of macros, copy the file + there. Otherwise, create a directory such as C:\mymacros and copy + the file into that directory. + +Step 2: Install the StatRep LaTeX Package + + If you are working with the MikTeX distribution on Windows and it is + configured to download and install packages automatically, you can + skip this step. Otherwise, see these instructions for installing + packages for MikTeX: + http://docs.miktex.org/manual/localadditions.html + + The following instructions show how to install the StatRep package in the + TeXLive LaTeX distribution for your personal use. If you maintain a + system-wide LaTeX distribution and you want to make StatRep + available to all users, see more detailed information about how + to install LaTeX packages at + https://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-440005.2 + + a) + Determine the location that LaTeX uses to load packages. From a + command-line prompt, give the following command: + kpsewhich -var-value=TEXMFHOME + + The command will return the root directory name in which LaTeX can + find your personally installed packages. + + b) + Create the directory if it does not exist and create the additional + subdirectories tex/latex/statrep + Your directory tree will have the following structure: + --------------- + root directory/ (given by kpsewhich command in 2a) + tex/ + latex/ + statrep/ + + d) + Copy the files statrep.dtx, statrepmanual.pdf, and statrepmanual.tex to + the statrep subdirectory. Your directory tree will have the following structure: + --------------- + root directory/ (given by kpsewhich command in 2a) + tex/ + latex/ + statrep/ + statrep.dtx + statrepmanual.pdf + statrepmanual.tex + --------------- + + e) + Change to the statrep directory and give the following command: + pdflatex statrep.dtx + + The command creates several files, one of which is the configuration + file, statrep.cfg. + +Step 3: Let the StatRep Package Know the Location of the StatRep SAS Macros + + Edit the statrep.cfg file generated in Step 2d so that the macro SRmacropath contains + the correct location of the macro file from step 1. For example, if + you copied the statrep_macros.sas file to a directory named 'C:\mymacros', + then you define macro \SRmacropath as follows: + \def\SRmacropath{c:/mymacros/statrep_macros.sas} + + Note the use of the forward slash in the definition. Use the forward slash + as the directory name delimiter instead of the backslash, which is a special + character in LaTeX. + +EXPLORE + + You can now test and experiment with the package. Create a working + directory and copy the file quickstart.tex into it. + + To generate the quickstart document: + 1) Compile the document with pdfLaTeX. You can use a LaTeX-aware + editor such as TeXworks, or you can use the command-line command 'pdflatex'. + This step generates the necessary SAS program that is needed to produce + the results. If the name of your document is myarticle.tex, the names of + the generated SAS programs will be myarticle_SR.sas and + myarticle_SR_preamble.sas by default. + + myarticle_SR.sas: Begins with a call to the preamble SAS file, then + the cleaning subdirectory, and then the aggregate SAS code present + in the LaTeX file. + myarticle_SR_preamble.sas: Mainly contains custom variables (see the + customizable settings section) and a call to the statrep_macros.sas + macro file. + + 2) Execute the SAS program quickstart_SR.sas, which was automatically + created in the preceding step. This step generates the SAS + results that are requested in the quickstart document. + + 3) Recompile the document with pdfLaTeX. This step compiles the + quickstart document to PDF, this time including the SAS results + that are generated in the preceding step. + + You might need to repeat this step so that LaTeX can re- + measure the listing outputs to ensure that they are framed properly. + + Notes: You can make changes to the file with a LaTeX-aware editor + or with any plain-text editor such as NotePad or emacs. + + You can read the StatRep User's Guide for complete usage details. + It is included in the file statrepmanual.pdf that you copied + in the installation step 2d. + +UNINSTALL + + To uninstall the package, delete the statrep directory that you created + in the installation step 2d and remove the SAS macro file statrep_macros.sas + that you copied in Installation step 1. + +NOTE + + StatRep now includes limited support for SAS ODS LaTeX output. + See the StatRep User's Guide for details. + +LICENSE + +statrep.dtx +statrep_macros.sas +statrep_tagset.sas +statrepmanual.tex + + ----------------------------------------------------------------- + Copyright (c) 2015 SAS Institute Inc. + Copyright (c) 2026 Martial Phélippé-Guinvarc'h + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3c + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt +----------------------------------------------------------------- + This work has the LPPL maintenance status 'maintained'. + + The Current Maintainer of this work is Martial Phélippé-Guinvarc'h. + Contact: Martial dot Phelippe-GuinvarcH at univ-lemans dot fr + + The original version was developed by Tim Arnold (SAS Institute). + This is an independent update and is not officially supported + by SAS Institute Inc. + +DESCRIPTION OF CHANGES (2026/04/28): + - Improved path resolution logic when using SASmode option. + - Added UTF-8 encoding support for SAS input files. + - Included new macros for automatic LaTeX export of SAS results + via specialized formats. +----------------------------------------------------------------- + This work consists of the files statrep.dtx, + statrep_macros.sas, + statrep_tagset.sas + and the derived file statrep.ins and statrep.sty. +----------------------------------------------------------------- + +REQUIREMENTS + + pdfLaTeX typesetting engine 1.30 or later + + LaTeX packages + verbatim, graphicx, ifthen, calc, etoolbox, xkeyval + SAS 9.2 or later + +See the StatRep User's Guide, included with this package, for complete details. + +This work consists of the files: + README (this file) + statrep_macros.sas + statrep_tagset.sas + statrepmanual.tex + statrepmanual.pdf + quickstart.tex + statrep.dtx + statrep.ins + statrep.pdf + statrep.sty + statrep.cfg diff --git a/README.md b/README.md index 2fb244c..e3899f7 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ -# Caution +# StatRep — LaTeX Package for Reproducible SAS Documents -This GitHub repository contains code to build and package the **StatRep** -LaTeX package. If you are looking for the package itself, please download the file ``statrep.zip`` from one of these locations. +This repository contains the source of the **StatRep** LaTeX package. +The package is available at: - * SAS (http://support.sas.com/StatRepPackage) - * CTAN (http://www.ctan.org/pkg/statrep) +* GitHub: https://github.com/MartialP-G/StatRep +* CTAN: http://www.ctan.org/pkg/statrep +* SAS (original): http://support.sas.com/StatRepPackage — *obsolete* -You can see a brief online example here: -http://tiarno.github.io/StatRep/ # Overview @@ -16,9 +15,86 @@ and a suite of SAS macros to enable you to create dynamic documents with reprodu With **StatRep**, your analysis is fully documented and reproducible from a single source--your LaTeX document. The system automatically produces a SAS program so that both the SAS output and the SAS code that produced the output are displayed. -The package provides two environments and two tags that work together to display your SAS code and results and to generate the SAS program that produces those results. The two environments (``Datastep`` and ``Sascode``) display SAS code. The two tags (``Listing`` and ``Graphic``) display SAS output. +The package provides two environments and two tags: -Full documentation is included in the distribution, available at the links provided above. +* Environments `Datastep` and `Sascode` display SAS code. +* Tags `Listing` and `Graphic` display SAS output. + +## Workflow + +1. Compile your `.tex` document with `pdflatex`. This generates two SAS + programs: + - `myarticle_SR.sas` — calls the preamble file, cleans output + directories, then runs the aggregated SAS code from your LaTeX file. + - `myarticle_SR_preamble.sas` — contains custom variables and a call + to `statrep_macros.sas`. +2. Execute `myarticle_SR.sas` in SAS to produce the results. +3. Recompile with `pdflatex` to include the SAS results in your document. + Repeat if necessary for correct framing of listings. + +## SAS Path Options + +The `SASmode` option controls how the current path is resolved: + +* `SASmode=WorkStation` (default): uses `.` as the root directory. +* `SASmode=Server`: uses `¤tpath`, derived from the + `&_SASPROGRAMFILE` SAS macro variable. Use this for SAS Studio, + SAS OnDemand, or any server-based SAS environment. + +## SAS Result Export Macros + +Three macros in `statrep_macros.sas` allow you to export SAS results or +macro variable values directly into your LaTeX document via +`jobname_VarSAStoTex.tex`, which is loaded automatically at compile time: + +* `%STATREPResults(variable, format)` — exports a single variable using + the specified format. +* `%STATREPAllResults()` — processes all numeric variables in a dataset + and generates their LaTeX definitions. +* `%STATREPMACROVAR(variable)` — exports a single SAS macro variable. + +The generated file contains `\def` commands (e.g. `\def\PARAMETER{365}`) +that can be used directly in your LaTeX document as `\PARAMETER`. + +## Character Encoding + +The package automatically maps the LaTeX `inputenc` encoding to the +correct SAS output encoding (`UTF-8` or `WLATIN1`). If `inputenc` is not +loaded, `UTF-8` is used by default. + +# Documentation + +* *StatRep User's Guide* (`statrepmanual.pdf`) — installation and usage +* `quickstart.tex` — simple working example +* `statrep.pdf` — LaTeX implementation details + +# License + + Copyright (c) 2015 SAS Institute Inc. + Copyright (c) 2026 Martial Phélippé-Guinvarc'h + + This work may be distributed and/or modified under the conditions of + the LaTeX Project Public License (LPPL), version 1.3c or later. + See http://www.latex-project.org/lppl.txt for details. + + This work has the LPPL maintenance status 'maintained'. + The Current Maintainer is Martial Phélippé-Guinvarc'h + (Martial dot Phelippe-GuinvarcH at univ-lemans dot fr). + + The original version was developed by Tim Arnold (SAS Institute). + This is an independent update and is not officially supported + by SAS Institute Inc. + +# Requirements + +* `pdfLaTeX` typesetting engine 1.30 or later +* LaTeX packages: `verbatim`, `graphicx`, `xkeyval`, `calc`, `ifthen`, + `etoolbox`. Included in standard distributions (TeXLive, MiKTeX). +* SAS 9.2 or later + +## Documentation + +Documentation is included in the distribution, available at the links provided above. * *The StatRep User's Guide* (`statrepmanual.pdf`) includes installation instructions and details on how to use the system. * A simple example of using the package (`quickstart.tex`) @@ -30,39 +106,32 @@ These SAS macros are included in this package (``statrep_macros.sas``). Limited support is provided for SAS-generated LaTeX output, using a special tagset: you can generate the tagset with the included SAS program ``statrep_tagset.sas``. -# License - - Copyright (c) 2014 SAS Institute Inc. - Permission is granted to copy, distribute, and/or modify this software - under the terms of the LaTeX Project Public License (LPPL), version 1.3. +# Distribution Layout - This software is provided by SAS Institute Inc. as a service to its users. - It is provided 'as is', without warranty of any kind, either expressed or - implied, including, but not limited to, the implied warranties of - merchantibility and fitness for a particular purpose. - See http://www.latex-project.org/lppl.txt for the details of that license. +## Files in this repository - This work has the LPPL maintenance status 'maintained'. - The Current Maintainer of this work is Tim Arnold - (tim dot arnold at sas dot com). + statrep.dtx — package source (documentation + code) + statrep.ins — install file (for MiKTeX users) + statrep_macros.sas — SAS macro file + statrep_tagset.sas — SAS tagset and style for LaTeX tabular output + README.md — this file -# Requirements +## Generating the package files - * ``pdfLaTeX`` typesetting engine 1.30 or later - * LaTeX packages: ``verbatim``, ``graphicx``, ``xkeyval``, ``calc``, ``ifthen``. These packages are contained in a standard LaTeX distribution, such as **TeXLive** or **MiKTeX**. - * SAS 9.2 or later +Compile `statrep.dtx` with `pdflatex` to generate all derived files: + pdflatex statrep.dtx -# Note on Packaging +This produces: +* `statrep.sty` — the LaTeX package +* `longfigure.sty` — the longfigure package +* `statrep.cfg` — default configuration file (edit to set your SAS macro path) +* `statrep.pdf` — this documentation -This github repo is meant for packaging the ``StatRep`` and ``longfigure`` packages. To create the packages, - 1. put the ``benchmark``, ``content``, and ``supplement`` directories along with ``build.py`` into a clean working directory. - 2. Execute the ``build.py`` script to create a new ``build`` directory. +## Distribution layout (statrep.zip) -Inside the ``build`` directory there will be subdirectories called ``ctan``, ``sas`` that contain the files to be distributed at those locations. There are also directories ``test`` and ``work`` that were used to create the new distributions. - -Inside the distribution directories are the zip files. For the ``sas`` distribution, the ``*.sty`` files are included so people don't have to do any extra steps. Here is the layout of the zip file for the distribution (``statrep.zip``): +For standard distribution, the zip file is structured as follows: README LICENSE @@ -70,39 +139,31 @@ Inside the distribution directories are the zip files. For the ``sas`` distribut statrep.ins statrep.sty longfigure.sty + statrep.cfg doc/ - images/ quickstart.tex statrepmanual.tex - statrepmanual.pdf -- with example.tex attached inside + statrepmanual.pdf statrep.pdf sas/ statrep_macros.sas statrep_tagset.sas -The CTAN folks don't want the extra ``*.sty`` files since they are normally just created by compiling the ``*.dtx`` file, so we omit them for the CTAN version. The layout for this version (``statrep.zip``) appears as follows: +## CTAN layout + +CTAN generates the `*.sty` files from `statrep.dtx` automatically, +so they are omitted from the CTAN submission: README LICENSE statrep.dtx statrep.ins doc/ - images/ quickstart.tex statrepmanual.tex - statrepmanual.pdf -- with example.tex attached inside + statrepmanual.pdf statrep.pdf sas/ statrep_macros.sas statrep_tagset.sas -The ``longfigure`` package is simple and exists only in the ``ctan`` directory. The layout of the zip file looks like this (``longfigure.zip``): - - README - LICENSE - longfigure.dtx - longfigure.ins - longfigure.pdf - - - diff --git a/supplement/images/default.png b/Statrepmanuel/images/default.png similarity index 100% rename from supplement/images/default.png rename to Statrepmanuel/images/default.png diff --git a/supplement/images/example_output.png b/Statrepmanuel/images/example_output.png similarity index 100% rename from supplement/images/example_output.png rename to Statrepmanuel/images/example_output.png diff --git a/supplement/images/htmlblue.png b/Statrepmanuel/images/htmlblue.png similarity index 100% rename from supplement/images/htmlblue.png rename to Statrepmanuel/images/htmlblue.png diff --git a/supplement/images/journal.png b/Statrepmanuel/images/journal.png similarity index 100% rename from supplement/images/journal.png rename to Statrepmanuel/images/journal.png diff --git a/supplement/images/listing.png b/Statrepmanuel/images/listing.png similarity index 100% rename from supplement/images/listing.png rename to Statrepmanuel/images/listing.png diff --git a/supplement/images/sasuniv1.png b/Statrepmanuel/images/sasuniv1.png similarity index 100% rename from supplement/images/sasuniv1.png rename to Statrepmanuel/images/sasuniv1.png diff --git a/supplement/images/statistical.png b/Statrepmanuel/images/statistical.png similarity index 100% rename from supplement/images/statistical.png rename to Statrepmanuel/images/statistical.png diff --git a/supplement/images/vm1.png b/Statrepmanuel/images/vm1.png similarity index 100% rename from supplement/images/vm1.png rename to Statrepmanuel/images/vm1.png diff --git a/supplement/images/vm2.png b/Statrepmanuel/images/vm2.png similarity index 100% rename from supplement/images/vm2.png rename to Statrepmanuel/images/vm2.png diff --git a/supplement/images/vm3.png b/Statrepmanuel/images/vm3.png similarity index 100% rename from supplement/images/vm3.png rename to Statrepmanuel/images/vm3.png diff --git a/Statrepmanuel/statrepmanual.pdf b/Statrepmanuel/statrepmanual.pdf new file mode 100644 index 0000000..a5d7a54 Binary files /dev/null and b/Statrepmanuel/statrepmanual.pdf differ diff --git a/supplement/statrepmanual.tex b/Statrepmanuel/statrepmanual.tex similarity index 95% rename from supplement/statrepmanual.tex rename to Statrepmanuel/statrepmanual.tex index 723fbb6..3404b6d 100644 --- a/supplement/statrepmanual.tex +++ b/Statrepmanuel/statrepmanual.tex @@ -32,7 +32,10 @@ \newcolumntype{P}[1]{>{\raggedright\arraybackslash}p{#1}} \setlength{\FrameSep}{1pt} \title{The \StatRep System for Reproducible Research} -\author{Tim Arnold and Warren F. Kuhfeld\\SAS Institute Inc.} +\author{Martial Phélippé-Guinvarc'h\\Le Mans Université \\\texttt{martial.phelippe-guinvarch@univ-lemans.fr}\\ +\smallskip + {\small Based on the original work by Tim Arnold and Warren F. Kuhfeld (SAS Institute Inc. 2015)}} + %\author{Tim Arnold and Warren F. Kuhfeld\\SAS Institute Inc.} \makeindex \begin{document} \maketitle @@ -109,10 +112,14 @@ \chapter{Introduction} \item Create your \LaTeX\ source file so that it contains your text, data, and SAS code. \item Compile the document with pdf\LaTeX. You can use a LaTeX-aware - editor such as \TeX works, or you can use the command-line command \Code{pdflatex}. - This step generates the SAS program that is needed to produce the results. - If the name of your document is \textit{myarticle.tex}, the name of the generated SAS - program is \textit{myarticle\_SR.sas} by default. +editor such as \TeX works, or you can use the command-line command \Code{pdflatex}. +This step generates the necessary SAS program that is needed to produce the results. +If the name of your document is \textit{myarticle.tex}, the names of the generated SAS +programs will be \textit{myarticle\_SR.sas} and \textit{myarticle\_SR\_preambule.sas} by default. +\begin{description} + \item[myarticle\_SR.sas] Begins with by a call to \Code{preambule} SAS file, then the cleaning subdirectory, and then then aggregate SAS code present in the \LaTeX file. + \item[myarticle\_SR\_preambule.sas] mainly contains custom variables (see section \ref{custom}) and a call to the \Code{statrep\_macros.sas} macro files. +\end{description} \item Execute the SAS program to capture your output. @@ -186,6 +193,11 @@ \section{Package Usage} \item \Code{resetby=} specifies that the counter for output numbering be reset with each change in the specified counter value. For example, if \Code{resetby=chapter}, all output numbering is reset when the chapter value changes.\index{resetby= option} + + \item \Code{SASmode=WorkStation} or \Code{SASmode=Server} change the current path definition. + For Workstation, the \Code{rootdir} or current path is ".", for Server, the current path is "\¤tpath", obtained from + "\&\_SASPROGRAMFILE" SAS macro variable. + \index{SASmode= option} \end{itemize} The options \Code{figname=} and \Code{resetby=} are not used directly by the \StatRep @@ -203,7 +215,7 @@ \chapter{Getting Started}\label{gs} This section provides a simple example of how you can use the \StatRep package to produce a document with reproducible results. You can follow along with the actual code: extract this -\textattachfile[color=0 0 0.6]{example.tex}{example \LaTeX\ file} that +\textattachfile[color=0 0 0.6]{../Quickstart/quickstart.tex}{examples \LaTeX\ file} that contains the code in this section if your PDF viewer supports file annotations. Two code environments @@ -856,11 +868,17 @@ \section{Using the Datastep Environment}\label{dsex} Female 32 0 Female 35 0 ; + + %LET PARAMETER=365; + %STATREPALLRESULTS(PARAMETER) \end{verbatim} \end{snugshade} \caption{Displayed \texttt{Datastep} Environment with Options}\label{fig:sd3} \end{figure} +The file \_SAStoTex.tex, which include the command \\def\\PARAMETER{365} could be use in \LaTeX document as \verb|\PARAMETER| (see also \ref{SAStoTex} subsection). + + \section{Using the Sascode Environment}\label{scex}\index{Sascode environment} Figure \ref{sb} displays an example \Code{Sascode} environment. @@ -1320,12 +1338,30 @@ \chapter{Customizing \StatRep}\label{custom} \item[\cs{SRverbfont}] specifies the font to use for code within \Code{Datastep} and \Code{Sascode} blocks. The default is \cs{ttfamily}\cs{bfseries} - (\texttt{\textbf{typewriter text, bold}}). + (\texttt{\textbf{typewriter text, bold}}). \index{verbatim font} + + + \item[\cs{SR@encoding}] specifies the encoding to SAS output text files (\texttt{UTF-8} or \texttt{WLATIN1}) (The \Code{SASencodingOutput} SAS macro variable). By default, this value utf8 or define from the \Code{inputenc}option package. + \index{Encoding} \end{description} - \chapter{About the Program Preamble} + \chapter{Character Encoding (\texttt{SASencodingOutput})} + + The \texttt{statrep} package automatically manages character encoding to ensure compatibility between your \LaTeX{} source document and the generated SAS output. + + \paragraph{Encoding Logic} + \index{Encoding} + The package operates on the following priority: + \begin{enumerate} + \item \textbf{Automatic Detection}: The package checks if the \texttt{inputenc} package is loaded. If present, \texttt{statrep} retrieves the active \LaTeX{} encoding (e.g., \texttt{utf8}, \texttt{latin1}, \texttt{ansinew}) and maps it to the corresponding SAS output encoding (\texttt{UTF-8} or \texttt{WLATIN1}). This ensures seamless handling of special characters and accents. + \item \textbf{Default Fallback}: If the \texttt{inputenc} package is not detected, the package defaults to using the modern standard UTF-8 for all SAS output files. + \item \textbf{Manual Override}: The encoding can be manually forced using the package option \texttt{SASencodingOutput}. Supported values include \texttt{utf8} and \texttt{wlatin1}. + \end{enumerate} + + + \chapter{About the Program Preamble} The \StatRep package automatically writes a preamble to the generated program and a preamble file. @@ -1340,7 +1376,7 @@ \chapter{Customizing \StatRep}\label{custom} The preamble in the generated program includes the preamble file and deletes the contents of the output directories (\Code{lst}, \Code{tex}, and \Code{png}, by default) so that obsolete files are not included in the document. -Figure \ref{fig:pgmpreamble} shows an example of the preamble lines +Figures \ref{fig:pgmpreambleW} and \ref{labelfig:pgmpreambleS} show an example of the preamble lines that are written to the generated program. \begin{figure}[H] \begin{snugshade} @@ -1357,15 +1393,34 @@ \chapter{Customizing \StatRep}\label{custom} %include "report_SR_preamble.sas" /nosource; /* Remove all output files. */ -%hostdel; +%cleandir(¤tpath, tex, tex); +%cleandir(¤tpath, png, png); +%cleandir(¤tpath, lst, lst); /* Start program with a null title. */ title; \end{verbatim} \end{snugshade} -\caption{Generated SAS Program Preamble}\label{fig:pgmpreamble} +\caption{The start of the SAS Program using the SASmode=Workstation}\label{fig:pgmpreambleW} \end{figure} +\begin{figure}[H] + \begin{snugshade} + \begin{verbatim} +filename current "&_SASPROGRAMFILE"; + *** get the full name of the file; +%let fullpath = %sysfunc(pathname(current)); +%let currentpath = %substr(&fullpath, 1, %length(&fullpath) + - %length(%scan(&fullpath, -1, '/\\'))-1 ); +%put &fullpath ¤tpath; +%let rc = %sysfunc(dlgcdir(¤tpath)); +%include "¤tpath/example_SR_preamble.sas" /nosource; + \end{verbatim} + \end{snugshade} + \caption{Changes to the start of the SAS program using the SASMODE=SERVER option}\label{fig:pgmpreambleS} +\end{figure} + + The external preamble file sets defaults, includes the output-capture macros, and creates the output directories if they do not exist. You can customize the preamble; see section \ref{custom} for details. @@ -1382,7 +1437,6 @@ \chapter{Customizing \StatRep}\label{custom} statrep.cfg for information on these settings. */ - /* Set and invoke macro variable defaults. */ %let defaultlinesize=80; %let defaultpagesize=500; @@ -1712,8 +1766,8 @@ \chapter{\StatRep SAS Macros}\label{macros} separated by a comma (,): \begin{description} - \item[\Code{code=}] specifies whether program code in the SAS log is included. - By default, code is captured (\Code{code=1}). Set \Code{code=0} to exclude code. + \item[\Code{store=}] specifies whether program code in the SAS log is included. + By default, code is captured (\Code{store=1}). Set \Code{store=0} to exclude code. \item[\Code{range=}] specifies a Boolean expression to select certain observations. For example, you can specify \Code{range=\_n\_ <= 5 } to select the first five lines. You can specify @@ -1722,6 +1776,21 @@ \chapter{\StatRep SAS Macros}\label{macros} contains a single line of the log. \end{description} +\section{STATREP results Macro from SAS to Tex}\label{SAStoTex} + + +The \texttt{statrep} package provides SAS macros designed to export numeric and date variables directly into \LaTeX{} documents in a consistent and properly formatted way. + +\begin{itemize} + \item Predefined \texttt{proc format} picture formats handle small numbers, large numbers, percentages, and dates. + \item \texttt{\%STATREPResults(variable, format)} writes a single variable to a \LaTeX{} file as a \verb|\def| command using the chosen format. + \item \texttt{\%STATREPAllResults()} automatically processes all numeric variables in a dataset and generates their \LaTeX{} definitions with appropriate formatting. + \item \texttt{\%STATREPMACROVAR(variable)} provides a convenient way to export one variable using \texttt{\%STATREPAllResults}. + \item All macros write the output to a file named \verb|\jobname\_SAStoTex.tex|, which can be included in your main \LaTeX{} document with \verb|\input|. +\end{itemize} + +These macros make it easy to **synchronize SAS results with \LaTeX{} reports**, ensuring consistency in number formatting, dates, and scientific notation across your documents. + \section{Macro Variable Defaults}\label{secdefaults} \index{macro variables}\index{default settings}\index{package!defaults} \index{SAS macros!variables} @@ -2206,15 +2275,15 @@ \section{Capturing Log Output} procedure code is executed, and the \Code{\%endlog} macro closes the file. To omit the PROC IML code from the captured log output, - specify the \Code{code=0} option in the \Code{\%endlog} macro as follows: + specify the \Code{store=0} option in the \Code{\%endlog} macro as follows: \begin{snugshade} \begin{verbatim} - %*; %endlog(code=0); + %*; %endlog(store=0); \end{verbatim} \end{snugshade} - With the \Code{code=0} option specified, the captured log output is + With the \Code{store=0} option specified, the captured log output is displayed as shown in Figure \ref{lognoproc}. \begin{figure}[H] @@ -2242,7 +2311,7 @@ \section{Capturing Log Output} \begin{snugshade} \begin{verbatim} - %*; %endlog(code=0, range=_n_ > 6 and _n_ le 24); + %*; %endlog(store=0, range=_n_ > 6 and _n_ le 24); \end{verbatim} \end{snugshade} With the both options specified, the captured log output is displayed as diff --git a/Testcases/sas.sty b/Testcases/sas.sty new file mode 100644 index 0000000..427580c --- /dev/null +++ b/Testcases/sas.sty @@ -0,0 +1,1003 @@ + +\RequirePackage[T1]{fontenc} +\RequirePackage{times} +\RequirePackage{fancyvrb} +\RequirePackage{array} +\RequirePackage{graphicx} + +\newbox\sas@fig +\newlength\sas@figwidth + +\newif\ifsas@color +\sas@colorfalse + +\DeclareOption{color}{\sas@colortrue} +\ProcessOptions + +\def\sasSaftercaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbatch{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbeforecaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbody{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbodydate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbycontentfolder{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSbyline{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSbylinecontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScaption{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScell{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentfolder{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasScontentitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasScontentproclabel{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontents{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontentsdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontenttitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasScontinued{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdata{% + \footnotesize% + \sffamily% +} +\def\sasSdataemphasis{% + \footnotesize% + \sffamily% +} +\def\sasSdataemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% +} +\def\sasSdataempty{% + \footnotesize% + \sffamily% +} +\def\sasSdatafixed{% + \footnotesize% + \ttfamily% +} +\def\sasSdatastrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdatastrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSdocument{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorcontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSerrorcontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSextendedpage{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalcontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfatalcontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfolderaction{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSfooter{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooteremphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooteremphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSfooterstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSframe{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSgraph{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheader{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderemphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheadersandfooters{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSheaderstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheaderstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{0.84,0.85,0.82}% +} +\def\sasSheadingb{% + \sffamily% +} +\def\sasSheadingc{% + \sffamily% +} +\def\sasSheadingd{% + \sffamily% +} +\def\sasSheadinge{% + \sffamily% +} +\def\sasSheadingf{% + \sffamily% +} +\def\sasSheadingg{% + \sffamily% +} +\def\sasSindex{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSindexaction{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSindexitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSindexprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSindextitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlayoutcontainer{% +} +\def\sasSlayoutregion{% +} +\def\sasSlinecontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlist{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSliste{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlisth{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlisti{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistiteme{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemh{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemi{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSlistitemj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnote{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotebanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotecontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSnotecontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSoutput{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpageno{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpages{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesdate{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesitem{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% +} +\def\sasSpagesproclabel{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagesprocname{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSpagestitle{% + \footnotesize% + \bfseries% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSparagraph{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSparskip{% + \footnotesize% + \bfseries% + \sffamily% +} +\def\sasSprepage{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSproctitle{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSproctitlefixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooter{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooteremphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooteremphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowfooterstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheader{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderemphasis{% + \footnotesize% + \itshape% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderemphasisfixed{% + \footnotesize% + \itshape% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderempty{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderstrong{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSrowheaderstrongfixed{% + \footnotesize% + \bfseries% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooter{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterba{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterc{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterd{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfootere{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterf{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterg{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterh{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooteri{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemfooterj{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitle{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleba{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlec{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitled{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlee{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlef{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleg{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitleh{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlei{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystemtitlej{% + \small% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSsystitleandfootercontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasStable{% +} +\def\sasStitleandnotecontainer{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasStitlesandfooters{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSusertext{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarnbanner{% + \footnotesize% + \bfseries% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarncontent{% + \footnotesize% + \sffamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +\def\sasSwarncontentfixed{% + \footnotesize% + \ttfamily% + \color[rgb]{0,0,0}% + \columncolor[rgb]{1,1,1}% +} +% Set cell padding +\renewcommand{\arraystretch}{1.3} + +% Headings +\newcommand{\sasheading}[3][c]{{% + \if#1r\flushright\else\if#1l\flushleft\else\centering\fi\fi% + {\csname sasS#2\endcsname #3}\mbox{}\\[0.1\baselineskip]% + \if#1r\endflushright\else\if#1l\endflushleft\else\fi\fi% +}} + +\newcommand{\sasbyline}[2][c]{\sasheading[#1]{byline}{#2}} +\newcommand{\sassystemtitle}[2][c]{\sasheading[#1]{systemtitle}{#2}} +\newcommand{\sassystemfooter}[2][c]{\sasheading[#1]{systemfooter}{#2}} +\newcommand{\sasproctitle}[2][c]{\sasheading[#1]{proctitle}{#2}} +\newcommand{\sascaption}[2][l]{\marginpar[#1]{\fbox{\parbox{0.7in}{\sasScaption{#2}}}}} + +% Declare new verbatim type +\DefineVerbatimEnvironment{sasverbatim}{BVerbatim}% + {fontsize=\footnotesize, + commandchars=\\\{\}, + formatcom=\sasSbatch} + +% Declare new column types +\newcolumntype{S}[2]{>{\csname sasS#1\endcsname}#2} +\newcolumntype{d}{r} + +% Set warning box style +\newlength\notewidth +\setlength\notewidth{4in} +\newcommand*{\saswarn}[2][c]{\sasmsg{warn}{#1}{#2}} +\newcommand*{\saserror}[2][c]{\sasmsg{error}{#1}{#2}} +\newcommand*{\sasnote}[2][c]{\sasmsg{note}{#1}{#2}} +\newcommand*{\sasfatal}[2][c]{\sasmsg{fatal}{#1}{#2}} +\newcommand*{\sasmsg}[3]{% + \ifsas@color\let\columncolor\undefined\fi% + \begin{center}% + \begin{tabular}{ll}\hline% + \multicolumn{1}{|S{#1banner}{p{0.7in}}|}{#1} & % + \multicolumn{1}{|S{#1content}{p{\notewidth}}|}{#3{\newline}}\\\hline% + \end{tabular}% + \end{center}% + \ifsas@color\let\columncolor\sascolumncolor\fi% +} + +\ifsas@color\RequirePackage{colortbl}\fi + +% Hack colortbl to allow \columncolor in macros +\let\CT@extract@org\CT@extract +\def\CT@extract{\futurelet\CT@NEXT\CT@extract@next} +\def\CT@extract@next{% + \ifx\CT@NEXT\csname + \@ReturnAfterFi{% + \expandafter\expandafter\expandafter + }% + \fi + \CT@extract@org +} +\long\def\@ReturnAfterFi#1\fi{\fi#1} + +\ifsas@color + + \newcommand{\foreground}[1]{\color[rgb]{#1}} + \newcommand{\sascolumncolor}[2][]{} + \let\columncolor\sascolumncolor + \newcommand{\documentforeground}[1]{\AtBeginDocument{\color[rgb]{#1}}} + \newcommand{\documentbackground}[1]{\AtBeginDocument{\pagecolor[rgb]{#1}}} + \def\sastable{\let\columncolor\undefined\tabular} + \def\endsastable{\endtabular\let\columncolor\sascolumncolor} + \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular} + \def\endstackedcell{\endtabular\egroup} + +\else + + \providecommand{\foreground}[1]{} + \providecommand{\color}[2][]{} + \newcommand{\sascolumncolor}[2][]{} + \let\columncolor\sascolumncolor + \newcommand{\documentforeground}[1]{} + \newcommand{\documentbackground}[1]{} + \def\sastable{\tabular} + \def\endsastable{\endtabular} + \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular} + \def\endstackedcell{\endtabular\egroup} + +\fi + +%\let\sasgraph\includegraphics +% Scale graphics so they always fit on the page +\newcommand\sasgraph[2][]{% + \savebox{\sas@fig}{\includegraphics[#1]{#2}}% + \settowidth{\sas@figwidth}{\usebox{\sas@fig}}% + \ifthenelse{\lengthtest{\sas@figwidth > \textwidth}}{% + \resizebox{0.95\textwidth}{!}{\usebox{\sas@fig}}}{% + \usebox{\sas@fig}} +} + diff --git a/Testcases/statrep_macros.sas b/Testcases/statrep_macros.sas new file mode 100644 index 0000000..cd0ebe7 --- /dev/null +++ b/Testcases/statrep_macros.sas @@ -0,0 +1,1721 @@ + /*---------------------------------------------*/ + /* The WRITE macro displays one or more pieces */ + /* of output (tables, notes, graphs, and so */ + /* on) that were captured into an ODS document */ + /* by the OUTPUT macro. */ + /*---------------------------------------------*/ +%macro write(fname, /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* or \Graphic tag in the LaTeX file. The */ + /* following examples show where the fname */ + /* keyword, in this case 'crsi1a', is */ + /* specified in the WRITE macro and in the */ + /* \Listing tag: */ + /* */ + /* %*;%write(crsi1a, objects=inertias) */ + /* \Listing[caption={... caption ...}]{crsi1a} */ + /* */ + dest=, /* specifies destination: latex or listing. */ + /* Null uses the defaultdests macro. */ + /* */ + width=, /* specifies the width of graphs. */ + /* Example: WIDTH=5.4in. */ + height=, /* specifies the height of graphs. */ + /* Example: HEIGHT=4in. */ + /* */ + dpi=, /* specifies DPI (dots per inch) for ODS */ + /* Graphics. You typically would not use this */ + /* option except when you would otherwise run */ + /* out of memory. The default is 300 DPI, and */ + /* a reasonable alternative for ODS graphs */ + /* with large file sizes is 100 DPI. More */ + /* details follow. */ + /* */ + /* This option controls the DPI for ODS */ + /* Graphics. Use the DPI= option in the */ + /* OUTPUT macro to control the DPI for GRSEG */ + /* graphics. */ + /* */ + /* If DPI= is specified, that DPI is used. */ + /* If DPI= is not specified, and if a macro */ + /* variable DefaultDPI is defined, its value */ + /* is used as the DPI. If DPI= is not */ + /* specified and the macro variable DefaultDPI */ + /* is not defined or if its value is null, */ + /* then the default DPI, 300, is used. */ + /* */ + /* In other words, the default DPI is 300. */ + /* However, you can set the default DPI to */ + /* (say) 100 by putting the following at the */ + /* top of your first Sascode block, beginning */ + /* in column 1: */ + /* */ + /* %*;%let defaultdpi=100; */ + /* */ + /* Since the %LET statement is preceded by a */ + /* null macro comment (%*;) beginning in */ + /* column 1, it will not show up in the */ + /* SAS code listing, but it will affect the */ + /* capture program and change the default */ + /* DPI for the duration of the running of the */ + /* program. You can change the default DPI at */ + /* any time with a %LET statement. */ + /* */ + /* With GRSEG graphics, 100 DPI is not */ + /* available, so this specification creates */ + /* graphs at 96 DPI. */ + /* */ + store=, /* specifies the name of the ODS document */ + /* that is created by the OUTPUT macro. This */ + /* is the ODS document that the WRITE macro */ + /* will process. By default, when null, the */ + /* current document from the last OUTPUT macro */ + /* is used. If you are processing the last */ + /* document created, you can omit specifying */ + /* the STORE= option. To use some other */ + /* document, specify STORE=documentlabel. */ + /* */ + pattern=, /* provides an optional additional selection */ + /* criterion. Specify part of a path, for */ + /* example, a group name. Then only objects */ + /* whose name includes this group name are */ + /* used. Comparisons are not case sensitive. */ + /* The macro looks for an appearance of the */ + /* PATTERN=value anywhere in the path. For */ + /* example, PATTERN=fit, will match */ + /* "Reg.m2.Fit.Population.ParameterEstimates" */ + /* and anything else with "fit" in it */ + /* including paths that contain "fitplot", */ + /* "fitness", "outfit" and so on. */ + /*---------------------------------------------*/ + firstobj=, /* specifies the first data object. */ + lastobj=, /* specifies the last data object. */ + objects=, /* specifies the list of data objects. */ + /* */ + /* To specify which objects go into a section */ + /* of output, specify one of the following */ + /* combinations: */ + /* * FIRSTOBJ=, */ + /* * LASTOBJ=, */ + /* * FIRSTOBJ= and LASTOBJ=, */ + /* * OBJECTS=, */ + /* * none of the above. */ + /* */ + /* If FIRSTOBJ= is specified and LASTOBJ= is */ + /* not specified, then the last object is the */ + /* last object produced by the procedure. If */ + /* LASTOBJ= is specified and FIRSTOBJ= is not */ + /* specified, then the default first object is */ + /* the first object produced by the procedure. */ + /* If OBJECTS= is specified, then only objects */ + /* in that list are used. If none of these */ + /* options is specified then, all objects are */ + /* used. */ + /* */ + /* The term "object" used in this */ + /* discussion refers to notes, tables, and */ + /* graphs. Specify the first or last object */ + /* or list of objects (tables, notes, graphs). */ + /* All object name comparisons are case */ + /* insensitive. */ + /* */ + /* All selections are based on paths instead */ + /* of label paths. You can specify the last m */ + /* levels of the path. Assuming that you have */ + /* one model and one ANOVA table, any of the */ + /* following specifications for the ANOVA */ + /* object are equivalent, along with many */ + /* other possibilities: */ + /* */ + /* Reg.MODEL1.Fit.Population.ANOVA */ + /* reg.model1.fit.population.anova */ + /* reg#1.model1#1.fit#1.population#1.anova#1 */ + /* reg#1.model1.fit.population#1.anova#1 */ + /* MODEL1.Fit.Population.ANOVA */ + /* Fit.Population.ANOVA */ + /* Population.ANOVA */ + /* ANOVA */ + /* ANOVA#1 */ + /* */ + /* Typically, you need to specify only the */ + /* last level. If an object appears more than */ + /* once, then you might need to specify more */ + /* levels. The #n notation is allowed, even */ + /* in cases where it does not work in an ODS */ + /* SELECT statement. You must specify a name, */ + /* using the #n notation that matches the name */ + /* (or the last few levels of the name) as it */ + /* appears in the ODS document. For example, */ + /* if there are multiple residual panels, you */ + /* can specify OBJECTS=residualplot and */ + /* OBJECTS=residualplot#2. The object list */ + /* produced by the macro will show every place */ + /* that a #2 or #n (n > 1) is required. */ + /* */ + /* If you run a procedure more than once for */ + /* this ODS document, then you need #2 on the */ + /* procedure name for the second group. For */ + /* example, here are the fully-qualified names */ + /* from a set of two PROC REG runs: */ + /* */ + /* Reg.MODEL1.Fit.Fail.NObs */ + /* Reg.MODEL1.Fit.Fail.ANOVA */ + /* Reg.MODEL1.Fit.Fail.FitStatistics */ + /* Reg.MODEL1.Fit.Fail.ParameterEstimates */ + /* Reg#2.MODEL1.Fit.Fail.NObs */ + /* Reg#2.MODEL1.Fit.Fail.ANOVA */ + /* Reg#2.MODEL1.Fit.Fail.FitStatistics */ + /* Reg#2.MODEL1.Fit.Fail.ParameterEstimates */ + /* */ + /* The order in which objects come out is */ + /* determined by the order in which they are */ + /* generated, not the order in which they are */ + /* specified in the OBJECTS= option. */ + /* */ + /* If you specify OBJECTS=, then you can also */ + /* specify where page breaks can occur. By */ + /* default, breaks might occur between the */ + /* bottom of a table and the top of the note */ + /* or table that comes after it. If you want */ + /* anything different to occur, use left and */ + /* right angled brackets, <>, to start and end */ + /* a new group and suppress normal page */ + /* breaking in between. After a <, no default */ + /* page breaking occurs until a > is hit. A */ + /* page break occurs at the > and then in the */ + /* default places after that. You can use */ + /* "< list >" in pairs (for example, "" to keep certain objects */ + /* together. You can instead use > to cause */ + /* page breaks in addition to the default page */ + /* breaks. You can also use < to designate */ + /* page breaks and suppress all default page */ + /* breaking. A break always occurs before and */ + /* after a graph regardless of what <> */ + /* specification you use. */ + /*---------------------------------------------*/ + pagesize=, /* specifies the page size. The default is */ + /* the page size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current page size is */ + /* restored at the end. */ + linesize=, /* specifies the line size. The default is */ + /* the line size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current line size is */ + /* restored at the end. */ + /* */ + options=, /* specifies one or more binary options: */ + /* */ + /* LIST - do not run PROC DOCUMENT for */ + /* each group of objects. Just */ + /* list the contents of the */ + /* document. */ + /* */ + /* TABLE - (or TABLES) selects only tables */ + /* and notes (more specifically, */ + /* anything but graphs). */ + /* */ + /* GRAPH - only selects graphs. */ + /* */ + /* NOPAGE - no page breaks at the top of */ + /* tables. */ + /* */ + /* NEWPAGE - forces a page break on the first */ + /* object. */ + /* */ + /* AUTOPAGE - same page breaks that the */ + /* procedure makes. There is a */ + /* page break on the first object */ + /* and where the proc forces a new */ + /* page. AUTOPAGE is the default. */ + /* */ + /* ONEBOX - is used with the \Listing tag */ + /* and specifies that only one */ + /* block of tables is made. This */ + /* option strips out all '<>' */ + /* characters from the OBJECTS= */ + /* list and adds a '<' to the */ + /* beginning of the list. With */ + /* FIRSTOBJ= or LASTOBJ= or no */ + /* OBJECTS= list, the effect is the */ + /* same even though the mechanism */ + /* is different. If anything other */ + /* than only tables or a single */ + /* graph is input, an error is */ + /* issued along with the object */ + /* list. */ + /* */ + /* SKIPFIRST- deletes the first object that */ + /* would otherwise be selected. */ + /* Typical usage is with FIRST= */ + /* to select every object after the */ + /* one that was named. */ + /* */ + /* SKIPLAST - deletes the last object that */ + /* would otherwise be selected. */ + /* Typical usage is with LAST= to */ + /* select every object before the */ + /* one that was named. */ + /* */ + /* Example: OPTIONS=TABLE ONEBOX. */ + /* */ + style=, /* specifies the ODS style for ODS Graphics. */ + /* Use the STYLE= option in the OUTPUT macro */ + /* to control the style for GRSEG graphics. */ + /* If STYLE= is specified, that style is used. */ + /* If STYLE= is not specified, and if a macro */ + /* variable DefaultStyle is defined, its value */ + /* is used as the style. If STYLE= is not */ + /* specified and the macro variable */ + /* DefaultStyle is not defined or if its value */ + /* is null, then the default style (which is */ + /* the HTMLBLUE style) is used. */ + /* */ + /* In other words, the default style is the */ + /* HTMLBLUE style. However, you can set the */ + /* default style to (say) LISTING by putting */ + /* the following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultstyle=listing; */ + /* */ + /* Since this line begins with a null macro */ + /* comment (%*;) that begins in column 1, it */ + /* will not show up in the SAS code listing, */ + /* but it will affect the capture program and */ + /* change the default style for the duration */ + /* of the running of the program. */ + /* */ + type=);; /* specifies the type of objects to select. */ + /* \Listing specifies TYPE=LISTING, which is */ + /* an alias for OPTIONS=TABLE. */ + /* \Graphic specifies TYPE=GRAPH, which is an */ + /* alias for OPTIONS=GRAPH. */ + /*---------------------------------------------*/ + +%local i j k flow error savenote holdlast allobjflag firstflag onlylist + lastflag rangeflag objflag ngroups h onebox isgraph savesize + left tyw stw grw abnormal selecttype savetime kl kh jl jh ls + pagebreak gdevice skipfirst skiplast; + +%let abnormal = 0; +%let error = 0; +%let savenote = %sysfunc(getoption(notes)); +%let savetime = %sysfunc(getoption(stimer)); +%let savesize = ls=%sysfunc(getoption(ls)) ps=%sysfunc(getoption(ps)); +%let holdlast = &syslast; +%let graphtype = %qlowcase(&graphtype); +%if %nrbquote(&graphtype) ne pdf %then %let graphtype = png; + +options nostimer %if &pagesize ne %then ps=&pagesize; + %if &linesize ne %then ls=&linesize;; + +%if %symexist(adsflow) %then %let flow = %lowcase(&adsflow); + +* Set the default style using STYLE= and a DefaultStyle macro variable.; +%if &style eq %then %let style = &defaultstyle; + +* Set the default DPI using DPI= and a DefaultDPI macro variable.; +%if &dpi eq %then %let dpi = &defaultDPI; + +%let gdevice = %substr(png300, 1, 3 * (1 + (&dpi eq 300))); +%if %nrbquote(&graphtype) eq pdf %then %let gdevice = pdf; + +* Find out what is in the document. Store the list in a SAS data set.; +%if %symexist(documentlabel) %then %do; + %if %nrbquote(&store) eq %then %let store = &documentLabel; + %end; + +%if %nrbquote(&store) eq %then %do; + %put ERROR: No ODS document available.; + %let error = 1; + %goto veryend; + %end; +%else %put NOTE: Processing document &store..; + +%if not %index(&flow, notes) %then %do; options nonotes; %end; + +ods document close; run; +ods _all_ close; + +proc document name=&store; + ods output properties=_ads_doclist(where=(not (type eq "Dir" or + (type =: 'R' and index(type, 'p.'))))); + list / details levels=all; + run; quit; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; +ods listing ; + +data _null_; + call symputx('ls', getoption('ls'), 'L'); + if 0 then set _ads_doclist nobs=nprts; + if nprts eq 0 then do; + put "ERROR: Document &store does not exist."; + call symputx('error', '1', 'L'); + end; + + length fname $ 40 c $ 1; + fname = symget('fname'); + c = substr(fname, length(fname), 1); + if '0' le c le '9' then do; + put 'ERROR: The name ' fname 'is invalid. It must not end in a numeral.'; + call symputx('error', '1', 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + stop; + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; + +* Basic option setting, checking, and processing.; +data _null_; + length c $ 1 c2 $ 2 firstobj lastobj options type $ 200 objects $ 32500; + + w = symget('width'); + if w = ' ' then w = '6.4in'; + h = symget('height'); + if h = ' ' then + call symputx('h', trim(put(0.75 * input(translate(lowcase(w), ' ', + 'incm'), 12.), best12.)) || substr(w, length(w) - 1, 2), 'L'); + else call symputx('h', trim(h), 'L'); + + options = lowcase(symget('defaultdests')); + options = compbl(options); + call symputx('defaultdests', options, 'G'); + i = index(options, 'listing'); if i then substr(options, i, 7) = ' '; + i = index(options, 'latex'); if i then substr(options, i, 5) = ' '; + + if options ne ' ' then do; + put 'ERROR: %LET ' "DEFAULTDESTS=&defaultdests is invalid."; + put 'WARNING: Choose from: listing latex.'; + call symputx('error', '1', 'L'); + end; + + options = lowcase(symget('dest')); + options = compbl(options); + + if not (options eq ' ' or options eq 'listing' or options eq 'latex') then do; + put "ERROR: DESTS=&dest is invalid."; + put 'WARNING: Choose from: listing latex.'; + call symputx('error', '1', 'L'); + end; + if options eq ' ' then options = symget('defaultdests'); + call symputx('dest', options, 'L'); + + * Flag which options were specified.; + + type = lowcase(symget('type')); + options = lowcase(symget('options')); + + tx = index(type , 'tables'); if tx then substr(type , tx, 6) = ' '; + tt = index(type , 'table'); if tt then substr(type , tt, 5) = ' '; + tl = index(type , 'listing'); if tl then substr(type , tl, 7) = ' '; + t1 = index(type , 'graphics'); if t1 then substr(type , t1, 8) = ' '; + t2 = index(type , 'graphic'); if t2 then substr(type , t2, 7) = ' '; + t3 = index(type , 'graphs'); if t3 then substr(type , t3, 6) = ' '; + t4 = index(type , 'graph'); if t4 then substr(type , t4, 5) = ' '; + no = index(options, 'nopage'); if no then substr(options, no, 6) = ' '; + nw = index(options, 'newpage'); if nw then substr(options, nw, 7) = ' '; + ap = index(options, 'autopage'); if ap then substr(options, ap, 8) = ' '; + li = index(options, 'listing'); if li then substr(options, li, 7) = ' '; + ls = index(options, 'list'); if ls then substr(options, ls, 4) = ' '; + ty = index(options, 'tables'); if ty then substr(options, ty, 6) = ' '; + ta = index(options, 'table'); if ta then substr(options, ta, 5) = ' '; + ob = index(options, 'onebox'); if ob then substr(options, ob, 6) = ' '; + g1 = index(options, 'graphics'); if g1 then substr(options, g1, 8) = ' '; + g2 = index(options, 'graphic'); if g2 then substr(options, g2, 7) = ' '; + g3 = index(options, 'graphs'); if g3 then substr(options, g3, 6) = ' '; + g4 = index(options, 'graph'); if g4 then substr(options, g4, 5) = ' '; + sf = index(options, 'skipfirst'); if sf then substr(options, sf, 9) = ' '; + sl = index(options, 'skiplast'); if sl then substr(options, sl, 8) = ' '; + + if options ne ' ' then do; + options = compbl(options); + put 'WARNING: WRITE macro OPTIONS=' options 'is invalid and is ignored.'; + end; + + if type ne ' ' then do; + type = compbl(type); + put 'WARNING: WRITE macro TYPE=' type 'is invalid and is ignored.'; + end; + + table = ta or ty or li or tt or tx or tl; + graph = g1 or g2 or g3 or g4 or t1 or t2 or t3 or t4; + + if no then call symputx('pagebreak', 'nopage'); + else if nw then call symputx('pagebreak', 'newpage'); + else call symputx('pagebreak', 'autopage'); + + call symputx('onlylist', ls ne 0, 'L'); + call symputx('onebox', ob, 'L'); + call symputx('isgraph', graph, 'L'); + call symputx('selecttype', ob or table or graph, 'L'); + call symputx('skipfirst', sf ne 0, 'L'); + call symputx('skiplast', sl ne 0, 'L'); + + if table and graph then do; + put "ERROR: TYPE=&type and OPTIONS=&options conflict."; + put "ERROR: Both tables and graphs were selected."; + call symputx('error', '1', 'L'); + end; + + * Process object names.; + firstobj = symget('firstobj'); + lastobj = symget('lastobj'); + objects = lowcase(symget('objects')); + if ob then objects = '<' || compbl(translate(objects, ' ', '<>')); + + call symputx('ngroups', '0', 'L'); + call symputx('pattern', lowcase(symget('pattern')), 'L'); + call symputx('firstobj', lowcase(firstobj), 'L'); + call symputx('lastobj', lowcase(lastobj), 'L'); + call symputx('objects', objects, 'L'); + + if (firstobj ne ' ' or lastobj ne ' ') and objects ne ' ' then do; + put 'ERROR: OBJECTS= may not be specified with FIRSTOBJ= and LASTOBJ=.'; + call symputx('error', '1', 'L'); + end; + + * Remove extra spaces and funkiness around < and >.; + if objects ne ' ' then do; + objects = ' ' || compbl(objects); + + * Get rid of trailing open brackets.; + done = 0; + do i = 1 to 32500 until(done); + l = length(objects); + if substr(objects, l, 1) eq '<' then substr(objects, l, 1) = ' '; + else done = 1; + end; + + * Get rid of multiple contiguous brackets.; + c = ' '; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 1); + if (c eq '<' and c2 eq '<') or + (c eq '>' and c2 eq '>') then substr(objects, i, 1) = ' '; + c2 = substr(objects, i, 1); + if not (c2 eq ' ' or c2 eq '<' or c2 eq '>') then c = ' '; + else if c2 eq '<' or c2 eq '>' then c = c2; + end; + end; + objects = ' ' || compbl(objects); + + * Move brackets next to names. + For example, change '< name' to '' to 'name>'.; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 2); + if c2 eq '< ' then substr(objects, i, 2) = ' <'; + if c2 eq ' >' then substr(objects, i, 2) = '> '; + c2 = substr(objects, i, 1); + if c2 eq '<' then do; + c = substr(objects, i - 1, 1); + if c ne ' ' then objects = substr(objects, 1, i - 1) || + ' <' || substr(objects, i + 1); + i + 1; + end; + else if c2 eq '>' then do; + c = substr(objects, i + 1, 1); + if c ne ' ' then objects = substr(objects, 1, i - 1) || + '> ' || substr(objects, i + 1); + i + 1; + end; + end; + end; + + * Get rid of null bracket groups.; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 2); + if c2 eq '<>' then substr(objects, i, 2) = ' '; + end; + end; + objects = compbl(left(objects)); + + * Get rid of leading close brackets.; + if objects =: '>' then objects = substr(objects, 2); + + call symputx('objects', left(compbl(objects)), 'L'); + end; + + call symputx('allobjflag', (firstobj eq ' ' and lastobj eq ' ' and + objects eq ' '), 'L'); + call symputx('firstflag', (firstobj eq ' ' and lastobj ne ' '), 'L'); + call symputx('lastflag' , (firstobj ne ' ' and lastobj eq ' '), 'L'); + call symputx('rangeflag', (firstobj ne ' ' and lastobj ne ' '), 'L'); + call symputx('objflag' , (objects ne ' '), 'L'); + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; + +data _ads_doclist(drop=i p); + set _ads_doclist; + + /*-------------Translate: Special characters not shown------------- + English German Spanish French Italian + Batch Batch Batch Traitement par lots Batch + Crosstab Kreuztabelle TablaCruzada Table a double entr*e Campi incr. + Dir Dir Dir R�p. Dir + File file Archivo Fichier File + Graph Grafik Gr*fico Graphique Grafico + Note Hinweis Nota Note Nota + Report Bericht Informe Rapport Report + Table Tabelle Tabla Tableau Tabella + Text Text Texto Texte Testo + Tree Baum *rbol Arbre Struttura + */ + + if trim(type) in ('Hinweis', 'Nota') then type = 'Note'; + else if type =: 'Kreuz' or type =: 'Tabla' or type =: 'Campi' or + index(trim(type), 'double') then type = 'Crosstab'; + else if type =: 'Tab' then type = 'Table'; + else if type =: 'Gra' then type = 'Graph'; + else if type =: 'Traite' then type = 'Batch'; + else if type =: 'Te' then type = 'Text'; + else if type =: 'Fi' or type =: 'fi' or type =: 'Archi' then type = 'File'; + else if trim(type) in ('Bericht', 'Informe', 'Rapport') then type ='Report'; + else if trim(type) in ('Baum', 'Arbre', 'Struttura') or index(type, 'rbol') + then type ='Tree'; + + ObjNum = _n_; + * The variable ourpath is used for group subsetting and display in the SAS log. + It is not used for actual selection (beyond group selection).; + ourpath = substr(translate(path, '.', '\'), 2); + do i = 1 to length(ourpath) until(p eq 0); + p = index(ourpath, '#1.'); + if p then substr(ourpath, p, 3) = '. '; + end; + ourpath = compress(ourpath, ' '); + p = length(ourpath) - 1; + if substr(ourpath, p, 2) eq '#1' then substr(ourpath, p, 2) = ' '; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +* Get object names specified in FIRSTOBJ=, LAST=, and OBJECTS= for error checking.; +%if not &allobjflag %then %do; + data _ads_objects(keep=object); + length l $ 32500 object $ 200; + l = symget('firstobj') || ' ' || symget('lastobj') || ' ' || symget('objects'); + do i = 1 to 32500 until(object eq ' '); + object = scan(l, i, ' <>'); + if object ne ' ' then output; + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + * Make sure every specified name is referenced.; + data _null_; + set _ads_objects; + length object holdobj $ 200; + holdobj = object; + + * Store object name with pounds and such to match document.; + %ads_expand_obj(object, holdobj) + + match = 0; + do i = 1 to nprts until(match); + set _ads_doclist nobs=nprts point=i; + + * If object has n levels, store in pathpart the last n levels from path.; + %ads_extr_path(pathpart, path, holdobj) + match = (pathpart eq object); + end; + if not match then do; + put 'ERROR: Object ' holdobj 'not found.'; + call symputx('error', '1', 'L'); + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Extract the relevant tables and notes from the list.; +data _ads_select(keep=path type left right object ourpath label pagebreak); + length objlist $ 32500 fullqualobj object firstlist lastlist $ 200; + retain object firstlist lastlist objlist ' ' inflag 0 objind 1; + set _ads_doclist; + + if type eq 'Report' and label =: 'Data Set ' and path =: '\Print' + then label = substr(label, 10); + else do; + label = ' '; + if type eq 'Report' then type = 'rpt'; + end; + + left = 0; right = 0; fullqualobj = ' '; + + if _n_ eq 1 then do; + firstlist = symget('firstobj'); + lastlist = symget('lastobj'); + objlist = symget('objects'); + end; + + * Perform preliminary subsetting based on group patterns.; + %if %nrbquote(&pattern) ne %then %do; + if index(lowcase(ourpath), "&pattern"); + %end; + + righttype = 1; + if &selecttype then righttype = (( &isgraph and type eq 'Graph') or + (not &isgraph and type ne 'Graph')); + + %* Are only the last ones selected (FIRSTOBJ= specified)?; + %if &lastflag and not &allobjflag %then %do; + %ads_extr_path(pathpart, path, firstlist) + %ads_expand_obj(fullqualobj, firstlist) + if pathpart eq fullqualobj then inflag = 1; + if inflag and righttype then output; + %end; + + %* Are only the first ones selected (LASTOBJ= specified)?; + %else %if &firstflag and not &allobjflag %then %do; + if _n_ eq 1 then inflag = 1; + %ads_extr_path(pathpart, path, lastlist) + %ads_expand_obj(fullqualobj, lastlist) + if inflag and righttype then output; + if pathpart eq fullqualobj then inflag = 0; + %end; + + %* Is a range being selected (FIRSTOBJ= and LASTOBJ= specified)?; + %else %if &rangeflag and not &allobjflag %then %do; + %ads_extr_path(pathpart, path, firstlist) + %ads_expand_obj(fullqualobj, firstlist) + if pathpart eq fullqualobj then inflag = 1; + %ads_extr_path(pathpart, path, lastlist) + %ads_expand_obj(fullqualobj, lastlist) + if inflag and righttype then output; + if pathpart eq fullqualobj then inflag = 0; + %end; + + %* Is a list being selected (OBJECTS= specified)?; + %else %if &objflag and not &allobjflag %then %do; + do i = 1 to 32500 until(object eq ' '); + object = scan(objlist, i, ' '); + + if object ne ' ' then do; + + * For an object has n levels, + store in pathpart the last n levels from the path.; + %ads_extr_path(pathpart, path, object) + + left = 0; right = 0; + if substr(object, 1, 1) eq '<' then do; + left = 1; + object = substr(object, 2); + end; + if substr(object, length(object), 1) eq '>' then do; + right = 1; + object = substr(object, 1, length(object) - 1); + end; + + * Store the object name with pounds and such to match the document.; + %ads_expand_obj(fullqualobj, object) + + if fullqualobj eq pathpart then do; + if righttype then output; + object = ' '; + end; + end; + end; + %end; + + %* Is everything selected?; + %else %do; + if righttype then output; + %end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + +* Omit the first or last object from the selection list with SKIPFIRST or SKIPLAST.; +%if &skipfirst or &skiplast %then %do; + data _ads_select; + set _ads_select end=eof; + + %if &skipfirst %then %do; if _n_ = 1 then delete; %end; + %if &skiplast %then %do; if eof then delete; %end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Set page breaks.; +data _ads_select(keep=path type left right object ourpath group label pagebreak); + set _ads_select end=eof; + retain Group 1 oldgroup anyleft 0; + if type in ('Graph', 'Report', 'rpt') then do; + left = 1; right = 1; + if type eq 'Graph' then ngraphs + 1; + end; + if left then do; + group = oldgroup + (not &onebox); + if &onebox and group eq 0 then group = 1; + anyleft = 1; + end; + oldgroup = group; + output; + if right then anyleft = 0; + + other + (type in ('Note', 'Report', 'rpt')); + tabtype = (type in ('Table', 'Tree', 'Batch', 'Crosstab', 'Text')); + if tabtype then ntabs + 1; + if right or (not anyleft and tabtype) then group = oldgroup + (not &onebox); + + if eof and &onebox and &isgraph and ((ntabs + other) or ngraphs ne 1) then do; + put 'ERROR: The Graphic tag must select ' + 'only one graph and nothing ' "else in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if eof and &onebox and not &isgraph and ((ntabs + other) lt 1 or ngraphs) + then do; + put 'ERROR: The Listing tag must select tables and no graphs ' + "in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if not &onlylist and eof and + not &onebox and (ntabs + other) and ngraphs then do; + put 'ERROR: You may request either tables or graphs but not both ' + "in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +%if %index(&flow, print) %then %do; + proc print; var path type group object; run; + proc print; var ourpath type group object; run; + %end; + +* Check for objects that match multiple document pieces.; +%if not &allobjflag %then %do; + proc sort data=_ads_select out=_ads_objects; + by object; + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + data _null_; + set _ads_objects; + by object; + if object ne ' ' and not (first.object and last.object) then do; + put 'ERROR: Multiple matches. Object ' object + 'matches ' ourpath +(-1)'.'; + call symputx('error', '1', 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Clear out titles, subtitles, and footnotes as necessary. Build rendering code.; +options nosource; + +data _null_; + length list $ 32500; + retain list ' ' forcepage &&__New_&store; + set _ads_select end=end; + by group; + if _n_ eq 1 then call execute("proc document name=&store;"); + + list = trim(list) || ' or _path_ = "' || trim(path) || '"'; + + %if &pagebreak eq autopage %then %do; /* default */ + first = pagebreak; + if type ne 'Graph' then do; + first = (first or forcepage); + forcepage = 0; + end; + %end; + %else %if &pagebreak eq nopage %then %do; + first = 0; + %end; + %else %do; /* new page */ + first = ((_n_ eq 1) or pagebreak); + %end; + + if first and type ne 'Graph' then put 'Note: New page for ' path; + + if first then call execute("obfootn " || path || ';'); + else if end then call execute('obtitle ' || path || '; obstitle ' || + path || '; run; quit;'); + else call execute('obfootn ' || path || '; obstitle ' || path || + '; obtitle ' || path || ';'); + + if last.group then do; + list = substr(list, 5); + call symputx('_list' || left(put(group, 5.)), trim(list), 'L'); + call symputx('_gtype' || left(put(group, 5.)), put(type, $1.), 'L'); + call symputx('ngroups', group, 'L'); + if type eq 'Report' then + call symputx('_data' || left(put(group, 5.)), trim(label), 'L'); + list = ' '; + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +options source &savenote; + +%let __new_&store = 0; + +%if &onebox and &ngroups ne 1 and not &abnormal %then %do; + %if &isgraph %then %let i = Graphic; + %else %let i = Listing; + %put ERROR: There must be exactly one group of objects with &i..; + %let onlylist = 1; + %let abnormal = 1; + %end; + +* Render each group of data objects.; +%if not &onlylist %then %do; + ods _all_ close; + ods graphics / reset=index imagename=""; + + %let kl = 0; %let kh = 0; + %do i = 1 %to &ngroups; + + %if %symexist(_list&i) %then %do; + %if &kl eq 0 %then %let jl = ; %else %let jl = &kl; + %if &kh eq 0 %then %let jh = ; %else %let jh = &kh; + %let kl = %eval(&kl + 1); + %let kh = %eval(&kh + 1); + + %if &&_gtype&i eq G %then %do; /* if graph replay */ + %if %nrbquote(&graphtype) eq pdf %then %do; + %if (%nrbquote(&sysver) < 9.3) %then %do; + %put WARNING: ODS PDF Graphics are unavailable in SAS 9.2; + %put WARNING: Generating PNG format in "png" directory.; + %let graphtype=png; + %let graphicdir=png; + %end; + %end; + + ods listing style=&style image_dpi=&dpi gpath="&graphicdir"; + ods graphics / reset=index imagename="&fname&jl" &odsgraphopts + %if %nrbquote(&width) ne %then width=&width; + %if %nrbquote(&height) ne %then height=&height; + %if %nrbquote(&graphtype) eq pdf %then outputfmt=pdf;; + + %if %sysprod(graph) = 1 %then %do; + goptions dev=&gdevice fileonly gsfname=gsasfile gsfmode=replace + hsize= + %if %nrbquote(&width) ne %then &width; + %else 6.4in; + vsize=&h border; + %end; + filename gsasfile "&graphicdir/&fname&jl..&graphtype"; + %put NOTE: Writing Graph file: &graphicdir/&fname&jl..&graphtype; + %end; + %else %do; + %if %index(&dest, listing) %then %do; + FILENAME LISTTMP "&listingdir/_tmp" ENCODING="&SASencodingTex."; + ODS LISTING FILE=LISTTMP ; + %end; + %if %index(&dest, latex) %then %do; + ods tagsets.statrep style=&latexstyle + file="&latexdir/&fname&jh..tex" (notop nobot) + stylesheet="&rootdir/sas.sty" + newfile=output + encoding="&SASencodingTex."; + %end; + %end; + %if not %index(&flow, notes) %then %do; options nonotes; %end; + proc document name=&store; + replay ^(where=(&&_list&i)) / levels=all; + run; quit; + %if &syserr > 4 %then %let error = 1; + %if &error %then %goto endit; + options &savenote; + %if &&_gtype&i eq G %then %do; /* if graph replay */ + filename gsasfile "&graphicdir/_tmp.&graphtype"; + %end; + ods _all_ close; + ods graphics / reset=index imagename="" reset=width reset=height; + %if &&_gtype&i ne G and /* if not graph */ + %index(&dest, listing) %then %do; + /* break up big listing files */ + options nonotes; + data _null_; + retain kl &jl; + length fn $ 200; + infile "&listingdir/_tmp" lrecl=%eval(&ls+1) pad; + input line $char%eval(&ls+1).; + page = substr(line, 1, 1) eq '0C'x; + if _n_ eq 1 or page then do; + fn = "&listingdir/&fname"; + if page then line = substr(line, 2); + if kl then fn = compress(fn || put(kl, 5.) || '.lst'); + else fn = compress(fn || '.lst'); + kl + 1; + call symputx('kl', kl, 'L'); + put 'Note: Writing Listing file : ' fn; + filename outlst "&listingdir/&fname..lst" encoding="&SASEncodingTex."; + end; + file outlst nopad ; + l = length(line); + put line $varying. l; + if _error_ then call symputx('error', '1', 'L'); + run; + filename outlst clear; + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + options &savenote; + %end; + %end; + %end; + ods listing; +%end; + +%if &ngroups eq 0 %then %do; + %put ERROR: No objects selected.; + %let error = 1; + %goto endit; + %end; + +%if not %index(&flow, notes) %then %do; options nonotes; %end; + +proc sort data=_ads_doclist; by path; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +proc sort data=_ads_select; by path; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +data _ads_doclist; + merge _ads_doclist(in=dl) _ads_select(keep=path group in=s); + by path; + if s then Status = 'Selected'; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +proc sort data=_ads_doclist; by objnum; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +%endit:; + +* Get some formatting information for rendering the document contents list.; +data _null_; + set _ads_doclist end=eof; + left = max(left, length(ourpath)); + tyw = max(tyw, length(type)); + if eof then do; + left + 1; tyw + 1; stw = 9; grw = 5; + atright = min(&ls - tyw - stw - grw - 1, left + 3); + call symputx('atright', atright, 'L'); + call symputx('tyw', tyw, 'L'); + call symputx('stw', stw, 'L'); + call symputx('grw', grw, 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; + +* Render the document contents list, wrapping the path if necessary.; +data _null_; + length p $ 500; + status = ' '; group = .; + file log; + set _ads_doclist; + ghead = 'Group'; thead = 'Type'; shead = 'Status'; + if _n_ eq 1 then put / 'Objects' + @&atright thead $&tyw.. + @%eval(&atright+&tyw) shead $&stw.. + @%eval(&atright+&tyw+&stw) ghead $&grw.. /; + do j = 1 to 100 while(ourpath ne ' '); + do l = &atright - 2 to &atright / 2 by -1 + while(not (substr(ourpath, l, 1) in ('.', ' '))); + end; + p = substr(ourpath, 1, l); + if j eq 1 then + put p $%eval(&atright-2). +1 type $&tyw.. status $&stw.. group 3.; + else put p $%eval(&atright-2).; + ourpath = substr(ourpath, l + 1); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; + +%veryend:; + +* Clean up.; +%if not %index(&flow, notes) %then %do; options nonotes; %end; +proc datasets nolist; delete _ads_select _ads_doclist _ads_objects; run; quit; + +%if &syserr > 4 %then %let error = 1; + +%let syslast = &holdlast; +%if &error or &abnormal %then %put ERROR: Macro write ended abnormally.; +run; + +filename __f1 "&listingdir/_tmp"; +filename __f2 "&graphicdir/_tmp.&graphtype"; +data _null_; rc = fdelete('__f1'); rc = fdelete('__f2'); run; + +options obs=max nosyntaxcheck &savenote &savetime &savesize; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The OUTPUT macro opens an ODS document and */ + /* captures output until it encounters an */ + /* ENDOUTPUT macro or a WRITE macro. */ + /*---------------------------------------------*/ +%macro output(label, /* is a required keyword that specifies the */ + /* ODS document name. This is used in the */ + /* STORE= option in the WRITE macro and in */ + /* \Listing and \Graphic tags. */ + /* */ + style=, /* specifies the ODS style for GRSEG graphics. */ + /* Use the STYLE= option in the WRITE macro to */ + /* control the style for ODS Graphics. If */ + /* STYLE= is specified, that style is used. */ + /* If STYLE= is not specified, and if a macro */ + /* variable DefaultStyle is defined, its value */ + /* is used as the style. If STYLE= is not */ + /* specified and the macro variable */ + /* DefaultStyle is not defined or if its value */ + /* is null, then the default style (which is */ + /* the HTMLBLUE style) is used. */ + /* */ + /* In other words, the default style is the */ + /* HTMLBLUE style. However, you can set the */ + /* default style to (say) LISTING by putting */ + /* the following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultstyle=listing; */ + /* */ + /* Since this line begins with a null macro */ + /* comment (%*;) in column 1, it will not show */ + /* up in the SAS code listing, but it will */ + /* affect the capture program and change the */ + /* default style for the duration of the */ + /* running of the program. */ + /* */ + dpi=);; /* specifies DPI (dots per inch) for GRSEG */ + /* graphics. You typically would not use this */ + /* except when you would otherwise run out of */ + /* memory. The default is 300 DPI, and a */ + /* reasonable alternative for GRSEG graphs */ + /* with a large file size is 96 DPI. More */ + /* details follow. */ + /* */ + /* With GRSEG graphics, you do not have */ + /* continuous control over DPI as you do with */ + /* ODS Graphics. With the macro default DPI */ + /* of 300, you get 300 DPI. Otherwise, you */ + /* get the device default of 96 DPI. */ + /* */ + /* This option controls the DPI for GRSEG */ + /* graphics. Use the DPI= option in the WRITE */ + /* macro to control the style for ODS */ + /* Graphics. If DPI= is specified, that DPI */ + /* is used. If DPI= is not specified, and if */ + /* a macro variable DefaultDPI is defined, its */ + /* value is used as the DPI. If DPI= is not */ + /* specified and the macro variable DefaultDPI */ + /* is not defined or if its value is null, */ + /* then the default DPI (300) is used. */ + /* */ + /* In other words, the default DPI is 300. */ + /* However, you can set the default DPI for */ + /* GRSEG graphics to 96 by putting the */ + /* following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultdpi=100; */ + /* */ + /* This is not a typo. If you set the default */ + /* DPI to anything other than 300, you get 96 */ + /* DPI with GRSEG graphics and the specified */ + /* value with ODS Graphics. With ODS */ + /* Graphics, the values of 300 and 100 are */ + /* most commonly used. */ + /* */ + /* Since the %LET statement is preceded by a */ + /* null macro comment (%*;) in column 1, it */ + /* will not show up in the SAS code listing, */ + /* but it will affect the capture program and */ + /* change the default DPI for the duration of */ + /* the running of the program. You can change */ + /* DPI at any time with one of these */ + /* statements. */ + /*---------------------------------------------*/ + +%local log lst savenote gdevice; + +* Set the default style using STYLE= and a DefaultStyle macro variable; +%if &style eq %then %let style = &defaultstyle; + +* Set the default DPI using DPI= and a DefaultDPI macro variable; +%if &dpi eq %then %let dpi = &defaultDPI; + +%let graphtype = %qlowcase(&graphtype); +%if %nrbquote(&graphtype) ne pdf %then %let graphtype = png; +%let gdevice = %substr(png300, 1, 3 * (1 + (&dpi eq 300))); +%if %nrbquote(&graphtype) eq pdf %then %let gdevice = pdf; + +%if not (&dpi eq 96 or &dpi eq 100 or &dpi eq 300) + %then %put NOTE: DPI=96 will be used for GRSEG graphics.; + +%let savenote = %sysfunc(getoption(notes)); +%if %sysfunc(symexist(_ads_debug)) %then %do; + %let log = 0; + %let lst = 0; + %let _ads_debug = %lowcase(&_ads_debug); + %if %index(&_ads_debug, flowall) %then %do; + %let log = 1; + %let lst = 1; + %end; + %else %if %index(&_ads_debug, flowlog) %then %let log = 1; + %else %if %index(&_ads_debug, flowlst) %then %let lst = 1; + %if &log or &lst %then %do; + ods listing; + data _null_; + %if &log %then %do; put "Begin Sascode block ""&label""."; %end; + %if &lst %then %do; + file print; + put _page_; + put "Begin Sascode block ""&label""."; + %end; + run; + %end; + %end; + +run; quit; + +options nonotes; +libname mydir '.'; +options nodate nonumber obs=max nosyntaxcheck; +%global documentlabel; + +ods _all_ close; +ods document close; + +data _null_; call symputx("__New_&label", '1', 'G'); run; + +proc datasets nolist nowarn; + delete gseg(memtype=catalog); + run; quit; + +proc datasets nolist nowarn library=sasuser; + delete __&label(memtype=catalog); + run; quit; + +* Select the style for GRSEG graphics.; +ods listing style=&style file="&listingdir/_tmp"; +ods listing select none; +filename __f "&listingdir/_tmp"; +data _null_; rc = fdelete('__f'); run; + +* Set the global label, and open the ODS Document.; +%let documentLabel = &label; +ods document name = &label(write) cat=sasuser.__&label; + +* Specify 300 DPI for GRSEG graphics (gdevice = png or png300).; +%if %sysprod(graph) = 1 %then %do; + goptions dev=&gdevice fileonly gsfname=gsasfile gsfmode=replace border; +%end; +filename gsasfile "&graphicdir/_tmp.&graphtype"; +options &savenote; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The ENDOUTPUT macro ends output capture. */ + /*---------------------------------------------*/ +%macro endoutput(label);;/* specifies the ODS document name. This is */ + /* used only to display program flow */ + /* information in the SAS log when the macro */ + /* variable _ads_debug is defined. */ + /*---------------------------------------------*/ + +run; quit; +options obs=max nosyntaxcheck; +ods document close; + +%local log lst; + +%if %sysfunc(symexist(_ads_debug)) %then %do; + %let log = 0; + %let lst = 0; + %let _ads_debug = %lowcase(&_ads_debug); + %if %index(&_ads_debug, flowall) %then %do; + %let log = 1; + %let lst = 1; + %end; + %else %if %index(&_ads_debug, flowlog) %then %let log = 1; + %else %if %index(&_ads_debug, flowlst) %then %let lst = 1; + %if &log or &lst %then %do; + ods listing; + data _null_; + %if &log %then %do; put "End Sascode block ""&label""."; %end; + %if &lst %then %do; + file print; + put "End Sascode block ""&label""."; + put _page_; + %end; + run; + %end; + %end; +ods _all_ close; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The STARTLIST macro starts the capture of */ + /* listing output. Use this macro when you */ + /* want to program your own output capture */ + /* (for example, when you want to show only */ + /* part of a table). */ + /*---------------------------------------------*/ +%macro startlist(fname, /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* tag. */ + /* */ + pagesize=, /* specifies page size. The default is the */ + /* page size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current page size is */ + /* restored at the end. */ + linesize=);;/* specifies line size. The default is the */ + /* line size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current line size is */ + /* restored at the end. */ + /*---------------------------------------------*/ + +%global _ads_printfname _ads_savesize; +%let _ads_printfname = &fname; +%let _ads_savesize = ls=%sysfunc(getoption(ls)) ps=%sysfunc(getoption(ps)); +quit; +ods _all_ close; +ods document close; +options nodate nonumber %if &pagesize ne %then ps=&pagesize; + %if &linesize ne %then ls=&linesize;; +ods listing file="&listingdir/_tmp"; +%mend; + + /*---------------------------------------------*/ +%macro endlist;; /* The ENDLIST macro ends the capture of */ + /* listing output. */ + /*---------------------------------------------*/ +%local ls savenote; +run; +ods _all_ close; +%let ls = %sysfunc(getoption(ls)); +%let savenote = %sysfunc(getoption(notes)); + +options nonotes; +data _null_; + retain kl 0; + length fn $ 40; + infile "&listingdir/_tmp" lrecl=%eval(&ls+1) pad; + input line $char%eval(&ls+1).; + page = substr(line, 1, 1) eq '0C'x; + if _n_ eq 1 or page then do; + ext = 'lst';; + fn = ext || "/&_ads_printfname"; + if page then line = substr(line, 2); + if kl then fn = compress(fn || put(kl, 5.) || '.' || ext); + else fn = compress(fn || '.' || ext); + kl + 1; + put 'Note: Writing Print file: ' fn; + end; + file x filevar=fn nopad; + l = length(line); + put line $varying. l; + run; + +options &savenote &_ads_savesize; + +filename __f "&listingdir/_tmp"; +data _null_; rc = fdelete('__f'); run; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The STARTLOG macro starts the capture of */ + /* the SAS log. */ + /*---------------------------------------------*/ +%macro startlog(fname);; /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* tag. */ + /*---------------------------------------------*/ +%global __fname __ls; +%let __fname=&fname; +%let __ls = %sysfunc(getoption(ls)); + +options nostimer nosource2 nosource; +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +proc printto log=LOGTMP new ; run; +%mend; + + + /*---------------------------------------------*/ + /* The ENDLOG macro ends the capture of the */ + /* SAS log. */ + /*---------------------------------------------*/ +%macro endlog(store=1, /* set STORE=0 to capture messages only and */ + /* not code. */ + range=1);; /* Specify a Boolean expression to select only */ + /* certain observations. Examples: */ + /* RANGE=_n_ < 5, */ + /* RANGE=not index(line, 'ERROR'). */ + /*---------------------------------------------*/ + +%local savenote; +%let savenote = %sysfunc(getoption(stimer)) %sysfunc(getoption(source2)) + %sysfunc(getoption(source)); + +proc printto log=log; run; + +options stimer source2 source; + +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +FILENAME LOGOUT "&listingdir/&__fname..lst" ENCODING='UTF-8'; +data _null_; + infile LOGTMP lrecl=%eval(&__ls+4) pad; + input line $char&__ls..; + if anycntrl(line) = 0; + %if &store %then %do; + if index(line, '%endlog') = 0; + %end; + %else %do; + if not (n(input(scan(line, 1, ' +'), ?? 12.)) and + compress(line, ' 0123456789') =: '+'); + %end; + if ⦥ + file LOGOUT lrecl=%eval(&__ls+4); + put line $char&__ls..; + run; + +filename __f "&listingdir/__tmp"; +data _null_; rc = fdelete('__f'); run; + +options &savenote; +%mend; + +*------------------------------------------------------------------------; + +* This utility macro stores in the out macro variable the + object name with pounds and such to match the name in the document.; +%macro ads_expand_obj(out, in); + length _w $ 200; + &out = ' '; + do _j = 1 to 32500 until(_w = ' '); + _w = scan(&in, _j, '.'); + if _w ne ' ' then do; + if not index(_w, '#') then _w = trim(_w) || '#1'; + &out = trim(&out) || '\' || _w; + end; + end; + &out = substr(&out, 3); + %mend; + +* This utility macro stores in the out macro variable the last n levels + (for an object with n levels) from the path.; +%macro ads_extr_path(out, path, object); + _levs = 1 + length(&object) - length(compress(&object, '.')); + call scan(&path, -_levs, _p, _len, '\'); + &out = lowcase(substr(&path, max(_p, 1))); + if substr(&out, 1, 1) eq '\' then &out = substr(&out, 2); + %mend; + +*------------------------------------------------------------------------; + +* 'this macro creates a directory if needed and deletes files with the +given extension to insure the directory exists and is empty of output files.; + +%macro cleandir(droot, dname, ext); + %local saveopts; + %let saveopts = %sysfunc(getoption(notes)); + options nonotes; + data _null_; + length ext $ 5 ; + droot = symget('droot'); + dname = symget('dname'); + ext = cats('.', upcase(symget('ext'))); + dpath = cats(droot, '/', dname); + + rc = filename('dref', droot); + rc = fexist('dref'); + if rc eq 0 then do; + put 'ERROR: Directory ' droot 'not found.'; + stop; + end; + + rc = filename('dref', dpath); + rc = fexist('dref'); + if rc eq 0 then do; + dpath = dcreate(dname, droot); + rc2 = filename('dreff', dpath); + rc2 = fexist('dreff'); + if rc2 eq 0 then do; + put 'ERROR: Directory ' dpath 'not created.'; + stop; + end; + else do; + put 'Note: Directory ' dpath 'created.'; + end; + end; + else do; + rc = filename('dreff', dpath); + did = dopen('dreff'); + if rc or not did then do; + put 'ERROR: Directory ' dpath 'not found.'; + stop; + end; + do i = 1 to dnum(did); /* Loops through entire directory */ + file = dread(did, i); + if index(upcase(file), ext) then do; /* file ends in dot extension */ + rc = filename('fref', cats(dpath, '/', file)); + rc = fdelete('fref'); + end; + end; + rc = dclose(did); + end; + run; + options &saveopts; +%mend cleandir; + + +proc format; + /* Format pour nombres < 100000 */ + picture STATREPS + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPR + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour nombres >= 100000 */ + picture STATREPL + 1000000000-high='000~000~000~009,99' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009,99' (decsep="," dig3sep=" ") + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009,99' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPK + 1000000000-high='000~000~000~009' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009' (decsep="," dig3sep=" ") + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour pourcentages/petits nombres */ + picture STATREPC + other='0~009,9900' (mult=1000000); + + /* Format date dd/mm/yyyy */ + picture STATREPD + low-high='%0d/%0m/%Y' (datatype=date); +run; +%macro STATREPResults(variable,format); + filename outtex "&SAStoTexname" encoding="utf-8" mod; + file outtex termstr=nl mod; + put "\def\&variable{" &variable &format '}'; +%mend; + +%macro STATREPAllResults(); + array _all _numeric_; + filename outtex "&SAStoTexname" encoding="utf-8" ; + file outtex termstr=nl mod; + + do over _all; + a = vname(_all); + fmt = vformat(_all); + + /* Test si variable de type date (format date appliqué) */ + if index(upcase(fmt),'DATE') or index(upcase(fmt),'DDMMYY') or + index(upcase(fmt),'MMDDYY') or index(upcase(fmt),'YYMMDD') or + index(upcase(fmt),'EURDFDD') or index(upcase(fmt),'NLDATE') or + (_all >= 0 and _all < 100000 and mod(_all,1)=0 and + vformat(_all) in ('BEST','F','') and a ne '') then do; + /* Vérification additionnelle : valeur dans la plage des dates SAS */ + if _all >= -109572 and _all <= 157377 then do; + put '\def\' a '{' _all STATREPD. '}'; + end; + else do; + /* Ce n'est pas une date, traiter comme nombre normal */ + if abs(_all) >= 100000 then + put '\def\' a '{' _all STATREPL. '}'; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + /* Sinon traiter comme nombre normal */ + else do; + if abs(_all) >= 100000 then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPK. '}'; + else + put '\def\' a '{' _all STATREPL. '}'; + end; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPR. '}'; + else + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + end; +DROP A FMT; +%mend; + +%MACRO STATREPMACROVAR(variable); +DATA _NULL_; +&variable = &&&variable; +%STATREPALLRESULTS() +;RUN; +%MEND; + + +PROC IML; +START STATREPFormatValue(value, varName); + ligne = ""; + + IF value = . THEN RETURN(ligne); + + IF value >= -109572 & value <= 157377 & MOD(value,1)=0 + & INDEX(UPCASE(varName),'DATE')>0 THEN + ligne = STRIP(PUTN(value, 'STATREPD.')); + + ELSE IF ABS(value) >= 100000 THEN DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPK.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPL.')); + END; + + ELSE IF ABS(value) < 1 THEN + ligne = STRIP(PUTN(value, 'STATREPC.')); + + ELSE DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPR.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPS.')); + END; + + RETURN(ligne); +FINISH; + +START STATREPResult(variable); + varName = PARENTNAME("variable"); + n = NROW(variable); + p = NCOL(variable); + v=variable; +IF p=1 & n>1 THEN DO; V=v`;p=n; n=1; END; + latex = ""; + +DO i = 1 TO n; + row = ""; + DO j = 1 TO p; + cell = STATREPFormatValue(v[i,j], varName); + IF cell ^= "" THEN DO; + IF j > 1 THEN row = row + " & "; + row = row + cell; + END; + END; + IF i > 1 THEN latex = latex + " \\ "; + latex = latex + row; +END; +IF n=1 & p=1 THEN + ligne = "\def\" + STRIP(varName) + " {" + latex + "}"; + +ELSE DO; + tabspec = "*{" + STRIP(CHAR(p)) + "}{c}"; + ligne = "\def\" + STRIP(varName) + + " {\begin{center}\begin{tabular}{" + + tabspec + "}" + + latex + + "\end{tabular}\end{center}}"; +END; + +EDIT WORK._STATREP_TEMP_; +APPEND FROM ligne; +CLOSE WORK._STATREP_TEMP_; +FINISH; + +STORE MODULE=( STATREPResult STATREPFormatValue ); +QUIT; + + +DATA WORK._STATREP_TEMP_; +LENGTH LIGNE $256; +STOP; +RUN; +QUIT; + +%MACRO STATREPIMLWrite(); +DATA _NULL_; + SET WORK._STATREP_TEMP_; + FILENAME outtex "&SAStoTexname" ENCODING="utf-8"; + FILE outtex TERMSTR=NL MOD; + PUT LIGNE; +RUN; + +%MEND STATREPIMLWrite; diff --git a/Testcases/statrep_tagset.sas b/Testcases/statrep_tagset.sas new file mode 100644 index 0000000..147a64a --- /dev/null +++ b/Testcases/statrep_tagset.sas @@ -0,0 +1,567 @@ +ODS PATH WORK.TEMPLAT(UPDATE) SASHELP.TMPLMST(READ); +proc template; + define style styles.StatRep; + parent = styles.statistical; + class colors / + 'link2' = cx0000FF + 'link1' = cx800080 + 'docbg' = cxFFFFFF + 'contentbg' = cxFFFFFF + 'systitlebg' = cxFFFFFF + 'titlebg' = cxFFFFFF + 'proctitlebg' = cxFFFFFF + 'headerbg' = cxFFFFFF + 'captionbg' = cxFFFFFF + 'captionfg' = cx000000 + 'bylinebg' = cxFFFFFF + 'notebg' = cxFFFFFF + 'tablebg' = cxFFFFFF + 'batchbg' = cxFFFFFF + 'systitlefg' = cx000000 + 'titlefg' = cx000000 + 'proctitlefg' = cx000000 + 'bylinefg' = cx000000 + 'notefg' = cx000000; + class Header / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class RowHeader / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class Footer / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class RowFooter / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class batch / + borderwidth = 0px; + class Data / + font = fonts('DocFont') + backgroundcolor = _undef_ + bordercolor = cx919191 + bordercollapse = collapse; + class DataEmphasis / + font = fonts('DocFont') + backgroundcolor = _undef_ + bordercolor = cx919191 + bordercollapse = collapse; + end; +run; + +proc template; +define tagset Tagsets.StatRep; + notes "This is the StatRep LaTeX definition"; + + define event initialize; + trigger set_options; + end; + + define event set_options; + set $options["junk" ] "junk" /if ^$options; + unset $cell_align; + + do /if cmp( $options["CELL_ALIGN"], "yes"); + set $cell_align "True"; + done; + + end; + + define event title_format_section; + put value; + end; + + define event cell_is_empty; + put " "; + end; + + define event list; + start: + put "\begin{itemize}" NL; + + finish: + put "\end{itemize}" NL; + end; + + define event list_item; + put "\item "; + end; + + define event list_entry; + put "\item "; + end; + + define event image; + put "\sasgraph{"; + put BASENAME /if ^exists( NOBASE); + put URL; + put "}" NL; + end; + + define event line; + put "\rule{\linewidth}{" colwidth; + put "pt}" NL; + end; + + define event text; + start: + put "\par " NL; + end; + + define event paragraph; + start: + put VALUE; + put NL; + put NL; + end; + + define event preformat; + start: + put "\verb?" NL; + + finish: + put "?" NL; + end; + + define event center; + start: + put "\begin{center}" NL; + + finish: + put "\end{center}" NL; + end; + + define event styles; + start: + put NL; + put "\RequirePackage[T1]{fontenc}" NL; + put "\RequirePackage{times}" NL; + put "\RequirePackage{fancyvrb}" NL; + put "\RequirePackage{array}" NL; + put "\RequirePackage{graphicx}" NL; + put NL; + put "\newbox\sas@fig" NL; + put "\newlength\sas@figwidth" NL; + put NL; + put "\newif\ifsas@color" NL; + put "\sas@colorfalse" NL; + put NL; + put "\DeclareOption{color}{\sas@colortrue}" NL; + put "\ProcessOptions" NL; + put NL; + + finish: + put %nrstr("%% Set cell padding") NL; + put "\renewcommand{\arraystretch}{1.3}" NL NL; + put %nrstr("%% Headings") NL; + put %nrstr("\newcommand{\sasheading}[3][c]{{%%") NL; + put %nrstr(" \if#1r\flushright\else\if#1l\flushleft\else\centering\fi\fi%%") NL; + put %nrstr(" {\csname sasS#2\endcsname #3}\mbox{}\\[0.1\baselineskip]%%") NL; + put %nrstr(" \if#1r\endflushright\else\if#1l\endflushleft\else\fi\fi%%") NL; + put "}}" NL; + put NL; + put "\newcommand{\sasbyline}[2][c]{\sasheading[#1]{byline}{#2}}" NL; + put "\newcommand{\sassystemtitle}[2][c]{\sasheading[#1]{systemtitle}{#2}}" NL; + put "\newcommand{\sassystemfooter}[2][c]{\sasheading[#1]{systemfooter}{#2}}" NL; + put "\newcommand{\sasproctitle}[2][c]{\sasheading[#1]{proctitle}{#2}}" NL; + put "\newcommand{\sascaption}[2][l]{\marginpar[#1]{\fbox{\parbox{0.7in}{\sasScaption{#2}}}}}" NL; + put NL; + put %nrstr("%% Declare new verbatim type") NL; + put %nrstr("\DefineVerbatimEnvironment{sasverbatim}{BVerbatim}%%") NL; + put " {fontsize=\footnotesize," NL; + put " commandchars=\\\{\}," NL; + put " formatcom=\sasSbatch}" NL; + put NL; + put %nrstr("%% Declare new column types") NL; + put "\newcolumntype{S}[2]{>{\csname sasS#1\endcsname}#2}" NL; + put "\newcolumntype{d}{r}" NL; + put NL; + put %nrstr("%% Set warning box style") NL; + put "\newlength\notewidth" NL; + put "\setlength\notewidth{4in}" NL; + put "\newcommand*{\saswarn}[2][c]{\sasmsg{warn}{#1}{#2}}" NL; + put "\newcommand*{\saserror}[2][c]{\sasmsg{error}{#1}{#2}}" NL; + put "\newcommand*{\sasnote}[2][c]{\sasmsg{note}{#1}{#2}}" NL; + put "\newcommand*{\sasfatal}[2][c]{\sasmsg{fatal}{#1}{#2}}" NL; + put %nrstr("\newcommand*{\sasmsg}[3]{%%") NL; + put %nrstr(" \ifsas@color\let\columncolor\undefined\fi%%") NL; + put %nrstr(" \begin{center}%%") NL; + put %nrstr(" \begin{tabular}{ll}\hline%%") NL; + put %nrstr(" \multicolumn{1}{|S{#1banner}{p{0.7in}}|}{#1} & %%") NL; + put %nrstr(" \multicolumn{1}{|S{#1content}{p{\notewidth}}|}{#3{\newline}}\\\hline%%") NL; + put %nrstr(" \end{tabular}%%") NL; + put %nrstr(" \end{center}%%") NL; + put %nrstr(" \ifsas@color\let\columncolor\sascolumncolor\fi%%") NL; + put "}" NL; + put NL; + put "\ifsas@color\RequirePackage{colortbl}\fi" NL; + put NL; + put %nrstr("%% Hack colortbl to allow \columncolor in macros") NL; + put "\let\CT@extract@org\CT@extract" NL; + put "\def\CT@extract{\futurelet\CT@NEXT\CT@extract@next}" NL; + put %nrstr("\def\CT@extract@next{%%") NL; + put " \ifx\CT@NEXT\csname" NL; + put %nrstr(" \@ReturnAfterFi{%%") NL; + put " \expandafter\expandafter\expandafter" NL; + put %nrstr(" }%%") NL; + put " \fi" NL; + put " \CT@extract@org" NL; + put "}" NL; + put "\long\def\@ReturnAfterFi#1\fi{\fi#1}" NL; + put "" NL; + put "\ifsas@color" NL; + put "" NL; + put " \newcommand{\foreground}[1]{\color[rgb]{#1}}" NL; + put " \newcommand{\sascolumncolor}[2][]{}" NL; + put " \let\columncolor\sascolumncolor" NL; + put " \newcommand{\documentforeground}[1]{\AtBeginDocument{\color[rgb]{#1}}}" NL; + put " \newcommand{\documentbackground}[1]{\AtBeginDocument{\pagecolor[rgb]{#1}}}" NL; + put " \def\sastable{\let\columncolor\undefined\tabular}" NL; + put " \def\endsastable{\endtabular\let\columncolor\sascolumncolor}" NL; + put " \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular}" NL; + put " \def\endstackedcell{\endtabular\egroup}" NL; + put NL; + put "\else" NL; + put NL; + put " \providecommand{\foreground}[1]{}" NL; + put " \providecommand{\color}[2][]{}" NL; + put " \newcommand{\sascolumncolor}[2][]{}" NL; + put " \let\columncolor\sascolumncolor" NL; + put " \newcommand{\documentforeground}[1]{}" NL; + put " \newcommand{\documentbackground}[1]{}" NL; + put " \def\sastable{\tabular}" NL; + put " \def\endsastable{\endtabular}" NL; + put " \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular}" NL; + put " \def\endstackedcell{\endtabular\egroup}" NL; + put "" NL; + put "\fi" NL; + put NL; + put %nrstr("%%\let\sasgraph\includegraphics") NL; + put %nrstr("%% Scale graphics so they always fit on the page") NL; + put %nrstr("\newcommand\sasgraph[2][]{%%") NL; + put %nrstr(" \savebox{\sas@fig}{\includegraphics[#1]{#2}}%%") NL; + put %nrstr(" \settowidth{\sas@figwidth}{\usebox{\sas@fig}}%%") NL; + put %nrstr(" \ifthenelse{\lengthtest{\sas@figwidth > \textwidth}}{%%") NL; + put %nrstr(" \resizebox{0.95\textwidth}{!}{\usebox{\sas@fig}}}{%%") NL; + put " \usebox{\sas@fig}}" NL; + put "}" NL; + put NL; + end; + + define event style_class; + start: + put "\def\sasS" lowcase(HTMLCLASS) %nrstr("{%%") NL; + put " " FONT_SIZE %nrstr("%%") NL /if exists( FONT_SIZE); + put " " FONT_WEIGHT %nrstr("%%") NL /if exists( FONT_WEIGHT); + put " " FONT_STYLE %nrstr("%%") NL /if exists( FONT_STYLE); + put " " FONT_FACE %nrstr("%%") NL /if exists( FONT_FACE); + put " \color[rgb]{" FOREGROUND %nrstr("}%%") NL /if exists( foreground); + put " \columncolor[rgb]{" BACKGROUND %nrstr("}%%") NL /if exists( background); + set $foreground foreground /if cmp( htmlclass, "body"); + set $background background /if cmp( htmlclass, "body"); + + finish: + put "}" NL; + end; + + define event caption; + start: + set $sascaption "true"; + block table; + block row; + block colspecs; + block colspec_entry; + put "\sascaption["; + put "l" /if cmp( TYPE, "L"); + put "r" /if cmp( TYPE, "R"); + put "b" /if cmp( TYPE, "B"); + put "t" /if cmp( TYPE, "T"); + put "]{"; + + finish: + put "}" NL; + unblock table; + unblock row; + unblock colspecs; + unblock colspec_entry; + set $sascaption "false"; + end; + + define event table; + start: + put NL; + put NL; + put "\begin{sastable}"; + + trigger alignment; + + finish: + put "\end{sastable}" NL; + put NL; + end; + + define event verbatim_text; + put VALUE; + put NL; + end; + + define event verbatim_container; + start: + put NL; + put NL; + put "\begin{center}" NL /if cmp( just, "c"); + put "\begin{sasverbatim}" NL; + + finish: + put "\end{sasverbatim}" NL; + put "\end{center}" NL /if cmp( just, "c"); + put NL; + end; + + define event alignment; + start: + put "[c]" /if cmp( just, "c"); + put "[c]" /if cmp( just, "d"); + put "[r]" /if cmp( just, "r"); + put "[l]" /if cmp( just, "l"); + flush; + end; + + define event colspecs; + start: + put "{"; + + finish: + put "}\hline" NL; + end; + + define event colspec_entry; + put just /if ^cmp( just, "d"); + put "r" /if cmp( just, "d"); + end; + + define event row; + + finish: + put NL "\\\hline" NL; + end; + + define event rowspanfillsep; + put %nrstr(" & ") NL; + end; + + define event rowspancolspanfill; + put " "; + put "\multicolumn{"; + put colspan; + put "1" /if ^exists( colspan); + put "}"; + put "{|S{"; + put lowcase(HTMLCLASS); + put "data" /if ^htmlclass; + put "}{"; + put just; + put "}|}{~}"; + end; + + define event header; + start: + + trigger data; + + finish: + + trigger data; + end; + + define event data; + start: + put VALUE /if cmp( $sascaption, "true"); + break /if cmp( $sascaption, "true"); + put %nrstr(" & ") NL /if ^cmp( COLSTART, "1"); + put " "; + put "\multicolumn{"; + put colspan; + put "1" /if ^colspan; + put "}"; + put "{"; + put "|" /if ^$instacked; + put "S{"; + put lowcase(HTMLCLASS); + put "}{"; + put just; + put "}"; + put "|" /if ^$instacked; + put "}"; + put "{"; + put tranwrd(VALUE,"-","$-$") /if contains( lowcase(HTMLCLASS), "data"); + put VALUE /if ^contains( lowcase(HTMLCLASS), "data"); + + finish: + break /if cmp( $sascaption, "true"); + put "}"; + end; + + define event data_note; + start: + + trigger data; + + finish: + + trigger data; + end; + + define event stacked_cell; + start: + put NL; + put "\begin{stackedcell}"; + + trigger alignment; + + finish: + put "\end{stackedcell}" NL; + end; + + define event stacked_value; + start: + unset $instacked; + set $instacked "true"; + + trigger data; + + finish: + + trigger data; + unset $instacked; + end; + + define event stacked_value_header; + start: + + trigger stacked_value; + + finish: + + trigger stacked_value; + end; + + define event stacked_cell_colspecs; + start: + put "{"; + + finish: + put "}" NL; + end; + + define event stacked_cell_colspec_entry; + put just /if ^cmp( just, "d"); + put "r" /if cmp( just, "d"); + end; + + define event stacked_cell_row; + + finish: + put NL "\\" NL; + end; + + define event put_value; + put VALUE; + end; + + define event put_value_cr; + put VALUE NL; + end; + + define event byline; + put NL; + put "\sasbyline"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event proc_title; + put "\sasproctitle"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event note; + put "\sasnote"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Error; + put "\saserror"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Warn; + put "\saswarn"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Fatal; + put "\sasfatal"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event system_title; + put "\sassystemtitle"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event system_footer; + put "\sassystemfooter"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + image_formats = "png,pdf"; + split = " {\newline} "; + nobreakspace = "~"; + mapsub = %nrstr("/\%%/\$/\&/\{/\}/\~/\^/\#/{\textunderscore}/{\textbackslash}/"); + map = %nrstr("%%$&{}~^#_\"); + output_type = "latex"; + stacked_columns = OFF; + embedded_stylesheet; + private; +end; +run; diff --git a/Testcases/testcases.pdf b/Testcases/testcases.pdf new file mode 100644 index 0000000..009d8c9 Binary files /dev/null and b/Testcases/testcases.pdf differ diff --git a/supplement/testcases.tex b/Testcases/testcases.tex similarity index 63% rename from supplement/testcases.tex rename to Testcases/testcases.tex index cc5c19f..bee5dfe 100644 --- a/supplement/testcases.tex +++ b/Testcases/testcases.tex @@ -1,9 +1,109 @@ -\documentclass{article} +\documentclass[a4paper]{article} \usepackage[margin=1in]{geometry} -\usepackage[color]{statrep} +\usepackage[utf8]{inputenc} +\usepackage[SASmode=Server,figname=Illustration]{../statrep} \begin{document} + +This document is named \texttt{testcases.tex}. +It contains the complete \textit{Getting Started} +example from the \textit{StatRep User's Guide}. +You can generate the final PDF document \texttt{testcases.pdf} as follows: + +\begin{description} + \item[Generate the SAS program]\mbox{}\newline + Compile this document with \texttt{pdflatex}. + The \texttt{StatRep} package automatically generates a SAS program from + the document source. The program is named + \texttt{example\_SR.sas} and it is created in the current directory. + + \item[Capture the SAS outputs]\mbox{}\newline + Run the SAS program \texttt{example\_SR.sas}. + The SAS working directory must be the directory that contains this document. + + \item[Create the final PDF]\mbox{}\newline + Compile this document with \texttt{pdflatex} once more. The outputs that SAS generated + in the preceding step are now included in the final PDF \texttt{example.pdf}. +\end{description} + +The code in the \texttt{Datastep} environment is written +unchanged to the generated SAS program. + +\begin{Datastep} + proc format; + value $sex 'F' = 'Female' 'M' = 'Male'; + data one; + set sashelp.class; + format sex $sex.; + run; +\end{Datastep} + + +Example of transfert of SAS parameters or results to \LaTeX : + +\begin{Sascode} + data test; + mydatea = '01JAN2024'd; + mydateb = '01JAN2024'd; + smallnum = 0.00523; + mediunnum = 1234.56; + largenum = 456789.12; + verylarge = 12345678.90; + %STATREPResults(mydatea, WEEKDATE.); + output; + run; + + data _null_; + set test (drop=mydatea); *don''t replace mydatea; + %STATREPAllResults(); + run; +\end{Sascode} + +Mydate (a) is equal \mydatea, (b) is equal to \mydateb{} and large numerical value is equal to \largenum. + + +The code in the \texttt{Sascode} environment is parsed before it is +written to the generated SAS program. For example, lines that begin with the string +\texttt{\%*;} are written to the SAS program and are not displayed in the +final document. The other lines in this example are written to the program +and are displayed in the final document. + +The first line of the following code block can be seen only +in the \LaTeX\ source file and in the generated SAS program. +The line insures that ODS Graphics are enabled. + +\begin{Sascode}[store=REGa] + %*; OPTIONS MPRINT MLOGIC SYMBOLGEN; + %*; ods graphics on; + %startlog(nameoflog) + proc reg; + model weight = height age; + run; + %endlog(store=0,range=_n_ <= 10) +\end{Sascode} + +The \texttt{Listing} and \texttt{Graphic} tags convey information to +\LaTeX\ and to SAS. The tags specify the names of the output files to +insert into the document and the captions for the output. +Additionally, they specify the names of the output files to create +and which ODS objects to capture. + +\Listing[store=REG,dest=latex, +caption={Regression Analysis LaTeX}]{REGa} + +\Graphic[store=REG, +caption={Graphs for Regression Analysis}]{REGb} + +\Listing[store=REG,dest=listing, +caption={Regression Analysis listing}]{REGc} +In this short example only the defaults are used. That is, all output +objects are selected and displayed. + +\Listing[caption={Log de la proc reg}]{nameoflog} + + +\section{More Cases} \begin{Datastep} title 'no options'; data one; diff --git a/Testcases/testcases_VarSAStoTex.tex b/Testcases/testcases_VarSAStoTex.tex new file mode 100644 index 0000000..a4dbb22 --- /dev/null +++ b/Testcases/testcases_VarSAStoTex.tex @@ -0,0 +1,6 @@ +\def\mydatea{ Monday, January 1, 2024} +\def \mydateb { 23 376,00} +\def \smallnum { 0,5230} +\def \mediunnum { 1 234,56} +\def \largenum { 456 789,12} +\def \verylarge { 12 345 678,90} diff --git a/benchmark/.gitignore b/benchmark/.gitignore deleted file mode 100644 index b3bd464..0000000 --- a/benchmark/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -#Whitelisted Files for benchmark -# -# PDF Files -!example.pdf -!quickstart.pdf -!testcases.pdf -# -# Generated Package Files -!longfigure.sty -!statrep.sty diff --git a/benchmark/example.pdf b/benchmark/example.pdf deleted file mode 100644 index 05b0408..0000000 Binary files a/benchmark/example.pdf and /dev/null differ diff --git a/benchmark/quickstart.pdf b/benchmark/quickstart.pdf deleted file mode 100644 index 41b7357..0000000 Binary files a/benchmark/quickstart.pdf and /dev/null differ diff --git a/benchmark/testcases.pdf b/benchmark/testcases.pdf deleted file mode 100644 index 3e8fc8c..0000000 Binary files a/benchmark/testcases.pdf and /dev/null differ diff --git a/build.py b/build.py deleted file mode 100644 index 4a522c9..0000000 --- a/build.py +++ /dev/null @@ -1,278 +0,0 @@ -import filecmp -import os -import shutil -import shlex -import subprocess -import time -import zipfile - -ROOT = os.getcwd() -SUPPLEMENT = os.path.join(ROOT, 'supplement') -CONTENT = os.path.join(ROOT, 'content') -BUILD = os.path.join(ROOT, 'build') -BENCH = os.path.join(ROOT, 'benchmark') -SASCMD = None -DEVNULL = open(os.devnull, 'wb') - - -def chmods(dirname): - for root, dnames, files in os.walk(os.path.join(ROOT, dirname)): - for dname in dnames: - fullname = os.path.join(root, dname) - os.chmod(fullname, 0755) - - for fname in files: - fullname = os.path.join(root, fname) - os.chmod(fullname, 0644) - -def unixlines(dirname): - skip_exts = ['.pdf', '.png', '.jpg'] - for root, dnames, files in os.walk(os.path.join(ROOT, dirname)): - for fname in files: - fullname = os.path.join(root, fname) - stem, ext = os.path.splitext(fname) - if ext and ext in skip_exts: - continue - - with open(fullname) as f: - lines = f.readlines() - - newlines = [line.replace('\r\n', '\n') for line in lines] - with open(fullname, 'w') as f: - f.writelines(newlines) - -def zipdir(fullpath): - ''' - Splits fullpath into its last directory name (package) - and the parent (dirpath). Creates a zip file named package.zip in the parent - which contains the files in fullpath. - ''' - package = os.path.basename(fullpath) - dirpath = os.path.dirname(fullpath) - z = zipfile.ZipFile(os.path.join(dirpath, '%s.zip' % package), 'w') - for root, _, fnames in os.walk(os.path.join(dirpath, package)): - for fname in fnames: - fullname = os.path.join(root, fname) - relroot = os.path.relpath(root, dirpath) - arcname = os.path.join(relroot, fname) - if os.path.isfile(fullname): - z.write(fullname, arcname) - z.close() - -def pdf(fname, cwd): - cmd = str('pdflatex %s' % fname) - p = subprocess.Popen(shlex.split(cmd), stdout=DEVNULL, - stderr=subprocess.STDOUT, - cwd=cwd) - p.wait() - -def idx(fname, cwd): - fname, ext = os.path.splitext(fname) - if ext == '.dtx': - option = ' -s gind.ist ' - else: - option ='' - cmd = str('makeindex %s %s' % (option, fname)) - p = subprocess.Popen(shlex.split(cmd), stdout=DEVNULL, - stderr=subprocess.STDOUT, cwd=cwd) - p.wait() - -class Tester(object): - def __init__(self): - if not SASCMD: - self.sascmd = raw_input('Enter your batch SAS command: ') - else: - self.sascmd = SASCMD - self.cwd = os.path.join(BUILD, 'test') - cmd = str('%s statrep_tagset.sas' % self.sascmd) - p = subprocess.Popen(shlex.split(cmd), cwd=self.cwd) - p.wait() - self.tests = 0 - self.passed = 0 - names = ['statrep', 'longfigure'] - for name in names: - src = os.path.join(BUILD, 'work', name, '%s.sty' % name) - tgt = os.path.join(BENCH, '%s.sty' % name) - shutil.copy(src, tgt) - - def test(self): - names = ['example', 'quickstart', 'testcases'] - for name in names: - pdf('%s.tex' % name, self.cwd) - for name in names: - cmd = str('%s %s_SR.sas' % (self.sascmd, name)) - p = subprocess.Popen(shlex.split(cmd), cwd=self.cwd) - p.wait() - pdf('%s.tex' % name, self.cwd) - pdf('%s.tex' % name, self.cwd) - - def diff(self): - names = ['testcases', 'example', 'quickstart'] - for name in names: - cmd = str('gs -sDEVICE=jpeg -dNOPAUSE -dBATCH -dSAFER ') - cmd += str('-sOutputFile=%s%%08d.jpg %s.pdf' % (name[0], name)) - - p = subprocess.Popen(shlex.split(cmd), stdout=DEVNULL, - stderr=subprocess.STDOUT, - cwd=BENCH, ) - p.wait() - p = subprocess.Popen(shlex.split(cmd), stdout=DEVNULL, - stderr=subprocess.STDOUT, - cwd=os.path.join(BUILD, 'test')) - p.wait() - - files = [x for x in os.listdir(BENCH) if x.endswith('jpg')] - for fname in files: - self.tests += 1 - if not filecmp.cmp(os.path.join(BENCH, fname), - os.path.join(BUILD, 'test', fname)): - print 'Diff for %s' % fname - else: - self.passed += 1 - print 'Total tests: %d. Passed: %d. Failed: %d' % (self.tests, self.passed, (self.tests - self.passed)) - - -class Packager(object): - def __init__(self): - if os.path.isdir(BUILD): - shutil.rmtree(BUILD) - time.sleep(2) - - self.ctan = os.path.join(BUILD, 'ctan') - self.work = os.path.join(BUILD, 'work') - self.test = os.path.join(BUILD, 'test') - self.sas = os.path.join(BUILD, 'sas') - for fname in [x for x in os.listdir(BENCH) if x.endswith('.jpg')]: - os.unlink(os.path.join(BENCH, fname)) - - - unixlines('content'); - unixlines('supplement') - chmods('content'); - chmods('supplement') - self.makedirs() - self.getcontent() - - def makedirs(self): - for dname in [self.ctan, self.sas]: - os.makedirs(os.path.join(dname, 'statrep', 'doc')) - os.makedirs(os.path.join(dname, 'statrep', 'sas')) - os.makedirs(os.path.join(dname, 'longfigure')) - - os.makedirs(self.test) - os.makedirs(os.path.join(self.work, 'statrep')) - os.makedirs(os.path.join(self.work, 'longfigure')) - - def getcontent(self): - self.content = dict() - with open(os.path.join(CONTENT, 'statrep.wrapper')) as f: - self.content['statrep'] = f.readlines() - with open(os.path.join(CONTENT, 'longfigure.wrapper')) as f: - self.content['longfigure'] = f.readlines() - with open(os.path.join(CONTENT, 'longfigure.inc')) as f: - self.content['common'] = f.readlines() - - def write_dtx(self): - def insert_common(wrapper): - newlines = list() - for line in self.content[wrapper]: - newlines.append(line) - if line.strip() == '% \\label{longfigure}': - newlines.extend(self.content['common']) - return newlines - - for name in ['statrep', 'longfigure']: - cwd = os.path.join(self.work, name) - with open(os.path.join(cwd, '%s.dtx' % name), 'wb') as f: - f.writelines(insert_common(name)) - - def run_dtx(self): - for name in ['statrep', 'longfigure']: - cwd = os.path.join(self.work, name) - pdf('%s.dtx' % name, cwd);idx('%s.dtx' % name, cwd); - pdf('%s.dtx' % name, cwd);pdf('%s.dtx' % name, cwd) - - def makemanual(self): - cwd = os.path.join(self.work, 'statrep') - shutil.copytree(os.path.join(SUPPLEMENT, 'images'), os.path.join(cwd, 'images')) - for fname in ['example.tex','statrepmanual.tex']: - shutil.copy(os.path.join(SUPPLEMENT, fname), - os.path.join(cwd, fname)) - - if fname == 'statrepmanual.tex': - pdf(fname, cwd);idx(fname, cwd); - pdf(fname, cwd);pdf(fname, cwd) - - def setup_tests(self): - for fname in ['testcases.tex', 'example.tex', 'quickstart.tex', - 'statrep_macros.sas', 'statrep_tagset.sas']: - shutil.copy(os.path.join(SUPPLEMENT, fname), - os.path.join(self.test, fname)) - - for name in ['statrep', 'longfigure']: - shutil.copy(os.path.join(self.work, name, '%s.sty' % name), - os.path.join(self.test, '%s.sty' % name)) - - def setup_delivery(self, package_name): - if package_name == 'ctan': - cwd = self.ctan - elif package_name == 'sas': - cwd = self.sas - - for name in ['statrep', 'longfigure']: - shutil.copy(os.path.join(SUPPLEMENT, 'LICENSE'), - os.path.join(cwd, name, 'LICENSE')) - - shutil.copy(os.path.join(self.work, name, 'README.'), - os.path.join(cwd, name, 'README')) - for fname in ['%s.dtx' % name, '%s.ins' % name]: - shutil.copy(os.path.join(self.work, name, fname), - os.path.join(cwd, name, fname)) - - if name == 'longfigure': - shutil.copy(os.path.join(self.work, name, '%s.pdf' % name), - os.path.join(cwd, name, '%s.pdf' % name)) - - elif name == 'statrep': - tcwd = os.path.join(cwd, 'statrep', 'sas') - for fname in ['statrep_macros.sas', 'statrep_tagset.sas']: - shutil.copy(os.path.join(SUPPLEMENT, fname), - os.path.join(tcwd, fname)) - - tcwd = os.path.join(cwd, 'statrep', 'doc') - shutil.copytree(os.path.join(SUPPLEMENT, 'images'), os.path.join(tcwd, 'images')) - shutil.copy(os.path.join(SUPPLEMENT, 'quickstart.tex'), - os.path.join(tcwd, 'quickstart.tex')) - - for fname in ['statrep.pdf', 'statrepmanual.pdf', 'statrepmanual.tex']: - shutil.copy(os.path.join(self.work, name, fname), - os.path.join(tcwd, fname)) - - if package_name == 'sas': - for fname in ['longfigure.sty', 'statrep.sty']: - shutil.copy(os.path.join(self.work, name, fname), - os.path.join(cwd, name, fname)) - - -if __name__ == '__main__': - p = Packager() - print('writing') - p.write_dtx() - print('running') - p.run_dtx() - p.makemanual() - print '-'*30 - p.setup_tests() - p.setup_delivery('ctan') - p.setup_delivery('sas') - - t = Tester() - t.test() - t.diff() - zipdir(os.path.join(p.ctan, 'statrep')) - zipdir(os.path.join(p.sas, 'statrep')) - - if t.tests == t.passed: - for fname in [x for x in os.listdir(BENCH) if x.endswith('.jpg')]: - os.unlink(os.path.join(BENCH, fname)) - print 'Ready for upload. See %s' % BUILD diff --git a/content/README.md b/content/README.md deleted file mode 100644 index f91b9c8..0000000 --- a/content/README.md +++ /dev/null @@ -1,18 +0,0 @@ - - -Creates statrep.dtx and longfigure.dtx in subdirectories of current dir. -Files present: - - * statrep.wrapper - * longfigure.wrapper - * longfigure.inc - -statrep.wrapper is read and longfigure.inc is inserted to create statrep.dtx -longfigure.wrapper is read and longfigure.inc is inserted to create longfigure.dtx - -This is used to keep the longfigure package synced with statrep. If any edits are -made to longfigure package, it should be in longfigure.inc since both the statrep -and longfigure package include that file. - -The files that are distributed still come from the *.dtx files; this subdirectory -is used only for creating them. diff --git a/content/longfigure.inc b/content/longfigure.inc deleted file mode 100644 index beef56e..0000000 --- a/content/longfigure.inc +++ /dev/null @@ -1,712 +0,0 @@ -% \index{longfigure package|usage} -% -% The |longfigure| package uses and relabels components of the -% well-known |longtable| package, written by David Carlisle, to -% provide a table-like environment that can display a stream -% of subfigures as a single figure that can break across pages. -% -% The |longtable| package defines a |longtable| environment, -% which produces tables that can be broken by \TeX's standard page-breaking algorithm. -% Similarly, the |longfigure| package defines a |longfigure| environment, which produces -% figures that can be broken by \TeX's standard page-breaking algorithm. -% The internal structure of a long figure is similar to a long table. -% Rows might contain (for example) tables or graphics. Page breaks -% can occur only between rows. -% -% The |longfigure| package differs from the |longtable| package in the following ways: -% \begin{itemize} -% \item The |longfigure| package supports two additional key-value options: -% \begin{itemize} -% \item The |figname=| option specifies the counter for numbering |longfigure| environments. -% You can specify any string; the default is |figure|. -% When you specify a |figname=| value for which no counter already exists, the -% |longfigure| package loads the |tocloft| package and creates the counter. -% \index{figname option|usage} -% -% \item The |resetby=| option specifies a counter (for example, |resetby=chapter|) such -% that output numbering is reset each time the counter value changes. -% If a counter is specified that does not exist, the |tocloft| package is -% loaded to create the new counter. -% \index{tocloft package|usage}% -% For information about how the lists are typeset, -% \index{list of outputs, creating|usage}% -% see the |tocloft| package documentation. -% \end{itemize} -% \item The counters and macros that start with \cs{LT} in the |longtable| package -% are renamed to start with \cs{LF} in the |longfigure| pacakge to avoid -% namespace conflicts when the two packages are used together. -% The generic macros that are defined in the |longtable| package -% (\cs{endfirsthead}, \cs{endhead}, \cs{endfoot}, and \cs{endlastfoot}) are -% also renamed with \cs{LF} as a prefix in the |longfigure| package. -% -% \item The \cs{LF@name} macro is based on the \cs{fnum@table} macro from -% the |longtable| package. The \cs{LF@name} macro returns the capitalized -% counter name and value. For example, if the counter is |figure| and the -% macro is processing the second |longfigure|, the \cs{LF@name} macro -% would contain the value ``Figure 2.'' -% -% \end{itemize} -% You can use the |longfigure| package defaults to produce a \emph{List of Figures} -% by inserting the following tag in your document at the point where you want -% the list to appear: -% \iffalse -%<*example> -% \fi -\begin{verbatim} - \listoffigures -\end{verbatim} -% \iffalse -% -% \fi -% -% The default counter used to display figures is the |figure| counter, -% but you can specify a different counter. For example, if you want your -% figures to be labeled as ``Display,'' specify |figname=display| when you -% load the |longfigure| package; to display a \emph{List of Displays}, insert the following -% command in your document at the point where you want the list to appear: -% \iffalse -%<*example> -% \fi -\begin{verbatim} - \listofdisplay -\end{verbatim} -% \iffalse -% -% \fi -% \textbf{Note:} If you specify a counter that does not exist, -% an auxiliary file with extension |.lft| is created to contain the information -% needed to create the list. -% -% If you want to use more advanced features of the |tocloft| package, -% load it before you load the |longfigure| package so that the |longfigure| -% package sees that the counters specified by the |figname=| and |resetby=| -% options are already defined and does not attempt to create them. -% -% -%\subsection{Example} -% The following lines produce a single figure that contains three images and -% one tabular environment. Each element is a row of the |longfigure| environment. -% Page breaks can occur between rows. -%% \iffalse -%<*example> -% \fi -\begin{verbatim} -\documentclass{book} -\usepackage{graphicx} -\usepackage{longfigure} - -\begin{document} - \begin{longfigure}{c} - \caption{My Long Figure}\label{mlfig}\\ - \includegraphics[width=3in]{myfig1}\\ - \includegraphics[width=3in]{myfig2}\\ - \includegraphics[width=3in]{myfig3}\\ - \begin{tabular}{ll} - one & two \\ - three & four\\ - \end{tabular} - \end{longfigure} -\end{document} -\end{verbatim} -% \iffalse -% -% \fi -% In this example, the |{c}| argument in the |\begin{longfigure}| command -% specifies only a single centered column. You can also specify multiple columns and, -% if needed, use the \cs{multicolumn} command for more flexibility. -% -% The following lines display another example that specifies a 'continued' heading -% when the figure breaks over a page. It also displays a double horizontal line at the -% end of the figure. -% \iffalse -%<*example> -% \fi -\begin{verbatim} -\documentclass{book} -\usepackage{graphicx} -\usepackage{longfigure} - -\begin{document} - \begin{longfigure}{c} - \caption{My Long Figure}\label{mlfig2}\\ - \hline\endLFfirsthead - \caption{continued}\\ - \hline\endLFhead - \hline\endLFfoot - \hline\hline\endLFlastfoot - \includegraphics[width=3in]{myfig1}\\ - \includegraphics[width=3in]{myfig2}\\ - \includegraphics[width=3in]{myfig3}\\ - \begin{tabular}{ll} - one & two \\ - three & four\\ - \end{tabular} - \end{longfigure} -\end{document} -\end{verbatim} -% \iffalse -% -% \fi -% \section{Implementation} -% -% This section describes the implementation of the |longfigure| package. -% The comments describe only the changes from the |longtable| package code. -% For complete details about the logic and usage of the |longtable| environment, -% see Carlisle (2004). -%\iffalse -%<*longfigure> -%\fi -% \begin{macrocode} -\ProvidesPackage{longfigure}[2014/01/06 longfigure] -% \end{macrocode} -% The following statement loads the |xkeyval| package for declaring -% and processing package options: -% \begin{macrocode} -\RequirePackage{xkeyval} -% \end{macrocode} -% The following statement defines a new command, \cs{LFcounter}, to -% contain the string |figure|. -% Later code tests whether a counter with that name exists. -% \begin{macrocode} -\newcommand*{\LFcounter}{figure} -% \end{macrocode} -% -% The following statement defines a new command, \cs{LFreset}, to contain -% the name of the counter within which the |longfigure| number should reset. -% If no value is specified, the long figures are numbered consecutively -% through the document. -% \begin{macrocode} -\newcommand*{\LFreset}{\@empty} -% \end{macrocode} -% \subsection{Options} -% The \cs{LFcounter} and \cs{LFreset} commands support the -% package options |figname=| and |resetby=| as follows: -% \begin{macrocode} -\DeclareOptionX{figname}[figure]{\renewcommand*{\LFcounter}{#1}} -\DeclareOptionX{resetby}{\renewcommand*{\LFreset}{#1}} -% \end{macrocode} -% The following statements further define the options -% that the |longtable| package defines: -% \begin{macrocode} -\DeclareOptionX{set}{} -\DeclareOptionX{final}{} -\DeclareOptionX{errorshow}{\def\LF@warn{\PackageInfo{longfigure}}} -\DeclareOptionX{pausing}{\def\LF@warn#1{\LF@err{#1}{This is not really an error}}} -\ProcessOptionsX -% \end{macrocode} -% The following statements process the options: -% \begin{macrocode} -\def\LFProcessOptions#1{ - \@ifundefined{c@#1}{% - \RequirePackage{tocloft} - \def\LFuc##1##2{\MakeUppercase{##1}{##2}} - \expandafter\def\csname list#1name\endcsname{List of \LFuc#1s} - \ifx\@empty\LFreset% - \newlistof{#1}{lft}{\csname list#1name\endcsname} - \else - \newlistof[\LFreset]{#1}{lft}{\csname list#1name\endcsname} - \fi - }{}% -} -\expandafter\LFProcessOptions\expandafter{\LFcounter} -% \end{macrocode} -% If a counter is specified that does not exist, its name (\cs{c@}\textit{countername}) -% is undefined and the |longfigure| package loads the |tocloft| package in order to -% use its commands to create the new counters and list. -% -% Thus, the |tocloft| package is required only when a new counter -% is specified, -% \index{tocloft package|usage}% -% and this automatic loading takes place only if the counter that is specified -% in the package options is not defined. -% -% You can load the |tocloft| package before loading the |longfigure| package -% and retain all of the flexibility that the |tocloft| package offers. -% However, you must define the new counters yourself by using the -% \cs{newlistof} command in the |tocloft| package, -% and you must define the new list to use an auxiliary |lft| file where -% its auxiliary information is written. -% \index{tocloft package|usage}% -% -% \subsection{Utilities} -% \DescribeMacro{\strcfstr} -% The following macro, \cs{strcfstr}, checks whether two strings, which are -% provided as arguments, are equal (Wilson, 2001). -% A new boolean \cs{ifLF@same} contains the result of the test. -% \begin{macrocode} -\newif\ifLF@same -\newcommand{\strcfstr}[2]{% - \LF@samefalse - \begingroup\def\2{#2} - \ifx\2#1\endgroup\LF@sametrue - \else\endgroup - \fi -} -% \end{macrocode} -% \DescribeMacro{\LFupcase} -% The following macro, \cs{LFupcase}, uppercases the first letter of -% a string (Lazarides, 2010): -% \begin{macrocode} -\def\LFupcase#1{% - \def\x##1##2{% - \MakeUppercase{##1}{##2}}\x#1% -} -% \end{macrocode} -% The following macro, \cs{LF@name}, creates a string to provide a label and number for -% an output. Analogous to the \cs{fnum@table} macro in the |longtable| package, -% it contains the capitalized version of the counter name and the counter -% number (for example, |Figure~3|). -% \begin{macrocode} -\def\LF@name{\expandafter\LFupcase% - \expandafter{\LFcounter}~% - \expandafter\csname the\LFcounter\endcsname}% -% \end{macrocode} -% The remainder of this package follows the |longtable| package -% almost identically, except that macros, skips, counters, and so on -% use an \cs{LF} prefix instead of the \cs{LT} prefix that the |longtable| package uses. -% -% \begin{macrocode} -\def\LF@err{\PackageError{longfigure}} -\def\LF@warn{\PackageWarning{longfigure}} -\def\LF@final@warn{% - \AtEndDocument{% - \LF@warn{\LFcounter \@width s have changed. Rerun \LaTeX\.\@gobbletwo}}% - \global\let\LF@final@warn\relax} -% -\newskip\LFleft \LFleft=\fill -\newskip\LFright \LFright=\fill -\newskip\LFpre \LFpre=\bigskipamount -\newskip\LFpost \LFpost=\bigskipamount -\newcount\LFchunksize \LFchunksize=20 -\let\c@LFchunksize\LFchunksize -\newdimen\LFcapwidth \LFcapwidth=4in -\newbox\LF@head -\newbox\LF@firsthead -\newbox\LF@foot -\newbox\LF@lastfoot -\newcount\LF@cols -\newcount\LF@rows -\newcounter{LF@tables} -\newcounter{LF@chunks}[LF@tables] -% -\newtoks\LF@p@ftn -\mathchardef\LF@end@pen=30000 -\def\longfigure{% - \par - \ifx\multicols\@undefined - \else - \ifnum\col@number>\@ne - \@twocolumntrue - \fi - \fi - \if@twocolumn - \LF@err{longfigure not in 1-column mode}\@ehc - \fi - \begingroup - \@ifnextchar[\LF@array{\LF@array[x]}} -\def\LF@array[#1]#2{% - \refstepcounter{\LFcounter}\stepcounter{LF@tables}% - \if l#1% - \LFleft\z@ \LFright\fill - \else\if r#1% - \LFleft\fill \LFright\z@ - \else\if c#1% - \LFleft\fill \LFright\fill - \fi\fi\fi - \let\LF@mcol\multicolumn - \let\LF@@tabarray\@tabarray - \let\LF@@hl\hline - \def\@tabarray{% - \let\hline\LF@@hl - \LF@@tabarray}% - \let\\\LF@tabularcr\let\tabularnewline\\% - \def\newpage{\noalign{\break}}% - \def\pagebreak{\noalign{\ifnum`}=0\fi\@testopt{\LF@no@pgbk-}4}% - \def\nopagebreak{\noalign{\ifnum`}=0\fi\@testopt\LF@no@pgbk4}% - \let\hline\LF@hline \let\kill\LF@kill\let\caption\LF@caption - \@tempdima\ht\strutbox - \let\@endpbox\LF@endpbox - \ifx\extrarowheight\@undefined - \let\@acol\@tabacol - \let\@classz\@tabclassz \let\@classiv\@tabclassiv - \def\@startpbox{\vtop\LF@startpbox}% - \let\@@startpbox\@startpbox - \let\@@endpbox\@endpbox - \let\LF@LL@FM@cr\@tabularcr - \else - \advance\@tempdima\extrarowheight - \col@sep\tabcolsep - \let\@startpbox\LF@startpbox\let\LF@LL@FM@cr\@arraycr - \fi - \setbox\@arstrutbox\hbox{\vrule - \@height \arraystretch \@tempdima - \@depth \arraystretch \dp \strutbox - \@width \z@}% - \let\@sharp##\let\protect\relax - \begingroup - \@mkpream{#2}% - \xdef\LF@bchunk{% - \global\advance\c@LF@chunks\@ne - \global\LF@rows\z@\setbox\z@\vbox\bgroup - \LF@setprevdepth - \tabskip\LFleft \noexpand\halign to\hsize\bgroup - \tabskip\z@ \@arstrut \@preamble \tabskip\LFright \cr}% - \endgroup - \expandafter\LF@nofcols\LF@bchunk&\LF@nofcols - \LF@make@row - \m@th\let\par\@empty - \everycr{}\lineskip\z@\baselineskip\z@ - \LF@bchunk} -\def\LF@no@pgbk#1[#2]{\penalty #1\@getpen{#2}\ifnum`{=0\fi}} -\def\LF@start{% - \let\LF@start\endgraf - \endgraf\penalty\z@\vskip\LFpre - \dimen@\pagetotal - \advance\dimen@ \ht\ifvoid\LF@firsthead\LF@head\else\LF@firsthead\fi - \advance\dimen@ \dp\ifvoid\LF@firsthead\LF@head\else\LF@firsthead\fi - \advance\dimen@ \ht\LF@foot - \dimen@ii\vfuzz - \vfuzz\maxdimen - \setbox\tw@\copy\z@ - \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox - \setbox\tw@\vbox{\unvbox\tw@}% - \vfuzz\dimen@ii - \advance\dimen@ \ht - \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi - \advance\dimen@\dp - \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi - \advance\dimen@ -\pagegoal - \ifdim \dimen@>\z@\vfil\break\fi - \global\@colroom\@colht - \ifvoid\LF@foot\else - \advance\vsize-\ht\LF@foot - \global\advance\@colroom-\ht\LF@foot - \dimen@\pagegoal\advance\dimen@-\ht\LF@foot\pagegoal\dimen@ - \maxdepth\z@ - \fi - \ifvoid\LF@firsthead\copy\LF@head\else\box\LF@firsthead\fi\nobreak - \output{\LF@output}} -\def\endlongfigure{% - \crcr - \noalign{% - \let\LF@entry\LF@entry@chop - \xdef\LF@save@row{\LF@save@row}}% - \LF@echunk - \LF@start - \unvbox\z@ - \LF@get@widths - \if@filesw - {\let\LF@entry\LF@entry@write\immediate\write\@auxout{% - \gdef\expandafter\noexpand - \csname LF@\romannumeral\c@LF@tables\endcsname - {\LF@save@row}}}% - \fi - \ifx\LF@save@row\LF@@save@row - \else - \LF@warn{Column \@width s have changed\MessageBreak - in table \thetable}% - \LF@final@warn - \fi - \endgraf\penalty -\LF@end@pen - \endgroup - \global\@mparbottom\z@ - \pagegoal\vsize - \endgraf\penalty\z@\addvspace\LFpost - \ifvoid\footins\else\insert\footins{}\fi} -\def\LF@nofcols#1&{% - \futurelet\@let@token\LF@n@fcols} -\def\LF@n@fcols{% - \advance\LF@cols\@ne - \ifx\@let@token\LF@nofcols - \expandafter\@gobble - \else - \expandafter\LF@nofcols - \fi} -\def\LF@tabularcr{% - \relax\iffalse{\fi\ifnum0=`}\fi - \@ifstar - {\def\crcr{\LF@crcr\noalign{\nobreak}}\let\cr\crcr - \LF@t@bularcr}% - {\LF@t@bularcr}} -\let\LF@crcr\crcr -\let\LF@setprevdepth\relax -\def\LF@t@bularcr{% - \global\advance\LF@rows\@ne - \ifnum\LF@rows=\LFchunksize - \gdef\LF@setprevdepth{% - \prevdepth\z@\global - \global\let\LF@setprevdepth\relax}% - \expandafter\LF@xtabularcr - \else - \ifnum0=`{}\fi - \expandafter\LF@LL@FM@cr - \fi} -\def\LF@xtabularcr{% - \@ifnextchar[\LF@argtabularcr\LF@ntabularcr} -\def\LF@ntabularcr{% - \ifnum0=`{}\fi - \LF@echunk - \LF@start - \unvbox\z@ - \LF@get@widths - \LF@bchunk} -\def\LF@argtabularcr[#1]{% - \ifnum0=`{}\fi - \ifdim #1>\z@ - \unskip\@xargarraycr{#1}% - \else - \@yargarraycr{#1}% - \fi - \LF@echunk - \LF@start - \unvbox\z@ - \LF@get@widths - \LF@bchunk} -\def\LF@echunk{% - \crcr\LF@save@row\cr\egroup - \global\setbox\@ne\lastbox - \unskip - \egroup} -\def\LF@entry#1#2{% - \ifhmode\@firstofone{&}\fi\omit - \ifnum#1=\c@LF@chunks - \else - \kern#2\relax - \fi} -\def\LF@entry@chop#1#2{% - \noexpand\LF@entry - {\ifnum#1>\c@LF@chunks - 1}{0pt% - \else - #1}{#2% - \fi}} -\def\LF@entry@write{% - \noexpand\LF@entry^^J% - \@spaces} -\def\LF@kill{% - \LF@echunk - \LF@get@widths - \expandafter\LF@rebox\LF@bchunk} -\def\LF@rebox#1\bgroup{% - #1\bgroup - \unvbox\z@ - \unskip - \setbox\z@\lastbox} -\def\LF@blank@row{% - \xdef\LF@save@row{\expandafter\LF@build@blank - \romannumeral\number\LF@cols 001 }} -\def\LF@build@blank#1{% - \if#1m% - \noexpand\LF@entry{1}{0pt}% - \expandafter\LF@build@blank - \fi} -\def\LF@make@row{% - \global\expandafter\let\expandafter\LF@save@row - \csname LF@\romannumeral\c@LF@tables\endcsname - \ifx\LF@save@row\relax - \LF@blank@row - \else - {\let\LF@entry\or - \if!% - \ifcase\expandafter\expandafter\expandafter\LF@cols - \expandafter\@gobble\LF@save@row - \or - \else - \relax - \fi - !% - \else - \aftergroup\LF@blank@row - \fi}% - \fi} -\let\setlongfigures\relax -\def\LF@get@widths{% - \setbox\tw@\hbox{% - \unhbox\@ne - \let\LF@old@row\LF@save@row - \global\let\LF@save@row\@empty - \count@\LF@cols - \loop - \unskip - \setbox\tw@\lastbox - \ifhbox\tw@ - \LF@def@row - \advance\count@\m@ne - \repeat}% - \ifx\LF@@save@row\@undefined - \let\LF@@save@row\LF@save@row - \fi} -\def\LF@def@row{% - \let\LF@entry\or - \edef\@tempa{% - \ifcase\expandafter\count@\LF@old@row - \else - {1}{0pt}% - \fi}% - \let\LF@entry\relax - \xdef\LF@save@row{% - \LF@entry - \expandafter\LF@max@sel\@tempa - \LF@save@row}} -\def\LF@max@sel#1#2{% - {\ifdim#2=\wd\tw@ - #1% - \else - \number\c@LF@chunks - \fi}% - {\the\wd\tw@}} -\def\LF@hline{% - \noalign{\ifnum0=`}\fi - \penalty\@M - \futurelet\@let@token\LF@@hline} -\def\LF@@hline{% - \ifx\@let@token\hline - \global\let\@gtempa\@gobble - \gdef\LF@sep{\penalty-\@medpenalty\vskip\doublerulesep}% - \else - \global\let\@gtempa\@empty - \gdef\LF@sep{\penalty-\@lowpenalty\vskip-\arrayrulewidth}% - \fi - \ifnum0=`{\fi}% - \multispan\LF@cols - \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr - \noalign{\LF@sep}% - \multispan\LF@cols - \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr - \noalign{\penalty\@M}% - \@gtempa} -% \end{macrocode} -% \subsection{Captioning} -% You can easily change how a long figure is captioned by -% redefining the \cs{LF@makecaption} macro after loading the |longfigure| package. -% The following statements show the default definition of the -% \cs{LF@makecaption}: -% -% \begin{macrocode} -\def\LF@caption{% - \noalign\bgroup - \@ifnextchar[{\egroup\LF@c@ption\@firstofone}\LF@capti@n} -% \end{macrocode} -% The \cs{LF@caption} command begins the process. -% If it includes an optional argument, it calls \cs{LF@c@ption}; otherwise -% it calls \cs{LF@capti@n}, which then calls \cs{LF@c@ption}. -% \begin{macrocode} -\def\LF@c@ption#1[#2]#3{% - \LF@makecaption#1\LF@name{#3}% - \def\@tempa{#2}% - \ifx\@tempa\@empty\else -% \end{macrocode} -% If a list of long figures is requested, the following code uses the -% previously defined \cs{strcfstr} macro and \cs{ifLF@same} boolean -% to determine the name of the counter and set the output file to -% contain the |longfigure| information. -% -% The code writes to one of the following files. -% \begin{itemize} -% \item If the counter is |figure|, write to the |lof| file. -% \item If the counter is |table|, write to the |lot| file. -% \item Otherwise, write to |lft|, a file created here for this purpose. -% \end{itemize} -% -% \begin{macrocode} - {\let\\\space - \strcfstr{\LFcounter}{figure} - \ifLF@same\def\LFoutfile{lof}\else - \strcfstr{\LFcounter}{table} - \ifLF@same\def\LFoutfile{lot}\else - \def\LFoutfile{lft}\fi\fi - \addcontentsline{\LFoutfile}{\LFcounter} - {\expandafter\protect\expandafter\numberline\expandafter% - {\expandafter\csname the\LFcounter\endcsname}{#2}}}% - \fi -} -% \end{macrocode} -% The \cs{LF@c@ption} macro ends the process when it calls the -% \cs{LF@makecaption} macro, which typesets the caption. -% \begin{macrocode} -\def\LF@capti@n{% - \@ifstar - {\egroup\LF@c@ption\@gobble[]}% - {\egroup\@xdblarg{\LF@c@ption\@firstofone}}} -% \end{macrocode} -% -% If you want to redefine how the |longfigure| is captioned, -% you need to override the following macro. -% The first argument is the name of the counter -% (for example, |Figure|), the second argument is the number of the counter, and the -% third argument is the caption itself. -% \begin{macrocode} -\def\LF@makecaption#1#2#3{% - \LF@mcol\LF@cols c{\hbox to\z@{\hss\parbox[t]\LFcapwidth{% - \sbox\@tempboxa{#1{#2: }#3}% - \ifdim\wd\@tempboxa>\hsize - #1{#2: }#3% - \else - \hbox to\hsize{\hfil\box\@tempboxa\hfil}% - \fi - \endgraf\vskip\baselineskip}% - \hss}}} -\def\LF@output{% - \ifnum\outputpenalty <-\@Mi - \ifnum\outputpenalty > -\LF@end@pen - \LF@err{floats and marginpars not allowed in a longfigure}\@ehc - \else - \setbox\z@\vbox{\unvbox\@cclv}% - \ifdim \ht\LF@lastfoot>\ht\LF@foot - \dimen@\pagegoal - \advance\dimen@-\ht\LF@lastfoot - \ifdim\dimen@<\ht\z@ - \setbox\@cclv\vbox{\unvbox\z@\copy\LF@foot\vss}% - \@makecol - \@outputpage - \setbox\z@\vbox{\box\LF@head}% - \fi - \fi - \global\@colroom\@colht - \global\vsize\@colht - \vbox - {\unvbox\z@\box\ifvoid\LF@lastfoot\LF@foot\else - \LF@lastfoot\fi}% - \fi - \else - \setbox\@cclv\vbox{\unvbox\@cclv\copy\LF@foot\vss}% - \@makecol - \@outputpage - \global\vsize\@colroom - \copy\LF@head\nobreak - \fi} -\def\LF@end@hd@ft#1{% - \LF@echunk - \ifx\LF@start\endgraf - \LF@err - {Longfigure head or foot not at start of table}% - {Increase LFchunksize}% - \fi - \setbox#1\box\z@ - \LF@get@widths - \LF@bchunk} -% \end{macrocode} -% The following four macros do not have an \cs{LT} prefix in the |longtable| package, -% but they must be redefined to have an \cs{LF} prefix in order to avoid a namespace clash; -% \begin{macrocode} -\def\endLFfirsthead{\LF@end@hd@ft\LF@firsthead} -\def\endLFhead{\LF@end@hd@ft\LF@head} -\def\endLFfoot{\LF@end@hd@ft\LF@foot} -\def\endLFlastfoot{\LF@end@hd@ft\LF@lastfoot} - % -\def\LF@startpbox#1{% - \bgroup - \let\@footnotetext\LF@p@ftntext - \setlength\hsize{#1}% - \@arrayparboxrestore - \vrule \@height \ht\@arstrutbox \@width \z@} -\def\LF@endpbox{% - \@finalstrut\@arstrutbox - \egroup - \the\LF@p@ftn - \global\LF@p@ftn{}% - \hfil} -\def\LF@p@ftntext#1{% - \edef\@tempa{\the\LF@p@ftn\noexpand\footnotetext[\the\c@footnote]}% - \global\LF@p@ftn\expandafter{\@tempa{#1}}}% -% \end{macrocode} diff --git a/content/longfigure.wrapper b/content/longfigure.wrapper deleted file mode 100644 index 4d1449b..0000000 --- a/content/longfigure.wrapper +++ /dev/null @@ -1,147 +0,0 @@ -% \iffalse meta-comment -%<*internal> -\iffalse -% -%<*readme> ----------------------------------------------------------------- -longfigure --- A LaTeX package providing a table-like environment - that can display a stream of figures as a single - figure that can be broken by \TeX's - standard page-breaking algorithm. - - Nearly identical to David Carlisle's |longtable| package, - but with some obvious changes to use figures instead of - tables. All credit goes to David Carlisle; this package - represents small changes to his code and logic. - -E-mail: tim.arnold@sas.com -Released under the LaTeX Project Public License v1.3c or later -See http://www.latex-project.org/lppl.txt ----------------------------------------------------------------- - -This work consists of the file longfigure.dtx -and the derived files: - README (this file) - longfigure.ins - longfigure.pdf - longfigure.sty -% -%<*internal> -\fi -\def\nameofplainTeX{plain} -\ifx\fmtname\nameofplainTeX\else - \expandafter\begingroup -\fi -% -%<*install> -\input docstrip.tex -\keepsilent -\askforoverwritefalse -\preamble ----------------------------------------------------------------- -longfigure --- A LaTeX package providing a table-like environment - that can display a stream of subfigures as a single - figure that can be broken by \TeX's - standard page-breaking algorithm. - -E-mail: tim.arnold@sas.com ----------------------------------------------------------------- -\endpreamble -\postamble -Copyright (C) 2014 by SAS Institute Inc. - -This work may be distributed and/or modified under the -conditions of the LaTeX Project Public License (LPPL), either -version 1.3c of this license or any later version. -The latest version of this license is in the file: -http://www.latex-project.org/lppl.txt - -This work is "maintained" (as per LPPL maintenance status) by -Tim Arnold. - -This work consists of the file longfigure.dtx -and the derived files: - README (this file) - longfigure.ins - longfigure.pdf - longfigure.sty -\endpostamble -\generate{\file{longfigure.sty}{\from{longfigure.dtx}{longfigure}}} -% -%\endbatchfile -%<*internal> -\generate{\file{longfigure.ins}{\from{longfigure.dtx}{install}}} -\nopreamble\nopostamble -\generate{\file{README.}{\from{longfigure.dtx}{readme}}} -\ifx\fmtname\nameofplainTeX - \expandafter\endbatchfile -\else - \expandafter\endgroup -\fi -% -%<*longfigure> -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{longfigure}[2014/1/06 v1.0] -% -%<*driver> -\documentclass{ltxdoc} -\usepackage[T1]{fontenc} -\usepackage{lmodern} -\usepackage{\jobname} -\usepackage[numbered]{hypdoc} -\EnableCrossrefs -\CodelineIndex -\RecordChanges -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -%\GetFileInfo{\jobname.sty} -% \def\fileversion{v1.0} -% -%\title{^^A -% The \textsf{longfigure} Package\thanks{^^A -% This file describes version \fileversion, last revised \filedate.^^A -% }^^A -%} -%\author{^^A -% Tim Arnold\thanks{E-mail: tim.arnold@sas.com}^^A -%} -%\date{Released \filedate} -% -%\maketitle -% -%\changes{v1.0}{2014/1/06}{First public release} -% \section{Usage} -% \label{longfigure} -% \subsection{References} -% \begin{description} -% \item[\textmd{Carlisle, D. 2004.}] -% \emph{The longtable Package}. -% Included in the ``Comprehensive \TeX\ Archive Network.'' \url{http://ctan.org}. -% -% \item[\textmd{Lazarides, Y. 2010.}] -% \TeX stackexchange, online forum. \url{http://tex.stackexchange.com/questions/7992}. -% -% \item[\textmd{Sch\"opf, R., B. Raichle, and C. Rowley. 2001.}] -% \emph{A New Implementation of \LaTeX's \texttt{verbatim} and \texttt{verbatim*} Environments}. -% Originally appeared in TUGboat 1990, 11(2), 284--296. -% -% \item[\textmd{Thanh, H., S. Rahtz, H. Hagen, and H. Henkel. 2009.}] -% ``The pdf\TeX\ User's Manual'' Revision 655, corresponding to pdf\TeX\ 1.40.11. -% \url{www.tug.org/applications/pdftex} -% -% \item[\textmd{Wilson, Peter. 2001.}] -% \emph{Glisterings} in TUGboat 22(4), 339--340. -% \end{description} -% -%\StopEventually{^^A -% \PrintChanges -% \PrintIndex -%} -% -% \begin{macrocode} -% -% \end{macrocode} -%\Finale diff --git a/benchmark/longfigure.sty b/longfigure.sty similarity index 92% rename from benchmark/longfigure.sty rename to longfigure.sty index 08be62b..88991d6 100644 --- a/benchmark/longfigure.sty +++ b/longfigure.sty @@ -4,17 +4,15 @@ %% %% The original source files were: %% -%% longfigure.dtx (with options: `longfigure') +%% statrep.dtx (with options: `longfigure') %% ---------------------------------------------------------------- -%% longfigure --- A LaTeX package providing a table-like environment -%% that can display a stream of subfigures as a single -%% figure that can be broken by T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX\spacefactor \@m {}'s -%% standard page-breaking algorithm. +%% StatRep --- A LaTeX package to generate documentation and a SAS program that +%% generates the SAS results used in the source document. +%% The package helps to support reproducible research. +%% +%% E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr %% -%% E-mail: tim.arnold@sas.com %% ---------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{longfigure}[2014/1/06 v1.0] %% \iffalse \ProvidesPackage{longfigure}[2014/01/06 longfigure] \RequirePackage{xkeyval} @@ -453,22 +451,19 @@ \def\LF@p@ftntext#1{% \edef\@tempa{\the\LF@p@ftn\noexpand\footnotetext[\the\c@footnote]}% \global\LF@p@ftn\expandafter{\@tempa{#1}}}% -%% Copyright (C) 2014 by SAS Institute Inc. -%% -%% This work may be distributed and/or modified under the -%% conditions of the LaTeX Project Public License (LPPL), either -%% version 1.3c of this license or any later version. -%% The latest version of this license is in the file: -%% http://www.latex-project.org/lppl.txt +%% Copyright (C) 2015 by SAS Institute Inc. %% -%% This work is "maintained" (as per LPPL maintenance status) by -%% Tim Arnold. +%% This work consists of the files +%% statrep.dtx, +%% statrep_macros.sas, +%% statrep_tagset.sas +%% statrepmanual.tex, +%% quickstart.tex %% -%% This work consists of the file longfigure.dtx -%% and the derived files: -%% README (this file) -%% longfigure.ins -%% longfigure.pdf -%% longfigure.sty +%% and the derived files +%% statrep.ins, statrep.cfg, statrep.sty, longfigure.sty, +%% statrep.pdf, +%% statrep_macros.sas, +%% statrepmanual.pdf %% %% End of file `longfigure.sty'. diff --git a/statrep.cfg b/statrep.cfg new file mode 100644 index 0000000..93fdf56 --- /dev/null +++ b/statrep.cfg @@ -0,0 +1,69 @@ +%% +%% This is file `statrep.cfg', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% statrep.dtx (with options: `cfg') +%% ---------------------------------------------------------------- +%% StatRep --- A LaTeX package to generate documentation and a SAS program that +%% generates the SAS results used in the source document. +%% The package helps to support reproducible research. +%% +%% E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr +%% +%% ---------------------------------------------------------------- +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Edit this line to point to the location of the StatRep macros. +\def\SRmacropath{\SRrootdir/statrep_macros.sas} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The following statements define line size, page size, graphic resolution, +%% and also specify the default ODS output style: +\ifSASServer +\def\SRrootdir{¤tpath} +\else +\def\SRrootdir{.} +\fi +\def\SRlinesize{80} +\def\SRpagesize{500} +\def\SRdpi{300} +\def\SRstyle{statistical} +\def\SRlatexstyle{statrep} +\def\SRodsgraphopts{} + +\def\SRgraphicdir{\SRrootdir/png} +\def\SRgraphtype{png} +\def\SRlistingdir{\SRrootdir/lst} +\def\SRlatexdir{\SRrootdir/tex} +\def\SRdefaultdests{listing} +\edef\SRprogramname{\jobname_SR.sas} +\edef\SRpreamblename{\jobname_SR_preamble.sas} +\def\SRmacroinclude{\@percentchar include "\SRmacropath" /nosource;} +\def\SRsasprogramline{% +\@percentchar cleandir(\SRrootdir, tex, tex);^^J% +\@percentchar cleandir(\SRrootdir, png, png);^^J% +\@percentchar cleandir(\SRrootdir, lst, lst);^^J% +}% +\def\SRparindent{3em} +\def\SRintertext{... more data lines ...} +\def\SRtempfilename{sr.tmp} +\def\SRcontinuedname{continued} +\def\SRcaptionfont{\sffamily} +\def\SRcaptioncontinuedfont{\sffamily\itshape} +\def\SRverbfont{\ttfamily\bfseries} +%% Copyright (C) 2015 by SAS Institute Inc. +%% +%% This work consists of the files +%% statrep.dtx, +%% statrep_macros.sas, +%% statrep_tagset.sas +%% statrepmanual.tex, +%% quickstart.tex +%% +%% and the derived files +%% statrep.ins, statrep.cfg, statrep.sty, longfigure.sty, +%% statrep.pdf, +%% statrep_macros.sas, +%% statrepmanual.pdf +%% +%% End of file `statrep.cfg'. diff --git a/content/statrep.wrapper b/statrep.dtx similarity index 73% rename from content/statrep.wrapper rename to statrep.dtx index 23c3b0c..facec59 100644 --- a/content/statrep.wrapper +++ b/statrep.dtx @@ -17,8 +17,9 @@ These SAS macros are included in this package (statrep_macros.sas). The package is available in two locations: - * http://support.sas.com/StatRepPackage - * http://mirror.ctan.org/macros/latex/contrib/statrep/ + * http://support.sas.com/StatRepPackage - Obsolet + * https://github.com/MartialP-G/StatRep + * http://mirror.ctan.org/macros/latex/contrib/statrep/ The distribution(statrep.zip) consists of the following files: README.txt (this file) @@ -55,7 +56,7 @@ Step 2: Install the StatRep LaTeX Package system-wide LaTeX distribution and you want to make StatRep available to all users, see more detailed information about how to install LaTeX packages at - http://www.tex.ac.uk/cgi-bin/texfaq2html?label=what-TDS + https://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-440005.2 a) Determine the location that LaTeX uses to load packages. From a @@ -113,9 +114,19 @@ EXPLORE directory and copy the file quickstart.tex into it. To generate the quickstart document: - 1) Compile the document with pdfLaTeX. You can use a LaTeX-aware - editor such as TeXworks or use the command-line command 'pdflatex'. - This step generates the SAS program that is needed to produce the results. + 1) Compile the document with pdfLaTeX. You can use a LaTeX-aware + editor such as TeXworks, or you can use the command-line command 'pdflatex'. + This step generates the necessary SAS program that is needed to produce + the results. If the name of your document is myarticle.tex, the names of + the generated SAS programs will be myarticle_SR.sas and + myarticle_SR_preamble.sas by default. + + myarticle_SR.sas: Begins with a call to the preamble SAS file, then + the cleaning subdirectory, and then the aggregate SAS code present + in the LaTeX file. + myarticle_SR_preamble.sas: Mainly contains custom variables (see the + customizable settings section) and a call to the statrep_macros.sas + macro file. 2) Execute the SAS program quickstart_SR.sas, which was automatically created in the preceding step. This step generates the SAS @@ -153,26 +164,43 @@ statrep_macros.sas statrep_tagset.sas statrepmanual.tex -Copyright (c) 2015 SAS Institute Inc. + ----------------------------------------------------------------- + Copyright (c) 2015 SAS Institute Inc. + Copyright (c) 2026 Martial Phélippé-Guinvarc'h + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3c + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt +----------------------------------------------------------------- + This work has the LPPL maintenance status 'maintained'. -Permission is granted to copy, distribute, and/or modify this software -under the terms of the LaTeX Project Public License (LPPL), version 1.3. + The Current Maintainer of this work is Martial Phélippé-Guinvarc'h. + Contact: Martial dot Phelippe-GuinvarcH at univ-lemans dot fr -This software is provided by SAS Institute Inc. as a service to its users. -It is provided 'as is', without warranty of any kind, either expressed or -implied, including, but not limited to, the implied warranties of -merchantibility and fitness for a particular purpose. -See http://www.latex-project.org/lppl.txt for the details of that license. + The original version was developed by Tim Arnold (SAS Institute). + This is an independent update and is not officially supported + by SAS Institute Inc. -This work has the LPPL maintenance status 'maintained'. -The Current Maintainer of this work is Tim Arnold (tim dot arnold at sas dot com). +DESCRIPTION OF CHANGES (2026/04/28): + - Improved path resolution logic when using SASmode option. + - Added UTF-8 encoding support for SAS input files. + - Included new macros for automatic LaTeX export of SAS results + via specialized formats. +----------------------------------------------------------------- + This work consists of the files statrep.dtx, + statrep_macros.sas, + statrep_tagset.sas + and the derived file statrep.ins and statrep.sty. +----------------------------------------------------------------- REQUIREMENTS pdfLaTeX typesetting engine 1.30 or later LaTeX packages - verbatim, graphicx, xkeyval, calc, ifthen + verbatim, graphicx, ifthen, calc, etoolbox, xkeyval SAS 9.2 or later See the StatRep User's Guide, included with this package, for complete details. @@ -207,7 +235,8 @@ StatRep --- A LaTeX package to generate documentation and a SAS program that generates the SAS results used in the source document. The package helps to support reproducible research. -E-mail: tim.arnold@sas.com +E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr + ---------------------------------------------------------------- \endpreamble \postamble @@ -244,7 +273,7 @@ and the derived files % %<*statrep> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{statrep}[2015/09/15 v1.07 The statrep package] +\ProvidesPackage{statrep}[2026/04/28 v2.0 The statrep package] % %<*driver> \documentclass[11pt]{ltxdoc} @@ -277,9 +306,9 @@ and the derived files % %\fi %\def\filename{statrep.dtx} -%\def\fileversion{1.07} +%\def\fileversion{2.0} %\def\filedate{\today} -%\CheckSum{2172} +%\CheckSum{2291} %\StopEventually{\PrintChanges\PrintIndex} % % \CharacterTable @@ -307,6 +336,9 @@ and the derived files %\changes{v1.05}{2014/10/27}{Added support SAS-generated LaTeX table output} %\changes{v1.06}{2015/01/15}{Added support for root directory specification} %\changes{v1.07}{2015/09/15}{Fixed bug with losing margins after an output} +%\changes{v2.0}{2026/04/28}{Added current path resolution for SASmode, +% UTF-8 encoding support for SAS input files, and automated result +% export macros using formats.} %\GetFileInfo{statrep.sty} % % @@ -357,12 +389,14 @@ and the derived files %\DoNotIndex{\z@} %\DoNotIndex{\@empty,\@tempa,\@tempboxa,\@tempdima,\@twocolumntrue,\baselineskip} %\DoNotIndex{\c@LF@tables,\detokenize,\hss,\LF@c@ption,\LF@capti@n,\LF@firsthead} -%\DoNotIndex{\LF@foot,\LF@head,\LF@hline\LF@make@row,\LF@name,\LF@start,\LFcounter} +%\DoNotIndex{\LF@foot,\LF@head,\LF@hline,\LF@make@row,\LF@name,\LF@start,\LFcounter} %\DoNotIndex{\LFProcessOptions,\RequirePackage,\string,\SR@outkey,\SR@outval,\usebox} % %\title{The \textsf{statrep} package\thanks{This document corresponds %to \textsf{statrep}~\fileversion, last revised \filedate.}} -%\author{Tim Arnold and Warren F. Kuhfeld\\SAS Institute Inc.\\\texttt{tim.arnold@sas.com}\\\texttt{warren.kuhfeld@sas.com}} +%\author{Martial Phélippé-Guinvarc'h\\Le Mans Université\\\texttt{martial.phelippe-guinvarch@univ-lemans.fr}\\ +%\smallskip +%{\small Based on the original work by Tim Arnold and Warren F. Kuhfeld (SAS Institute Inc. 2015)}} %\date{\filedate} %\maketitle %\iffalse @@ -419,7 +453,14 @@ and the derived files % each change in the specified counter value. For example, if \Code{resetby=chapter}, % all output numbering is reset when the chapter value changes. See section % \ref{longfigure} for details. Also, refer to the \Code{tocloft} package documentation -% for information about how the lists are typeset.\index{list of outputs, creating}% +% for information about how the lists are typeset. +% \index{list of outputs, creating}% +% +% \item \Code{SASmode=WorkStation} or \Code{SASmode=Server} changes the current path definition. +% For \Code{WorkStation}, the \Code{rootdir} or current path is \Code{.} (the working directory); +% for \Code{Server}, the current path is \Code{\¤tpath}, obtained from the +% \Code{\&\_SASPROGRAMFILE} SAS macro variable. +% \index{SASmode= option} % \end{itemize} % % The options \Code{figname=} and \Code{resetby=} are not used directly by the \Statrep @@ -446,6 +487,30 @@ and the derived files % % % For more information about how to use the \Statrep package, see the \Statrep User's Guide % (\texttt{statrepmanual.pdf}) that accompanies the \Statrep distribution. + +% +% \subsection{Workflow} +% To produce a complete document with \Statrep, follow these steps: +% \begin{enumerate} +% \item Compile the document with pdf\LaTeX. You can use a \LaTeX-aware +% editor such as \TeX works, or you can use the command-line command \Code{pdflatex}. +% This step generates the necessary SAS program that is needed to produce the results. +% If the name of your document is \textit{myarticle.tex}, the names of the generated SAS +% programs will be \textit{myarticle\_SR.sas} and \textit{myarticle\_SR\_preamble.sas} by default. +% \begin{description} +% \item[\textit{myarticle\_SR.sas}] Begins with a call to the preamble SAS file, +% then the cleaning subdirectory, and then the aggregate SAS code present in the \LaTeX\ file. +% \item[\textit{myarticle\_SR\_preamble.sas}] Mainly contains custom variables +% (see section~\ref{custom}) and a call to the \Code{statrep\_macros.sas} macro file. +% \end{description} +% +% \item Execute the generated SAS program \textit{myarticle\_SR.sas}. +% This step generates the SAS results requested in your document. +% +% \item Recompile the document with pdf\LaTeX. This step includes the SAS results +% in the final document. You might need to repeat this step so that \LaTeX\ can +% re-measure the listing outputs to ensure that they are framed properly. +% \end{enumerate} % % \section{\Statrep Implementation} % @@ -456,18 +521,44 @@ and the derived files % \begin{macrocode} \RequirePackage{verbatim} \RequirePackage{graphicx} -\RequirePackage{xkeyval} -\RequirePackage{calc} \RequirePackage{ifthen} +\RequirePackage{calc} +\RequirePackage{etoolbox} +\RequirePackage{xkeyval} % \end{macrocode} % \begin{itemize} % \item The |verbatim| package provides the foundation for the \Statrep package. % \item The |graphicx| package enables inclusion of images and is used by the \cs{Graphic} tag. % \item The |xkeyval|, |calc|, and |ifthen| packages provide programming capabilities that are % used throughout the \Statrep package. +% \item The |etoolbox| is needed for string comparison (ifstrequal) % \end{itemize} % % \begin{macrocode} +\newif\ifSASServer +\SASServerfalse % Default is Workstation +% Define the ‘SASmode’ key for the ‘statrep’ package +\DeclareOptionX{SASmode}{\setkeys{statrep}{SASmode=#1}} +\define@key{statrep}{SASmode}{% + \ifstrequal{#1}{Server}{% if value is 'Server' + \SASServertrue + \PackageInfo{statrep}{Mode SAS: Serveur (utilise \string&\string_SASPROGRAMFILE).} + }{% If value is not 'Serveur', we control if it is 'WorkStation' + \ifstrequal{#1}{WorkStation}{% + \SASServerfalse + \PackageInfo{statrep}{Mode SAS: WorkStation (use ./).} + }{% + % If value is unknown, we print an warning + \SASServerfalse + \PackageWarning{statrep}{Unknown value for SASmode (#1). Default use of WorkStation (uses ./).} + }% + }% +} +% \end{macrocode} +% The SASmode option is defined to provide an explicit current path +% when the default "./" does not work (SAS Server/SAS on Demand, etc.). +% +% \begin{macrocode} \newif\ifSR@generate\SR@generatetrue \DeclareOptionX{generate}[true]{\@nameuse{SR@generate#1}} \DeclareOptionX{color}[true]{% @@ -478,10 +569,6 @@ and the derived files \DeclareOptionX{figname}{\PassOptionsToPackage{\CurrentOption}{longfigure}} \DeclareOptionX{resetby}{\PassOptionsToPackage{\CurrentOption}{longfigure}} \ProcessOptionsX -\IfFileExists{sas.sty} - {\RequirePackage{sas}} - {\relax} -\RequirePackage{longfigure} % \end{macrocode} % % Declare an option for \texttt{color}; Pass the value to the \texttt{sas} @@ -499,6 +586,37 @@ and the derived files % throughout the package: % % \begin{macrocode} +\providecommand{\SR@encoding}{utf-8} +\def\statrep@map@sas@encoding#1{% + \def\SR@encoding{utf-8} + \ifstrequal{#1}{utf8}{\def\SR@encoding{utf-8}}{}% + \ifstrequal{#1}{utf8x}{\def\SR@encoding{utf-8}}{}% +% latin1, latin9, ansinew, etc. is mapped to wlatin1 + \ifstrequal{#1}{latin1}{\def\SR@encoding{wlatin1}}{}% + \ifstrequal{#1}{latin9}{\def\SR@encoding{wlatin1}}{}% + \ifstrequal{#1}{ansinew}{\def\SR@encoding{wlatin1}}{}% +} +\AtBeginDocument{% +\@ifpackageloaded{inputenc}{% + \statrep@map@sas@encoding{\inputencodingname}% + \PackageInfo{statrep}{Encodind LaTeX ({\inputencodingname}) detected and mapped to SAS: + \\SR@encoding.} + }{% + % else, default utf-8 is retained. + \PackageInfo{statrep}{inputenc unfund. Default SAS encoding: \\SR@encoding utf-8.} + } +} +\IfFileExists{sas.sty} + {\RequirePackage{sas}} + {\relax} +\IfFileExists{\jobname _VarSAStoTex.tex}{\input{\jobname _VarSAStoTex.tex}}{} +\RequirePackage{longfigure} +% \end{macrocode} +% +% Management of the encoding of the input SAS file +% Control of the presence of the SAS.sty product file in the SAS compilation +% +% \begin{macrocode} \ifSR@generate\def\SR@writepgm{\immediate\write} \else\let\SR@writepgm\@gobbletwo \fi @@ -714,7 +832,7 @@ and the derived files objects = \@empty, pattern = \@empty, options = \@empty, height = \@empty, pagesize = \@empty}{} % \end{macrocode} -% \subsection{Customizable Settings} +% \subsection{Customizable Settings}\label{custom} %\iffalse % %<*cfg> @@ -732,12 +850,13 @@ and the derived files % must insert a backslash character into this argument by using the % \cs{@backslashchar} command. % The default value is the current -% directory. That is, the definition for the path to the macro file +% directory that depend of Server or Workstation option. +% That is, the definition for the path to the macro file % is the filename itself, |statrep_macros.sas|. % \begin{macrocode} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Edit this line to point to the location of the StatRep macros. -\def\SRmacropath{statrep_macros.sas} +\def\SRmacropath{\SRrootdir/statrep_macros.sas} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \end{macrocode} %% The following statements define line size, page size, graphic resolution, @@ -747,7 +866,11 @@ and the derived files % \DescribeMacro{\SRlatexstyle} %\changes{v1.06}{2015/01/15}{Added rootdir for SAS/Studio support.} % \begin{macrocode} -\def\SRrootdir{.} +\ifSASServer + \def\SRrootdir{¤tpath} + \else + \def\SRrootdir{.} +\fi \def\SRlinesize{80} \def\SRpagesize{500} \def\SRdpi{300} @@ -790,8 +913,8 @@ and the derived files %\changes{v1.01}{2012/05/23}{Changed SRsasprogramline to call hostdel SAS macro} %\changes{v1.06}{2015/01/15}{Changed hostdel macro to cleandir for SAS/Studio support.} % \begin{macrocode} -\def\SRprogramname{\jobname_SR.sas} -\def\SRpreamblename{\jobname_SR_preamble.sas} +\edef\SRprogramname{\jobname_SR.sas} +\edef\SRpreamblename{\jobname_SR_preamble.sas} \def\SRmacroinclude{\@percentchar include "\SRmacropath" /nosource;} \def\SRsasprogramline{% \@percentchar cleandir(\SRrootdir, tex, tex);^^J% @@ -856,8 +979,37 @@ and the derived files % |Sascode| blocks. The default is \cs{ttfamily}\cs{bfseries} % ({\bfseries\texttt{typewriter text, bold}}). % +% \index{verbatim font} +% +% \item \cs{SR@encoding} specifies the encoding of the SAS output text files +% (\Code{UTF-8} or \Code{WLATIN1}), corresponding to the \Code{SASencodingOutput} +% SAS macro variable. By default, this value is \Code{utf-8} or is derived from +% the \Code{inputenc} package option. +% \index{encoding} % \end{itemize} % +% +% \subsection{Character Encoding (\texttt{SASencodingOutput})}\label{encoding} +% \index{encoding} +% The \Statrep package automatically manages character encoding to ensure +% compatibility between your \LaTeX\ source document and the generated SAS output. +% +% The package operates on the following priority: +% \begin{enumerate} +% \item \textbf{Automatic Detection}: The package checks if the \Code{inputenc} +% package is loaded. If present, \Statrep retrieves the active \LaTeX\ encoding +% (for example, \Code{utf8}, \Code{latin1}, \Code{ansinew}) and maps it to the +% corresponding SAS output encoding (\Code{UTF-8} or \Code{WLATIN1}). This ensures +% seamless handling of special characters and accents. +% +% \item \textbf{Default Fallback}: If the \Code{inputenc} package is not detected, +% the package defaults to \Code{UTF-8} for all SAS output files. +% +% \item \textbf{Manual Override}: The encoding can be manually forced using the +% package option \Code{SASencodingOutput}. Supported values include \Code{utf8} +% and \Code{wlatin1}. +% \end{enumerate} +% %\iffalse % %<*statrep> @@ -914,6 +1066,7 @@ and the derived files \SR@writepgm\SR@tempfile@stream{\@percentchar let defaultdpi=\SRdpi;} \SR@writepgm\SR@tempfile@stream{\@percentchar let odsgraphopts=\SRodsgraphopts;} \SR@writepgm\SR@tempfile@stream{\@percentchar let defaultdests=\SRdefaultdests;} + \SR@writepgm\SR@tempfile@stream{\@percentchar let SASencodingTex=\SR@encoding;} \SR@writepgm\SR@tempfile@stream{} \SR@writepgm\SR@tempfile@stream{options nodate nonumber} \SR@writepgm\SR@tempfile@stream{ls=&defaultlinesize ps=&defaultpagesize} @@ -932,9 +1085,25 @@ and the derived files % The preamble is written to a separate file and not directly into the capture % program so that users who copy and paste code from the \LaTeX\ source to a SAS % session can include only the preamble in their SAS session. +% Code has been added to automatically define the current file path for the Sever SASmode option. % \begin{macrocode} \immediate\openout\SR@program@stream\SRprogramname \SR@writepgm\SR@program@stream{\SR@preambletext} + \SR@writepgm\SR@program@stream{FILENAME current "&_SASPROGRAMFILE"; *** get the full name of the file;} + \SR@writepgm\SR@program@stream{\@percentchar LET fullpath = \@percentchar sysfunc(pathname(current));} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname = \@percentchar scan(&fullpath, -2, '/.\\');} + \SR@writepgm\SR@program@stream{\@percentchar IF \@percentchar index(&SAStoTexname,_SR) \@percentchar then \@percentchar DO;} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname=\@percentchar substr(&SAStoTexname,1,\@percentchar index(&SAStoTexname,_SR)-1);} + \SR@writepgm\SR@program@stream{\@percentchar END;} + \SR@writepgm\SR@program@stream{\@percentchar let currentpath = \@percentchar substr(&fullpath, 1, \@percentchar length(&fullpath) -} + \SR@writepgm\SR@program@stream{\@percentchar length(\@percentchar scan(&fullpath, -1, '/\\'))-1 );} + \SR@writepgm\SR@program@stream{\@percentchar put &fullpath ¤tpath;} + \SR@writepgm\SR@program@stream{\@percentchar let rc = \@percentchar sysfunc(dlgcdir(¤tpath));} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname = &SAStoTexname._VarSAStoTex.tex;} + \SR@writepgm\SR@program@stream{\@percentchar put &SAStoTexname;} + \SR@writepgm\SR@program@stream{ FILENAME outtex "&SAStoTexname" ENCODING="utf-8";} + \SR@writepgm\SR@program@stream{ DATA _NULL_; FILE outtex LRECL=32767; RUN;} + \SR@writepgm\SR@program@stream{ FILENAME outtex CLEAR;} \SR@writepgm\SR@program@stream{\@percentchar include "\SRrootdir/\SRpreamblename" /nosource;} \SR@writepgm\SR@program@stream{/* Remove all output files. */} \SR@writepgm\SR@program@stream{\SRsasprogramline} @@ -2214,12 +2383,780 @@ and the derived files % \cs{dosloppy} is never called, calling \cs{unsloppy} causes no problem. % % \end{macro} +% +% +% \subsection{SAS Result Export Macros}\label{SAStoTex} +% The \Statrep package provides SAS macros designed to export numeric and +% date variables directly into \LaTeX\ documents in a consistent and +% properly formatted way. +% \begin{itemize} +% \item Predefined \Code{proc format} picture formats handle small numbers, +% large numbers, percentages, and dates. +% \item \Code{\%STATREPResults(variable, format)} writes a single variable +% to a \LaTeX\ file as a \verb|\def| command using the chosen format. +% \item \Code{\%STATREPAllResults()} automatically processes all numeric +% variables in a dataset and generates their \LaTeX\ definitions with +% appropriate formatting. +% \item \Code{\%STATREPMACROVAR(variable)} provides a convenient way to +% export one variable using \Code{\%STATREPAllResults}. +% \item All macros write the output to a file named +% \verb|\jobname\_SAStoTex.tex|, which can be included in your main +% \LaTeX\ document with \verb|\input|. +% \end{itemize} +% These macros make it easy to synchronize SAS results with \LaTeX\ reports, +% ensuring consistency in number formatting, dates, and scientific notation +% across your documents. +%% +%\iffalse +%<*example> +%\fi +%\begin{figure}[H] +%\begin{snugshade} +%\begin{verbatim} +% title 'Probit Analysis, Newspaper Survey'; +% proc format; +% value subscrib 1 = 'accept' 0 = 'reject'; +% run; +% data news; +% input sex $ 1-6 age 12-13 subs 18 ; +% datalines; +% Female 35 0 +% Male 45 1 +% ... more data lines ... +% Female 32 0 +% Female 35 0 +% ; +% +% %LET PARAMETER=365; +% %STATREPALLRESULTS(PARAMETER) +%\end{verbatim} +%\end{snugshade} +%\caption{Example of \texttt{\%STATREPALLRESULTS} Usage}\label{fig:sd3} +%\end{figure} +% The file \Code{\_VarSAStoTex.tex} includes the command +% \verb|\def\PARAMETER{365}|, which can be used in the \LaTeX\ document +% as \verb|\PARAMETER| (see also section~\ref{SAStoTex}). +%\iffalse +% +%\fi %\iffalse % %\fi %<*longfigure> % \section{\textsf{\small longfigure} Usage} % \label{longfigure} +% \index{longfigure package|usage} +% +% The |longfigure| package uses and relabels components of the +% well-known |longtable| package, written by David Carlisle, to +% provide a table-like environment that can display a stream +% of subfigures as a single figure that can break across pages. +% +% The |longtable| package defines a |longtable| environment, +% which produces tables that can be broken by \TeX's standard page-breaking algorithm. +% Similarly, the |longfigure| package defines a |longfigure| environment, which produces +% figures that can be broken by \TeX's standard page-breaking algorithm. +% The internal structure of a long figure is similar to a long table. +% Rows might contain (for example) tables or graphics. Page breaks +% can occur only between rows. +% +% The |longfigure| package differs from the |longtable| package in the following ways: +% \begin{itemize} +% \item The |longfigure| package supports two additional key-value options: +% \begin{itemize} +% \item The |figname=| option specifies the counter for numbering |longfigure| environments. +% You can specify any string; the default is |figure|. +% When you specify a |figname=| value for which no counter already exists, the +% |longfigure| package loads the |tocloft| package and creates the counter. +% \index{figname option|usage} +% +% \item The |resetby=| option specifies a counter (for example, |resetby=chapter|) such +% that output numbering is reset each time the counter value changes. +% If a counter is specified that does not exist, the |tocloft| package is +% loaded to create the new counter. +% \index{tocloft package|usage}% +% For information about how the lists are typeset, +% \index{list of outputs, creating|usage}% +% see the |tocloft| package documentation. +% \end{itemize} +% \item The counters and macros that start with \cs{LT} in the |longtable| package +% are renamed to start with \cs{LF} in the |longfigure| pacakge to avoid +% namespace conflicts when the two packages are used together. +% The generic macros that are defined in the |longtable| package +% (\cs{endfirsthead}, \cs{endhead}, \cs{endfoot}, and \cs{endlastfoot}) are +% also renamed with \cs{LF} as a prefix in the |longfigure| package. +% +% \item The \cs{LF@name} macro is based on the \cs{fnum@table} macro from +% the |longtable| package. The \cs{LF@name} macro returns the capitalized +% counter name and value. For example, if the counter is |figure| and the +% macro is processing the second |longfigure|, the \cs{LF@name} macro +% would contain the value ``Figure 2.'' +% +% \end{itemize} +% You can use the |longfigure| package defaults to produce a \emph{List of Figures} +% by inserting the following tag in your document at the point where you want +% the list to appear: +% \iffalse +%<*example> +% \fi +\begin{verbatim} + \listoffigures +\end{verbatim} +% \iffalse +% +% \fi +% +% The default counter used to display figures is the |figure| counter, +% but you can specify a different counter. For example, if you want your +% figures to be labeled as ``Display,'' specify |figname=display| when you +% load the |longfigure| package; to display a \emph{List of Displays}, insert the following +% command in your document at the point where you want the list to appear: +% \iffalse +%<*example> +% \fi +\begin{verbatim} + \listofdisplay +\end{verbatim} +% \iffalse +% +% \fi +% \textbf{Note:} If you specify a counter that does not exist, +% an auxiliary file with extension |.lft| is created to contain the information +% needed to create the list. +% +% If you want to use more advanced features of the |tocloft| package, +% load it before you load the |longfigure| package so that the |longfigure| +% package sees that the counters specified by the |figname=| and |resetby=| +% options are already defined and does not attempt to create them. +% +% +%\subsection{Example} +% The following lines produce a single figure that contains three images and +% one tabular environment. Each element is a row of the |longfigure| environment. +% Page breaks can occur between rows. +%% \iffalse +%<*example> +% \fi +\begin{verbatim} +\documentclass{book} +\usepackage{graphicx} +\usepackage{longfigure} + +\begin{document} + \begin{longfigure}{c} + \caption{My Long Figure}\label{mlfig}\\ + \includegraphics[width=3in]{myfig1}\\ + \includegraphics[width=3in]{myfig2}\\ + \includegraphics[width=3in]{myfig3}\\ + \begin{tabular}{ll} + one & two \\ + three & four\\ + \end{tabular} + \end{longfigure} +\end{document} +\end{verbatim} +% \iffalse +% +% \fi +% In this example, the |{c}| argument in the |\begin{longfigure}| command +% specifies only a single centered column. You can also specify multiple columns and, +% if needed, use the \cs{multicolumn} command for more flexibility. +% +% The following lines display another example that specifies a 'continued' heading +% when the figure breaks over a page. It also displays a double horizontal line at the +% end of the figure. +% \iffalse +%<*example> +% \fi +\begin{verbatim} +\documentclass{book} +\usepackage{graphicx} +\usepackage{longfigure} + +\begin{document} + \begin{longfigure}{c} + \caption{My Long Figure}\label{mlfig2}\\ + \hline\endLFfirsthead + \caption{continued}\\ + \hline\endLFhead + \hline\endLFfoot + \hline\hline\endLFlastfoot + \includegraphics[width=3in]{myfig1}\\ + \includegraphics[width=3in]{myfig2}\\ + \includegraphics[width=3in]{myfig3}\\ + \begin{tabular}{ll} + one & two \\ + three & four\\ + \end{tabular} + \end{longfigure} +\end{document} +\end{verbatim} +% \iffalse +% +% \fi +% \section{Implementation} +% +% This section describes the implementation of the |longfigure| package. +% The comments describe only the changes from the |longtable| package code. +% For complete details about the logic and usage of the |longtable| environment, +% see Carlisle (2004). +%\iffalse +%<*longfigure> +%\fi +% \begin{macrocode} +\ProvidesPackage{longfigure}[2014/01/06 longfigure] +% \end{macrocode} +% The following statement loads the |xkeyval| package for declaring +% and processing package options: +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +% The following statement defines a new command, \cs{LFcounter}, to +% contain the string |figure|. +% Later code tests whether a counter with that name exists. +% \begin{macrocode} +\newcommand*{\LFcounter}{figure} +% \end{macrocode} +% +% The following statement defines a new command, \cs{LFreset}, to contain +% the name of the counter within which the |longfigure| number should reset. +% If no value is specified, the long figures are numbered consecutively +% through the document. +% \begin{macrocode} +\newcommand*{\LFreset}{\@empty} +% \end{macrocode} +% \subsection{Options} +% The \cs{LFcounter} and \cs{LFreset} commands support the +% package options |figname=| and |resetby=| as follows: +% \begin{macrocode} +\DeclareOptionX{figname}[figure]{\renewcommand*{\LFcounter}{#1}} +\DeclareOptionX{resetby}{\renewcommand*{\LFreset}{#1}} +% \end{macrocode} +% The following statements further define the options +% that the |longtable| package defines: +% \begin{macrocode} +\DeclareOptionX{set}{} +\DeclareOptionX{final}{} +\DeclareOptionX{errorshow}{\def\LF@warn{\PackageInfo{longfigure}}} +\DeclareOptionX{pausing}{\def\LF@warn#1{\LF@err{#1}{This is not really an error}}} +\ProcessOptionsX +% \end{macrocode} +% The following statements process the options: +% \begin{macrocode} +\def\LFProcessOptions#1{ + \@ifundefined{c@#1}{% + \RequirePackage{tocloft} + \def\LFuc##1##2{\MakeUppercase{##1}{##2}} + \expandafter\def\csname list#1name\endcsname{List of \LFuc#1s} + \ifx\@empty\LFreset% + \newlistof{#1}{lft}{\csname list#1name\endcsname} + \else + \newlistof[\LFreset]{#1}{lft}{\csname list#1name\endcsname} + \fi + }{}% +} +\expandafter\LFProcessOptions\expandafter{\LFcounter} +% \end{macrocode} +% If a counter is specified that does not exist, its name (\cs{c@}\textit{countername}) +% is undefined and the |longfigure| package loads the |tocloft| package in order to +% use its commands to create the new counters and list. +% +% Thus, the |tocloft| package is required only when a new counter +% is specified, +% \index{tocloft package|usage}% +% and this automatic loading takes place only if the counter that is specified +% in the package options is not defined. +% +% You can load the |tocloft| package before loading the |longfigure| package +% and retain all of the flexibility that the |tocloft| package offers. +% However, you must define the new counters yourself by using the +% \cs{newlistof} command in the |tocloft| package, +% and you must define the new list to use an auxiliary |lft| file where +% its auxiliary information is written. +% \index{tocloft package|usage}% +% +% \subsection{Utilities} +% \DescribeMacro{\strcfstr} +% The following macro, \cs{strcfstr}, checks whether two strings, which are +% provided as arguments, are equal (Wilson, 2001). +% A new boolean \cs{ifLF@same} contains the result of the test. +% \begin{macrocode} +\newif\ifLF@same +\newcommand{\strcfstr}[2]{% + \LF@samefalse + \begingroup\def\2{#2} + \ifx\2#1\endgroup\LF@sametrue + \else\endgroup + \fi +} +% \end{macrocode} +% \DescribeMacro{\LFupcase} +% The following macro, \cs{LFupcase}, uppercases the first letter of +% a string (Lazarides, 2010): +% \begin{macrocode} +\def\LFupcase#1{% + \def\x##1##2{% + \MakeUppercase{##1}{##2}}\x#1% +} +% \end{macrocode} +% The following macro, \cs{LF@name}, creates a string to provide a label and number for +% an output. Analogous to the \cs{fnum@table} macro in the |longtable| package, +% it contains the capitalized version of the counter name and the counter +% number (for example, |Figure~3|). +% \begin{macrocode} +\def\LF@name{\expandafter\LFupcase% + \expandafter{\LFcounter}~% + \expandafter\csname the\LFcounter\endcsname}% +% \end{macrocode} +% The remainder of this package follows the |longtable| package +% almost identically, except that macros, skips, counters, and so on +% use an \cs{LF} prefix instead of the \cs{LT} prefix that the |longtable| package uses. +% +% \begin{macrocode} +\def\LF@err{\PackageError{longfigure}} +\def\LF@warn{\PackageWarning{longfigure}} +\def\LF@final@warn{% + \AtEndDocument{% + \LF@warn{\LFcounter \@width s have changed. Rerun \LaTeX\.\@gobbletwo}}% + \global\let\LF@final@warn\relax} +% +\newskip\LFleft \LFleft=\fill +\newskip\LFright \LFright=\fill +\newskip\LFpre \LFpre=\bigskipamount +\newskip\LFpost \LFpost=\bigskipamount +\newcount\LFchunksize \LFchunksize=20 +\let\c@LFchunksize\LFchunksize +\newdimen\LFcapwidth \LFcapwidth=4in +\newbox\LF@head +\newbox\LF@firsthead +\newbox\LF@foot +\newbox\LF@lastfoot +\newcount\LF@cols +\newcount\LF@rows +\newcounter{LF@tables} +\newcounter{LF@chunks}[LF@tables] +% +\newtoks\LF@p@ftn +\mathchardef\LF@end@pen=30000 +\def\longfigure{% + \par + \ifx\multicols\@undefined + \else + \ifnum\col@number>\@ne + \@twocolumntrue + \fi + \fi + \if@twocolumn + \LF@err{longfigure not in 1-column mode}\@ehc + \fi + \begingroup + \@ifnextchar[\LF@array{\LF@array[x]}} +\def\LF@array[#1]#2{% + \refstepcounter{\LFcounter}\stepcounter{LF@tables}% + \if l#1% + \LFleft\z@ \LFright\fill + \else\if r#1% + \LFleft\fill \LFright\z@ + \else\if c#1% + \LFleft\fill \LFright\fill + \fi\fi\fi + \let\LF@mcol\multicolumn + \let\LF@@tabarray\@tabarray + \let\LF@@hl\hline + \def\@tabarray{% + \let\hline\LF@@hl + \LF@@tabarray}% + \let\\\LF@tabularcr\let\tabularnewline\\% + \def\newpage{\noalign{\break}}% + \def\pagebreak{\noalign{\ifnum`}=0\fi\@testopt{\LF@no@pgbk-}4}% + \def\nopagebreak{\noalign{\ifnum`}=0\fi\@testopt\LF@no@pgbk4}% + \let\hline\LF@hline \let\kill\LF@kill\let\caption\LF@caption + \@tempdima\ht\strutbox + \let\@endpbox\LF@endpbox + \ifx\extrarowheight\@undefined + \let\@acol\@tabacol + \let\@classz\@tabclassz \let\@classiv\@tabclassiv + \def\@startpbox{\vtop\LF@startpbox}% + \let\@@startpbox\@startpbox + \let\@@endpbox\@endpbox + \let\LF@LL@FM@cr\@tabularcr + \else + \advance\@tempdima\extrarowheight + \col@sep\tabcolsep + \let\@startpbox\LF@startpbox\let\LF@LL@FM@cr\@arraycr + \fi + \setbox\@arstrutbox\hbox{\vrule + \@height \arraystretch \@tempdima + \@depth \arraystretch \dp \strutbox + \@width \z@}% + \let\@sharp##\let\protect\relax + \begingroup + \@mkpream{#2}% + \xdef\LF@bchunk{% + \global\advance\c@LF@chunks\@ne + \global\LF@rows\z@\setbox\z@\vbox\bgroup + \LF@setprevdepth + \tabskip\LFleft \noexpand\halign to\hsize\bgroup + \tabskip\z@ \@arstrut \@preamble \tabskip\LFright \cr}% + \endgroup + \expandafter\LF@nofcols\LF@bchunk&\LF@nofcols + \LF@make@row + \m@th\let\par\@empty + \everycr{}\lineskip\z@\baselineskip\z@ + \LF@bchunk} +\def\LF@no@pgbk#1[#2]{\penalty #1\@getpen{#2}\ifnum`{=0\fi}} +\def\LF@start{% + \let\LF@start\endgraf + \endgraf\penalty\z@\vskip\LFpre + \dimen@\pagetotal + \advance\dimen@ \ht\ifvoid\LF@firsthead\LF@head\else\LF@firsthead\fi + \advance\dimen@ \dp\ifvoid\LF@firsthead\LF@head\else\LF@firsthead\fi + \advance\dimen@ \ht\LF@foot + \dimen@ii\vfuzz + \vfuzz\maxdimen + \setbox\tw@\copy\z@ + \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox + \setbox\tw@\vbox{\unvbox\tw@}% + \vfuzz\dimen@ii + \advance\dimen@ \ht + \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi + \advance\dimen@\dp + \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi + \advance\dimen@ -\pagegoal + \ifdim \dimen@>\z@\vfil\break\fi + \global\@colroom\@colht + \ifvoid\LF@foot\else + \advance\vsize-\ht\LF@foot + \global\advance\@colroom-\ht\LF@foot + \dimen@\pagegoal\advance\dimen@-\ht\LF@foot\pagegoal\dimen@ + \maxdepth\z@ + \fi + \ifvoid\LF@firsthead\copy\LF@head\else\box\LF@firsthead\fi\nobreak + \output{\LF@output}} +\def\endlongfigure{% + \crcr + \noalign{% + \let\LF@entry\LF@entry@chop + \xdef\LF@save@row{\LF@save@row}}% + \LF@echunk + \LF@start + \unvbox\z@ + \LF@get@widths + \if@filesw + {\let\LF@entry\LF@entry@write\immediate\write\@auxout{% + \gdef\expandafter\noexpand + \csname LF@\romannumeral\c@LF@tables\endcsname + {\LF@save@row}}}% + \fi + \ifx\LF@save@row\LF@@save@row + \else + \LF@warn{Column \@width s have changed\MessageBreak + in table \thetable}% + \LF@final@warn + \fi + \endgraf\penalty -\LF@end@pen + \endgroup + \global\@mparbottom\z@ + \pagegoal\vsize + \endgraf\penalty\z@\addvspace\LFpost + \ifvoid\footins\else\insert\footins{}\fi} +\def\LF@nofcols#1&{% + \futurelet\@let@token\LF@n@fcols} +\def\LF@n@fcols{% + \advance\LF@cols\@ne + \ifx\@let@token\LF@nofcols + \expandafter\@gobble + \else + \expandafter\LF@nofcols + \fi} +\def\LF@tabularcr{% + \relax\iffalse{\fi\ifnum0=`}\fi + \@ifstar + {\def\crcr{\LF@crcr\noalign{\nobreak}}\let\cr\crcr + \LF@t@bularcr}% + {\LF@t@bularcr}} +\let\LF@crcr\crcr +\let\LF@setprevdepth\relax +\def\LF@t@bularcr{% + \global\advance\LF@rows\@ne + \ifnum\LF@rows=\LFchunksize + \gdef\LF@setprevdepth{% + \prevdepth\z@\global + \global\let\LF@setprevdepth\relax}% + \expandafter\LF@xtabularcr + \else + \ifnum0=`{}\fi + \expandafter\LF@LL@FM@cr + \fi} +\def\LF@xtabularcr{% + \@ifnextchar[\LF@argtabularcr\LF@ntabularcr} +\def\LF@ntabularcr{% + \ifnum0=`{}\fi + \LF@echunk + \LF@start + \unvbox\z@ + \LF@get@widths + \LF@bchunk} +\def\LF@argtabularcr[#1]{% + \ifnum0=`{}\fi + \ifdim #1>\z@ + \unskip\@xargarraycr{#1}% + \else + \@yargarraycr{#1}% + \fi + \LF@echunk + \LF@start + \unvbox\z@ + \LF@get@widths + \LF@bchunk} +\def\LF@echunk{% + \crcr\LF@save@row\cr\egroup + \global\setbox\@ne\lastbox + \unskip + \egroup} +\def\LF@entry#1#2{% + \ifhmode\@firstofone{&}\fi\omit + \ifnum#1=\c@LF@chunks + \else + \kern#2\relax + \fi} +\def\LF@entry@chop#1#2{% + \noexpand\LF@entry + {\ifnum#1>\c@LF@chunks + 1}{0pt% + \else + #1}{#2% + \fi}} +\def\LF@entry@write{% + \noexpand\LF@entry^^J% + \@spaces} +\def\LF@kill{% + \LF@echunk + \LF@get@widths + \expandafter\LF@rebox\LF@bchunk} +\def\LF@rebox#1\bgroup{% + #1\bgroup + \unvbox\z@ + \unskip + \setbox\z@\lastbox} +\def\LF@blank@row{% + \xdef\LF@save@row{\expandafter\LF@build@blank + \romannumeral\number\LF@cols 001 }} +\def\LF@build@blank#1{% + \if#1m% + \noexpand\LF@entry{1}{0pt}% + \expandafter\LF@build@blank + \fi} +\def\LF@make@row{% + \global\expandafter\let\expandafter\LF@save@row + \csname LF@\romannumeral\c@LF@tables\endcsname + \ifx\LF@save@row\relax + \LF@blank@row + \else + {\let\LF@entry\or + \if!% + \ifcase\expandafter\expandafter\expandafter\LF@cols + \expandafter\@gobble\LF@save@row + \or + \else + \relax + \fi + !% + \else + \aftergroup\LF@blank@row + \fi}% + \fi} +\let\setlongfigures\relax +\def\LF@get@widths{% + \setbox\tw@\hbox{% + \unhbox\@ne + \let\LF@old@row\LF@save@row + \global\let\LF@save@row\@empty + \count@\LF@cols + \loop + \unskip + \setbox\tw@\lastbox + \ifhbox\tw@ + \LF@def@row + \advance\count@\m@ne + \repeat}% + \ifx\LF@@save@row\@undefined + \let\LF@@save@row\LF@save@row + \fi} +\def\LF@def@row{% + \let\LF@entry\or + \edef\@tempa{% + \ifcase\expandafter\count@\LF@old@row + \else + {1}{0pt}% + \fi}% + \let\LF@entry\relax + \xdef\LF@save@row{% + \LF@entry + \expandafter\LF@max@sel\@tempa + \LF@save@row}} +\def\LF@max@sel#1#2{% + {\ifdim#2=\wd\tw@ + #1% + \else + \number\c@LF@chunks + \fi}% + {\the\wd\tw@}} +\def\LF@hline{% + \noalign{\ifnum0=`}\fi + \penalty\@M + \futurelet\@let@token\LF@@hline} +\def\LF@@hline{% + \ifx\@let@token\hline + \global\let\@gtempa\@gobble + \gdef\LF@sep{\penalty-\@medpenalty\vskip\doublerulesep}% + \else + \global\let\@gtempa\@empty + \gdef\LF@sep{\penalty-\@lowpenalty\vskip-\arrayrulewidth}% + \fi + \ifnum0=`{\fi}% + \multispan\LF@cols + \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr + \noalign{\LF@sep}% + \multispan\LF@cols + \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr + \noalign{\penalty\@M}% + \@gtempa} +% \end{macrocode} +% \subsection{Captioning} +% You can easily change how a long figure is captioned by +% redefining the \cs{LF@makecaption} macro after loading the |longfigure| package. +% The following statements show the default definition of the +% \cs{LF@makecaption}: +% +% \begin{macrocode} +\def\LF@caption{% + \noalign\bgroup + \@ifnextchar[{\egroup\LF@c@ption\@firstofone}\LF@capti@n} +% \end{macrocode} +% The \cs{LF@caption} command begins the process. +% If it includes an optional argument, it calls \cs{LF@c@ption}; otherwise +% it calls \cs{LF@capti@n}, which then calls \cs{LF@c@ption}. +% \begin{macrocode} +\def\LF@c@ption#1[#2]#3{% + \LF@makecaption#1\LF@name{#3}% + \def\@tempa{#2}% + \ifx\@tempa\@empty\else +% \end{macrocode} +% If a list of long figures is requested, the following code uses the +% previously defined \cs{strcfstr} macro and \cs{ifLF@same} boolean +% to determine the name of the counter and set the output file to +% contain the |longfigure| information. +% +% The code writes to one of the following files. +% \begin{itemize} +% \item If the counter is |figure|, write to the |lof| file. +% \item If the counter is |table|, write to the |lot| file. +% \item Otherwise, write to |lft|, a file created here for this purpose. +% \end{itemize} +% +% \begin{macrocode} + {\let\\\space + \strcfstr{\LFcounter}{figure} + \ifLF@same\def\LFoutfile{lof}\else + \strcfstr{\LFcounter}{table} + \ifLF@same\def\LFoutfile{lot}\else + \def\LFoutfile{lft}\fi\fi + \addcontentsline{\LFoutfile}{\LFcounter} + {\expandafter\protect\expandafter\numberline\expandafter% + {\expandafter\csname the\LFcounter\endcsname}{#2}}}% + \fi +} +% \end{macrocode} +% The \cs{LF@c@ption} macro ends the process when it calls the +% \cs{LF@makecaption} macro, which typesets the caption. +% \begin{macrocode} +\def\LF@capti@n{% + \@ifstar + {\egroup\LF@c@ption\@gobble[]}% + {\egroup\@xdblarg{\LF@c@ption\@firstofone}}} +% \end{macrocode} +% +% If you want to redefine how the |longfigure| is captioned, +% you need to override the following macro. +% The first argument is the name of the counter +% (for example, |Figure|), the second argument is the number of the counter, and the +% third argument is the caption itself. +% \begin{macrocode} +\def\LF@makecaption#1#2#3{% + \LF@mcol\LF@cols c{\hbox to\z@{\hss\parbox[t]\LFcapwidth{% + \sbox\@tempboxa{#1{#2: }#3}% + \ifdim\wd\@tempboxa>\hsize + #1{#2: }#3% + \else + \hbox to\hsize{\hfil\box\@tempboxa\hfil}% + \fi + \endgraf\vskip\baselineskip}% + \hss}}} +\def\LF@output{% + \ifnum\outputpenalty <-\@Mi + \ifnum\outputpenalty > -\LF@end@pen + \LF@err{floats and marginpars not allowed in a longfigure}\@ehc + \else + \setbox\z@\vbox{\unvbox\@cclv}% + \ifdim \ht\LF@lastfoot>\ht\LF@foot + \dimen@\pagegoal + \advance\dimen@-\ht\LF@lastfoot + \ifdim\dimen@<\ht\z@ + \setbox\@cclv\vbox{\unvbox\z@\copy\LF@foot\vss}% + \@makecol + \@outputpage + \setbox\z@\vbox{\box\LF@head}% + \fi + \fi + \global\@colroom\@colht + \global\vsize\@colht + \vbox + {\unvbox\z@\box\ifvoid\LF@lastfoot\LF@foot\else + \LF@lastfoot\fi}% + \fi + \else + \setbox\@cclv\vbox{\unvbox\@cclv\copy\LF@foot\vss}% + \@makecol + \@outputpage + \global\vsize\@colroom + \copy\LF@head\nobreak + \fi} +\def\LF@end@hd@ft#1{% + \LF@echunk + \ifx\LF@start\endgraf + \LF@err + {Longfigure head or foot not at start of table}% + {Increase LFchunksize}% + \fi + \setbox#1\box\z@ + \LF@get@widths + \LF@bchunk} +% \end{macrocode} +% The following four macros do not have an \cs{LT} prefix in the |longtable| package, +% but they must be redefined to have an \cs{LF} prefix in order to avoid a namespace clash; +% \begin{macrocode} +\def\endLFfirsthead{\LF@end@hd@ft\LF@firsthead} +\def\endLFhead{\LF@end@hd@ft\LF@head} +\def\endLFfoot{\LF@end@hd@ft\LF@foot} +\def\endLFlastfoot{\LF@end@hd@ft\LF@lastfoot} + % +\def\LF@startpbox#1{% + \bgroup + \let\@footnotetext\LF@p@ftntext + \setlength\hsize{#1}% + \@arrayparboxrestore + \vrule \@height \ht\@arstrutbox \@width \z@} +\def\LF@endpbox{% + \@finalstrut\@arstrutbox + \egroup + \the\LF@p@ftn + \global\LF@p@ftn{}% + \hfil} +\def\LF@p@ftntext#1{% + \edef\@tempa{\the\LF@p@ftn\noexpand\footnotetext[\the\c@footnote]}% + \global\LF@p@ftn\expandafter{\@tempa{#1}}}% +% \end{macrocode} % \subsection{References} % % Carlisle, D. 2004. diff --git a/statrep.hd b/statrep.hd new file mode 100644 index 0000000..e69de29 diff --git a/statrep.ins b/statrep.ins new file mode 100644 index 0000000..a949f94 --- /dev/null +++ b/statrep.ins @@ -0,0 +1,64 @@ +%% +%% This is file `statrep.ins', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% statrep.dtx (with options: `install') +%% ---------------------------------------------------------------- +%% StatRep --- A LaTeX package to generate documentation and a SAS program that +%% generates the SAS results used in the source document. +%% The package helps to support reproducible research. +%% +%% E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr +%% +%% ---------------------------------------------------------------- +\input docstrip.tex +\keepsilent +\askforoverwritefalse +\preamble +---------------------------------------------------------------- +StatRep --- A LaTeX package to generate documentation and a SAS program that + generates the SAS results used in the source document. + The package helps to support reproducible research. + +E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr + +---------------------------------------------------------------- +\endpreamble +\postamble +Copyright (C) 2015 by SAS Institute Inc. + +This work consists of the files + statrep.dtx, + statrep_macros.sas, + statrep_tagset.sas + statrepmanual.tex, + quickstart.tex + +and the derived files + statrep.ins, statrep.cfg, statrep.sty, longfigure.sty, + statrep.pdf, + statrep_macros.sas, + statrepmanual.pdf +\endpostamble +\generate{\file{statrep.sty}{\from{statrep.dtx}{statrep,cfg}}} +\generate{\file{statrep.cfg}{\from{statrep.dtx}{cfg}}} +\generate{\file{longfigure.sty}{\from{statrep.dtx}{longfigure}}} +\endbatchfile +%% Copyright (C) 2015 by SAS Institute Inc. +%% +%% This work consists of the files +%% statrep.dtx, +%% statrep_macros.sas, +%% statrep_tagset.sas +%% statrepmanual.tex, +%% quickstart.tex +%% +%% and the derived files +%% statrep.ins, statrep.cfg, statrep.sty, longfigure.sty, +%% statrep.pdf, +%% statrep_macros.sas, +%% statrepmanual.pdf +%% +%% End of file `statrep.ins'. diff --git a/statrep.pdf b/statrep.pdf new file mode 100644 index 0000000..3b238e6 Binary files /dev/null and b/statrep.pdf differ diff --git a/benchmark/statrep.sty b/statrep.sty similarity index 85% rename from benchmark/statrep.sty rename to statrep.sty index 53a50bf..d1ea893 100644 --- a/benchmark/statrep.sty +++ b/statrep.sty @@ -10,15 +10,36 @@ %% generates the SAS results used in the source document. %% The package helps to support reproducible research. %% -%% E-mail: tim.arnold@sas.com +%% E-mail: Martial.Phelippe-GuinvarcH@univ-lemans.fr +%% %% ---------------------------------------------------------------- \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{statrep}[2015/09/15 v1.07 The statrep package] +\ProvidesPackage{statrep}[2026/04/28 v2.0 The statrep package] + \RequirePackage{verbatim} \RequirePackage{graphicx} -\RequirePackage{xkeyval} -\RequirePackage{calc} \RequirePackage{ifthen} +\RequirePackage{calc} +\RequirePackage{etoolbox} +\RequirePackage{xkeyval} +\newif\ifSASServer +\SASServerfalse % Default is Workstation +\DeclareOptionX{SASmode}{\setkeys{statrep}{SASmode=#1}} +\define@key{statrep}{SASmode}{% + \ifstrequal{#1}{Server}{% if value is 'Server' + \SASServertrue + \PackageInfo{statrep}{Mode SAS: Serveur (utilise \string&\string_SASPROGRAMFILE).} + }{% If value is not 'Serveur', we control if it is 'WorkStation' + \ifstrequal{#1}{WorkStation}{% + \SASServerfalse + \PackageInfo{statrep}{Mode SAS: WorkStation (use ./).} + }{% + % If value is unknown, we print an warning + \SASServerfalse + \PackageWarning{statrep}{Unknown value for SASmode (#1). Default use of WorkStation (uses ./).} + }% + }% +} \newif\ifSR@generate\SR@generatetrue \DeclareOptionX{generate}[true]{\@nameuse{SR@generate#1}} \DeclareOptionX{color}[true]{% @@ -29,9 +50,29 @@ \DeclareOptionX{figname}{\PassOptionsToPackage{\CurrentOption}{longfigure}} \DeclareOptionX{resetby}{\PassOptionsToPackage{\CurrentOption}{longfigure}} \ProcessOptionsX +\providecommand{\SR@encoding}{utf-8} +\def\statrep@map@sas@encoding#1{% + \def\SR@encoding{utf-8} + \ifstrequal{#1}{utf8}{\def\SR@encoding{utf-8}}{}% + \ifstrequal{#1}{utf8x}{\def\SR@encoding{utf-8}}{}% + \ifstrequal{#1}{latin1}{\def\SR@encoding{wlatin1}}{}% + \ifstrequal{#1}{latin9}{\def\SR@encoding{wlatin1}}{}% + \ifstrequal{#1}{ansinew}{\def\SR@encoding{wlatin1}}{}% +} +\AtBeginDocument{% +\@ifpackageloaded{inputenc}{% + \statrep@map@sas@encoding{\inputencodingname}% + \PackageInfo{statrep}{Encodind LaTeX ({\inputencodingname}) detected and mapped to SAS: + \\SR@encoding.} + }{% + % else, default utf-8 is retained. + \PackageInfo{statrep}{inputenc unfund. Default SAS encoding: \\SR@encoding utf-8.} + } +} \IfFileExists{sas.sty} {\RequirePackage{sas}} {\relax} +\IfFileExists{\jobname _VarSAStoTex.tex}{\input{\jobname _VarSAStoTex.tex}}{} \RequirePackage{longfigure} \ifSR@generate\def\SR@writepgm{\immediate\write} \else\let\SR@writepgm\@gobbletwo @@ -72,11 +113,15 @@ height = \@empty, pagesize = \@empty}{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Edit this line to point to the location of the StatRep macros. -\def\SRmacropath{statrep_macros.sas} +\def\SRmacropath{\SRrootdir/statrep_macros.sas} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% The following statements define line size, page size, graphic resolution, %% and also specify the default ODS output style: +\ifSASServer +\def\SRrootdir{¤tpath} +\else \def\SRrootdir{.} +\fi \def\SRlinesize{80} \def\SRpagesize{500} \def\SRdpi{300} @@ -89,8 +134,8 @@ \def\SRlistingdir{\SRrootdir/lst} \def\SRlatexdir{\SRrootdir/tex} \def\SRdefaultdests{listing} -\def\SRprogramname{\jobname_SR.sas} -\def\SRpreamblename{\jobname_SR_preamble.sas} +\edef\SRprogramname{\jobname_SR.sas} +\edef\SRpreamblename{\jobname_SR_preamble.sas} \def\SRmacroinclude{\@percentchar include "\SRmacropath" /nosource;} \def\SRsasprogramline{% \@percentchar cleandir(\SRrootdir, tex, tex);^^J% @@ -136,6 +181,7 @@ \SR@writepgm\SR@tempfile@stream{\@percentchar let defaultdpi=\SRdpi;} \SR@writepgm\SR@tempfile@stream{\@percentchar let odsgraphopts=\SRodsgraphopts;} \SR@writepgm\SR@tempfile@stream{\@percentchar let defaultdests=\SRdefaultdests;} + \SR@writepgm\SR@tempfile@stream{\@percentchar let SASencodingTex=\SR@encoding;} \SR@writepgm\SR@tempfile@stream{} \SR@writepgm\SR@tempfile@stream{options nodate nonumber} \SR@writepgm\SR@tempfile@stream{ls=&defaultlinesize ps=&defaultpagesize} @@ -148,6 +194,21 @@ \immediate\closeout\SR@tempfile@stream \immediate\openout\SR@program@stream\SRprogramname \SR@writepgm\SR@program@stream{\SR@preambletext} + \SR@writepgm\SR@program@stream{FILENAME current "&_SASPROGRAMFILE"; *** get the full name of the file;} + \SR@writepgm\SR@program@stream{\@percentchar LET fullpath = \@percentchar sysfunc(pathname(current));} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname = \@percentchar scan(&fullpath, -2, '/.\\');} + \SR@writepgm\SR@program@stream{\@percentchar IF \@percentchar index(&SAStoTexname,_SR) \@percentchar then \@percentchar DO;} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname=\@percentchar substr(&SAStoTexname,1,\@percentchar index(&SAStoTexname,_SR)-1);} + \SR@writepgm\SR@program@stream{\@percentchar END;} + \SR@writepgm\SR@program@stream{\@percentchar let currentpath = \@percentchar substr(&fullpath, 1, \@percentchar length(&fullpath) -} + \SR@writepgm\SR@program@stream{\@percentchar length(\@percentchar scan(&fullpath, -1, '/\\'))-1 );} + \SR@writepgm\SR@program@stream{\@percentchar put &fullpath ¤tpath;} + \SR@writepgm\SR@program@stream{\@percentchar let rc = \@percentchar sysfunc(dlgcdir(¤tpath));} + \SR@writepgm\SR@program@stream{\@percentchar LET SAStoTexname = &SAStoTexname._VarSAStoTex.tex;} + \SR@writepgm\SR@program@stream{\@percentchar put &SAStoTexname;} + \SR@writepgm\SR@program@stream{ FILENAME outtex "&SAStoTexname" ENCODING="utf-8";} + \SR@writepgm\SR@program@stream{ DATA _NULL_; FILE outtex LRECL=32767; RUN;} + \SR@writepgm\SR@program@stream{ FILENAME outtex CLEAR;} \SR@writepgm\SR@program@stream{\@percentchar include "\SRrootdir/\SRpreamblename" /nosource;} \SR@writepgm\SR@program@stream{/* Remove all output files. */} \SR@writepgm\SR@program@stream{\SRsasprogramline} @@ -497,6 +558,7 @@ \endlongfigure\egroup% \unsloppy% } +%% %% Copyright (C) 2015 by SAS Institute Inc. %% %% This work consists of the files diff --git a/statrep_macros.sas b/statrep_macros.sas new file mode 100644 index 0000000..cd0ebe7 --- /dev/null +++ b/statrep_macros.sas @@ -0,0 +1,1721 @@ + /*---------------------------------------------*/ + /* The WRITE macro displays one or more pieces */ + /* of output (tables, notes, graphs, and so */ + /* on) that were captured into an ODS document */ + /* by the OUTPUT macro. */ + /*---------------------------------------------*/ +%macro write(fname, /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* or \Graphic tag in the LaTeX file. The */ + /* following examples show where the fname */ + /* keyword, in this case 'crsi1a', is */ + /* specified in the WRITE macro and in the */ + /* \Listing tag: */ + /* */ + /* %*;%write(crsi1a, objects=inertias) */ + /* \Listing[caption={... caption ...}]{crsi1a} */ + /* */ + dest=, /* specifies destination: latex or listing. */ + /* Null uses the defaultdests macro. */ + /* */ + width=, /* specifies the width of graphs. */ + /* Example: WIDTH=5.4in. */ + height=, /* specifies the height of graphs. */ + /* Example: HEIGHT=4in. */ + /* */ + dpi=, /* specifies DPI (dots per inch) for ODS */ + /* Graphics. You typically would not use this */ + /* option except when you would otherwise run */ + /* out of memory. The default is 300 DPI, and */ + /* a reasonable alternative for ODS graphs */ + /* with large file sizes is 100 DPI. More */ + /* details follow. */ + /* */ + /* This option controls the DPI for ODS */ + /* Graphics. Use the DPI= option in the */ + /* OUTPUT macro to control the DPI for GRSEG */ + /* graphics. */ + /* */ + /* If DPI= is specified, that DPI is used. */ + /* If DPI= is not specified, and if a macro */ + /* variable DefaultDPI is defined, its value */ + /* is used as the DPI. If DPI= is not */ + /* specified and the macro variable DefaultDPI */ + /* is not defined or if its value is null, */ + /* then the default DPI, 300, is used. */ + /* */ + /* In other words, the default DPI is 300. */ + /* However, you can set the default DPI to */ + /* (say) 100 by putting the following at the */ + /* top of your first Sascode block, beginning */ + /* in column 1: */ + /* */ + /* %*;%let defaultdpi=100; */ + /* */ + /* Since the %LET statement is preceded by a */ + /* null macro comment (%*;) beginning in */ + /* column 1, it will not show up in the */ + /* SAS code listing, but it will affect the */ + /* capture program and change the default */ + /* DPI for the duration of the running of the */ + /* program. You can change the default DPI at */ + /* any time with a %LET statement. */ + /* */ + /* With GRSEG graphics, 100 DPI is not */ + /* available, so this specification creates */ + /* graphs at 96 DPI. */ + /* */ + store=, /* specifies the name of the ODS document */ + /* that is created by the OUTPUT macro. This */ + /* is the ODS document that the WRITE macro */ + /* will process. By default, when null, the */ + /* current document from the last OUTPUT macro */ + /* is used. If you are processing the last */ + /* document created, you can omit specifying */ + /* the STORE= option. To use some other */ + /* document, specify STORE=documentlabel. */ + /* */ + pattern=, /* provides an optional additional selection */ + /* criterion. Specify part of a path, for */ + /* example, a group name. Then only objects */ + /* whose name includes this group name are */ + /* used. Comparisons are not case sensitive. */ + /* The macro looks for an appearance of the */ + /* PATTERN=value anywhere in the path. For */ + /* example, PATTERN=fit, will match */ + /* "Reg.m2.Fit.Population.ParameterEstimates" */ + /* and anything else with "fit" in it */ + /* including paths that contain "fitplot", */ + /* "fitness", "outfit" and so on. */ + /*---------------------------------------------*/ + firstobj=, /* specifies the first data object. */ + lastobj=, /* specifies the last data object. */ + objects=, /* specifies the list of data objects. */ + /* */ + /* To specify which objects go into a section */ + /* of output, specify one of the following */ + /* combinations: */ + /* * FIRSTOBJ=, */ + /* * LASTOBJ=, */ + /* * FIRSTOBJ= and LASTOBJ=, */ + /* * OBJECTS=, */ + /* * none of the above. */ + /* */ + /* If FIRSTOBJ= is specified and LASTOBJ= is */ + /* not specified, then the last object is the */ + /* last object produced by the procedure. If */ + /* LASTOBJ= is specified and FIRSTOBJ= is not */ + /* specified, then the default first object is */ + /* the first object produced by the procedure. */ + /* If OBJECTS= is specified, then only objects */ + /* in that list are used. If none of these */ + /* options is specified then, all objects are */ + /* used. */ + /* */ + /* The term "object" used in this */ + /* discussion refers to notes, tables, and */ + /* graphs. Specify the first or last object */ + /* or list of objects (tables, notes, graphs). */ + /* All object name comparisons are case */ + /* insensitive. */ + /* */ + /* All selections are based on paths instead */ + /* of label paths. You can specify the last m */ + /* levels of the path. Assuming that you have */ + /* one model and one ANOVA table, any of the */ + /* following specifications for the ANOVA */ + /* object are equivalent, along with many */ + /* other possibilities: */ + /* */ + /* Reg.MODEL1.Fit.Population.ANOVA */ + /* reg.model1.fit.population.anova */ + /* reg#1.model1#1.fit#1.population#1.anova#1 */ + /* reg#1.model1.fit.population#1.anova#1 */ + /* MODEL1.Fit.Population.ANOVA */ + /* Fit.Population.ANOVA */ + /* Population.ANOVA */ + /* ANOVA */ + /* ANOVA#1 */ + /* */ + /* Typically, you need to specify only the */ + /* last level. If an object appears more than */ + /* once, then you might need to specify more */ + /* levels. The #n notation is allowed, even */ + /* in cases where it does not work in an ODS */ + /* SELECT statement. You must specify a name, */ + /* using the #n notation that matches the name */ + /* (or the last few levels of the name) as it */ + /* appears in the ODS document. For example, */ + /* if there are multiple residual panels, you */ + /* can specify OBJECTS=residualplot and */ + /* OBJECTS=residualplot#2. The object list */ + /* produced by the macro will show every place */ + /* that a #2 or #n (n > 1) is required. */ + /* */ + /* If you run a procedure more than once for */ + /* this ODS document, then you need #2 on the */ + /* procedure name for the second group. For */ + /* example, here are the fully-qualified names */ + /* from a set of two PROC REG runs: */ + /* */ + /* Reg.MODEL1.Fit.Fail.NObs */ + /* Reg.MODEL1.Fit.Fail.ANOVA */ + /* Reg.MODEL1.Fit.Fail.FitStatistics */ + /* Reg.MODEL1.Fit.Fail.ParameterEstimates */ + /* Reg#2.MODEL1.Fit.Fail.NObs */ + /* Reg#2.MODEL1.Fit.Fail.ANOVA */ + /* Reg#2.MODEL1.Fit.Fail.FitStatistics */ + /* Reg#2.MODEL1.Fit.Fail.ParameterEstimates */ + /* */ + /* The order in which objects come out is */ + /* determined by the order in which they are */ + /* generated, not the order in which they are */ + /* specified in the OBJECTS= option. */ + /* */ + /* If you specify OBJECTS=, then you can also */ + /* specify where page breaks can occur. By */ + /* default, breaks might occur between the */ + /* bottom of a table and the top of the note */ + /* or table that comes after it. If you want */ + /* anything different to occur, use left and */ + /* right angled brackets, <>, to start and end */ + /* a new group and suppress normal page */ + /* breaking in between. After a <, no default */ + /* page breaking occurs until a > is hit. A */ + /* page break occurs at the > and then in the */ + /* default places after that. You can use */ + /* "< list >" in pairs (for example, "" to keep certain objects */ + /* together. You can instead use > to cause */ + /* page breaks in addition to the default page */ + /* breaks. You can also use < to designate */ + /* page breaks and suppress all default page */ + /* breaking. A break always occurs before and */ + /* after a graph regardless of what <> */ + /* specification you use. */ + /*---------------------------------------------*/ + pagesize=, /* specifies the page size. The default is */ + /* the page size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current page size is */ + /* restored at the end. */ + linesize=, /* specifies the line size. The default is */ + /* the line size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current line size is */ + /* restored at the end. */ + /* */ + options=, /* specifies one or more binary options: */ + /* */ + /* LIST - do not run PROC DOCUMENT for */ + /* each group of objects. Just */ + /* list the contents of the */ + /* document. */ + /* */ + /* TABLE - (or TABLES) selects only tables */ + /* and notes (more specifically, */ + /* anything but graphs). */ + /* */ + /* GRAPH - only selects graphs. */ + /* */ + /* NOPAGE - no page breaks at the top of */ + /* tables. */ + /* */ + /* NEWPAGE - forces a page break on the first */ + /* object. */ + /* */ + /* AUTOPAGE - same page breaks that the */ + /* procedure makes. There is a */ + /* page break on the first object */ + /* and where the proc forces a new */ + /* page. AUTOPAGE is the default. */ + /* */ + /* ONEBOX - is used with the \Listing tag */ + /* and specifies that only one */ + /* block of tables is made. This */ + /* option strips out all '<>' */ + /* characters from the OBJECTS= */ + /* list and adds a '<' to the */ + /* beginning of the list. With */ + /* FIRSTOBJ= or LASTOBJ= or no */ + /* OBJECTS= list, the effect is the */ + /* same even though the mechanism */ + /* is different. If anything other */ + /* than only tables or a single */ + /* graph is input, an error is */ + /* issued along with the object */ + /* list. */ + /* */ + /* SKIPFIRST- deletes the first object that */ + /* would otherwise be selected. */ + /* Typical usage is with FIRST= */ + /* to select every object after the */ + /* one that was named. */ + /* */ + /* SKIPLAST - deletes the last object that */ + /* would otherwise be selected. */ + /* Typical usage is with LAST= to */ + /* select every object before the */ + /* one that was named. */ + /* */ + /* Example: OPTIONS=TABLE ONEBOX. */ + /* */ + style=, /* specifies the ODS style for ODS Graphics. */ + /* Use the STYLE= option in the OUTPUT macro */ + /* to control the style for GRSEG graphics. */ + /* If STYLE= is specified, that style is used. */ + /* If STYLE= is not specified, and if a macro */ + /* variable DefaultStyle is defined, its value */ + /* is used as the style. If STYLE= is not */ + /* specified and the macro variable */ + /* DefaultStyle is not defined or if its value */ + /* is null, then the default style (which is */ + /* the HTMLBLUE style) is used. */ + /* */ + /* In other words, the default style is the */ + /* HTMLBLUE style. However, you can set the */ + /* default style to (say) LISTING by putting */ + /* the following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultstyle=listing; */ + /* */ + /* Since this line begins with a null macro */ + /* comment (%*;) that begins in column 1, it */ + /* will not show up in the SAS code listing, */ + /* but it will affect the capture program and */ + /* change the default style for the duration */ + /* of the running of the program. */ + /* */ + type=);; /* specifies the type of objects to select. */ + /* \Listing specifies TYPE=LISTING, which is */ + /* an alias for OPTIONS=TABLE. */ + /* \Graphic specifies TYPE=GRAPH, which is an */ + /* alias for OPTIONS=GRAPH. */ + /*---------------------------------------------*/ + +%local i j k flow error savenote holdlast allobjflag firstflag onlylist + lastflag rangeflag objflag ngroups h onebox isgraph savesize + left tyw stw grw abnormal selecttype savetime kl kh jl jh ls + pagebreak gdevice skipfirst skiplast; + +%let abnormal = 0; +%let error = 0; +%let savenote = %sysfunc(getoption(notes)); +%let savetime = %sysfunc(getoption(stimer)); +%let savesize = ls=%sysfunc(getoption(ls)) ps=%sysfunc(getoption(ps)); +%let holdlast = &syslast; +%let graphtype = %qlowcase(&graphtype); +%if %nrbquote(&graphtype) ne pdf %then %let graphtype = png; + +options nostimer %if &pagesize ne %then ps=&pagesize; + %if &linesize ne %then ls=&linesize;; + +%if %symexist(adsflow) %then %let flow = %lowcase(&adsflow); + +* Set the default style using STYLE= and a DefaultStyle macro variable.; +%if &style eq %then %let style = &defaultstyle; + +* Set the default DPI using DPI= and a DefaultDPI macro variable.; +%if &dpi eq %then %let dpi = &defaultDPI; + +%let gdevice = %substr(png300, 1, 3 * (1 + (&dpi eq 300))); +%if %nrbquote(&graphtype) eq pdf %then %let gdevice = pdf; + +* Find out what is in the document. Store the list in a SAS data set.; +%if %symexist(documentlabel) %then %do; + %if %nrbquote(&store) eq %then %let store = &documentLabel; + %end; + +%if %nrbquote(&store) eq %then %do; + %put ERROR: No ODS document available.; + %let error = 1; + %goto veryend; + %end; +%else %put NOTE: Processing document &store..; + +%if not %index(&flow, notes) %then %do; options nonotes; %end; + +ods document close; run; +ods _all_ close; + +proc document name=&store; + ods output properties=_ads_doclist(where=(not (type eq "Dir" or + (type =: 'R' and index(type, 'p.'))))); + list / details levels=all; + run; quit; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; +ods listing ; + +data _null_; + call symputx('ls', getoption('ls'), 'L'); + if 0 then set _ads_doclist nobs=nprts; + if nprts eq 0 then do; + put "ERROR: Document &store does not exist."; + call symputx('error', '1', 'L'); + end; + + length fname $ 40 c $ 1; + fname = symget('fname'); + c = substr(fname, length(fname), 1); + if '0' le c le '9' then do; + put 'ERROR: The name ' fname 'is invalid. It must not end in a numeral.'; + call symputx('error', '1', 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + stop; + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; + +* Basic option setting, checking, and processing.; +data _null_; + length c $ 1 c2 $ 2 firstobj lastobj options type $ 200 objects $ 32500; + + w = symget('width'); + if w = ' ' then w = '6.4in'; + h = symget('height'); + if h = ' ' then + call symputx('h', trim(put(0.75 * input(translate(lowcase(w), ' ', + 'incm'), 12.), best12.)) || substr(w, length(w) - 1, 2), 'L'); + else call symputx('h', trim(h), 'L'); + + options = lowcase(symget('defaultdests')); + options = compbl(options); + call symputx('defaultdests', options, 'G'); + i = index(options, 'listing'); if i then substr(options, i, 7) = ' '; + i = index(options, 'latex'); if i then substr(options, i, 5) = ' '; + + if options ne ' ' then do; + put 'ERROR: %LET ' "DEFAULTDESTS=&defaultdests is invalid."; + put 'WARNING: Choose from: listing latex.'; + call symputx('error', '1', 'L'); + end; + + options = lowcase(symget('dest')); + options = compbl(options); + + if not (options eq ' ' or options eq 'listing' or options eq 'latex') then do; + put "ERROR: DESTS=&dest is invalid."; + put 'WARNING: Choose from: listing latex.'; + call symputx('error', '1', 'L'); + end; + if options eq ' ' then options = symget('defaultdests'); + call symputx('dest', options, 'L'); + + * Flag which options were specified.; + + type = lowcase(symget('type')); + options = lowcase(symget('options')); + + tx = index(type , 'tables'); if tx then substr(type , tx, 6) = ' '; + tt = index(type , 'table'); if tt then substr(type , tt, 5) = ' '; + tl = index(type , 'listing'); if tl then substr(type , tl, 7) = ' '; + t1 = index(type , 'graphics'); if t1 then substr(type , t1, 8) = ' '; + t2 = index(type , 'graphic'); if t2 then substr(type , t2, 7) = ' '; + t3 = index(type , 'graphs'); if t3 then substr(type , t3, 6) = ' '; + t4 = index(type , 'graph'); if t4 then substr(type , t4, 5) = ' '; + no = index(options, 'nopage'); if no then substr(options, no, 6) = ' '; + nw = index(options, 'newpage'); if nw then substr(options, nw, 7) = ' '; + ap = index(options, 'autopage'); if ap then substr(options, ap, 8) = ' '; + li = index(options, 'listing'); if li then substr(options, li, 7) = ' '; + ls = index(options, 'list'); if ls then substr(options, ls, 4) = ' '; + ty = index(options, 'tables'); if ty then substr(options, ty, 6) = ' '; + ta = index(options, 'table'); if ta then substr(options, ta, 5) = ' '; + ob = index(options, 'onebox'); if ob then substr(options, ob, 6) = ' '; + g1 = index(options, 'graphics'); if g1 then substr(options, g1, 8) = ' '; + g2 = index(options, 'graphic'); if g2 then substr(options, g2, 7) = ' '; + g3 = index(options, 'graphs'); if g3 then substr(options, g3, 6) = ' '; + g4 = index(options, 'graph'); if g4 then substr(options, g4, 5) = ' '; + sf = index(options, 'skipfirst'); if sf then substr(options, sf, 9) = ' '; + sl = index(options, 'skiplast'); if sl then substr(options, sl, 8) = ' '; + + if options ne ' ' then do; + options = compbl(options); + put 'WARNING: WRITE macro OPTIONS=' options 'is invalid and is ignored.'; + end; + + if type ne ' ' then do; + type = compbl(type); + put 'WARNING: WRITE macro TYPE=' type 'is invalid and is ignored.'; + end; + + table = ta or ty or li or tt or tx or tl; + graph = g1 or g2 or g3 or g4 or t1 or t2 or t3 or t4; + + if no then call symputx('pagebreak', 'nopage'); + else if nw then call symputx('pagebreak', 'newpage'); + else call symputx('pagebreak', 'autopage'); + + call symputx('onlylist', ls ne 0, 'L'); + call symputx('onebox', ob, 'L'); + call symputx('isgraph', graph, 'L'); + call symputx('selecttype', ob or table or graph, 'L'); + call symputx('skipfirst', sf ne 0, 'L'); + call symputx('skiplast', sl ne 0, 'L'); + + if table and graph then do; + put "ERROR: TYPE=&type and OPTIONS=&options conflict."; + put "ERROR: Both tables and graphs were selected."; + call symputx('error', '1', 'L'); + end; + + * Process object names.; + firstobj = symget('firstobj'); + lastobj = symget('lastobj'); + objects = lowcase(symget('objects')); + if ob then objects = '<' || compbl(translate(objects, ' ', '<>')); + + call symputx('ngroups', '0', 'L'); + call symputx('pattern', lowcase(symget('pattern')), 'L'); + call symputx('firstobj', lowcase(firstobj), 'L'); + call symputx('lastobj', lowcase(lastobj), 'L'); + call symputx('objects', objects, 'L'); + + if (firstobj ne ' ' or lastobj ne ' ') and objects ne ' ' then do; + put 'ERROR: OBJECTS= may not be specified with FIRSTOBJ= and LASTOBJ=.'; + call symputx('error', '1', 'L'); + end; + + * Remove extra spaces and funkiness around < and >.; + if objects ne ' ' then do; + objects = ' ' || compbl(objects); + + * Get rid of trailing open brackets.; + done = 0; + do i = 1 to 32500 until(done); + l = length(objects); + if substr(objects, l, 1) eq '<' then substr(objects, l, 1) = ' '; + else done = 1; + end; + + * Get rid of multiple contiguous brackets.; + c = ' '; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 1); + if (c eq '<' and c2 eq '<') or + (c eq '>' and c2 eq '>') then substr(objects, i, 1) = ' '; + c2 = substr(objects, i, 1); + if not (c2 eq ' ' or c2 eq '<' or c2 eq '>') then c = ' '; + else if c2 eq '<' or c2 eq '>' then c = c2; + end; + end; + objects = ' ' || compbl(objects); + + * Move brackets next to names. + For example, change '< name' to '' to 'name>'.; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 2); + if c2 eq '< ' then substr(objects, i, 2) = ' <'; + if c2 eq ' >' then substr(objects, i, 2) = '> '; + c2 = substr(objects, i, 1); + if c2 eq '<' then do; + c = substr(objects, i - 1, 1); + if c ne ' ' then objects = substr(objects, 1, i - 1) || + ' <' || substr(objects, i + 1); + i + 1; + end; + else if c2 eq '>' then do; + c = substr(objects, i + 1, 1); + if c ne ' ' then objects = substr(objects, 1, i - 1) || + '> ' || substr(objects, i + 1); + i + 1; + end; + end; + end; + + * Get rid of null bracket groups.; + done = 0; + do i = 1 to 32500 until(done); + if i gt length(objects) then done = 1; + else do; + c2 = substr(objects, i, 2); + if c2 eq '<>' then substr(objects, i, 2) = ' '; + end; + end; + objects = compbl(left(objects)); + + * Get rid of leading close brackets.; + if objects =: '>' then objects = substr(objects, 2); + + call symputx('objects', left(compbl(objects)), 'L'); + end; + + call symputx('allobjflag', (firstobj eq ' ' and lastobj eq ' ' and + objects eq ' '), 'L'); + call symputx('firstflag', (firstobj eq ' ' and lastobj ne ' '), 'L'); + call symputx('lastflag' , (firstobj ne ' ' and lastobj eq ' '), 'L'); + call symputx('rangeflag', (firstobj ne ' ' and lastobj ne ' '), 'L'); + call symputx('objflag' , (objects ne ' '), 'L'); + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto veryend; + +data _ads_doclist(drop=i p); + set _ads_doclist; + + /*-------------Translate: Special characters not shown------------- + English German Spanish French Italian + Batch Batch Batch Traitement par lots Batch + Crosstab Kreuztabelle TablaCruzada Table a double entr*e Campi incr. + Dir Dir Dir R�p. Dir + File file Archivo Fichier File + Graph Grafik Gr*fico Graphique Grafico + Note Hinweis Nota Note Nota + Report Bericht Informe Rapport Report + Table Tabelle Tabla Tableau Tabella + Text Text Texto Texte Testo + Tree Baum *rbol Arbre Struttura + */ + + if trim(type) in ('Hinweis', 'Nota') then type = 'Note'; + else if type =: 'Kreuz' or type =: 'Tabla' or type =: 'Campi' or + index(trim(type), 'double') then type = 'Crosstab'; + else if type =: 'Tab' then type = 'Table'; + else if type =: 'Gra' then type = 'Graph'; + else if type =: 'Traite' then type = 'Batch'; + else if type =: 'Te' then type = 'Text'; + else if type =: 'Fi' or type =: 'fi' or type =: 'Archi' then type = 'File'; + else if trim(type) in ('Bericht', 'Informe', 'Rapport') then type ='Report'; + else if trim(type) in ('Baum', 'Arbre', 'Struttura') or index(type, 'rbol') + then type ='Tree'; + + ObjNum = _n_; + * The variable ourpath is used for group subsetting and display in the SAS log. + It is not used for actual selection (beyond group selection).; + ourpath = substr(translate(path, '.', '\'), 2); + do i = 1 to length(ourpath) until(p eq 0); + p = index(ourpath, '#1.'); + if p then substr(ourpath, p, 3) = '. '; + end; + ourpath = compress(ourpath, ' '); + p = length(ourpath) - 1; + if substr(ourpath, p, 2) eq '#1' then substr(ourpath, p, 2) = ' '; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +* Get object names specified in FIRSTOBJ=, LAST=, and OBJECTS= for error checking.; +%if not &allobjflag %then %do; + data _ads_objects(keep=object); + length l $ 32500 object $ 200; + l = symget('firstobj') || ' ' || symget('lastobj') || ' ' || symget('objects'); + do i = 1 to 32500 until(object eq ' '); + object = scan(l, i, ' <>'); + if object ne ' ' then output; + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + * Make sure every specified name is referenced.; + data _null_; + set _ads_objects; + length object holdobj $ 200; + holdobj = object; + + * Store object name with pounds and such to match document.; + %ads_expand_obj(object, holdobj) + + match = 0; + do i = 1 to nprts until(match); + set _ads_doclist nobs=nprts point=i; + + * If object has n levels, store in pathpart the last n levels from path.; + %ads_extr_path(pathpart, path, holdobj) + match = (pathpart eq object); + end; + if not match then do; + put 'ERROR: Object ' holdobj 'not found.'; + call symputx('error', '1', 'L'); + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Extract the relevant tables and notes from the list.; +data _ads_select(keep=path type left right object ourpath label pagebreak); + length objlist $ 32500 fullqualobj object firstlist lastlist $ 200; + retain object firstlist lastlist objlist ' ' inflag 0 objind 1; + set _ads_doclist; + + if type eq 'Report' and label =: 'Data Set ' and path =: '\Print' + then label = substr(label, 10); + else do; + label = ' '; + if type eq 'Report' then type = 'rpt'; + end; + + left = 0; right = 0; fullqualobj = ' '; + + if _n_ eq 1 then do; + firstlist = symget('firstobj'); + lastlist = symget('lastobj'); + objlist = symget('objects'); + end; + + * Perform preliminary subsetting based on group patterns.; + %if %nrbquote(&pattern) ne %then %do; + if index(lowcase(ourpath), "&pattern"); + %end; + + righttype = 1; + if &selecttype then righttype = (( &isgraph and type eq 'Graph') or + (not &isgraph and type ne 'Graph')); + + %* Are only the last ones selected (FIRSTOBJ= specified)?; + %if &lastflag and not &allobjflag %then %do; + %ads_extr_path(pathpart, path, firstlist) + %ads_expand_obj(fullqualobj, firstlist) + if pathpart eq fullqualobj then inflag = 1; + if inflag and righttype then output; + %end; + + %* Are only the first ones selected (LASTOBJ= specified)?; + %else %if &firstflag and not &allobjflag %then %do; + if _n_ eq 1 then inflag = 1; + %ads_extr_path(pathpart, path, lastlist) + %ads_expand_obj(fullqualobj, lastlist) + if inflag and righttype then output; + if pathpart eq fullqualobj then inflag = 0; + %end; + + %* Is a range being selected (FIRSTOBJ= and LASTOBJ= specified)?; + %else %if &rangeflag and not &allobjflag %then %do; + %ads_extr_path(pathpart, path, firstlist) + %ads_expand_obj(fullqualobj, firstlist) + if pathpart eq fullqualobj then inflag = 1; + %ads_extr_path(pathpart, path, lastlist) + %ads_expand_obj(fullqualobj, lastlist) + if inflag and righttype then output; + if pathpart eq fullqualobj then inflag = 0; + %end; + + %* Is a list being selected (OBJECTS= specified)?; + %else %if &objflag and not &allobjflag %then %do; + do i = 1 to 32500 until(object eq ' '); + object = scan(objlist, i, ' '); + + if object ne ' ' then do; + + * For an object has n levels, + store in pathpart the last n levels from the path.; + %ads_extr_path(pathpart, path, object) + + left = 0; right = 0; + if substr(object, 1, 1) eq '<' then do; + left = 1; + object = substr(object, 2); + end; + if substr(object, length(object), 1) eq '>' then do; + right = 1; + object = substr(object, 1, length(object) - 1); + end; + + * Store the object name with pounds and such to match the document.; + %ads_expand_obj(fullqualobj, object) + + if fullqualobj eq pathpart then do; + if righttype then output; + object = ' '; + end; + end; + end; + %end; + + %* Is everything selected?; + %else %do; + if righttype then output; + %end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + +* Omit the first or last object from the selection list with SKIPFIRST or SKIPLAST.; +%if &skipfirst or &skiplast %then %do; + data _ads_select; + set _ads_select end=eof; + + %if &skipfirst %then %do; if _n_ = 1 then delete; %end; + %if &skiplast %then %do; if eof then delete; %end; + + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Set page breaks.; +data _ads_select(keep=path type left right object ourpath group label pagebreak); + set _ads_select end=eof; + retain Group 1 oldgroup anyleft 0; + if type in ('Graph', 'Report', 'rpt') then do; + left = 1; right = 1; + if type eq 'Graph' then ngraphs + 1; + end; + if left then do; + group = oldgroup + (not &onebox); + if &onebox and group eq 0 then group = 1; + anyleft = 1; + end; + oldgroup = group; + output; + if right then anyleft = 0; + + other + (type in ('Note', 'Report', 'rpt')); + tabtype = (type in ('Table', 'Tree', 'Batch', 'Crosstab', 'Text')); + if tabtype then ntabs + 1; + if right or (not anyleft and tabtype) then group = oldgroup + (not &onebox); + + if eof and &onebox and &isgraph and ((ntabs + other) or ngraphs ne 1) then do; + put 'ERROR: The Graphic tag must select ' + 'only one graph and nothing ' "else in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if eof and &onebox and not &isgraph and ((ntabs + other) lt 1 or ngraphs) + then do; + put 'ERROR: The Listing tag must select tables and no graphs ' + "in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if not &onlylist and eof and + not &onebox and (ntabs + other) and ngraphs then do; + put 'ERROR: You may request either tables or graphs but not both ' + "in document &store.."; + call symputx('onlylist', '1', 'L'); + call symputx('abnormal', '1', 'L'); + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +%if %index(&flow, print) %then %do; + proc print; var path type group object; run; + proc print; var ourpath type group object; run; + %end; + +* Check for objects that match multiple document pieces.; +%if not &allobjflag %then %do; + proc sort data=_ads_select out=_ads_objects; + by object; + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + + data _null_; + set _ads_objects; + by object; + if object ne ' ' and not (first.object and last.object) then do; + put 'ERROR: Multiple matches. Object ' object + 'matches ' ourpath +(-1)'.'; + call symputx('error', '1', 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + %end; + +* Clear out titles, subtitles, and footnotes as necessary. Build rendering code.; +options nosource; + +data _null_; + length list $ 32500; + retain list ' ' forcepage &&__New_&store; + set _ads_select end=end; + by group; + if _n_ eq 1 then call execute("proc document name=&store;"); + + list = trim(list) || ' or _path_ = "' || trim(path) || '"'; + + %if &pagebreak eq autopage %then %do; /* default */ + first = pagebreak; + if type ne 'Graph' then do; + first = (first or forcepage); + forcepage = 0; + end; + %end; + %else %if &pagebreak eq nopage %then %do; + first = 0; + %end; + %else %do; /* new page */ + first = ((_n_ eq 1) or pagebreak); + %end; + + if first and type ne 'Graph' then put 'Note: New page for ' path; + + if first then call execute("obfootn " || path || ';'); + else if end then call execute('obtitle ' || path || '; obstitle ' || + path || '; run; quit;'); + else call execute('obfootn ' || path || '; obstitle ' || path || + '; obtitle ' || path || ';'); + + if last.group then do; + list = substr(list, 5); + call symputx('_list' || left(put(group, 5.)), trim(list), 'L'); + call symputx('_gtype' || left(put(group, 5.)), put(type, $1.), 'L'); + call symputx('ngroups', group, 'L'); + if type eq 'Report' then + call symputx('_data' || left(put(group, 5.)), trim(label), 'L'); + list = ' '; + end; + + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +options source &savenote; + +%let __new_&store = 0; + +%if &onebox and &ngroups ne 1 and not &abnormal %then %do; + %if &isgraph %then %let i = Graphic; + %else %let i = Listing; + %put ERROR: There must be exactly one group of objects with &i..; + %let onlylist = 1; + %let abnormal = 1; + %end; + +* Render each group of data objects.; +%if not &onlylist %then %do; + ods _all_ close; + ods graphics / reset=index imagename=""; + + %let kl = 0; %let kh = 0; + %do i = 1 %to &ngroups; + + %if %symexist(_list&i) %then %do; + %if &kl eq 0 %then %let jl = ; %else %let jl = &kl; + %if &kh eq 0 %then %let jh = ; %else %let jh = &kh; + %let kl = %eval(&kl + 1); + %let kh = %eval(&kh + 1); + + %if &&_gtype&i eq G %then %do; /* if graph replay */ + %if %nrbquote(&graphtype) eq pdf %then %do; + %if (%nrbquote(&sysver) < 9.3) %then %do; + %put WARNING: ODS PDF Graphics are unavailable in SAS 9.2; + %put WARNING: Generating PNG format in "png" directory.; + %let graphtype=png; + %let graphicdir=png; + %end; + %end; + + ods listing style=&style image_dpi=&dpi gpath="&graphicdir"; + ods graphics / reset=index imagename="&fname&jl" &odsgraphopts + %if %nrbquote(&width) ne %then width=&width; + %if %nrbquote(&height) ne %then height=&height; + %if %nrbquote(&graphtype) eq pdf %then outputfmt=pdf;; + + %if %sysprod(graph) = 1 %then %do; + goptions dev=&gdevice fileonly gsfname=gsasfile gsfmode=replace + hsize= + %if %nrbquote(&width) ne %then &width; + %else 6.4in; + vsize=&h border; + %end; + filename gsasfile "&graphicdir/&fname&jl..&graphtype"; + %put NOTE: Writing Graph file: &graphicdir/&fname&jl..&graphtype; + %end; + %else %do; + %if %index(&dest, listing) %then %do; + FILENAME LISTTMP "&listingdir/_tmp" ENCODING="&SASencodingTex."; + ODS LISTING FILE=LISTTMP ; + %end; + %if %index(&dest, latex) %then %do; + ods tagsets.statrep style=&latexstyle + file="&latexdir/&fname&jh..tex" (notop nobot) + stylesheet="&rootdir/sas.sty" + newfile=output + encoding="&SASencodingTex."; + %end; + %end; + %if not %index(&flow, notes) %then %do; options nonotes; %end; + proc document name=&store; + replay ^(where=(&&_list&i)) / levels=all; + run; quit; + %if &syserr > 4 %then %let error = 1; + %if &error %then %goto endit; + options &savenote; + %if &&_gtype&i eq G %then %do; /* if graph replay */ + filename gsasfile "&graphicdir/_tmp.&graphtype"; + %end; + ods _all_ close; + ods graphics / reset=index imagename="" reset=width reset=height; + %if &&_gtype&i ne G and /* if not graph */ + %index(&dest, listing) %then %do; + /* break up big listing files */ + options nonotes; + data _null_; + retain kl &jl; + length fn $ 200; + infile "&listingdir/_tmp" lrecl=%eval(&ls+1) pad; + input line $char%eval(&ls+1).; + page = substr(line, 1, 1) eq '0C'x; + if _n_ eq 1 or page then do; + fn = "&listingdir/&fname"; + if page then line = substr(line, 2); + if kl then fn = compress(fn || put(kl, 5.) || '.lst'); + else fn = compress(fn || '.lst'); + kl + 1; + call symputx('kl', kl, 'L'); + put 'Note: Writing Listing file : ' fn; + filename outlst "&listingdir/&fname..lst" encoding="&SASEncodingTex."; + end; + file outlst nopad ; + l = length(line); + put line $varying. l; + if _error_ then call symputx('error', '1', 'L'); + run; + filename outlst clear; + %if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + options &savenote; + %end; + %end; + %end; + ods listing; +%end; + +%if &ngroups eq 0 %then %do; + %put ERROR: No objects selected.; + %let error = 1; + %goto endit; + %end; + +%if not %index(&flow, notes) %then %do; options nonotes; %end; + +proc sort data=_ads_doclist; by path; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +proc sort data=_ads_select; by path; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +data _ads_doclist; + merge _ads_doclist(in=dl) _ads_select(keep=path group in=s); + by path; + if s then Status = 'Selected'; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +proc sort data=_ads_doclist; by objnum; run; + +%if &syserr > 4 %then %let error = 1; %if &error %then %goto endit; + +%endit:; + +* Get some formatting information for rendering the document contents list.; +data _null_; + set _ads_doclist end=eof; + left = max(left, length(ourpath)); + tyw = max(tyw, length(type)); + if eof then do; + left + 1; tyw + 1; stw = 9; grw = 5; + atright = min(&ls - tyw - stw - grw - 1, left + 3); + call symputx('atright', atright, 'L'); + call symputx('tyw', tyw, 'L'); + call symputx('stw', stw, 'L'); + call symputx('grw', grw, 'L'); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; + +* Render the document contents list, wrapping the path if necessary.; +data _null_; + length p $ 500; + status = ' '; group = .; + file log; + set _ads_doclist; + ghead = 'Group'; thead = 'Type'; shead = 'Status'; + if _n_ eq 1 then put / 'Objects' + @&atright thead $&tyw.. + @%eval(&atright+&tyw) shead $&stw.. + @%eval(&atright+&tyw+&stw) ghead $&grw.. /; + do j = 1 to 100 while(ourpath ne ' '); + do l = &atright - 2 to &atright / 2 by -1 + while(not (substr(ourpath, l, 1) in ('.', ' '))); + end; + p = substr(ourpath, 1, l); + if j eq 1 then + put p $%eval(&atright-2). +1 type $&tyw.. status $&stw.. group 3.; + else put p $%eval(&atright-2).; + ourpath = substr(ourpath, l + 1); + end; + if _error_ then call symputx('error', '1', 'L'); + run; + +%if &syserr > 4 %then %let error = 1; + +%veryend:; + +* Clean up.; +%if not %index(&flow, notes) %then %do; options nonotes; %end; +proc datasets nolist; delete _ads_select _ads_doclist _ads_objects; run; quit; + +%if &syserr > 4 %then %let error = 1; + +%let syslast = &holdlast; +%if &error or &abnormal %then %put ERROR: Macro write ended abnormally.; +run; + +filename __f1 "&listingdir/_tmp"; +filename __f2 "&graphicdir/_tmp.&graphtype"; +data _null_; rc = fdelete('__f1'); rc = fdelete('__f2'); run; + +options obs=max nosyntaxcheck &savenote &savetime &savesize; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The OUTPUT macro opens an ODS document and */ + /* captures output until it encounters an */ + /* ENDOUTPUT macro or a WRITE macro. */ + /*---------------------------------------------*/ +%macro output(label, /* is a required keyword that specifies the */ + /* ODS document name. This is used in the */ + /* STORE= option in the WRITE macro and in */ + /* \Listing and \Graphic tags. */ + /* */ + style=, /* specifies the ODS style for GRSEG graphics. */ + /* Use the STYLE= option in the WRITE macro to */ + /* control the style for ODS Graphics. If */ + /* STYLE= is specified, that style is used. */ + /* If STYLE= is not specified, and if a macro */ + /* variable DefaultStyle is defined, its value */ + /* is used as the style. If STYLE= is not */ + /* specified and the macro variable */ + /* DefaultStyle is not defined or if its value */ + /* is null, then the default style (which is */ + /* the HTMLBLUE style) is used. */ + /* */ + /* In other words, the default style is the */ + /* HTMLBLUE style. However, you can set the */ + /* default style to (say) LISTING by putting */ + /* the following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultstyle=listing; */ + /* */ + /* Since this line begins with a null macro */ + /* comment (%*;) in column 1, it will not show */ + /* up in the SAS code listing, but it will */ + /* affect the capture program and change the */ + /* default style for the duration of the */ + /* running of the program. */ + /* */ + dpi=);; /* specifies DPI (dots per inch) for GRSEG */ + /* graphics. You typically would not use this */ + /* except when you would otherwise run out of */ + /* memory. The default is 300 DPI, and a */ + /* reasonable alternative for GRSEG graphs */ + /* with a large file size is 96 DPI. More */ + /* details follow. */ + /* */ + /* With GRSEG graphics, you do not have */ + /* continuous control over DPI as you do with */ + /* ODS Graphics. With the macro default DPI */ + /* of 300, you get 300 DPI. Otherwise, you */ + /* get the device default of 96 DPI. */ + /* */ + /* This option controls the DPI for GRSEG */ + /* graphics. Use the DPI= option in the WRITE */ + /* macro to control the style for ODS */ + /* Graphics. If DPI= is specified, that DPI */ + /* is used. If DPI= is not specified, and if */ + /* a macro variable DefaultDPI is defined, its */ + /* value is used as the DPI. If DPI= is not */ + /* specified and the macro variable DefaultDPI */ + /* is not defined or if its value is null, */ + /* then the default DPI (300) is used. */ + /* */ + /* In other words, the default DPI is 300. */ + /* However, you can set the default DPI for */ + /* GRSEG graphics to 96 by putting the */ + /* following line at the top of your first */ + /* Sascode block, beginning in column 1: */ + /* */ + /* %*;%let defaultdpi=100; */ + /* */ + /* This is not a typo. If you set the default */ + /* DPI to anything other than 300, you get 96 */ + /* DPI with GRSEG graphics and the specified */ + /* value with ODS Graphics. With ODS */ + /* Graphics, the values of 300 and 100 are */ + /* most commonly used. */ + /* */ + /* Since the %LET statement is preceded by a */ + /* null macro comment (%*;) in column 1, it */ + /* will not show up in the SAS code listing, */ + /* but it will affect the capture program and */ + /* change the default DPI for the duration of */ + /* the running of the program. You can change */ + /* DPI at any time with one of these */ + /* statements. */ + /*---------------------------------------------*/ + +%local log lst savenote gdevice; + +* Set the default style using STYLE= and a DefaultStyle macro variable; +%if &style eq %then %let style = &defaultstyle; + +* Set the default DPI using DPI= and a DefaultDPI macro variable; +%if &dpi eq %then %let dpi = &defaultDPI; + +%let graphtype = %qlowcase(&graphtype); +%if %nrbquote(&graphtype) ne pdf %then %let graphtype = png; +%let gdevice = %substr(png300, 1, 3 * (1 + (&dpi eq 300))); +%if %nrbquote(&graphtype) eq pdf %then %let gdevice = pdf; + +%if not (&dpi eq 96 or &dpi eq 100 or &dpi eq 300) + %then %put NOTE: DPI=96 will be used for GRSEG graphics.; + +%let savenote = %sysfunc(getoption(notes)); +%if %sysfunc(symexist(_ads_debug)) %then %do; + %let log = 0; + %let lst = 0; + %let _ads_debug = %lowcase(&_ads_debug); + %if %index(&_ads_debug, flowall) %then %do; + %let log = 1; + %let lst = 1; + %end; + %else %if %index(&_ads_debug, flowlog) %then %let log = 1; + %else %if %index(&_ads_debug, flowlst) %then %let lst = 1; + %if &log or &lst %then %do; + ods listing; + data _null_; + %if &log %then %do; put "Begin Sascode block ""&label""."; %end; + %if &lst %then %do; + file print; + put _page_; + put "Begin Sascode block ""&label""."; + %end; + run; + %end; + %end; + +run; quit; + +options nonotes; +libname mydir '.'; +options nodate nonumber obs=max nosyntaxcheck; +%global documentlabel; + +ods _all_ close; +ods document close; + +data _null_; call symputx("__New_&label", '1', 'G'); run; + +proc datasets nolist nowarn; + delete gseg(memtype=catalog); + run; quit; + +proc datasets nolist nowarn library=sasuser; + delete __&label(memtype=catalog); + run; quit; + +* Select the style for GRSEG graphics.; +ods listing style=&style file="&listingdir/_tmp"; +ods listing select none; +filename __f "&listingdir/_tmp"; +data _null_; rc = fdelete('__f'); run; + +* Set the global label, and open the ODS Document.; +%let documentLabel = &label; +ods document name = &label(write) cat=sasuser.__&label; + +* Specify 300 DPI for GRSEG graphics (gdevice = png or png300).; +%if %sysprod(graph) = 1 %then %do; + goptions dev=&gdevice fileonly gsfname=gsasfile gsfmode=replace border; +%end; +filename gsasfile "&graphicdir/_tmp.&graphtype"; +options &savenote; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The ENDOUTPUT macro ends output capture. */ + /*---------------------------------------------*/ +%macro endoutput(label);;/* specifies the ODS document name. This is */ + /* used only to display program flow */ + /* information in the SAS log when the macro */ + /* variable _ads_debug is defined. */ + /*---------------------------------------------*/ + +run; quit; +options obs=max nosyntaxcheck; +ods document close; + +%local log lst; + +%if %sysfunc(symexist(_ads_debug)) %then %do; + %let log = 0; + %let lst = 0; + %let _ads_debug = %lowcase(&_ads_debug); + %if %index(&_ads_debug, flowall) %then %do; + %let log = 1; + %let lst = 1; + %end; + %else %if %index(&_ads_debug, flowlog) %then %let log = 1; + %else %if %index(&_ads_debug, flowlst) %then %let lst = 1; + %if &log or &lst %then %do; + ods listing; + data _null_; + %if &log %then %do; put "End Sascode block ""&label""."; %end; + %if &lst %then %do; + file print; + put "End Sascode block ""&label""."; + put _page_; + %end; + run; + %end; + %end; +ods _all_ close; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The STARTLIST macro starts the capture of */ + /* listing output. Use this macro when you */ + /* want to program your own output capture */ + /* (for example, when you want to show only */ + /* part of a table). */ + /*---------------------------------------------*/ +%macro startlist(fname, /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* tag. */ + /* */ + pagesize=, /* specifies page size. The default is the */ + /* page size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current page size is */ + /* restored at the end. */ + linesize=);;/* specifies line size. The default is the */ + /* line size currently in effect. This */ + /* specification lasts for the duration of */ + /* this step. The current line size is */ + /* restored at the end. */ + /*---------------------------------------------*/ + +%global _ads_printfname _ads_savesize; +%let _ads_printfname = &fname; +%let _ads_savesize = ls=%sysfunc(getoption(ls)) ps=%sysfunc(getoption(ps)); +quit; +ods _all_ close; +ods document close; +options nodate nonumber %if &pagesize ne %then ps=&pagesize; + %if &linesize ne %then ls=&linesize;; +ods listing file="&listingdir/_tmp"; +%mend; + + /*---------------------------------------------*/ +%macro endlist;; /* The ENDLIST macro ends the capture of */ + /* listing output. */ + /*---------------------------------------------*/ +%local ls savenote; +run; +ods _all_ close; +%let ls = %sysfunc(getoption(ls)); +%let savenote = %sysfunc(getoption(notes)); + +options nonotes; +data _null_; + retain kl 0; + length fn $ 40; + infile "&listingdir/_tmp" lrecl=%eval(&ls+1) pad; + input line $char%eval(&ls+1).; + page = substr(line, 1, 1) eq '0C'x; + if _n_ eq 1 or page then do; + ext = 'lst';; + fn = ext || "/&_ads_printfname"; + if page then line = substr(line, 2); + if kl then fn = compress(fn || put(kl, 5.) || '.' || ext); + else fn = compress(fn || '.' || ext); + kl + 1; + put 'Note: Writing Print file: ' fn; + end; + file x filevar=fn nopad; + l = length(line); + put line $varying. l; + run; + +options &savenote &_ads_savesize; + +filename __f "&listingdir/_tmp"; +data _null_; rc = fdelete('__f'); run; +%mend; + +*------------------------------------------------------------------------; + + /*---------------------------------------------*/ + /* The STARTLOG macro starts the capture of */ + /* the SAS log. */ + /*---------------------------------------------*/ +%macro startlog(fname);; /* is a required keyword that specifies the */ + /* first level of the output file name. This */ + /* name will appear at the end of the \Listing */ + /* tag. */ + /*---------------------------------------------*/ +%global __fname __ls; +%let __fname=&fname; +%let __ls = %sysfunc(getoption(ls)); + +options nostimer nosource2 nosource; +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +proc printto log=LOGTMP new ; run; +%mend; + + + /*---------------------------------------------*/ + /* The ENDLOG macro ends the capture of the */ + /* SAS log. */ + /*---------------------------------------------*/ +%macro endlog(store=1, /* set STORE=0 to capture messages only and */ + /* not code. */ + range=1);; /* Specify a Boolean expression to select only */ + /* certain observations. Examples: */ + /* RANGE=_n_ < 5, */ + /* RANGE=not index(line, 'ERROR'). */ + /*---------------------------------------------*/ + +%local savenote; +%let savenote = %sysfunc(getoption(stimer)) %sysfunc(getoption(source2)) + %sysfunc(getoption(source)); + +proc printto log=log; run; + +options stimer source2 source; + +FILENAME LOGTMP "&listingdir/__tmp" ENCODING='UTF-8'; +FILENAME LOGOUT "&listingdir/&__fname..lst" ENCODING='UTF-8'; +data _null_; + infile LOGTMP lrecl=%eval(&__ls+4) pad; + input line $char&__ls..; + if anycntrl(line) = 0; + %if &store %then %do; + if index(line, '%endlog') = 0; + %end; + %else %do; + if not (n(input(scan(line, 1, ' +'), ?? 12.)) and + compress(line, ' 0123456789') =: '+'); + %end; + if ⦥ + file LOGOUT lrecl=%eval(&__ls+4); + put line $char&__ls..; + run; + +filename __f "&listingdir/__tmp"; +data _null_; rc = fdelete('__f'); run; + +options &savenote; +%mend; + +*------------------------------------------------------------------------; + +* This utility macro stores in the out macro variable the + object name with pounds and such to match the name in the document.; +%macro ads_expand_obj(out, in); + length _w $ 200; + &out = ' '; + do _j = 1 to 32500 until(_w = ' '); + _w = scan(&in, _j, '.'); + if _w ne ' ' then do; + if not index(_w, '#') then _w = trim(_w) || '#1'; + &out = trim(&out) || '\' || _w; + end; + end; + &out = substr(&out, 3); + %mend; + +* This utility macro stores in the out macro variable the last n levels + (for an object with n levels) from the path.; +%macro ads_extr_path(out, path, object); + _levs = 1 + length(&object) - length(compress(&object, '.')); + call scan(&path, -_levs, _p, _len, '\'); + &out = lowcase(substr(&path, max(_p, 1))); + if substr(&out, 1, 1) eq '\' then &out = substr(&out, 2); + %mend; + +*------------------------------------------------------------------------; + +* 'this macro creates a directory if needed and deletes files with the +given extension to insure the directory exists and is empty of output files.; + +%macro cleandir(droot, dname, ext); + %local saveopts; + %let saveopts = %sysfunc(getoption(notes)); + options nonotes; + data _null_; + length ext $ 5 ; + droot = symget('droot'); + dname = symget('dname'); + ext = cats('.', upcase(symget('ext'))); + dpath = cats(droot, '/', dname); + + rc = filename('dref', droot); + rc = fexist('dref'); + if rc eq 0 then do; + put 'ERROR: Directory ' droot 'not found.'; + stop; + end; + + rc = filename('dref', dpath); + rc = fexist('dref'); + if rc eq 0 then do; + dpath = dcreate(dname, droot); + rc2 = filename('dreff', dpath); + rc2 = fexist('dreff'); + if rc2 eq 0 then do; + put 'ERROR: Directory ' dpath 'not created.'; + stop; + end; + else do; + put 'Note: Directory ' dpath 'created.'; + end; + end; + else do; + rc = filename('dreff', dpath); + did = dopen('dreff'); + if rc or not did then do; + put 'ERROR: Directory ' dpath 'not found.'; + stop; + end; + do i = 1 to dnum(did); /* Loops through entire directory */ + file = dread(did, i); + if index(upcase(file), ext) then do; /* file ends in dot extension */ + rc = filename('fref', cats(dpath, '/', file)); + rc = fdelete('fref'); + end; + end; + rc = dclose(did); + end; + run; + options &saveopts; +%mend cleandir; + + +proc format; + /* Format pour nombres < 100000 */ + picture STATREPS + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPR + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour nombres >= 100000 */ + picture STATREPL + 1000000000-high='000~000~000~009,99' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009,99' (decsep="," dig3sep=" ") + 1000-<100000='000~009,99' (decsep="," dig3sep=" ") + 0-<1000='009,99' (decsep="," dig3sep=" ") + -1000-<0='009,99' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009,99' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009,99' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009,99' (decsep="," dig3sep=" " prefix='-'); + picture STATREPK + 1000000000-high='000~000~000~009' (decsep="," dig3sep=" ") + 100000-<1000000000='000~000~009' (decsep="," dig3sep=" ") + 1000-<100000='000~009' (decsep="," dig3sep=" ") + 0-<1000='009' (decsep="," dig3sep=" ") + -1000-<0='009' (decsep="," dig3sep=" " prefix='-') + -100000-<-1000='000~009' (decsep="," dig3sep=" " prefix='-') + -1000000000-<-100000='000~000~009' (decsep="," dig3sep=" " prefix='-') + low -< -1000000000='000~000~000~009' (decsep="," dig3sep=" " prefix='-'); + + /* Format pour pourcentages/petits nombres */ + picture STATREPC + other='0~009,9900' (mult=1000000); + + /* Format date dd/mm/yyyy */ + picture STATREPD + low-high='%0d/%0m/%Y' (datatype=date); +run; +%macro STATREPResults(variable,format); + filename outtex "&SAStoTexname" encoding="utf-8" mod; + file outtex termstr=nl mod; + put "\def\&variable{" &variable &format '}'; +%mend; + +%macro STATREPAllResults(); + array _all _numeric_; + filename outtex "&SAStoTexname" encoding="utf-8" ; + file outtex termstr=nl mod; + + do over _all; + a = vname(_all); + fmt = vformat(_all); + + /* Test si variable de type date (format date appliqué) */ + if index(upcase(fmt),'DATE') or index(upcase(fmt),'DDMMYY') or + index(upcase(fmt),'MMDDYY') or index(upcase(fmt),'YYMMDD') or + index(upcase(fmt),'EURDFDD') or index(upcase(fmt),'NLDATE') or + (_all >= 0 and _all < 100000 and mod(_all,1)=0 and + vformat(_all) in ('BEST','F','') and a ne '') then do; + /* Vérification additionnelle : valeur dans la plage des dates SAS */ + if _all >= -109572 and _all <= 157377 then do; + put '\def\' a '{' _all STATREPD. '}'; + end; + else do; + /* Ce n'est pas une date, traiter comme nombre normal */ + if abs(_all) >= 100000 then + put '\def\' a '{' _all STATREPL. '}'; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + /* Sinon traiter comme nombre normal */ + else do; + if abs(_all) >= 100000 then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPK. '}'; + else + put '\def\' a '{' _all STATREPL. '}'; + end; + else if abs(_all) < 1 and _all ne . then + put '\def\' a '{' _all STATREPC. '}'; + else if _all ne . then do; + if mod(_all,1)=0 then + put '\def\' a '{' _all STATREPR. '}'; + else + put '\def\' a '{' _all STATREPS. '}'; + end; + end; + end; +DROP A FMT; +%mend; + +%MACRO STATREPMACROVAR(variable); +DATA _NULL_; +&variable = &&&variable; +%STATREPALLRESULTS() +;RUN; +%MEND; + + +PROC IML; +START STATREPFormatValue(value, varName); + ligne = ""; + + IF value = . THEN RETURN(ligne); + + IF value >= -109572 & value <= 157377 & MOD(value,1)=0 + & INDEX(UPCASE(varName),'DATE')>0 THEN + ligne = STRIP(PUTN(value, 'STATREPD.')); + + ELSE IF ABS(value) >= 100000 THEN DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPK.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPL.')); + END; + + ELSE IF ABS(value) < 1 THEN + ligne = STRIP(PUTN(value, 'STATREPC.')); + + ELSE DO; + IF MOD(value,1)=0 THEN + ligne = STRIP(PUTN(value, 'STATREPR.')); + ELSE + ligne = STRIP(PUTN(value, 'STATREPS.')); + END; + + RETURN(ligne); +FINISH; + +START STATREPResult(variable); + varName = PARENTNAME("variable"); + n = NROW(variable); + p = NCOL(variable); + v=variable; +IF p=1 & n>1 THEN DO; V=v`;p=n; n=1; END; + latex = ""; + +DO i = 1 TO n; + row = ""; + DO j = 1 TO p; + cell = STATREPFormatValue(v[i,j], varName); + IF cell ^= "" THEN DO; + IF j > 1 THEN row = row + " & "; + row = row + cell; + END; + END; + IF i > 1 THEN latex = latex + " \\ "; + latex = latex + row; +END; +IF n=1 & p=1 THEN + ligne = "\def\" + STRIP(varName) + " {" + latex + "}"; + +ELSE DO; + tabspec = "*{" + STRIP(CHAR(p)) + "}{c}"; + ligne = "\def\" + STRIP(varName) + + " {\begin{center}\begin{tabular}{" + + tabspec + "}" + + latex + + "\end{tabular}\end{center}}"; +END; + +EDIT WORK._STATREP_TEMP_; +APPEND FROM ligne; +CLOSE WORK._STATREP_TEMP_; +FINISH; + +STORE MODULE=( STATREPResult STATREPFormatValue ); +QUIT; + + +DATA WORK._STATREP_TEMP_; +LENGTH LIGNE $256; +STOP; +RUN; +QUIT; + +%MACRO STATREPIMLWrite(); +DATA _NULL_; + SET WORK._STATREP_TEMP_; + FILENAME outtex "&SAStoTexname" ENCODING="utf-8"; + FILE outtex TERMSTR=NL MOD; + PUT LIGNE; +RUN; + +%MEND STATREPIMLWrite; diff --git a/statrep_tagset.sas b/statrep_tagset.sas new file mode 100644 index 0000000..147a64a --- /dev/null +++ b/statrep_tagset.sas @@ -0,0 +1,567 @@ +ODS PATH WORK.TEMPLAT(UPDATE) SASHELP.TMPLMST(READ); +proc template; + define style styles.StatRep; + parent = styles.statistical; + class colors / + 'link2' = cx0000FF + 'link1' = cx800080 + 'docbg' = cxFFFFFF + 'contentbg' = cxFFFFFF + 'systitlebg' = cxFFFFFF + 'titlebg' = cxFFFFFF + 'proctitlebg' = cxFFFFFF + 'headerbg' = cxFFFFFF + 'captionbg' = cxFFFFFF + 'captionfg' = cx000000 + 'bylinebg' = cxFFFFFF + 'notebg' = cxFFFFFF + 'tablebg' = cxFFFFFF + 'batchbg' = cxFFFFFF + 'systitlefg' = cx000000 + 'titlefg' = cx000000 + 'proctitlefg' = cx000000 + 'bylinefg' = cx000000 + 'notefg' = cx000000; + class Header / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class RowHeader / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class Footer / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class RowFooter / + color = cx000000 + backgroundcolor = cxFFFFFF + bordercolor = cxB0B7BB + bordercollapse = collapse; + class batch / + borderwidth = 0px; + class Data / + font = fonts('DocFont') + backgroundcolor = _undef_ + bordercolor = cx919191 + bordercollapse = collapse; + class DataEmphasis / + font = fonts('DocFont') + backgroundcolor = _undef_ + bordercolor = cx919191 + bordercollapse = collapse; + end; +run; + +proc template; +define tagset Tagsets.StatRep; + notes "This is the StatRep LaTeX definition"; + + define event initialize; + trigger set_options; + end; + + define event set_options; + set $options["junk" ] "junk" /if ^$options; + unset $cell_align; + + do /if cmp( $options["CELL_ALIGN"], "yes"); + set $cell_align "True"; + done; + + end; + + define event title_format_section; + put value; + end; + + define event cell_is_empty; + put " "; + end; + + define event list; + start: + put "\begin{itemize}" NL; + + finish: + put "\end{itemize}" NL; + end; + + define event list_item; + put "\item "; + end; + + define event list_entry; + put "\item "; + end; + + define event image; + put "\sasgraph{"; + put BASENAME /if ^exists( NOBASE); + put URL; + put "}" NL; + end; + + define event line; + put "\rule{\linewidth}{" colwidth; + put "pt}" NL; + end; + + define event text; + start: + put "\par " NL; + end; + + define event paragraph; + start: + put VALUE; + put NL; + put NL; + end; + + define event preformat; + start: + put "\verb?" NL; + + finish: + put "?" NL; + end; + + define event center; + start: + put "\begin{center}" NL; + + finish: + put "\end{center}" NL; + end; + + define event styles; + start: + put NL; + put "\RequirePackage[T1]{fontenc}" NL; + put "\RequirePackage{times}" NL; + put "\RequirePackage{fancyvrb}" NL; + put "\RequirePackage{array}" NL; + put "\RequirePackage{graphicx}" NL; + put NL; + put "\newbox\sas@fig" NL; + put "\newlength\sas@figwidth" NL; + put NL; + put "\newif\ifsas@color" NL; + put "\sas@colorfalse" NL; + put NL; + put "\DeclareOption{color}{\sas@colortrue}" NL; + put "\ProcessOptions" NL; + put NL; + + finish: + put %nrstr("%% Set cell padding") NL; + put "\renewcommand{\arraystretch}{1.3}" NL NL; + put %nrstr("%% Headings") NL; + put %nrstr("\newcommand{\sasheading}[3][c]{{%%") NL; + put %nrstr(" \if#1r\flushright\else\if#1l\flushleft\else\centering\fi\fi%%") NL; + put %nrstr(" {\csname sasS#2\endcsname #3}\mbox{}\\[0.1\baselineskip]%%") NL; + put %nrstr(" \if#1r\endflushright\else\if#1l\endflushleft\else\fi\fi%%") NL; + put "}}" NL; + put NL; + put "\newcommand{\sasbyline}[2][c]{\sasheading[#1]{byline}{#2}}" NL; + put "\newcommand{\sassystemtitle}[2][c]{\sasheading[#1]{systemtitle}{#2}}" NL; + put "\newcommand{\sassystemfooter}[2][c]{\sasheading[#1]{systemfooter}{#2}}" NL; + put "\newcommand{\sasproctitle}[2][c]{\sasheading[#1]{proctitle}{#2}}" NL; + put "\newcommand{\sascaption}[2][l]{\marginpar[#1]{\fbox{\parbox{0.7in}{\sasScaption{#2}}}}}" NL; + put NL; + put %nrstr("%% Declare new verbatim type") NL; + put %nrstr("\DefineVerbatimEnvironment{sasverbatim}{BVerbatim}%%") NL; + put " {fontsize=\footnotesize," NL; + put " commandchars=\\\{\}," NL; + put " formatcom=\sasSbatch}" NL; + put NL; + put %nrstr("%% Declare new column types") NL; + put "\newcolumntype{S}[2]{>{\csname sasS#1\endcsname}#2}" NL; + put "\newcolumntype{d}{r}" NL; + put NL; + put %nrstr("%% Set warning box style") NL; + put "\newlength\notewidth" NL; + put "\setlength\notewidth{4in}" NL; + put "\newcommand*{\saswarn}[2][c]{\sasmsg{warn}{#1}{#2}}" NL; + put "\newcommand*{\saserror}[2][c]{\sasmsg{error}{#1}{#2}}" NL; + put "\newcommand*{\sasnote}[2][c]{\sasmsg{note}{#1}{#2}}" NL; + put "\newcommand*{\sasfatal}[2][c]{\sasmsg{fatal}{#1}{#2}}" NL; + put %nrstr("\newcommand*{\sasmsg}[3]{%%") NL; + put %nrstr(" \ifsas@color\let\columncolor\undefined\fi%%") NL; + put %nrstr(" \begin{center}%%") NL; + put %nrstr(" \begin{tabular}{ll}\hline%%") NL; + put %nrstr(" \multicolumn{1}{|S{#1banner}{p{0.7in}}|}{#1} & %%") NL; + put %nrstr(" \multicolumn{1}{|S{#1content}{p{\notewidth}}|}{#3{\newline}}\\\hline%%") NL; + put %nrstr(" \end{tabular}%%") NL; + put %nrstr(" \end{center}%%") NL; + put %nrstr(" \ifsas@color\let\columncolor\sascolumncolor\fi%%") NL; + put "}" NL; + put NL; + put "\ifsas@color\RequirePackage{colortbl}\fi" NL; + put NL; + put %nrstr("%% Hack colortbl to allow \columncolor in macros") NL; + put "\let\CT@extract@org\CT@extract" NL; + put "\def\CT@extract{\futurelet\CT@NEXT\CT@extract@next}" NL; + put %nrstr("\def\CT@extract@next{%%") NL; + put " \ifx\CT@NEXT\csname" NL; + put %nrstr(" \@ReturnAfterFi{%%") NL; + put " \expandafter\expandafter\expandafter" NL; + put %nrstr(" }%%") NL; + put " \fi" NL; + put " \CT@extract@org" NL; + put "}" NL; + put "\long\def\@ReturnAfterFi#1\fi{\fi#1}" NL; + put "" NL; + put "\ifsas@color" NL; + put "" NL; + put " \newcommand{\foreground}[1]{\color[rgb]{#1}}" NL; + put " \newcommand{\sascolumncolor}[2][]{}" NL; + put " \let\columncolor\sascolumncolor" NL; + put " \newcommand{\documentforeground}[1]{\AtBeginDocument{\color[rgb]{#1}}}" NL; + put " \newcommand{\documentbackground}[1]{\AtBeginDocument{\pagecolor[rgb]{#1}}}" NL; + put " \def\sastable{\let\columncolor\undefined\tabular}" NL; + put " \def\endsastable{\endtabular\let\columncolor\sascolumncolor}" NL; + put " \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular}" NL; + put " \def\endstackedcell{\endtabular\egroup}" NL; + put NL; + put "\else" NL; + put NL; + put " \providecommand{\foreground}[1]{}" NL; + put " \providecommand{\color}[2][]{}" NL; + put " \newcommand{\sascolumncolor}[2][]{}" NL; + put " \let\columncolor\sascolumncolor" NL; + put " \newcommand{\documentforeground}[1]{}" NL; + put " \newcommand{\documentbackground}[1]{}" NL; + put " \def\sastable{\tabular}" NL; + put " \def\endsastable{\endtabular}" NL; + put " \def\stackedcell{\bgroup\renewcommand{\arraystretch}{1}\tabular}" NL; + put " \def\endstackedcell{\endtabular\egroup}" NL; + put "" NL; + put "\fi" NL; + put NL; + put %nrstr("%%\let\sasgraph\includegraphics") NL; + put %nrstr("%% Scale graphics so they always fit on the page") NL; + put %nrstr("\newcommand\sasgraph[2][]{%%") NL; + put %nrstr(" \savebox{\sas@fig}{\includegraphics[#1]{#2}}%%") NL; + put %nrstr(" \settowidth{\sas@figwidth}{\usebox{\sas@fig}}%%") NL; + put %nrstr(" \ifthenelse{\lengthtest{\sas@figwidth > \textwidth}}{%%") NL; + put %nrstr(" \resizebox{0.95\textwidth}{!}{\usebox{\sas@fig}}}{%%") NL; + put " \usebox{\sas@fig}}" NL; + put "}" NL; + put NL; + end; + + define event style_class; + start: + put "\def\sasS" lowcase(HTMLCLASS) %nrstr("{%%") NL; + put " " FONT_SIZE %nrstr("%%") NL /if exists( FONT_SIZE); + put " " FONT_WEIGHT %nrstr("%%") NL /if exists( FONT_WEIGHT); + put " " FONT_STYLE %nrstr("%%") NL /if exists( FONT_STYLE); + put " " FONT_FACE %nrstr("%%") NL /if exists( FONT_FACE); + put " \color[rgb]{" FOREGROUND %nrstr("}%%") NL /if exists( foreground); + put " \columncolor[rgb]{" BACKGROUND %nrstr("}%%") NL /if exists( background); + set $foreground foreground /if cmp( htmlclass, "body"); + set $background background /if cmp( htmlclass, "body"); + + finish: + put "}" NL; + end; + + define event caption; + start: + set $sascaption "true"; + block table; + block row; + block colspecs; + block colspec_entry; + put "\sascaption["; + put "l" /if cmp( TYPE, "L"); + put "r" /if cmp( TYPE, "R"); + put "b" /if cmp( TYPE, "B"); + put "t" /if cmp( TYPE, "T"); + put "]{"; + + finish: + put "}" NL; + unblock table; + unblock row; + unblock colspecs; + unblock colspec_entry; + set $sascaption "false"; + end; + + define event table; + start: + put NL; + put NL; + put "\begin{sastable}"; + + trigger alignment; + + finish: + put "\end{sastable}" NL; + put NL; + end; + + define event verbatim_text; + put VALUE; + put NL; + end; + + define event verbatim_container; + start: + put NL; + put NL; + put "\begin{center}" NL /if cmp( just, "c"); + put "\begin{sasverbatim}" NL; + + finish: + put "\end{sasverbatim}" NL; + put "\end{center}" NL /if cmp( just, "c"); + put NL; + end; + + define event alignment; + start: + put "[c]" /if cmp( just, "c"); + put "[c]" /if cmp( just, "d"); + put "[r]" /if cmp( just, "r"); + put "[l]" /if cmp( just, "l"); + flush; + end; + + define event colspecs; + start: + put "{"; + + finish: + put "}\hline" NL; + end; + + define event colspec_entry; + put just /if ^cmp( just, "d"); + put "r" /if cmp( just, "d"); + end; + + define event row; + + finish: + put NL "\\\hline" NL; + end; + + define event rowspanfillsep; + put %nrstr(" & ") NL; + end; + + define event rowspancolspanfill; + put " "; + put "\multicolumn{"; + put colspan; + put "1" /if ^exists( colspan); + put "}"; + put "{|S{"; + put lowcase(HTMLCLASS); + put "data" /if ^htmlclass; + put "}{"; + put just; + put "}|}{~}"; + end; + + define event header; + start: + + trigger data; + + finish: + + trigger data; + end; + + define event data; + start: + put VALUE /if cmp( $sascaption, "true"); + break /if cmp( $sascaption, "true"); + put %nrstr(" & ") NL /if ^cmp( COLSTART, "1"); + put " "; + put "\multicolumn{"; + put colspan; + put "1" /if ^colspan; + put "}"; + put "{"; + put "|" /if ^$instacked; + put "S{"; + put lowcase(HTMLCLASS); + put "}{"; + put just; + put "}"; + put "|" /if ^$instacked; + put "}"; + put "{"; + put tranwrd(VALUE,"-","$-$") /if contains( lowcase(HTMLCLASS), "data"); + put VALUE /if ^contains( lowcase(HTMLCLASS), "data"); + + finish: + break /if cmp( $sascaption, "true"); + put "}"; + end; + + define event data_note; + start: + + trigger data; + + finish: + + trigger data; + end; + + define event stacked_cell; + start: + put NL; + put "\begin{stackedcell}"; + + trigger alignment; + + finish: + put "\end{stackedcell}" NL; + end; + + define event stacked_value; + start: + unset $instacked; + set $instacked "true"; + + trigger data; + + finish: + + trigger data; + unset $instacked; + end; + + define event stacked_value_header; + start: + + trigger stacked_value; + + finish: + + trigger stacked_value; + end; + + define event stacked_cell_colspecs; + start: + put "{"; + + finish: + put "}" NL; + end; + + define event stacked_cell_colspec_entry; + put just /if ^cmp( just, "d"); + put "r" /if cmp( just, "d"); + end; + + define event stacked_cell_row; + + finish: + put NL "\\" NL; + end; + + define event put_value; + put VALUE; + end; + + define event put_value_cr; + put VALUE NL; + end; + + define event byline; + put NL; + put "\sasbyline"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event proc_title; + put "\sasproctitle"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event note; + put "\sasnote"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Error; + put "\saserror"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Warn; + put "\saswarn"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event Fatal; + put "\sasfatal"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event system_title; + put "\sassystemtitle"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + define event system_footer; + put "\sassystemfooter"; + + trigger alignment; + put "{"; + put VALUE; + put "}" NL; + end; + + image_formats = "png,pdf"; + split = " {\newline} "; + nobreakspace = "~"; + mapsub = %nrstr("/\%%/\$/\&/\{/\}/\~/\^/\#/{\textunderscore}/{\textbackslash}/"); + map = %nrstr("%%$&{}~^#_\"); + output_type = "latex"; + stacked_columns = OFF; + embedded_stylesheet; + private; +end; +run; diff --git a/supplement/LICENSE b/supplement/LICENSE deleted file mode 100644 index f8b699e..0000000 --- a/supplement/LICENSE +++ /dev/null @@ -1,415 +0,0 @@ -The LaTeX Project Public License -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -LPPL Version 1.3c 2008-05-04 - -Copyright 1999 2002-2008 LaTeX3 Project - Everyone is allowed to distribute verbatim copies of this - license document, but modification of it is not allowed. - - -PREAMBLE -======== - -The LaTeX Project Public License (LPPL) is the primary license under -which the LaTeX kernel and the base LaTeX packages are distributed. - -You may use this license for any work of which you hold the copyright -and which you wish to distribute. This license may be particularly -suitable if your work is TeX-related (such as a LaTeX package), but -it is written in such a way that you can use it even if your work is -unrelated to TeX. - -The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE', -below, gives instructions, examples, and recommendations for authors -who are considering distributing their works under this license. - -This license gives conditions under which a work may be distributed -and modified, as well as conditions under which modified versions of -that work may be distributed. - -We, the LaTeX3 Project, believe that the conditions below give you -the freedom to make and distribute modified versions of your work -that conform with whatever technical specifications you wish while -maintaining the availability, integrity, and reliability of -that work. If you do not see how to achieve your goal while -meeting these conditions, then read the document `cfgguide.tex' -and `modguide.tex' in the base LaTeX distribution for suggestions. - - -DEFINITIONS -=========== - -In this license document the following terms are used: - - `Work' - Any work being distributed under this License. - - `Derived Work' - Any work that under any applicable law is derived from the Work. - - `Modification' - Any procedure that produces a Derived Work under any applicable - law -- for example, the production of a file containing an - original file associated with the Work or a significant portion of - such a file, either verbatim or with modifications and/or - translated into another language. - - `Modify' - To apply any procedure that produces a Derived Work under any - applicable law. - - `Distribution' - Making copies of the Work available from one person to another, in - whole or in part. Distribution includes (but is not limited to) - making any electronic components of the Work accessible by - file transfer protocols such as FTP or HTTP or by shared file - systems such as Sun's Network File System (NFS). - - `Compiled Work' - A version of the Work that has been processed into a form where it - is directly usable on a computer system. This processing may - include using installation facilities provided by the Work, - transformations of the Work, copying of components of the Work, or - other activities. Note that modification of any installation - facilities provided by the Work constitutes modification of the Work. - - `Current Maintainer' - A person or persons nominated as such within the Work. If there is - no such explicit nomination then it is the `Copyright Holder' under - any applicable law. - - `Base Interpreter' - A program or process that is normally needed for running or - interpreting a part or the whole of the Work. - - A Base Interpreter may depend on external components but these - are not considered part of the Base Interpreter provided that each - external component clearly identifies itself whenever it is used - interactively. Unless explicitly specified when applying the - license to the Work, the only applicable Base Interpreter is a - `LaTeX-Format' or in the case of files belonging to the - `LaTeX-format' a program implementing the `TeX language'. - - - -CONDITIONS ON DISTRIBUTION AND MODIFICATION -=========================================== - -1. Activities other than distribution and/or modification of the Work -are not covered by this license; they are outside its scope. In -particular, the act of running the Work is not restricted and no -requirements are made concerning any offers of support for the Work. - -2. You may distribute a complete, unmodified copy of the Work as you -received it. Distribution of only part of the Work is considered -modification of the Work, and no right to distribute such a Derived -Work may be assumed under the terms of this clause. - -3. You may distribute a Compiled Work that has been generated from a -complete, unmodified copy of the Work as distributed under Clause 2 -above, as long as that Compiled Work is distributed in such a way that -the recipients may install the Compiled Work on their system exactly -as it would have been installed if they generated a Compiled Work -directly from the Work. - -4. If you are the Current Maintainer of the Work, you may, without -restriction, modify the Work, thus creating a Derived Work. You may -also distribute the Derived Work without restriction, including -Compiled Works generated from the Derived Work. Derived Works -distributed in this manner by the Current Maintainer are considered to -be updated versions of the Work. - -5. If you are not the Current Maintainer of the Work, you may modify -your copy of the Work, thus creating a Derived Work based on the Work, -and compile this Derived Work, thus creating a Compiled Work based on -the Derived Work. - -6. If you are not the Current Maintainer of the Work, you may -distribute a Derived Work provided the following conditions are met -for every component of the Work unless that component clearly states -in the copyright notice that it is exempt from that condition. Only -the Current Maintainer is allowed to add such statements of exemption -to a component of the Work. - - a. If a component of this Derived Work can be a direct replacement - for a component of the Work when that component is used with the - Base Interpreter, then, wherever this component of the Work - identifies itself to the user when used interactively with that - Base Interpreter, the replacement component of this Derived Work - clearly and unambiguously identifies itself as a modified version - of this component to the user when used interactively with that - Base Interpreter. - - b. Every component of the Derived Work contains prominent notices - detailing the nature of the changes to that component, or a - prominent reference to another file that is distributed as part - of the Derived Work and that contains a complete and accurate log - of the changes. - - c. No information in the Derived Work implies that any persons, - including (but not limited to) the authors of the original version - of the Work, provide any support, including (but not limited to) - the reporting and handling of errors, to recipients of the - Derived Work unless those persons have stated explicitly that - they do provide such support for the Derived Work. - - d. You distribute at least one of the following with the Derived Work: - - 1. A complete, unmodified copy of the Work; - if your distribution of a modified component is made by - offering access to copy the modified component from a - designated place, then offering equivalent access to copy - the Work from the same or some similar place meets this - condition, even though third parties are not compelled to - copy the Work along with the modified component; - - 2. Information that is sufficient to obtain a complete, - unmodified copy of the Work. - -7. If you are not the Current Maintainer of the Work, you may -distribute a Compiled Work generated from a Derived Work, as long as -the Derived Work is distributed to all recipients of the Compiled -Work, and as long as the conditions of Clause 6, above, are met with -regard to the Derived Work. - -8. The conditions above are not intended to prohibit, and hence do not -apply to, the modification, by any method, of any component so that it -becomes identical to an updated version of that component of the Work as -it is distributed by the Current Maintainer under Clause 4, above. - -9. Distribution of the Work or any Derived Work in an alternative -format, where the Work or that Derived Work (in whole or in part) is -then produced by applying some process to that format, does not relax or -nullify any sections of this license as they pertain to the results of -applying that process. - -10. a. A Derived Work may be distributed under a different license - provided that license itself honors the conditions listed in - Clause 6 above, in regard to the Work, though it does not have - to honor the rest of the conditions in this license. - - b. If a Derived Work is distributed under a different license, that - Derived Work must provide sufficient documentation as part of - itself to allow each recipient of that Derived Work to honor the - restrictions in Clause 6 above, concerning changes from the Work. - -11. This license places no restrictions on works that are unrelated to -the Work, nor does this license place any restrictions on aggregating -such works with the Work by any means. - -12. Nothing in this license is intended to, or may be used to, prevent -complete compliance by all parties with all applicable laws. - - -NO WARRANTY -=========== - -There is no warranty for the Work. Except when otherwise stated in -writing, the Copyright Holder provides the Work `as is', without -warranty of any kind, either expressed or implied, including, but not -limited to, the implied warranties of merchantability and fitness for a -particular purpose. The entire risk as to the quality and performance -of the Work is with you. Should the Work prove defective, you assume -the cost of all necessary servicing, repair, or correction. - -In no event unless required by applicable law or agreed to in writing -will The Copyright Holder, or any author named in the components of the -Work, or any other party who may distribute and/or modify the Work as -permitted above, be liable to you for damages, including any general, -special, incidental or consequential damages arising out of any use of -the Work or out of inability to use the Work (including, but not limited -to, loss of data, data being rendered inaccurate, or losses sustained by -anyone as a result of any failure of the Work to operate with any other -programs), even if the Copyright Holder or said author or said other -party has been advised of the possibility of such damages. - - -MAINTENANCE OF THE WORK -======================= - -The Work has the status `author-maintained' if the Copyright Holder -explicitly and prominently states near the primary copyright notice in -the Work that the Work can only be maintained by the Copyright Holder -or simply that it is `author-maintained'. - -The Work has the status `maintained' if there is a Current Maintainer -who has indicated in the Work that they are willing to receive error -reports for the Work (for example, by supplying a valid e-mail -address). It is not required for the Current Maintainer to acknowledge -or act upon these error reports. - -The Work changes from status `maintained' to `unmaintained' if there -is no Current Maintainer, or the person stated to be Current -Maintainer of the work cannot be reached through the indicated means -of communication for a period of six months, and there are no other -significant signs of active maintenance. - -You can become the Current Maintainer of the Work by agreement with -any existing Current Maintainer to take over this role. - -If the Work is unmaintained, you can become the Current Maintainer of -the Work through the following steps: - - 1. Make a reasonable attempt to trace the Current Maintainer (and - the Copyright Holder, if the two differ) through the means of - an Internet or similar search. - - 2. If this search is successful, then enquire whether the Work - is still maintained. - - a. If it is being maintained, then ask the Current Maintainer - to update their communication data within one month. - - b. If the search is unsuccessful or no action to resume active - maintenance is taken by the Current Maintainer, then announce - within the pertinent community your intention to take over - maintenance. (If the Work is a LaTeX work, this could be - done, for example, by posting to comp.text.tex.) - - 3a. If the Current Maintainer is reachable and agrees to pass - maintenance of the Work to you, then this takes effect - immediately upon announcement. - - b. If the Current Maintainer is not reachable and the Copyright - Holder agrees that maintenance of the Work be passed to you, - then this takes effect immediately upon announcement. - - 4. If you make an `intention announcement' as described in 2b. above - and after three months your intention is challenged neither by - the Current Maintainer nor by the Copyright Holder nor by other - people, then you may arrange for the Work to be changed so as - to name you as the (new) Current Maintainer. - - 5. If the previously unreachable Current Maintainer becomes - reachable once more within three months of a change completed - under the terms of 3b) or 4), then that Current Maintainer must - become or remain the Current Maintainer upon request provided - they then update their communication data within one month. - -A change in the Current Maintainer does not, of itself, alter the fact -that the Work is distributed under the LPPL license. - -If you become the Current Maintainer of the Work, you should -immediately provide, within the Work, a prominent and unambiguous -statement of your status as Current Maintainer. You should also -announce your new status to the same pertinent community as -in 2b) above. - - -WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE -====================================================== - -This section contains important instructions, examples, and -recommendations for authors who are considering distributing their -works under this license. These authors are addressed as `you' in -this section. - -Choosing This License or Another License ----------------------------------------- - -If for any part of your work you want or need to use *distribution* -conditions that differ significantly from those in this license, then -do not refer to this license anywhere in your work but, instead, -distribute your work under a different license. You may use the text -of this license as a model for your own license, but your license -should not refer to the LPPL or otherwise give the impression that -your work is distributed under the LPPL. - -The document `modguide.tex' in the base LaTeX distribution explains -the motivation behind the conditions of this license. It explains, -for example, why distributing LaTeX under the GNU General Public -License (GPL) was considered inappropriate. Even if your work is -unrelated to LaTeX, the discussion in `modguide.tex' may still be -relevant, and authors intending to distribute their works under any -license are encouraged to read it. - -A Recommendation on Modification Without Distribution ------------------------------------------------------ - -It is wise never to modify a component of the Work, even for your own -personal use, without also meeting the above conditions for -distributing the modified component. While you might intend that such -modifications will never be distributed, often this will happen by -accident -- you may forget that you have modified that component; or -it may not occur to you when allowing others to access the modified -version that you are thus distributing it and violating the conditions -of this license in ways that could have legal implications and, worse, -cause problems for the community. It is therefore usually in your -best interest to keep your copy of the Work identical with the public -one. Many works provide ways to control the behavior of that work -without altering any of its licensed components. - -How to Use This License ------------------------ - -To use this license, place in each of the components of your work both -an explicit copyright notice including your name and the year the work -was authored and/or last substantially modified. Include also a -statement that the distribution and/or modification of that -component is constrained by the conditions in this license. - -Here is an example of such a notice and statement: - - %% pig.dtx - %% Copyright 2005 M. Y. Name - % - % This work may be distributed and/or modified under the - % conditions of the LaTeX Project Public License, either version 1.3 - % of this license or (at your option) any later version. - % The latest version of this license is in - % http://www.latex-project.org/lppl.txt - % and version 1.3 or later is part of all distributions of LaTeX - % version 2005/12/01 or later. - % - % This work has the LPPL maintenance status `maintained'. - % - % The Current Maintainer of this work is M. Y. Name. - % - % This work consists of the files pig.dtx and pig.ins - % and the derived file pig.sty. - -Given such a notice and statement in a file, the conditions -given in this license document would apply, with the `Work' referring -to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being -generated from `pig.dtx' using `pig.ins'), the `Base Interpreter' -referring to any `LaTeX-Format', and both `Copyright Holder' and -`Current Maintainer' referring to the person `M. Y. Name'. - -If you do not want the Maintenance section of LPPL to apply to your -Work, change `maintained' above into `author-maintained'. -However, we recommend that you use `maintained', as the Maintenance -section was added in order to ensure that your Work remains useful to -the community even when you can no longer maintain and support it -yourself. - -Derived Works That Are Not Replacements ---------------------------------------- - -Several clauses of the LPPL specify means to provide reliability and -stability for the user community. They therefore concern themselves -with the case that a Derived Work is intended to be used as a -(compatible or incompatible) replacement of the original Work. If -this is not the case (e.g., if a few lines of code are reused for a -completely different task), then clauses 6b and 6d shall not apply. - - -Important Recommendations -------------------------- - - Defining What Constitutes the Work - - The LPPL requires that distributions of the Work contain all the - files of the Work. It is therefore important that you provide a - way for the licensee to determine which files constitute the Work. - This could, for example, be achieved by explicitly listing all the - files of the Work near the copyright notice of each file or by - using a line such as: - - % This work consists of all files listed in manifest.txt. - - in that place. In the absence of an unequivocal list it might be - impossible for the licensee to determine what is considered by you - to comprise the Work and, in such a case, the licensee would be - entitled to make reasonable conjectures as to which files comprise - the Work. diff --git a/supplement/example.tex b/supplement/example.tex deleted file mode 100644 index 3684877..0000000 --- a/supplement/example.tex +++ /dev/null @@ -1,70 +0,0 @@ -\documentclass{article} -\usepackage{statrep} -\begin{document} - -This document is named \texttt{example.tex}. -It contains the complete \textit{Getting Started} -example from the \textit{StatRep User's Guide}. -You can generate the final PDF document \texttt{example.pdf} as follows: - -\begin{description} -\item[Generate the SAS program]\mbox{}\newline -Compile this document with \texttt{pdflatex}. -The \texttt{StatRep} package automatically generates a SAS program from -the document source. The program is named -\texttt{example\_SR.sas} and it is created in the current directory. - -\item[Capture the SAS outputs]\mbox{}\newline -Run the SAS program \texttt{example\_SR.sas}. -The SAS working directory must be the directory that contains this document. - -\item[Create the final PDF]\mbox{}\newline -Compile this document with \texttt{pdflatex} once more. The outputs that SAS generated -in the preceding step are now included in the final PDF \texttt{example.pdf}. -\end{description} - -The code in the \texttt{Datastep} environment is written -unchanged to the generated SAS program. - -\begin{Datastep} -proc format; - value $sex 'F' = 'Female' 'M' = 'Male'; -data one; - set sashelp.class; - format sex $sex.; -run; -\end{Datastep} - - The code in the \texttt{Sascode} environment is parsed before it is - written to the generated SAS program. For example, lines that begin with the string - \texttt{\%*;} are written to the SAS program and are not displayed in the - final document. The other lines in this example are written to the program - and are displayed in the final document. - - The first line of the following code block can be seen only - in the \LaTeX\ source file and in the generated SAS program. - The line insures that ODS Graphics are enabled. - -\begin{Sascode}[store=class] -%*; ods graphics on; -proc reg; - model weight = height age; -run; -\end{Sascode} - - The \texttt{Listing} and \texttt{Graphic} tags convey information to - \LaTeX\ and to SAS. The tags specify the names of the output files to - insert into the document and the captions for the output. - Additionally, they specify the names of the output files to create - and which ODS objects to capture. - -\Listing[store=class, - caption={Regression Analysis}]{rega} - -\Graphic[store=class, - caption={Graphs for Regression Analysis}]{regb} - -In this short example only the defaults are used. That is, all output -objects are selected and displayed. - -\end{document} \ No newline at end of file