I'm trying to make a simple macro that checks whether a specific macro variable is either missing or does not exist. Normally, this would require two statements: a %symexist, and if it does exist, additional logic to detect whether it's a null value. The below code combines all of that into one.
%macro isnull(macvar);
%sysevalf(%superq(%superq(macvar)) NE %str(), boolean);
%mend isnull;
Problem
I cannot use %isNull() in a %if statement, because the returned value always seems to be a character. This behavior differs if it's in open code or within a macro itself.
What I've tried
I've narrowed it down to the macro not resolving as a numeric value. I've tried everything from enclosing it with %sysfunc(putn()) to %cmpres() to %sysfunc(compress()). If it's in open code, it is numeric. If it's in another macro, it's character. You can see it with this code:
/* Miss2 resolves incorrectly as character */
%macro check;
%let miss1=%sysevalf(%superq(asdf) =, boolean);
%let miss2=%isNull(asdf);
%put Miss1: %datatyp(&miss1);
%put Miss2: %datatyp(&miss2);
%mend;
%check;
/* Miss2 resolves correctly as numeric */
%let miss1=%sysevalf(%superq(asdf) =, boolean);
%let miss2=%isNull(asdf);
%put Miss1: %datatyp(&miss1);
%put Miss2: %datatyp(&miss2);
Want
I want to be able to use this in a %if statement to check whether a macro both exists and is not blank simultaneously.
%macro foo;
%if(%isNull(sysuserid) = 1) %then %put sysuserid exists;
%if(%isNull(asdffdsa) = 0) %then %put asdffdsa does not exist;
%if(%isNull(sysuserid) > 0) %then %put this should resolve;
%if(%isNull(asdffdsa) > 0) %then %put this should not resolve;
%mend;
%foo;
The problem you have here is that your macro has a semicolon in it. See this:
174 %macro check;
175 %let miss1=%sysevalf(%superq(asdf) NE %str(), boolean);
176 %let miss2=%missm(asdf);
177
178 %put &miss1. Miss1: %datatyp(&miss1);
179 %put &miss2. Miss2: %datatyp(%unquote(&miss2));
180 %mend;
181 %check;
WARNING: Apparent symbolic reference ASDF not resolved.
WARNING: Apparent symbolic reference ASDF not resolved.
0 Miss1: NUMERIC
0; Miss2: CHAR
Note the ;? Compile this instead:
%macro missm(macvar);
%sysevalf(%superq(%superq(macvar)) NE %str(), boolean)
%mend missm;
and you get:
185 %macro check;
186 %let miss1=%sysevalf(%superq(asdf) NE %str(), boolean);
187 %let miss2=%missm(asdf);
188
189 %put &miss1. Miss1: %datatyp(&miss1);
190 %put &miss2. Miss2: %datatyp(%unquote(&miss2));
191 %mend;
192 %check;
WARNING: Apparent symbolic reference ASDF not resolved.
WARNING: Apparent symbolic reference ASDF not resolved.
0 Miss1: NUMERIC
0 Miss2: NUMERIC
I'll also add that I think you should not skip the %symexist. You get a warning in the log the way you're doing it here, that's easily avoided.
%macro missm(macvar);
%if %symexist(&macvar.) %then
%sysevalf(%superq(%superq(macvar)) NE , boolean)
%else
0
%mend missm;
You'll also note I remove your unnecessary %str() which doesn't really do anything. See Chang Chung's seminal paper, Is This Macro Parameter Blank, for why (and for some more great information, if you haven't already read it).
Finally - I think I would suggest renaming your macro and/or reversing the direction. %if %missm says to me 'if this macro variable is missing', which is the opposite of what you're telling: TRUE is returned if it is NOT missing. %missm should return true for EQ [blank], or NOT %symexist; it should return false for [defined and contains a value].
Related
Note: code edited after remarks from #user667489 but issues remain.
I built a fairly simple macro to return the intersection of 2 space separated lists as a new space separated list but for some reason the definition of the macro returns errors.
The macro loops through both lists and keep an element if a match is found (very straightforward, no handling of duplicates or optimization).
I cannot make sense of the log, which shows a combination of following error messages:
ERROR: Macro keyword LET appears as text.
ERROR: Macro keyword MACRO appears as text.
%macro list_intersection
(list1= /* space separated list, or unique term */
,list2= /* space separated list, or unique term */
);
%local output;
%local i;
%local j;
%let i = 1;
%let j = 1;
%do %while (%length(%scan(&list1,&i)));
%do %while (%length(%scan(&list2,&j)));
%if (%scan(&list1,&i) = %scan(&list2,&j)) %then
%let output = &output %scan(&list1,&i);
%let j = %eval(&j+1);
%end;
%let i = %eval(&i+1);
%end;
&output
%mend;
Can you help me circling the issue ?
I'm also open to a more efficient/robust/simple way of achieving the same output.
Reproducible log
Using SAS 9.3, I put above code in a separate program for it not to be polluted, save project, close and reopen. Open program, click run button, and here is the complete log:
1 The SAS System 09:50 Monday, January 22, 2018
1 ;*';*";*/;quit;run;
2 OPTIONS PAGENO=MIN;
3 %LET _CLIENTTASKLABEL='Program3';
ERROR: Macro keyword LET appears as text.
4 %LET _CLIENTPROJECTPATH='F:\CI\Projects\Wealth Indicators\106 Explore DIM_PHYSICALPERSON\SAS\Rework_table_auto2.egp';
ERROR: Macro keyword LET appears as text.
5 %LET _CLIENTPROJECTNAME='Rework_table_auto2.egp';
ERROR: Macro keyword LET appears as text.
6 %LET _SASPROGRAMFILE=;
ERROR: Macro keyword LET appears as text.
7
8 ODS _ALL_ CLOSE;
9 OPTIONS DEV=ACTIVEX;
10 GOPTIONS XPIXELS=0 YPIXELS=0;
11 FILENAME EGSR TEMP;
12 ODS tagsets.sasreport13(ID=EGSR) FILE=EGSR STYLE=HtmlBlue
12 ! STYLESHEET=(URL="file:///C:/Program%20Files/SASHome/x86/SASEnterpriseGuide/5.1/Styles/HtmlBlue.css") NOGTITLE NOGFOOTNOTE
12 ! GPATH=&sasworklocation ENCODING=UTF8 options(rolap="on");
13
14 GOPTIONS ACCESSIBLE;
15 %macro list_intersection
ERROR: Macro keyword MACRO appears as text.
16 (list1= /* space separated list, or unique term */
17 ,list2= /* space separated list, or unique term */
18 );
19 %local output;
ERROR: Macro keyword LOCAL appears as text.
20 %local i;
ERROR: Macro keyword LOCAL appears as text.
21 %local j;
ERROR: Macro keyword LOCAL appears as text.
22 %let i = 1;
ERROR: Macro keyword LET appears as text.
23 %let j = 1;
ERROR: Macro keyword LET appears as text.
24 %do %while (%length(%scan(&list1,&i)));
ERROR: Macro keyword DO appears as text.
25 %do %while (%length(%scan(&list2,&j)));
ERROR: Macro keyword DO appears as text.
26 %if (%scan(&list1,&i) = %scan(&list2,&j)) %then
ERROR: Macro keyword IF appears as text.
27 %let output = &output %scan(&list1,&i);
28 %let j = %eval(&j+1);
ERROR: Macro keyword LET appears as text.
29 %end;
ERROR: Macro keyword END appears as text.
30 %let i = %eval(&i+1);
ERROR: Macro keyword LET appears as text.
31 %end;
ERROR: Macro keyword END appears as text.
32 &output
33 %mend;
ERROR: Macro keyword MEND appears as text.
34
35 GOPTIONS NOACCESSIBLE;
36 %LET _CLIENTTASKLABEL=;
ERROR: Macro keyword LET appears as text.
37 %LET _CLIENTPROJECTPATH=;
2 The SAS System 09:50 Monday, January 22, 2018
ERROR: Macro keyword LET appears as text.
38 %LET _CLIENTPROJECTNAME=;
ERROR: Macro keyword LET appears as text.
39 %LET _SASPROGRAMFILE=;
ERROR: Macro keyword LET appears as text.
40
41 ;*';*";*/;quit;run;
42 ODS _ALL_ CLOSE;
43
44
45 QUIT; RUN;
46
Initial code before edit:
%macro list_intersection
(list1= /* space separated list, or unique term */
,list2= /* space separated list, or unique term */
);
%local output =;
%local i = 1;
%local j = 1;
%do %while (%length(%scan(&list1,&i)));
%do %while (%length(%scan(&list2,&j)));
%if (%scan(&list1,&i) = %scan(&list2,&j) %then
%local output = &output %scan(&list1,&i);
%let j = %eval(&j+1);
%end;
%let i = %eval(&i+1);
%end;
&output
%mend;
A few things immediately stand out:
You cannot use %local to set a value for a macro variable. Instead of %local i=1; you must write two separate statements: %local i; %let i = 1;. %local initialises macro variables to an empty string.
You have unbalanced brackets in your %if statement.
Try moving %let j = %eval(&j+1); into the outer %do %while loop.
Also, you probably want to make sure that %scan only uses space as a delimiter - it defaults to space plus . < ( + & ! $ * ) ; ^ - / , % |
Here's a working version:
%macro list_intersection
(list1= /* space separated list, or unique term */
,list2= /* space separated list, or unique term */
);
%local output;
%local i;
%local j;
%let i = 1;
%do %while (%length(%scan(&list1,&i,%str( ))));
%let j = 1;
%do %while (%length(%scan(&list2,&j,%str( ))));
%if %scan(&list1,&i,%str( )) = %scan(&list2,&j,%str( )) %then
%let output = &output %scan(&list1,&i,%str( ));
%let j = %eval(&j+1);
%end;
%let i = %eval(&i+1);
%end;
&output
%mend;
%put %list_intersection(list1=1 2 3,list2=2 3 4);
You can use SAS functions to make that much easier. Use the COUNTW() function to find the upper bound for the %DO loop. Use the FINDW() function to test if word is found in the other list.
%macro list_intersection
(list1 /* space separated list of terms */
,list2 /* space separated list of terms */
);
%local output i next ;
%do i=1 %to %sysfunc(countw(&list1,%str( ))) ;
%let next=%scan(&list1,&i,%str( ));
%if %sysfunc(findw(&list2,&next,,s)) %then %let output=&output &next ;
%end;
&output
%mend;
You could include the i modifier in the findw() call to make it case insensitive. You could also test if the word is already in the output string to eliminate duplicates.
%macro list_intersection_nodups
(list1 /* space separated list of terms */
,list2 /* space separated list of terms */
);
%local output i next ;
%do i=1 %to %sysfunc(countw(&list1,%str( ))) ;
%let next=%scan(&list1,&i,%str( ));
%if %sysfunc(findw(&list2,&next,,si)) and not %sysfunc(findw(&output,&next,,si))
%then %let output=&output &next ;
%end;
&output
%mend;
Example:
274 %put %list_intersection_nodups(A B a C,a c d);
A C
/* Here is the code that is having an issue*/
%macro numstats(var = ,file=, format=);
%let dsid=open(&file.,i);
%if %LENGTH(&var.) > 8 AND %VARTYPE(&dsid.,%VARNUM(&dsid.,&var.))='N' %then %do;
Proc SQL;
SQL code
quit;
end;
%mend numstats;
I am having the following error when running this code: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required.
I have played with this code extensively to try different online solutions and cannot figure out why I am still receiving this issue. Please help!
Side Note: The reason I had to add this IF statement is to try to find out whether the variable was a date variable. All my date variables are Date9. so if it is Numeric and has a length greater than 8, then I want to add date formatting that I would not add to regular numeric variables. If anyone can think of an easier way to do that, then i am open to that as well, but please help me figure out this error!
If you want to call data step functions within macro code then you need to call them with the %SYSFUNC() macro function. Here is an example of a macro function that will do that for you.
%macro varinfo
/*----------------------------------------------------------------------
Retrieve attribute of a specified variable.
----------------------------------------------------------------------*/
(ds /* Data set name */
,var /* Variable name */
,info /* information attribute to return - Default is NUM */
);
/*----------------------------------------------------------------------
Example values for INFO parameter:
NUM = variable number
LEN = length of variable
FMT = format of variable
INFMT = informat of variable
LABEL = label of variable
TYPE = type of variable (N for numeric, C for character)
------------------------------------------------------------------------
Usage Examples:
%if %varinfo(&data,NAME)
%then %put input data set contains variable NAME;
%put Variable &column in &data has type %varinfo(&data,&column,type);
------------------------------------------------------------------------
Notes:
The macro call resolves to 0 when either the data set does not exist
or the variable is not in the specified data set.
Invalid values for the INFO parameter generate a SAS ERROR message.
----------------------------------------------------------------------*/
%local dsid rc varnum;
%let dsid = %sysfunc(open(&ds));
%if (&dsid) %then %do;
%let varnum = %sysfunc(varnum(&dsid,&var));
%if (&varnum) & %length(&info) %then
%sysfunc(var&info(&dsid,&varnum))
;
%else
&varnum
;
%let rc = %sysfunc(close(&dsid));
%end;
%else 0;
%mend varinfo;
Using this your macro might become something like this:
%macro numstats(var = ,file=, format=);
%if %varinfo(&file,&var,type)=N and
DATE = %sysfunc(substrn(%varinfo(&file,&var,fmt),1,4))
%then %do;
* do something ;
%end;
%mend numstats;
I'm trying to do a date comparison but I'm not getting the correct results. Does anyone know what's going on?
%macro ttt;
%let check_start = 28APR2014;
%if "&check_start."d < "25may2014"d %then %let true = 1;
%else %if "&check_start."d > "25may2014"d %then %let true = 2;
%put &true;
%mend;
%ttt;
14 %macro ttt;
15 %let check_start = 28APR2010;
16 %if "&check_start."d < "25may2014"d %then %let true = 1;
17 %else %if "&check_start."d > "25may2014"d %then %let true = 2;
18 %put &true;
19 %mend;
20 %ttt;
true = 2
Macro-variable true should equal 1
You need to use %sysevalf() to evaluate the comparison in this case. The following works.
%macro ttt;
%let check_start = 28APR2015;
%if %sysevalf("&check_start"d < '25may2014'd) %then %let true=1;
%else %if %sysevalf("&check_start."d > '25may2014'd) %then %let true=2;
%put &true.;
%mend;
%ttt;
Reeza has provided a good solution but I thought I'd add a few suggestions as well.
The problem you are having is the reason I recommend never using date literals when working in the macro language. Instead, of date literals (i.e. "01jan2000"d) I recommend using macro variables that contain date values (i.e. %let start_of_21st_century = %sysfunc(mdy(1,1,2000)); ). By using macro variables, not only do you avoid your above issue, but you also get the benefit of being able to self-document your code.
Currently I have no idea what significance the 25th May 2014 has in your code, but if you had this line:
%let product_launch_date = %sysfunc(mdy(5,25,2014));
... then it would be clear to anyone reading it what the significance is.
Your code would then become:
%macro ttt;
%local check_start compare_date;
%let check_start = %sysfunc(mdy(4,28,2014));
%let compare_date = %sysfunc(mdy(5,25,2014));
%if &check_start < &compare_date %then %let true = 1;
%else %if &check_start > &compare_date %then %let true = 2;
%put &true;
%mend;
There's still a few more things I'd consider changing. One thing I noticed is that if the 2 date values are equal, than true will not be assigned a value. So that should probably be remedied.
Also, in SAS, the typical concept of true/false is typically represented as follows:
A value of zero represents FALSE
Any non-zero number (including negatives) represents TRUE
So having a macro variable named true with either a value of 1 or 2 (both values would normally represent a value of true) may be confusing to some. I'd consider either renaming the macro variable, or using values of 0, and 1 (or other non-zero number).
Incorporating all of this, the macro would become something like:
%macro check_dates;
%local check_start compare_date;
%let check_start = %sysfunc(mdy(4,28,2014));
%let compare_date = %sysfunc(mdy(5,25,2014));
%let check_start_compared_higher = &check_start > &compare_date;
%if &check_start_compared_higher %then %do;
%put It was higher =) ;
%end;
%else %do;
%put It was equal to or lower =( ;
%end;
%mend;
%check_dates;
A few comments on the final macro... The macro variable named true has been replaced with a more descriptive variable named check_start_compared_higher. Because we just need a boolean value stored in it, we can simply assigning it the result of evaluating the expression &check_start > &compare_date which will return either a 0 (if false) or a 1 (if true). This is easier to read than using %if...%else... statements to do an assignment, as it is immediately clear that the line of code is simply performing an assignment and nothing more.
The line %if &check_start_compared_higher %then %do; shows how we can use the newly saved value to control program flow. Because the value in &check_start_compared_higher resolves to either TRUE or FALSE we can easily use it this way to make easy-to-read if-statements.
Having an issue when trying to get macro variables to resolve inside a macro definition when using underscores. I would like to keep the naming convention I have here but need the macro variables to resolve to do so. What am I missing?
%macro mymacro(dd=,mm=,yy=,dnr=,dma=);
.
.
.
%if dnr = 1 %then %let dnrname=est;
%if dnr = 2 %then %let dnrname=cen;
%if dnr = 3 %then %let dnrname=mtec;
%if dnr = 4 %then %let dnrname=pac;
%if dnr = 5 %then %let dnrname=mtwp;
data setoff_&dnrname._&dma._&mm.&dd.&yy.;
set restart_no retimed one_min_durations;
run;
.
.
.
%mend mymacro;
The error looks like:
NOTE: Line generated by the invoked macro "SETOFF".
89 data setoff_&dnrname._&dma._&mm.&dd.&yy.; set restart_no retimed one_min_durations;
-
22
200
89 ! run; proc sort data = setoff_&dnrname._&dma._&mm.&dd.&yy.; by &dims_list. sid; run;
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, (, /, ;,
_DATA_, _LAST_, _NULL_.
%if dnr = 1 %then %let dnrname=est;
This is the problem. dnr never equals 1. You are missing the ampersand.
data sample;
input x $;
datalines;
one
two
three
;
%macro variable_to_macvar(variable=, dataset=);
proc sql noprint;
select &variable into : outlist separated by ' '
from &dataset;
quit;
&outlist
%mend variable_to_macvar;
%put %variable_to_macvar(variable=x, dataset=sample);
Expected output: one two three. Instead I get an error. Why? Is this fixable?
I've successfully created other macros of a very similar form, where the function "returns" a value using the ¯ovariable at the end of the macro without a semicolon. For example, here is a similar type of function that works:
%macro zcat(first=5, last=15, prefix=freq);
%let x=;
%do i = &first %to &last;
%let x=&x &prefix.&i;
%end;
&x
%mend zcat;
%put %zcat();
You cannot execute a macro that involves running a proc or a data step in the way that you're trying to do here. You would need to use something like %sysfunc(dosubl(proc sql...)) in order for that to work (assuming you have SAS 9.3+ - see Joe's answer above). Otherwise, you can't use proc sql within a function-style macro.
More details about dosubl:
http://support.sas.com/documentation/cdl/en/lefunctionsref/67398/HTML/default/viewer.htm#p09dcftd1xxg1kn1brnjyc0q93yk.htm
It would be a bit fiddly, but if you really wanted to make this work as a function-style macro in earlier versions of SAS, you could construct it using the open, fetchobs and getvarc functions instead.
Update: Here's an example (using call set rather than getvarc, as this turned out to be simpler), in case anyone needs to do this in SAS 9.2 or earlier.
%macro variable_to_macvar(var,ds);
%local rc dsid i;
%let &var =;
%global outlist;
%let outlist=;
%let dsid = %sysfunc(open(&ds,i));
%syscall set(dsid);
%let rc = 0;
%let i = 0;
%do %while(&rc = 0);
%let i = %eval(&i + 1);
%let rc = %sysfunc(fetchobs(&dsid,&i));
%if &rc = 0 %then %let outlist = &outlist &&&var;
%end;
%let rc = %sysfunc(close(&dsid));
&outlist
%mend;
%put %variable_to_macvar(var=x, ds=sample);
Now works for views as well as ordinary datasets.
DOSUBL is available (but experimental) in 9.3 (at least, 9.3TS1M2, which I have). This is how you'd do it.
data sample;
input x $;
datalines;
one
two
three
;
%macro variable_to_macvar(variable=, dataset=);
%let rc=%sysfunc(dosubl(%str(
proc sql noprint;
select &variable into : outlist separated by ' '
from &dataset;
quit;
)));
&outlist
%mend variable_to_macvar;
%put %variable_to_macvar(variable=x, dataset=sample);;
If you can't use DOSUBL, or want to avoid experimental things, you can do this with PROC FCMP rather than a macro. If you like to write functions, PROC FCMP is probably for you: actually being able to write functions, rather than having to deal with the annoyances of the macro language.
Alter your code at the end to
%global outlist;
%variable_to_macvar(variable=x, dataset=sample);
%put &outlist;
The %put wants to resolve only a macro variable or a single value. It cannot call a procedure. So call your macro and then print the result.
Also, delete the &outlist from the macro definition. Sorry I missed that initially.
EDIT: Alternative.
Change your macro definition to
%macro variable_to_macvar(variable=, dataset=);
proc sql noprint;
select &variable into : outlist separated by ' '
from &dataset;
quit;
%put &outlist
%mend variable_to_macvar;
Just do the %put inside the macro.
%variable_to_macvar(variable=x, dataset=sample);
will print the string to the log.
We have a utility macro that is probably one of our most used pieces of code that does this for us. It is similar to the code that #user667489 provided but includes some nice features including error catching, allows both character and numeric vars, allows you to specify seperators, quotes, quote characters, filters to the dataset, etc....
We just put this macro in our autocall library so that it's avaialble to all of our programs. Some examples of running the macro:
Example 1 - Default behaviour:
%put %variable_to_macvar(var=x, ds=samplex);
Result 1:
one,two,three
Not quite the desired output as the default seperator is a comma, this is easily changed though...
Example 2 - Specify to use a space character as a delimiter:
%put %ds2list(iDs=samplex, iField=x, iDelimiter=%str( ));
Result 2:
one two three
Example 3 - Quoting & example usage
data names;
input name $;
datalines;
John
Jim
Frankie
;
run;
%put %ds2list(iDs=names, iField=name, iQuote=1);
proc sql noprint;
create table xx as
select *
from sashelp.class
where name in (%ds2list(iDs=names, iField=name, iQuote=1))
;
quit;
Result 3:
The below is printed to the log:
'John','Jim','Frankie'
Notice how we don't need to even save the result to a macro variable to use it in the SQL statement! Swweeet! This works just as well for SQL passthrough queries, and any other data step or proc statement that you can throw it at. In the above example, a single row is returned as 'John' is the only match found...
Anyway, that's our solution here... been using this for >10 years and works well for me. Here is the macro:
/***************************************************************************
** PROGRAM: MACRO.DS2LIST.SAS
**
** UTILITY PROGRAM THAT DETECTS RETURNS A LIST OF FIELD VALUES FROM A
** DATASET IN DELIMITED FORMAT.
**
** PARAMETERS:
** iDs : THE LIBNAME.DATASET NAME THAT YOU WANT TO CHECK.
** iField : THE FIELD THAT CONTAINS THE VALUES YOU WANT RETURNED IN A
** DELIMITED FORMAT.
** iDelimiter: DEFAULT IS A COMMA. THE DELIMITER TO USE FOR THE RETURNED LIST.
** iDsOptions: ANY STANDARD DATASET OPTIONS THAT YOU WOULD LIKE TO APPLY SUCH
** AS A WHERE STATEMENT.
** iQuote : (0=NO,1=YES). DEFAULT=0/NO. DETERMINES WHETHER THE RETURNED
** LIST IS QUOTED OR NOT.
** iQuoteChar: (SINGLE,DOUBLE) DEFAULT=SINGLE. SPECIFIES WHETHER SINGLE
** OR DOUBLE QUOTES ARE USED WHEN QUOTING THE RETURNED LIST
**
*****************************************************************************
** VERSION:
** 1.8 MODIFIED: 11-OCT-2010 BY: KN
** ALLOW BLANK CHARACTER VALUES AND ALSO REMOVED TRAILING
** ALLOW PARENTHESES IN CHARACTER VALUES
*****************************************************************************/
%macro ds2list(iDs=, iField=, iDsOptions=, iDelimiter=%str(,), iQuote=0, iQuoteChar=single);
%local dsid pos rc result cnt quotechar;
%let result=;
%let cnt=0;
%if &iQuote %then %do;
%if "%upcase(&iQuoteChar)" eq "DOUBLE" %then %do;
%let quotechar = %nrstr(%");
%end;
%else %if "%upcase(&iQuoteChar)" eq "SINGLE" %then %do;
%let quotechar = %nrstr(%');
%end;
%else %do;
%let quotechar = %nrstr(%");
%put WARNING: MACRO.DS2LIST.SAS: PARAMETER IQUOTECHAR INCORRECT. DEFAULTED TO DOUBLE;
%end;
%end;
%else %do;
%let quotechar = ;
%end;
/*
** ENSURE ALL THE REQUIRED PARAMETERS WERE PASSED IN.
*/
%if "&iDs" ne "" and "&iField" ne "" %then %do;
%let dsid=%sysfunc(open(&iDs(&iDsOptions),i));
%if &dsid %then %do;
%let pos=%sysfunc(varnum(&dsid,&iField));
%if &pos %then %do;
%let rc=%sysfunc(fetch(&dsid));
%do %while (&rc eq 0);
%if "%sysfunc(vartype(&dsid,&pos))" = "C" %then %do;
%let value = %qsysfunc(getvarc(&dsid,&pos));
%if "%trim(&value)" ne "" %then %do;
%let value = %qsysfunc(cats(%nrstr(&value)));
%end;
%end;
%else %do;
%let value = %sysfunc(getvarn(&dsid,&pos));
%end;
/* WHITESPACE/CARRIAGE RETURNS REMOVED IN THE BELOW LINE */
/* TO ENSURE NO WHITESPACE IS RETURNED IN THE OUTPUT. */
%if &cnt ne 0 %then %do;%unquote(&iDelimiter)%end;%unquote("echar&value"echar.)
%let cnt = %eval(&cnt + 1);
%let rc = %sysfunc(fetch(&dsid));
%end;
%if &rc ne -1 %then %do;
%put WARNING: MACRO.DS2LIST.SAS: %sysfunc(sysmsg());
%end;
%end;
%else %do;
%put ERROR: MACRO.DS2LIST.SAS: FIELD &iField NOT FOUND IN DATASET %upcase(&iDs).;
%end;
%end;
%else %do;
%put ERROR: MACRO.DS2LIST.SAS: DATASET %upcase(&iDs) COULD NOT BE OPENED.;
%end;
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put ERROR: MACRO.DS2LIST.SAS: YOU MUST SPECIFY BOTH THE IDS AND IFIELD PARAMETERS TO CALL THIS MACRO.;
%end;
%mend;