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
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.