/* Appendix 3 MFC Application Source Code Files */ /* ---- MFCAUDST ---- HOST DATA steps in this file */ /* have been set up for fixed length 80 byte records */ /* with the s=72and s2=72 options. If your source is */ /* different, adjust the INFILE, FILE, INPUT and PUT */ /* INFILE, FILE, INPUT and PUT statements as needed. */ %put NOTE: MFC PREEDIT has no errors.; /* copy the source, place value of full library location */ /* location and file name into &MFCSRLBF. */ data _null_; length dsn176 $176 temp54 $54; /* HOST See MFCGETNA code for MVS hosts */ /* regarding using jfcb= option or not. */ **infile &mfcsrref(&mfcchpgm) jfcb=dsn176; /* HOST */ infile &mfcsrref(&mfcchpgm) ; /* HOST */ file &mfcxtref notitles; /* HOST */ if _n_ eq 1 then do; **temp54=dsn176; /* HOST MVS */ temp54=symget('mfcsrlib'); /* HOST */ substr(temp54,45)=symget('mfcchpgm'); %include &mfcsrref(mfcgetna); /* HOST */ call symput('mfcsrlbf',temp54); end; /* make exact copy of DATA step source */ input; put _infile_; run; %put NOTE: MFC adding audit trail statements.; /* Update DATA step source to be compiled. In this */ /* DATA step, if your application source being compiled */ /* has a PUT command without a preceding file reference, */ /* that is, if you are writing to the SAS LOG, you will */ /* have to insert a file statement prior to your PUT. If */ /* you do not, your PUT will be to the file you've */ /* designated as the audit trail because it will now be */ /* the last one mentioned in the DATA step to that point. */ data _null_; length work $200 datapart $12 ; length mfcsrlbf $54 mfcrulib $44 time $16 mfcchpgm $8; retain mfcsrlbf mfcrulib time mfcchpgm; retain sq "'"; /* a single quote ' */ retain null b ' ' mfcqtya 0 ; retain no 'n' yes 'y'; if _n_ eq 1 then link start; infile &mfcxtref; /* HOST */ file &mfcsrref(&mfcchpgm) notitles; /* HOST */ /* read and write existing lines exactly */ input @1 line $char72.; /* HOST */ put @1 line $char72.; work=compress(upcase(line)); /* Try to capture kind of DATA step, so MFCCH variable is */ /* not added to user's output data sets. Assumes that DATA */ /* and _NULL_ are in same DATA statement line. */ if null eq b then do; datapart=left(upcase(line)); if datapart eq: 'DATA ' then do; datapart=left(substr(datapart,6)); if (datapart eq: '_NULL_ ') or (datapart eq: '_NULL_;') then null=yes; else null=no; end; end; /* find macro variable, insert statements */ if (index(work,'&MFCCOMPI; ') gt 0) and (null ne b) and (mfcqtya eq 0) then do; mfcqtya+1; set mfctrdat key=mfcchpgm; put ' /* start MFC audit trail */' ; if null eq no then put 'drop mfcch;' ; put 'if _n_ eq 1 then do;' ; put ' file &mfctrref;' ; /* HOST */ /* Code below could be simplified via use of the */ /* $QUOTEW. format if like. Audit trail will not print */ /* for the SOURCED choice if source is executed via */ /* %MFCDRIVR macro. */ put @2 'mfcch=symget(' @15 sq @16 'mfcch' @21 sq @22 ');' / @2 'if mfcch ne' @14 sq @15 'SOURCED' @22 sq @24 'then' / @2 'put / ' @10 sq @11 mfcsrlbf sq / @10 sq @11 'compiled at ' time sq; /* see MFCTRDAT source for logon value */ if logon eq: '*' then put @3 '/ ' @7 sq @8 'no source file data available' sq; else put @3 '/ ' @7 sq @8 'last mod by' @20 logon @29 modymd8 @39 modhhmm sq; put @3 '/ ' @7 sq @8 'stored pgm to SAS lib:' @31 mfcrulib sq '/;' / 'end;' / ' /* ends MFC audit trail */' ; end; return; /* first time through */ start: time=put(datetime(),datetime16.); mfcsrlbf=symget('mfcsrlbf'); mfcrulib=symget('mfcrulib'); mfcchpgm=symget('mfcchpgm'); return; run; /* ---- MFCCMPL ---- Model statements to replace DATA */ /* step source in application. Complete the = values. */ /* DATA step name MFC choice */ %mfcdrivr(mfcchpgm= ,mfcch= ); /* driver macro */ /* ---- MFCDRIVR ---- The macro to generate and execute */ /* code to perform the compile and run functions of the */ /* MFC. */ %macro mfcdrivr(mfcchpgm=,mfcch=); %let mfcchpgm=%upcase(&mfcchpgm); %let mfcch=%upcase(&mfcch); %let mfctype=%upcase(&mfctype); %let mfcerrn=00; %let mfcerrch=; %let nulvalu=; %if (&mfctype ne APPLICA) and (&mfctype ne INDCOMP) %then %do; /* End SAS for invalid &MFCTYPE */ %let mfcerrn=08; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ %end; %if &mfcch eq RUNCOMP %then %do; %if &mfctype eq APPLICA %then %do; %if &mfcredir eq &nulvalu %then %do; data pgm=&mfcruref..&mfcchpgm; run; %end; %else %do; data pgm=&mfcruref..&mfcchpgm; &mfcredir; run; %end; %end; %else %do; %let mfcerrn=02; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; /* ensure null value after each use */ %let mfcredir=; %end; /* RUNCOMP section */ %else %if &mfcch eq SOURCED %then %do; %if &mfctype eq APPLICA %then %do; %let mfccompi=; options source source2; %include &mfcsrref(&mfcchpgm); /* HOST */ options nosource2; %end; %else %do; %let mfcerrn=02; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; %end; /* SOURCED section */ /* Start CPENDIT CPSTORU processing. */ %else %if (&mfcch eq CPSTORU) or (&mfcch eq CPENDIT) %then %do; /* CPSTORY,CPENDIT choices are only valid when used in */ /* an application stream. */ %if &mfctype eq APPLICA %then %do; /* don't show source for MFCEDITS step in the */ /* SAS LOG */ options nosource nosource2; /* Bring in MFCEDITS to review source. At the end */ /* of MFCEDITS DATA step a SYMPUT routine is used */ /* to place a value into the &MFCNEXTS macvar as */ /* follows: */ /* call symput('mfcnexts', ARGUMENT ); */ /* The value of argument is either a blank or a */ /* %INCLUDE stmt for MFCREPT or MFCAUDST */ /* processing. The last line in the MFCEDITS file */ /* is &mfcnexts; a resolved value of blank */ /* returns processing to this section of the */ /* macro; a %INCLUDE brings in the next MFC file */ /* of code. The final MFC DATA step returns */ /* control to the macro. */ %include &mfcsrref(mfcedits); /* HOST */ /* Establish the values of the stored program */ /* libref and program name for the compile. */ %let mfccompi=/pgm=&mfcruref..&mfcchpgm; /* Leave a message in the SAS LOG. */ %put NOTE: MFC/SAS compiling &mfcchpgm.; /* Make all source visible in the SAS LOG for the */ /* upcoming compile. */ options source source2; /* Bring in DATA step source to compile. */ %include &mfcsrref(&mfcchpgm); /* HOST */ /* Save the value of the automatic MACVAR which */ /* contains the status of the compile attempt. */ %let mfcerrch=&syserr; /* Don't show source for MFC processing. */ options nosource nosource2; /* Assign error values for MFCREPT code. */ %if &mfcch eq CPENDIT %then %let mfcerrn=06; %else %let mfcerrn=07; /* HOST on &MFCERRCH=&SYSERR values. The compile */ /* was clean or had warnings. Run the stored pgm. */ /* If there was a compile warning, make mention */ /* by including the MFCREPT step. */ %if (&mfcerrch lt 5) %then %do; data pgm=&mfcruref..&mfcchpgm; run; %if &mfcerrch gt 3 %then %do; %include &mfcsrref(mfcrept); /* HOST */ %end; %end; /* The compile was bad. MFC code will run to */ /* restore the source to its original condition */ /* and a report will be produced. MFCREPT will */ /* end SAS. */ %else %if &mfcch eq CPENDIT %then %do; options nosource nosource2; %include &mfcsrref(mfcrstrs,mfcrept); /* HOST */ %end; /* Similar processing to CPENDIT above, but */ /* MFCREPTwill not end SAS. This section will run */ /* a prior compiled version of the source. */ %else %if &mfcch eq CPSTORU %then %do; options nosource nosource2; %include &mfcsrref(mfcrstrs,mfcrept); /* HOST */ options source; data pgm=&mfcruref..&mfcchpgm; run; %end; %end; /* CPSTORU, CPENDIT are not valid for INDCOMP. */ /* Assign values to MACVARS and bring in MFCREPT */ /* processing. */ %else %do; %let mfcerrn=02; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; %end; /* CPSTORU CPENDIT section */ %else %if &mfcch eq COMPILE %then %do; %if &mfctype eq INDCOMP %then %do; options nosource nosource2; %include &mfcsrref(mfcedits); /* HOST */ /* preedit must have no MFC errors to allow a */ /* compile attempt. MFCEDITS and MFCREPT end */ /* CPSTORU and CPENDIT */ %if &mfcerrn eq 00 %then %do; %let mfccompi=/pgm=&mfcruref..&mfcchpgm; options source source2; %include &mfcsrref(&mfcchpgm); /* HOST */ %let mfcerrch=&syserr; options nosource nosource2; %if &mfcerrch ge 5 %then %do; %let mfcerrn=05; %include &mfcsrref(mfcrstrs,mfcrept); /* HOST */ %end; %end; options source; %end; %else %do; %let mfcerrn=03; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; %end; /* end COMPILE section */ %else %if &mfcch eq PREEDIT %then %do; %if &mfctype eq INDCOMP %then %do; options nosource nosource2; %include &mfcsrref(mfcedits); /* HOST */ options source; %end; %else %do; %let mfcerrn=03; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; %end; /* end PREEDIT section */ /* MFCCH=INVALID function choice */ %else %do; %let mfcerrn=01; %let mfcerrch=bad choice; options nosource nosource2; %include &mfcsrref(mfcrept); /* HOST */ options source; %end; %mend mfcdrivr; /* ---- MFCEDITS ---- Edit source for &MFCCOMPI macro */ /* placement and other MFC rules. Ensure that the mfctrdat */ /* indexed data set can be accessed. */ /* HOST- This MFC DATA step has been set up for source */ /* files where the S=72 and S2=72 SAS options are used. If */ /* your source is different, adjust the $CHAR72. format to */ /* your requirements. MVS HOST Further, if you use */ /* line-numbered members in your source PDS, you will have */ /* to make sure the code below does not include them in */ /* the testing for blanks after finding the &MFCCOMPI */ /* macro variable via the INDEX statement and the RUN */ /* statement at the end of your DATA step. */ /* &MFCCOMPI placement is critical to auto insertion of */ /* audit trail statements. The other warnings are some */ /* items on which SAS compilation logic is silent. It */ /* would be duplicating SAS's effort to build in more */ /* 'hard' errors to prevent a compile from being */ /* attempted. */ data _null_; infile &mfcsrref(&mfcchpgm) end=eof; /* HOST */ file &mfctrref; /* HOST */ length work $200; length mfcchpgm $8 mfcch $7; retain mfcchpgm mfcch; retain qtycompi qtyfatal qtyerr qtydatst 0; retain dataon no 'n' yes 'y'; if _n_ eq 1 then do; /* MFCCHPGM is 8 character source file name */ mfcchpgm=symget('mfcchpgm'); put / @3 'Source preedit --------' @28 mfcchpgm @38 20*'-'; set mfctrdat key=mfcchpgm; if _iorc_ ne 0 then do; qtyfatal+1; put / 'ERROR, mfctrdat audit trail data has NO RECORD' ' for source file ' mfcchpgm '.' / 'This is a technical error. User will have' ' to figure out' / 'why all files in source library did not get to' ' the indexed data set.' / 'You may use if _iorc_ eq %sysrc( mnenomic ) method' ' here to get ' / 'failed i/o reason value. See Tech Report P-222' ' page 318. ' ; _error_+ -1; /* avoid dump for THIS ERROR */ end; mfcch=symget('mfcch'); end; input @1 line $char72. @1 prtline $char72.; /* HOST */ line=left(upcase(line)); work=compress(line); if (qtydatst eq 0) and (line eq: 'DATA ') then dataon=yes; if dataon eq yes then do; qtydatst+1; /* quantity data statement lines */ bytemfc=index(work,'&MFCCOMPI;'); if bytemfc gt 0 then do; qtycompi+1; /* warn if &vars are to left of &mfccompi */ if bytemfc gt 2 then if index(substr(work,1,bytemfc-1),'&') gt 0 then link ampermsg; if work ne: '&MFCCOMPI; ' then do; byte=bytemfc+10; link cheksemi; if work ne: ' ' then do; qtyerr+1; put / 'ERROR, &mfccompi; can have nothing to ' 'its right on the same line.' / 'Line=' prtline ; end; end; end; /* &MFCCOMPI found */ else if index(work,'&') gt 0 then link ampermsg; if substr(line,length(line),1) eq ';' then dataon=no; end; /* 1st DATA statement */ else do; if index(line,'&') gt 0 then link ampermsg; if (index(line,'SET ') gt 0) or (index(line,'MERGE ') gt 0) or (index(line,'MODIFY ') gt 0) or (index(line,'UPDATE ') gt 0) then put / 'Warning, when compiling a data step all ' 'input SAS data sets must' / ' be available.' / 'Line=' prtline ; if line eq 'DATA ' then put / 'Warning, you can compile only a single data step ' 'if the word data' / ' starts a second data step.' / 'Line=' prtline; end; /* not the 1st DATA statement */ if eof then do; if work ne: 'RUN; ' then do; qtyerr+1; put / 'ERROR, RUN; must be the only text in last' ' line of data step.' / 'Last line=' prtline; end; if qtydatst lt 1 then do; qtyerr+1; put / 'ERROR, could not find start of DATA statement.' ' Remember MFC rule' / ' about no text being to the left of the DATA' ' statement''s start.' ; end; if qtycompi eq 0 then put / 'ERROR, &mfccompi missing' ' from data statement.' ; if _error_ gt 0 then do; qtyfatal+1; put / 'MFCEDITS step has failed in processing data ' 'step source.' / 'Turn on source source2 options' ' to debug. Sorry.' / 'SAS _error_ value=' _error_ /; end; /* decide final action on edit results */ if (qtycompi eq 1) and (qtyfatal eq 0) and (qtyerr eq 0) then do; put / 'NO MFC errors.'; if mfcch eq 'PREEDIT' then call symput('mfcnexts',' '); else call symput('mfcnexts', '%include &mfcsrref(mfcaudst);'); /*HOST*/ end; else do; call symput('mfcerrn','04'); call symput('mfcerrch','bad edit'); call symput('mfcnexts', '%include &mfcsrref(mfcrept);'); /*HOST*/ end; if mfcch eq 'PREEDIT' then put 'MFC Function Choice: ' 'mfcch=PREEDIT'; put 25*'*' @28 mfcchpgm @37 'ended' @44 14*'*' /; stop; end; /* end of file logic */ return; ampermsg: put / 'Warning, if & is macro variable text in a data step ' 'it''s value will' / ' be CONSTANT in a stored program. Assess impact.' / 'Line=' prtline; return; /* remove semicolons, keep rest of line */ cheksemi: substr(work,byte)=translate(substr(work,byte),' ',';'); work=compress(substr(work,byte)); return; run; &mfcnexts; /* ---- MFCGETNA ---- HOST Formats a flat MVS external */ /* file, or partitioned library and (file/member) name */ /* into a consistently 'printable' variable. TEMP54 comes */ /* into this code with bytes: */ /* 1-44 full data set name */ /* 45-52 pds member file name (if not = HEX low values) */ /* 53-54 ignorable data */ /* TEMP54 is returned in print form. */ /* --------------------------------------- */ /* To use JFCB= option in INFILE statement for MVS HOST */ /* where DDNAME, DSN= JCL is used instead of filename and */ /* libname statments for source library and SAS library */ /* containing the stored pgms. */ /* Set $54 length for TEMP54 in mainline. To pick up full */ /* external file name, place a TEMP54=VAR statement after */ /* your INFILE statement with the JFCB=VAR option in the */ /* mainline. Then include this code in the general form: */ /* %include fileref(mfcgetna); */ if substr(temp54,45,1) eq '00'x then substr(temp54,45)=' '; else do; _8ch_=substr(temp54,45,8); substr(temp54,45,10)='( )'; substr(temp54,46,08)=_8ch_; temp54=compress(temp54); end; /* ---- MFCINIT ---- Executes initial processing for */ /* the MFC which is common to application streams and the */ /* optional independent compile job. */ %global mfcch mfcerrch mfcredir mfcsrlbf mfctrref mfcchpgm mfcerrn mfcrulib mfcsrlib mfctype mfccompi mfcnexts mfcruref mfcsrref mfcxtref ; %let mfctrref=AUDITCMP; /* HOST audit trail fileref */ filename &mfctrref sysout=*; /* HOST */ %let mfcxtref=TEMP80; /* HOST external work fileref */ filename &mfcxtref '&TEMP80' disp=new unit=sysda space=(trk,(5,1),rlse) recfm=fb lrecl=80 blksize=6160; %let mfcredir=; /* default value, optional redirect */ /* initial compile of macro */ %include &mfcsrref(mfcdrivr); /* HOST */ /* ---- MFCINITA ---- Executes initial processing to */ /* compile DATA steps in a stream. Gets source file data */ /* for audit trail statement creation and compiles the */ /* %MFCDRIVR macro. Any DATA step compiles in your stream */ /* using the MFC must follow the inclusion of this code. */ %let mfctype=APPLICA; /* required for application stream */ /* HOST values for MFCRUREF, MFCRULIB */ %let mfcruref=runpgms; /* SAS library libref */ %let mfcrulib=hilevel.sas.runpgms; /* HOST libr. location */ /* MVS HOST must read comments in MFCLIBNA */ * %include &mfcsrref(mfclibna); libname &mfcruref "&mfcrulib"; /* common initialization with independent compile job */ %include &mfcsrref(mfcinit); /* In a production environment, RUNCOMP is the only */ /* choice used. As there is no need to develop audit trail */ /* data, CPU can be saved by commenting out the include */ /* for MFCTRDAT processing. */ %include &mfcsrref(mfctrdat); /* HOST */ /* ---- MFCLIBNA ---- Get location/library names via */ /* jfcb= infile option for the source library and the SAS */ /* library containing the stored programs so MFCAUDST can */ /* insert audit trail statements with their names. In a */ /* production environment where only RUNCOMP is used, this */ /* code codedoes not have to be included. There are */ /* choices for development: */ /* NOT-MVS HOST--You will not need this code since you */ /* already assigned a value to &MFCSRLIB and &MFCRULIB. Do */ /* not %INCLUDE MFCLIBNA into MFCINITA, MFCINITC. */ /* MVS HOST--If you have added NO DDNAME JCL for the */ /* source library and the SAS library for stored programs, */ /* follow the NOT-MVS HOST instructions. If you have added */ /* DDNAME JCL for these two libraries, you can include */ /* MFCLIBNA to automatically assign values for &MFCSRLIB */ /* &MFCRULIB. You must delete these statements- */ /* In application stream initialization: */ /* %let mfcsrlib=.... */ /* filename &mfcsrref .... */ /* In MFCINITA code: */ /* %let mfcrulib=.... */ /* libname &mfcruref .... */ data _null_; /* mvs data set name in bytes 1-44 of dsn176 var. */ infile &mfcruref jfcb=dsn176; call symput('mfcrulib',substr(dsn176,1,44)); infile &mfcsrref(mfcdrivr) jfcb=dsn176a; call symput('mfcsrlib',substr(dsn176a,1,44)); run; /* ---- MFCREPT ---- Write messages, decide next */ /* actions, and determine the return code. (HOST for */ /* return code). The instructions which put the value of */ /* 'endsas' into the &mfcnexts macro variable are based on */ /* the function choices for &mfcch. If you add logic to */ /* this DATA step, the choice for the &mfcnexts value is */ /* yours. */ data _null_; file &mfctrref; /* HOST */ length mfcerrch $8 mfcerrn $2 mfcch $7 prtfnc $20 mfcsrlib $44; mfcchpgm=symget('mfcchpgm'); mfcsrlib=symget('mfcsrlib'); mfcerrch=symget('mfcerrch'); mfcerrn=symget('mfcerrn'); mfcch=symget('mfcch'); mfcruref=symget('mfcruref'); prtfnc=symget('mfcch'); %let mfcnexts=; put 'Source lib: ' mfcsrlib ' file: ' mfcchpgm / 'MFC Function Choice: ' mfcch= ; if (mfcerrn ge '01') and (mfcerrn le '03') then do; if mfcerrn eq '01' then put prtfnc 'is an invalid choice' ' for mfcch= .' / 'Choices are: SOURCED CPSTORU CPENDIT RUNCOMP PREEDIT ' 'COMPILE.'; else if mfcerrn eq '02' then put mfcch 'is an invalid ' 'choice for mfcch= in the independent compile job.' / 'PREEDIT and COMPILE are valid.'; else if mfcerrn eq '03' then put mfcch 'is an invalid' ' choice for mfcch= in an application stream.' / 'Valid choices are SOURCED CPSTORU CPENDIT RUNCOMP.'; put 'SAS will end.' /; call symput('mfcnexts','endsas'); abort return 8; /* HOST */ end; else if mfcerrn eq '04' then do; /* MFCEDITS has found hard preedit errors */ put mfcchpgm 'Data step source fails MFC ' 'PREEDIT compile rules.' / 'ERRORS M U S T ' 'be fixed prior to compiling.'; if (mfcch eq 'PREEDIT') or (mfcch eq 'COMPILE') then do; put 'SAS will NOT end as there may be other ' 'PREEDITS or COMPILEs.'; put /; end; else do; /* SAS ends on errors for CPSTORU CPENDIT */ call symput('mfcnexts','endsas'); /* HOST code 8 */ put 'forcing a return code of 8, SAS will end.' /; abort return 8; /* HOST */ end; end; /* simplify &syserr value for compile status */ if (length(mfcerrch) gt 1) or (mfcerrch eq: '8') then number=8; else if mfcerrch eq: '4' then number=4; if mfcerrn eq '05' then do; put 'Data step has not=0 return code from' ' SAS compile, value was ' mfcerrch '.' / 'SAS will not end. Additional files may ' 'need PREEDIT COMPILE choices.' /; end; else if mfcerrn eq '06' then do; put 'Data step has not=0 return code from' ' SAS compile, value was ' mfcerrch '.'; if number eq 4 then put 'CPENDIT will not end SAS for warnings.'/; else if number eq 8 then do; put 'mfcch=CPENDIT specifies that SAS will end.' /; call symput('mfcnexts','endsas'); abort return 8; /* HOST */ end; end; else if mfcerrn eq '07' then do; put 'Data step has not=0 return code from' ' SAS compile, value was ' mfcerrch '.'; if number eq 4 then put 'CPSTORU will not end SAS for warnings.'/; else if number eq 8 then do; put 'CPSTORU runs a prior-compiled ' mfcchpgm 'if it''s in ' mfcruref 'SAS library.' / ; end; end; else if mfcerrn eq '08' then do; mfctype=symget('mfctype'); put MFCTYPE= ' is an invalid value. Source lib file ' 'MFCINITA requires' / ' APPLICA and INDCOMP source lib' ' file MFCINITC requires INDCOMP. SAS will end.'; call symput('mfcnexts','endsas'); abort return 8; /* HOST */ end; run; &mfcnexts; /* ---- MFCRSTRS ---- Restore source from copy after */ /* bad compile to remove MFC added audit trail statements. */ /* HOST This DATA step has been setup for MVS source files */ /* where the s=72 and s2=72 SAS options are used for fixed */ /* length 80 byte source lines. If your source is */ /* different you may have to adjust the code for your */ /* needs. You may need other variable length record kinds */ /* of changes. */ %put NOTE: MFC is restoring &mfcsrref &mfcchpgm.; data _null_; infile &mfcxtref; /* HOST */ file &mfcsrref(&mfcchpgm) notitles; /* HOST */ input; put _infile_; /* HOST */ run; /* ---- MFCTRDAT ---- Create mfctrdat indexed data set */ /* containing information about files in the source */ /* library. */ %put NOTE: MFC creating audit trail data.; /* HOST You will have to create a workaround for the PROC */ /* SOURCE below to create the &MFCXTREF external file for */ /* non MVS hosts. You should try to modify the DATA step */ /* which produces the MFCTRDAT data set to read the source */ /* library directory in a more direct manner. */ /* make external file of directory data */ proc source indd=&mfcsrref dirdd=&mfcxtref nodata noprint null nosummary; /* Make MFCTRDAT indexed SAS data set by source file */ /* member name. The DATA step below is run from source. It */ /* took more cpu cycles to execute a compiled version */ /* followed by a PROC DATASETS to create the index, versus */ /* running the DATA step from source and creating the */ /* index at the same time. SAS does not allow a stored */ /* program to create an index. */ data mfctrdat (keep= mfcchpgm dtchange modymd8 modhhmm logon index=(mfcchpgm=(mfcchpgm)/unique)); length b8 modymd8 $8 modhhmm $5; infile &mfcxtref; /* HOST */ /* HOST layout of directory data will be different */ input @1 mfcchpgm $char08. @22 dtchange ?? pd3. @25 hour ?? pk1. @26 min ?? pk1. @33 logon $char08.; /* MVS if logon is blank, file has no data */ if logon ne b8 then do; dtchange=datejul(dtchange); modymd8=put(dtchange,yymmdd8.); modhhmm=' : '; substr(modhhmm,1,2)=put(hour,z2.); substr(modhhmm,4)=put(min,z2.); modymd8=translate(modymd8,'/','-'); end; else logon='*nostats'; return; run; /* Sample DATA Steps */ /* ---- MFCSAMP1 ---- no error no warn source */ data _null_ &mfccompi; do x=1 to 3; put 'MFCSAMP1 TEST COMPILE'; end; run; /* ---- MFCSAMP2 ---- source with errors and warns */ *test; data a &mfccompi; /* test comment */ /* array forces compile error for testing */ array testay (4) var1 var2 var3; set intosamp; if &macvar ne: 'TESTIT' then do x=1 to dim(testay); if testay(x) lt 0 then output; end; delete; run;