Below is the optsave/optload macro that I am currently using. I'm not sure the code is mine or borrowed.
It addresses the problem described in this discussion
Solved: Why does Proc OPTLOAD change the PAGESIZE to 55? - SAS Support Communities
by only reloading options that were changed.
I would like to figure a way that this macro can be called from a macro that has already called it and not overwrite the data sets from the level above.
unique data set names
macro1 %u_optstore(SAVE) change options macro2 %u_optstore(SAVE) change options %u_optsave(LOAD) macro2 mend change more options maybe. %u_optstore(LOAD); macro1 mend
Maybe create a unique global macro variable to save a unique call index. &SYSINDEX involved I think.
%macro u_isnull(macvar);
%if %symexist(&macvar.) %then %sysevalf(%superq(%superq(macvar)) =, boolean);
%else 1
%mend u_isnull;
%macro u_optstore(arg);
%put NOTE: &=SYSINDEX;
%if %qupcase(&arg) eq SAVE or %u_isnull(arg) %then %do;
proc optsave out=__optbase__;
run;
%end;
%else %do;
proc optsave out=__optcomp__;
run;
proc compare base=__optbase__ comp=__optcomp__ out=__optload__ outbase outnoequal noprint;
run;
proc optload data=__optload__;
run;
proc delete data=__optbase__ __optcomp__ __optload__;
run;
%end;
%mend u_optstore;
Sysindex may be problematic because of this: "You can use SYSINDEX in a program that uses macros when you need a unique number that changes after each macro invocation." (taken form documentation)
But maybe something like this:
%macro u_isnull(macvar);
%if %symexist(&macvar.) %then %sysevalf(%superq(%superq(macvar)) =, boolean);
%else 1
%mend u_isnull;
%macro u_optstore(arg,caller);
%put NOTE: &=SYSINDEX;
%if %qupcase(&arg) eq SAVE or %u_isnull(arg) %then %do;
proc optsave out=__optbase_&caller._;
run;
%end;
%else %do;
proc optsave out=__optcomp_&caller._;
run;
proc compare base=__optbase_&caller._ comp=__optcomp_&caller._ out=__optload_&caller._ outbase outnoequal noprint;
run;
proc optload data=__optload_&caller._;
run;
proc delete data=__optbase_&caller._ __optcomp_&caller._ __optload_&caller._;
run;
%end;
%mend u_optstore;
options mprint;
%macro macro2();
%put B;
%local caller;
%let caller=&sysmacroname.;
%u_optstore(SAVE,&caller.)
%put BB;
%u_optstore(LOAD,&caller.)
%put BBB;
%mend macro2;
%macro macro1();
%put A;
%local caller;
%let caller=&sysmacroname.;
%u_optstore(SAVE,&caller.)
%put AA;
%macro2()
%put AAA;
%u_optstore(LOAD,&caller.)
%put AAAA;
%mend macro1;
%macro1()
The only restriction is that &CALLER. cannot be "to long".
Bart
Sysindex may be problematic because of this: "You can use SYSINDEX in a program that uses macros when you need a unique number that changes after each macro invocation." (taken form documentation)
But maybe something like this:
%macro u_isnull(macvar);
%if %symexist(&macvar.) %then %sysevalf(%superq(%superq(macvar)) =, boolean);
%else 1
%mend u_isnull;
%macro u_optstore(arg,caller);
%put NOTE: &=SYSINDEX;
%if %qupcase(&arg) eq SAVE or %u_isnull(arg) %then %do;
proc optsave out=__optbase_&caller._;
run;
%end;
%else %do;
proc optsave out=__optcomp_&caller._;
run;
proc compare base=__optbase_&caller._ comp=__optcomp_&caller._ out=__optload_&caller._ outbase outnoequal noprint;
run;
proc optload data=__optload_&caller._;
run;
proc delete data=__optbase_&caller._ __optcomp_&caller._ __optload_&caller._;
run;
%end;
%mend u_optstore;
options mprint;
%macro macro2();
%put B;
%local caller;
%let caller=&sysmacroname.;
%u_optstore(SAVE,&caller.)
%put BB;
%u_optstore(LOAD,&caller.)
%put BBB;
%mend macro2;
%macro macro1();
%put A;
%local caller;
%let caller=&sysmacroname.;
%u_optstore(SAVE,&caller.)
%put AA;
%macro2()
%put AAA;
%u_optstore(LOAD,&caller.)
%put AAAA;
%mend macro1;
%macro1()
The only restriction is that &CALLER. cannot be "to long".
Bart
Hi @yabwon
Yes, this is good idea. You could use SAS Help Center: %SYSMEXECNAME Macro Function to retrieve the name of the calling macro. But I think all we need to know is the depth of the call SAS Help Center: %SYSMEXECDEPTH Macro Function and not have to worry about the length of the caller's name.
%macro u_isnull(macvar);
%if %symexist(&macvar.) %then %sysevalf(%superq(%superq(macvar)) =, boolean);
%else 1
%mend u_isnull;
%macro u_optstore(arg);
%put NOTE: %nrstr(%%)sysmexecdepth=%sysmexecdepth;
%put NOTE: &=depth;
%local /readonly depth=%sysmexecdepth;
%if %qupcase(&arg) eq SAVE or %u_isnull(arg) %then %do;
proc optsave out=__optbase_&depth.__;
run;
%end;
%else %do;
proc optsave out=__optcomp_&depth.__;
run;
proc compare base=__optbase_&depth.__ comp=__optcomp_&depth.__ out=__optload_&depth.__ outbase outnoequal noprint;
run;
proc print;
run;
proc optload data=__optload_&depth.__;
run;
proc delete data=__optbase_&depth.__ __optcomp_&depth.__ __optload_&depth.__;
run;
%end;
%mend u_optstore;
%put %nrstr(%%)sysmexecdepth=%sysmexecdepth;
%u_optstore(save)
%macro macro2();
%put %nrstr(%%)sysmexecdepth=%sysmexecdepth;
%put B;
%u_optstore(SAVE)
%put BB;
%u_optstore(LOAD)
%put BBB;
%mend macro2;
%macro macro1();
%put %nrstr(%%)sysmexecdepth=%sysmexecdepth;
%put A;
%u_optstore(SAVE)
%put AA;
%macro2()
%put AAA;
%u_optstore(LOAD)
%put AAAA;
%mend macro1;
%macro1()
%u_optstore(LOAD);
Yes, that's better idea!
With just a small modification:
%put NOTE: %nrstr(%%)sysmexecdepth=%sysmexecdepth;
%local / readonly depth=%sysmexecdepth;
%put NOTE: &=depth;
to avoid:
"WARNING: Apparent symbolic reference DEPTH not resolved."
Bart
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.