Prev: Command that runs at DOS prompt does not run when using X command
Next: Using PROC FCMP Functions with %SYSFUNC
From: Kevin Myers on 9 Mar 2010 12:39 Under SAS 9.2 I have several user defined functions that have been = compiled using PROC FCMP. These functions work fine when I use them in = data step code. However, when I attempt to use any of these functions = in a macro via %SYSFUNC, I get an error message that the function cannot = be found, e.g.: 116 data _null_; 117 118 n=3Dnchars("asdf "); 119 put n=3D; 120 121 c=3Dxsubstr("asdf ",-4,2); 122 put c=3D; 123 124 n=3Dxindexc("asdf ","sd",1,1,"","","",""); 125 put n=3D; 126 127 run; n=3D5 c=3Dsd n=3D2 NOTE: DATA statement used (Total process time): real time 0.15 seconds cpu time 0.15 seconds ? ERROR: The NCHARS function referenced in the %SYSFUNC or %QSYSFUNC macro = function is not found. 128 129 %put %sysfunc(nchars(asdf)); 130 %put %sysfunc(xsubstr(asdf,2,2)); ERROR: The XSUBSTR function referenced in the %SYSFUNC or %QSYSFUNC = macro function is not found. 131 %put %sysfunc(xindexc(asdf,sd,1,1,%str(),%str(),%str(),%str())); ERROR: The XINDEXC function referenced in the %SYSFUNC or %QSYSFUNC = macro function is not found. My nchars function is left over from V8 days, and is easily replaced = with the lengthc function in V9, but the other 2 functions (for which I = previously used SAS/Toolkit functions in V8) are not so easily replaced, = as there are still no equivalent built-in functions in V9.2, and I no = longer have access to SAS/Toolkit in 9.2. Shouldn't these functions work with %SYSFUNC? Is this a known bug? Any = fixes/workarounds/alternate suggestions? The proc fcmp code for these = functions is provided below. Thanks, s/KAM proc fcmp outlib=3DSASUtils.KAMUtils.V8Functions; function nChars(inStr $); return (lengthc(inStr)); endsub; function xSubstr(inStr $, aStart, length) $; if aStart<0 then start=3Dlengthc(inStr) + aStart + 1; else = start=3DaStart; if missing(length) then return (substrn(inStr,start)); else return (substrn(inStr,start,length)); endsub; function xIndexC(inStr $, search $, aStart, aValNo, aQuotes1 $, = aQuotes2 $, aParens1 $, aParens2 $); length start valNo 8 quotes1 quotes2 parens1 parens2 $256; length cInstr cQuotes1 cQuotes2 cParens1 cParens2 valNo2 8; length inChar $1 strTemp $256; length cTemp inc cPos quoteNo parenNo nParens 8; array parens[1] /NOSYMBOLS; start=3DaStart; valNo=3DaValNo; quotes1=3DaQuotes1; quotes2=3DaQuotes2; parens1=3DaParens1; = parens2=3DaParens2; cInstr=3Dlengthc(inStr); call dynamic_array(parens,cInstr); /* get start position and occurance arg values */ if missing(start) then start=3D1; else if start<0 then start=3DcInstr+ceil(start)+1; else start=3Dfloor(start); if missing(valNo) then valNo=3D1; else if valNo<0 then valNo=3Dceil(valNo); else valNo=3Dfloor(valNo); if start<=3DcInstr and valNo>=3D1 or start>=3D1 and valNo<=3D-1 then = do; /* adjust start position and determine increment */ if valNo>0 then do; inc=3D1; if start<1 then start=3D1; end; else do; inc=3D-1; if start>cInstr then start=3DcInstr; end; /* get optional quote and parenthesis arg values */ cQuotes1=3Dlengthn(quotes1); if lengthn(quotes2)=3D0 then quotes2=3Dquotes1; cQuotes2=3Dlengthn(quotes2); cParens1=3Dlengthn(parens1); cParens2=3Dlengthn(parens2); if inc<0 then do; /* if searching backwards swap quote and paren arg values */ strTemp=3Dquotes1; quotes1=3Dquotes2; quotes2=3DstrTemp; cTemp=3DcQuotes1; cQuotes1=3DcQuotes2; cQuotes2=3DcTemp; strTemp=3Dparens1; parens1=3Dparens2; parens2=3DstrTemp; cTemp=3DcParens1; cParens1=3DcParens2; cParens2=3DcTemp; end; valNo2=3Dabs(valNo); quoteNo=3D0; /* not yet in quoted string */ nParens=3D0; /* not yet in parentheses */ cPos=3Dstart; dPos=3D0; *put inStr=3D search=3D start=3D valNo=3D quotes1=3D quotes2=3D = parens1=3D parens2=3D; *put cInstr=3D inc=3D cQuotes1=3D cQuotes2=3D cParens1=3D = cParens2=3D; *put valNo2=3D quoteNo=3D nParens=3D; do while (cPos>=3D1 and cPos<=3DcInstr and not dPos); inChar=3Dsubstrn(inStr,cPos,1); *put / cPos=3D inChar=3D quoteNo=3D nParens=3D; if quoteNo then do; /* process quoted string */ /* if closing quote found signal non-quoted mode */ if quoteNo<=3DcQuotes2 and inChar=3Dsubstrn(quotes2,quoteNo) then = do; quoteNo=3D0; *put quoteNo=3D; end; end; /* if quoteNo */ else /* if not quoteNo */ do; /* not in quoted string */ /* if quote found then save closing quote */ /* which also signals quoted string mode */ if indexc(quotes1,inChar) then do; quoteNo=3Dindexc(quotes1,inChar); *put quoteNo=3D; end; /* if open parenthesis found then save closing paren */ /* in parens array and increment paren levels counter */ /* which also signals parenthesized string mode */ else if indexc(parens1,inChar) then do; nParens+1; parenNo=3Dindexc(parens1,inChar); parens[nParens]=3DparenNo; *put nParens=3D parenNo=3D; end; else if nParens then do; /* process parenthesized string */ /* if closing parenthesis found then decrement */ /* paren levels counter and set new closing paren */ if parenNo<=3DcParens2 and inChar=3Dsubstrn(parens2,parenNo,1) = then do; nParens+(-1); if nParens then parenNo=3Dparens[nParens]; *put nParens=3D parenNo=3D; end; end; /* else if nParens */ /* if search character found then set return value */ else if indexc(search,inChar) then do; valNo2+(-1); if valNo2<1 then dPos=3DcPos; *put valNo2=3D dPos=3D; end; end; /* if not quoteNo */ /* increment input character pointer */ cPos+inc; end; /* while (cPos>=3D1 and cPos<=3DcInstr and not dPos) */ if not dPos then do; dPos=3DcPos; *put dPos=3D; end; end; /* if start not past EOS */ else if start<1 then do; dPos=3D0; *put dPos=3D; end; else if start>lengthc(inStr) then do; dPos=3Dlengthc(inStr)+1; *put = dPos=3D; end; else do; dPos=3Dstart; *put dPos=3D; end; /* valNo=3D0 */ return (dPos); endsub; run; |