| Date: | Sun, 12 Jul 1998 23:20:04 -0700 |
| Reply-To: | Patricia Flickner <pflick@ACCESS1.NET> |
| Sender: | "SAS(r) Discussion" <SAS-L@UGA.CC.UGA.EDU> |
| From: | Patricia Flickner <pflick@ACCESS1.NET> |
| Subject: | Some macros you may find useful |
| Content-Type: | multipart/mixed; |
|---|
SAS-Lers:
I've developed some macros over the last several months that I've found
to be very useful and thought I'd share them since they've saved me so
much time. To briefly describe them, the first ones, centerl, centert
and underln are useful when you have to create reports and procs print
and report are just not enough, so you're forced to use data _null_.
The last, init, is to initialize variables quickly and easily. The
first three macros replace the hideous COBOL-like manual labor of
setting up the column locations to center a line, title and any
underlines. The init copies the ease of COBOLs initialization process.
If you couldn't tell, I was a COBOL programmer in a past life and have
no desire to be so again. Ever.
For the first three, set the &rptlen to the width of your report.
Otherwise, the report will default to 132.
We'll start with centerl, since this is the most useful and absolutely
wonderful in centering everything on a page. The only drawback is that
you have to pass it all the lengths of the variables in order, but
that's the only thing you have to figure out besides what you want to
see on a page.
%MACRO CENTERL(SCANLST);
%* /*
%* MACRO CENTERS A STRING OF VARIABLES ON A PAGE, REMOVING THE NECESSITY
%* OF FIGURING OUT THE COLUMN STARTS BASED ON MANUAL CALCULATIONS.
%* THIS IS ACTUALLY QUITE GOOD, AND WILL BLOW UP YOUR JOB IF THE
%* TOTAL VARIABLE LENGTHS PLUS ONE SPACE PER VARIABLE IS GREATER THAN
%* THE REPORT WIDTH MINUS TWO (ALLOWS FOR ONE SPACE ON EITHER SIDE OF
%* THE FIRST AND LAST VARIABLE). I PAT MYSELF ON THE BACK FOR A
%* WHOLE WEEK WHEN I DEVELOPED THIS ONE.
%* */;
RETAIN PI1 - PI30 0;
%LET TOT = 0;
%DO X = 1 %TO 30;
%LET SC&X = %SCAN(&SCANLST , &X , ' ');
%IF &&SC&X = %THEN %DO;
%LET X = 30;
%END;
%ELSE %DO;
%LET TOT = %EVAL(&TOT + &&SC&X );
%LET NBR = &X;
%END;
%END;
%LET L = %EVAL(&TOT + &NBR - 1);
%IF %SYMCHK(RPTLEN) = YES %THEN %LET MAXIMUM = &RPTLEN;
%ELSE %LET MAXIMUM = 132;
%* symchk can be found in the SAS Macro Reference, I believe page 132 in
the appendix. If you don't need it, get rid of it.;
%IF &L > &MAXIMUM %THEN %DO;
FILE SASLOG;
PUT '*======================================================*' /
'* *' /
'* ERROR -- TOTAL VAR LENGTHS GREATER THAN REPORT *' /
'* *' /
PUT '*======================================================*';
STOP SAS;
%END;
%ELSE %DO;
%*===============================================================;
%* GET THE NUMBER OF SPACES BETWEEN EACH VARIABLE (SP), THEN ;
%* CALCULATE THE STARTING POSITION OF EACH VARIABLE BY STARTING ;
%* THE FIRST AT THE SPACE CALCULATION, THEN, FOR EACH SUBSEQUENT ;
%* POSITION, ADD SPACE VALUE + LENGTH OF PREVIOUS VAR + POSITION ;
%* OF PREVIOUS VAR TO GET THE STARTING POSITION OF THE NEXT VAR ;
%*===============================================================;
%LET SP = %EVAL(((&MAXIMUM - 2) - &TOT ) / &NBR );
PI1 = &SP;
%DO X = 1 %TO &NBR;
%LET J = %EVAL(&X + 1);
%IF &X < &NBR %THEN %DO; PI&J = &SP + &&SC&X + PI&X; %END;
%END;
%*===============================================================;
%* NOW, DO PRETTY MUCH THE SAME THING TO GET THE MACRIVARS FOR ;
%* THE POSITION INTERVALS. ;
%*===============================================================;
%LET P1 = &SP;
%DO X = 1 %TO &NBR;
%LET J = %EVAL(&X + 1);
%LET P&J = %EVAL(&SP + &&SC&X + &&P&X );
%IF &J = &NBR %THEN %DO;
%LET J = %EVAL(&J + 1);
%LET P&J = %EVAL(&SP + &&SC&NBR + &&P&NBR );
%END;
%END;
%END;
%MEND CENTERL;
Basically, you would use it in this manner:
if _n_ = 1 then do;
%centerl(20 5 7 10 5 5 5 5 1);
end;
The variables that you create are retained, so this needs only be done
once. You would use position intervals 1 through 8 (I add a "1" to the
end of all my stuff, which would be PI9, so that, when I do the
underline (later), I can get the underline to line up perfectly without
having to figure out how many underscores to add) in the puts:
file saslist notitles header=hdr;
if linecnt > 54 then put _page_;
put @pi1 var1 @pi2 var2 ...etc.;
Centert simply centers a title on the page, whether the title be a
literal or a variable. It's your choice.
%MACRO CENTERT(TITLE);
%* /*
%* MACRO CENTERS A TITLE ON THE PAGE. YOU MAY USE EITHER THE TITLE
%* IN QUOTES, E.G., %CENTERT('TITLE 1'), OR A VARIABLE WHICH CONTAINS
%* THE TITLE, E.G., %CENTERT(TITLE1), SINCE THE LENGTH OF THE TITLE
%* VARIABLE WILL BE THE LENGTH OF THE TITLE YOU WISH TO USE. COOL,
%* HUH?
%* */;
%IF %SYMCHK(RPTLEN) = YES %THEN %LET MAXIMUM = &RPTLEN;
%ELSE %LET MAXIMUM = 132;
%LET LEN = %LENGTH(&TITLE);
%LET START = %EVAL((&MAXIMUM - &LEN ) / 2);
%* %IF &L > &MAXIMUM %THEN %DO;
PUT @&START &TITLE
%MEND CENTERT;
Quite simply, just say %centert('this is the title of your choice');
Underlin is neat and is to be used in concert with centerl, since
centerl sets the macrovars to the correct numbers. For some reason
which I haven't had much time to figure out, this macro won't allow you
to pass numeric variables but insists on the actual number, so you'll
see above in centerl that there's the statement %let p&x = %EVAL(&SP +
&&SC&NBR + &&P&NBR ); If you really want to use underlin without having
used centerl, you'll need to pass two numbers to underlin, the second
being greater than the first by 1 plus the value of &sp if you created
it.
%MACRO UNDERLN(START,FINISH);
%* /*
%* MACRO TO CALCULATE THE NUMBER OF UNDERSCORES TO PRINT. THIS ONE
%* IS PRETTY DECENT IN THAT IT ACTUALLY USES EITHER THE MACROVARIABLES
%* PRODUCED BY %CENTERL IF IT WAS USED, OR YOU CAN FEED IT REAL
%* NUMBERS.
%* */;
%IF &START > 1 %THEN %DO;
%IF %SYMCHK(SP) = NO %THEN %LET RAB = 0;
%ELSE %LET RAB = &SP;
%LET RAA = %EVAL((&FINISH - &START )+ 1);
%LET RAP = %EVAL(&RAA - &RAB );
%END;
%ELSE %LET RAP = &FINISH;
OVERPRINT @&START &RAP*'_'
%MEND UNDERLN;
Now, with the values set up with centerl (pi1-pi9 -- the last being the
dummy value), I would now user underlin as follows:
put @pi1 desc1 @pi2 desc2 ... etc... %underlin(&p1,&p9);
Notice that I use &p9 instead of &p8. Assuming that you've used the
centerl, &rap would be the value of (&p9 minus &p1 + 1) minus &sp (the
number of spaces between each variable on the page). So, if &p1 is 5
and &p9 is 125 and &sp is 5, the numeber of underscores that would be
printed would be, according to the calculation (125 - 5 + 1) - 5 would
be 119 starting at position 5.
Try them if you have to do all this stuff manually.
This last macro, I love. It's a little bit complicated, but the benefit
of not having to type in: var1=0; var2=0; var3=0;...var20=0; is such a
blessing that I had to make is flexible for multiple uses. So it now
can be used not only to initialize several numeric variables (the
default), but it can also set alphanumeric vars to spaces or whatever
you want. It can also simplify initializing same-name variables that
end in sequencial numbers: p1-p30. Dontcha love it?
%MACRO INIT(SCANLST,INIT,NBR,NAME);
%* /*
%* MACRO INITIALIZES UP TO 40 NUMERIC VARIABLES TO 0 EACH EXECUTION FOR
THE SCANLIST;
%* */;
%IF &INIT = %THEN %LET INIT = 0.;
%IF &SCANLST = %THEN %DO;
%DO X = 1 %TO &NBR;
&&NAME&X = &INIT;
%END;
%END;
%ELSE %DO; %* THIS PART'S FOR THE SCANLIST VARIABLES;
%DO X = 1 %TO 40;
%LET SC&X = %SCAN(&SCANLST , &X , ' ');
%IF &&SC&X = %THEN %LET X = 40;
%ELSE &&SC&X = &INIT;;
%END;
%END;
%MEND INIT;
To use:
%init(var1 var2 var3 var4...etc,0); This initializes all the vars in
scanlist to zero.
%init(var1 var2 var3 var4...etc,'a'); This initializes all the vars in
scanlist to 'a'.
%init(,0,50,p); This initializes vars p1-p50 to 0. Note the initial
comma. Without it, the macro will bomb. This last one is great
especially when you're setting up arrays. Please note that if you
really only need to initialize something once, put the %init in an
if-then do statement and retain the variables after using the %init.
This will save a lot of processing time if you have a lot of data.
Another thing, for those of you unfamiliar with automatic macros, you
can use these macros over and over again without copying them forever
into your code if you set up the followint statement:
OPTIONS MAUTOSOURCE SASAUTOS=(SASAUTOS,"your.data.set"); "Your data
set" can be mvs, unix or pc. Doesn't matter. If you copy these macros
into a dataset, you can set up that dataset as your automac dataset.
For unix people, it's very, very important that everything is
case-sensitive, as you know, which means that, if you want to refer to
these macros in lowercase, you must set the %macro and %mend statements
to lowercase as well, and save the macros as macroname.sas. If you just
cut and paste them, no big deal, just remember that the .SAS must be
uppercase as well as the macroname.
PDC, huh? (Pretty darned cool -- favorite expression with my kids, and
they look at me like the fungus is getting a bit thick around the ears.
Apparently, they're not geeks.)
Anyway, I have fun. If you have any questions, please feel free to
contact me. If I made any mistakes (the macros should be okay, cuz I
cut and pasted), feel free to tell me.
Thanks for your time and for putting up with this long e-mail.
Hope some of you find this helpful.
Pat Flickner
--
I used to have an open mind but my brains kept falling out.
[text/x-vcard]
begin: vcard
fn: Patricia Flickner
n: Flickner;Patricia
org: believe me, very little
email;internet: pflick@access1.net
title: Or Not... (Shakespear in Pittsburghese)
x-mozilla-cpt: ;0
x-mozilla-html: FALSE
version: 2.1
end: vcard
|