diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/statrep/sas/statrep_macros.sas |
Initial commit
Diffstat (limited to 'macros/latex/contrib/statrep/sas/statrep_macros.sas')
-rw-r--r-- | macros/latex/contrib/statrep/sas/statrep_macros.sas | 1523 |
1 files changed, 1523 insertions, 0 deletions
diff --git a/macros/latex/contrib/statrep/sas/statrep_macros.sas b/macros/latex/contrib/statrep/sas/statrep_macros.sas new file mode 100644 index 0000000000..3681c4b653 --- /dev/null +++ b/macros/latex/contrib/statrep/sas/statrep_macros.sas @@ -0,0 +1,1523 @@ + /*---------------------------------------------*/ + /* 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, "<ANOVA */ + /* FitStatistics>" 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 '<name' and 'name >' 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; + ods listing file="&listingdir/_tmp"; + %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 ; + %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; + end; + file x filevar=fn 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; + 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; +proc printto log="&listingdir/__tmp" 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; + +data _null_; + infile "&listingdir/__tmp" 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 "&listingdir/&__fname..lst" 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; + + |