Hello everyone. I have a macro which needs to take an input (file name), and another input (time).
So the macro and call could look like this (silly example).
%macro mymacro(fileinput=,timewait=);
data yay;
infile "&fileinput.";
input variable1;
run;
data _null_;
var1=sleep(&timewait.);
run;
%mend mymacro;
%mymacro;
%mymacro(c:\mydirectory\Filenamefilename(date1.csv, 1);
The problem is that SAS can't run this macro correctly because it recognizes the "(" in the first paramater as a ( function definition. How would one get around this problem? I want users to be able to put in any file name they want, but this one (and several others) cause problems at execution time.
The only thing i've been able to do so far is to make the first input a macro variable itself, and then to wrap it's call inside a %Bquote() function. Aka my "solution" is
%let var1=c:\mydirectory\Filenamefilename(date1.csv;
%mymacro(%bquote(&var1.), 1);
I don't consider this a solution really, does anyone have any idea of how to solve this problem without first having to define a macro var and using %Bquote()?
Thanks!
I would agree with all the previous posts here. I would question firstly why people are using brackets in a filename, not good practice. Secondly, I would avoid passing paths and what not into a macro at all. There are many ways to approach this problem. My initial thought is to ask then to assign a fileref *before* calling your macro. They can do this anyway they like, and means the checking (i.e. existence) is done on their end rather than in your macro. In your example there is no error checking for invalid parameter, missing file etc. Do you really want to accept responsibility for checking every possible permutation, considering its obvious that unbalanced brackets appears already? If you go with the fileref, then you only need to check that that has been created.
Another alternative, is to put your parameters in a dataset. You then have the full functionality of dataset operation, your macro could check the existence of the paramter dataset, then have a datastep which checks the contents, then generates the code from that.
I am sure your Functional Design Specification (following SLDC) would cover such things as how to get parameters in/out and what testing needs to be done within this library macro? If its not a library macro, why bother with the macro at all, just call execute the statements anyways.
Not entirely sure why the wait is there. This would indicate to me that you intend to pass an Excel file into the macro, open the DDE system and then read data in. My suggestion, don't. DDE is old, and my not be supported, plus only has functionality from years ago. There are better ways to get data into SAS.
You are needing those quotes at the filename. is it acceptable to instruct the users to code it with those quotes.
the syspbuff is the only way that gives you full control on what is coded by your users. The disadvantage is having a lot of work to be done.
SAS(R) 9.2 Macro Language: Reference
So the problem is that users have a file name with an unmatched parenthesis in it? Ugh. : )
I think Jaap is right that asking users to pass the filename in quotes should work. (As long as you don't have file names with quotes in them… )
If users of your macro are SAS programmers, then I would think fair to require them to understand macro quoting if they want to use your macro and are silly enough to name their files in such an odd way, so that they could come up with something like below, which should work (?):
%mymacro(fileinput=c:\mydirectory\Filenamefilename%str(%()date1.csv, timewait=1)
If your users are not SAS programmers, then hopefully they are passing the file name to some stored process (or whatever) as a macro variable, in which case your idea of using %BQUOTE or %SUPERQ should suffice.
There are really two problems here.
1) Is how to call the macro with the unbalanced value.
You could use macro quoting such as
%mymacro(%str(c:\mydirectory\Filenamefilename%(date1.csv), 1);
Or you could just use actual quotes such as
%mymacro('c:\mydirectory\Filenamefilename(date1.csv', 1);
2) How to deal with the value in the macro.
For physical filenames it is useful to use the QUOTE() function so you can properly handle filenames that might include double quote characters.
You can also use the DEQUOTE() function to remove outer quotes that user might have provided. Note that if the value is not quoted then DEQUOTE() does nothing.
infile %sysfunc(quote(%qsysfunc(dequote(&fileinput)))) ;
I would agree with all the previous posts here. I would question firstly why people are using brackets in a filename, not good practice. Secondly, I would avoid passing paths and what not into a macro at all. There are many ways to approach this problem. My initial thought is to ask then to assign a fileref *before* calling your macro. They can do this anyway they like, and means the checking (i.e. existence) is done on their end rather than in your macro. In your example there is no error checking for invalid parameter, missing file etc. Do you really want to accept responsibility for checking every possible permutation, considering its obvious that unbalanced brackets appears already? If you go with the fileref, then you only need to check that that has been created.
Another alternative, is to put your parameters in a dataset. You then have the full functionality of dataset operation, your macro could check the existence of the paramter dataset, then have a datastep which checks the contents, then generates the code from that.
I am sure your Functional Design Specification (following SLDC) would cover such things as how to get parameters in/out and what testing needs to be done within this library macro? If its not a library macro, why bother with the macro at all, just call execute the statements anyways.
Not entirely sure why the wait is there. This would indicate to me that you intend to pass an Excel file into the macro, open the DDE system and then read data in. My suggestion, don't. DDE is old, and my not be supported, plus only has functionality from years ago. There are better ways to get data into SAS.
Hey everyone. Your assumptions are correct, we have files with "(" in them. If you think that's bad, you should see some of the other file names..... If it can be put into a file name, it HAS been put into the files we receive.
Tom, your asnwer is exactly what I was looking for. I wasn't aware you could simply use the %str() function around the filename. I wil instruct that use in the explanation of the macro as it stands now.
RW9 I really like the idea of having the user assign a fileref BEFORE calling the macro. I honestly never even thought of that as a possibility, and I really really like it. I think I am going to try to re-write the macro and to use this route, so thank you!
Fyi: The wait is just there for demo purposes. I just wanted to put another paramater into the macro so people could try to call it to see what happens with the unbalanced "(" and I couldn't think of anything easier than a wait. I've actually never used DDE before. I NEVER EVER read in Excel files in any of my code. Honestly I feel like reading in data from Excel is a mistake (just my opinion).
Thanks for your help!
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.