71%macro mp_derivedvarcheck(inds=,
78%local deny denycnt physcnt resv_list phys_list i w bad_deny denyrx w_ok;
80%mp_abort(iftrue= (%length(&inds)=0)
82 ,msg=%str(Please provide the definitions to check in inds)
84%mp_abort(iftrue= (%mf_existds(libds=&inds) ne 1)
86 ,msg=%str(Definitions not found: &inds)
94%let deny=DOSUBL|JAVAOBJ|JAVAMETA|SYMGET|SYMPUTX?|SYSGET|GETOPTION;
95%let deny=&deny.|PATHNAME|FILEEXIST|FOPEN|FREAD|FGET|FCLOSE;
96%let deny=&deny.|DOPEN|DREAD|DNUM|MOPEN|SLEEP;
97%let deny=&deny.|FILENAME|FDELETE|FCOPY|DCREATE|DLCREATE;
101%let denyrx=%str(/^[A-Z][A-Z0-9_]*$/);
102%let denycnt=%sysfunc(countw(&denyfuncs,%str( )));
103%
if "%upcase(&denyfuncs)" ne
"0" %then %
do i=1 %to &denycnt;
104 %let w=%upcase(%scan(&denyfuncs,&i,%str( )));
105 %let w_ok=%sysfunc(prxmatch(&denyrx,&w));
106 %
if &w_ok=0 %then %let bad_deny=1;
107 %
else %let deny=&deny.|&w;
109%mp_abort(iftrue= (&bad_deny=1)
111 ,msg=%str(denyfuncs must be a space separated list of
function names)
117%let physcnt=%sysfunc(countw(&physlist,%str( )));
118%
if %length(&physlist)>0 and
"%upcase(&physlist)" ne
"0"
119 %then %
do i=1 %to &physcnt;
120 %let w=%scan(&physlist,&i,%str( ));
121 %let phys_list=&phys_list.%str(,)%str(%
")%upcase(&w)%str(%");
123%
if %length(&phys_list)>0 %then %let phys_list=%substr(&phys_list,2);
127%
if "&reserved" ne
"0" %then %
do i=1 %to %sysfunc(countw(&reserved,%str( )));
128 %let w=%scan(&reserved,&i,%str( ));
129 %let resv_list=&resv_list.%str(,)%str(%
")%upcase(&w)%str(%");
131%
if %length(&resv_list)>0 %then %let resv_list=%substr(&resv_list,2);
133data &outds(keep=name reason);
135 length name $32 reason $200 l $4000;
136 call missing(reason);
137 name=upcase(strip(var_nm));
141 l=prxchange(
"s/'([^']|'')*'//",-1,var_logic);
142 l=prxchange(
's/\"([^\"]|\"\")*\"//',-1,l);
144 if name=
'' then reason=
'VAR_NM is required';
145 else if verify(strip(name),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_')>0
146 then reason=
'VAR_NM must be a valid SAS name';
147 else if verify(substr(name,1,1),
'0123456789')=0
148 then reason=
'VAR_NM must not start with a digit';
149 else if name in (
'_N_',
'_ERROR_',
'_IORC_')
150 then reason='VAR_NM is an automatic variable of the data step';
151 %if %length(&phys_list)>0 %then %do;
152 else if name in (%unquote(&phys_list))
153 then reason='VAR_NM collides with a column in the target table';
155 %if %length(&resv_list)>0 %then %do;
156 else if name in (%unquote(&resv_list))
157 then reason='VAR_NM is reserved';
159 else if upcase(strip(var_type)) not in ('C','N')
160 then reason='VAR_TYPE must be C or N';
161 else if missing(var_len) or var_len ne
int(var_len) or var_len<1
162 then reason='VAR_LEN must be a positive integer';
163 else if upcase(strip(var_type))='C' and var_len>32767
164 then reason='VAR_LEN exceeds 32767 for a character variable';
165 else if upcase(strip(var_type))='N' and var_len>8
166 then reason='VAR_LEN exceeds 8 for a numeric variable';
167 else if index(var_fmt,';')>0 or indexc(var_fmt,'&%')>0
168 or index(var_fmt,'')>0
169 then reason='VAR_FMT must be a format name, without ; & % or ';
170 else if verify(strip(upcase(var_fmt))
171 ,'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$.')>0
172 then reason='VAR_FMT must be a format name';
173 %if %mf_existvar(&inds,VAR_LABEL) gt 0 %then %do;
178 else if anycntrl(translate(var_label,' ','0D0A'x))>0
179 then reason='VAR_LABEL must be plain text - no control characters';
180 else if klength(var_label)>256
181 then reason='VAR_LABEL exceeds 256 characters';
183 else if missing(var_logic)
184 then reason='VAR_LOGIC is required';
185 else if klength(var_logic)>4000
186 then reason='VAR_LOGIC exceeds 4000 characters';
187 else if index(var_logic,';')>0
188 then reason='VAR_LOGIC must be a single expression - remove the ;';
189 else if indexc(var_logic,'&%')>0
190 then reason='VAR_LOGIC must not contain macro triggers';
191 else if index(var_logic,'')>0
192 then reason='VAR_LOGIC must not contain comments';
193 else if prxmatch("/\b(&deny)\s*\(/",upcase(l))>0
194 then reason='VAR_LOGIC may not call a function that submits code or'
195 ||' reaches the file system, the environment or the macro symbol table';
197 if missing(reason)=0 then output;
200%mend mp_derivedvarcheck;