LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (July 1998, week 2)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
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


Back to: Top of message | Previous page | Main SAS-L page