Dear Miss SAS Answers,
I run a lot of programs that call other programs with %include. I was wondering if there was a way, perhaps through a SAS Automatic Macro variable, to determine 1) whether a program was called or "included" from another program? And if so, what is the name of the calling program and the directory where it's stored?
Misplaced My Programs
p.s.I'm running SAS 9.1.3 on Windows XP.
If you had the platform for SAS Business Analytics or SAS Data Integration Studio installed, this would be much easier. Both SAS Managment Console and SAS Data Integration Studio have lineage components that allow you to trace the pieces that create a particular metadata object or to see all the pieces that use that metadata object down stream. Instead, I have a macro program solution for tracing all %INCLUDE statements in a particular directory.
What this macro code does is run through all the files in the directory looking for the "%include" token. When it finds that token, it writes out the directory path and the included program name to a SAS data set named work.IncludedFiles.
Let's walk through the code:
/* You can uncomment the following OPTIONS statement to see the macro code, the */
/* macro logic, and the macro variable resolved values displayed in the SAS log.*/
/* Several 'housekeeping' statements to declare local macro variables, upper */
/* case the value of &ext and open the directory */
%local fileref rc did dnum dmem memname didc dsdc dsid dir ext dirname;
/* If the directory does not exists, stop the macro from executing. */
%if &did=0 %then %do;
%put ERROR: Directory does not exist;
/* Otherwise, see if the work.IncludedFiles SAS data set exists. */
%let dsid = %sysfunc(open('work.includedfiles','I'));
/* If the data set does not exist, create it. */
%if dsid = 0 %then %do;
create table IncludedFiles
/* Find the number of entries in the directory for the subsequent DO loop. */
%do dmem=1 %to &dnum;
/* Read the first entry name, search for the last "word" with a period as the */
/* delimiter. */
/* If the last word is the same as the requested value of &ext, the look for */
/* the first "word" with a period as the delimiter, and write the DATA step */
/* to the input stack. */
%if %upcase(%scan(&memname,-1,.))=&ext %then %do;
%let member=%sysfunc(compress(member,' '));
/* DATA step creates a work data set by reading each line of code from the */
/* entry and checking for the word "%include. */
data &member&ext(keep=program calledfile);
length program $ 50 calledFile $ 50;
infile "&dir\&memname" truncover;
input @1 var $80.;
/* If %include is found, then write out the calling program (program) and the */
/* file included (CalledFile) to work.&member&ext. */
if lowcase(scan(var,1, " ")) = "%include" then do;
program = "&dir\&memname";
calledFile = scan(var,2, ' /"');
/* Append the just created file to the work.IncludedFiles data set. */
proc append base=IncludedFiles
/* Delete the file just created. */
proc datasets lib=work nolist;
/* Housekeeping to close the directory and clear the fileref. */
/* Sample call: value of dir parameter is c:\workshop\MissSASAnswers; */
/* value of ext parameter is sas. */
While this looks complicated if you aren't used to SAS macro code, it is very straightforward and fairly quick. The drawbacks are:
- You have to know the directory you want scanned.
- You have to call the macro multiple times if you have multiple directories or subdirectories to be scanned.
I hope this helps you trace your %INCLUDEd SAS code.
Miss SAS Answers