/* 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;