Validating Macro Parameters for Blind Users with Blind Quoting
In the macro language, a matching pair of double quotes (" ") are required for a macro variable to resolve. So if a user calls a macro and needs to pass in, for example, a path or filename, it is a sensible test to determine if the value is quoted and if so, with double quotes. It is especially important to program in this defensive way if your macro resides in a shared macro library and the end user is not savvy with their source code.
Consider the following simple example:
%macro testit(path=); data readin; infile "&path"; input; run; %mend testit;
With such parameters, it is feasible the user could call the macro in any of the following three styles:
%testit(path=D:Projects); %testit(path='D:Projects'); %testit(path="D:Projects");
Now let's introduce some defensive programming to allow any of these styles to be used, but allow the same results to be achieved without causing errors:
%macro quote_check(path=); %if %bquote(%substr(&path.,1,1))=%str(%') %then %do; %put NOTE: Found a single quote.; %end; %else %if %bquote(%substr(&path.,1,1))=%str(%") %then %do; %put NOTE: Found a double quote.; %end; %else %put NOTE: No quote mark found.; %mend quote_check;
%quote_check(path="path") %quote_check(path='path') %quote_check(path=path)
The check requires extracting the first character from the PATH parameter and comparing this text against single and double quotes.
This first character is extracted from the PATH parameter with the macro SUBSTR function. However, this is potentially text that will cause SAS syntax parsing to believe we have just opened a string. To prevent this we need to quote the text, i.e. take away its usual meaning in SAS language. The %BQUOTE function does exactly this when the macro is executing. Note that I have not used the %NRBQUOTE function, which would prevent a user's value from containing references to other macro variables from resolving.
On the other side of the comparison we face a similar challenge. However, we can be less aggressive with our quoting as the symbol will be hardcoded into our program. We can type a single or double quote in the macro language within a %STR( ) and prefix the symbol with a % sign. This prevents the SAS syntax parser from treating it as an open quote, therefore requiring a balancing quote to close the string. Hence the resulting %str(%') and %str(%").
In my example, I simply put a note message into the log indicating the result. When authoring a robust macro we should take action to replace the parameter value with the type of quoting required in your logic.