1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-03 23:50:06 +00:00

Compare commits

...

21 Commits

Author SHA1 Message Date
Allan Bowe
0297509aa0 Merge pull request #159 from sasjs/woff3
fix: avoiding error and including test in mp_streamfile.sas
2022-02-03 20:59:11 +02:00
munja
c5a8bc745d chore: fix test 2022-02-03 19:58:12 +01:00
munja
36aa466561 fix: avoiding error and including a test 2022-02-03 19:44:21 +01:00
Allan Bowe
009485e5b9 Merge pull request #158 from sasjs/woff2
fix: support for WOFF2 and TTF
2022-02-03 19:51:39 +02:00
munja
eb01c8772d fix: support for WOFF2 and TTF 2022-02-03 18:51:07 +01:00
Allan Bowe
e3fb69928c Merge pull request #157 from sasjs/dependabot
chore: adding dependabot
2022-02-03 19:31:16 +02:00
munja
65afa14466 chore: removing leading spaces 2022-02-03 18:30:49 +01:00
munja
0176b19616 chore: adding dependabot 2022-02-03 18:29:31 +01:00
Allan Bowe
9f3dfd9a59 Merge pull request #156 from sasjs/csv
adding WOFF to mp_streamfile
2022-02-03 19:23:09 +02:00
munja
513ea354ab chore: updating headers in mp_streamfile and running all.sas 2022-02-03 16:45:42 +01:00
munja
7b686e11c9 feat: adding WOFF support to mp_streamfile (also re-ordering sections alphabetically) 2022-02-03 16:44:39 +01:00
munja
3997000266 fix: encoding issue in mp_ds2csv (option should have been in quotes) 2022-02-03 15:00:46 +01:00
Allan Bowe
6e177d4cae Merge pull request #155 from sasjs/cmplib
fix: auto-detect cmplib in mcfxx funcs, mp_ds2csv supports dates etc,…
2022-02-02 23:43:43 +02:00
munja
3554991ff8 fix: auto-detect cmplib in mcfxx funcs, mp_ds2csv supports dates etc, fix to mp_abort in viya due to abort cancel FILE hard stop (according to docs it should continue outside of the include) 2022-02-02 21:18:51 +01:00
Allan Bowe
58d2d6382a Merge pull request #154 from sasjs/errtext
fix: removing syserrortext as it breaks when commas are embedded
2022-02-02 21:36:30 +02:00
Allan Bowe
67f28a366c fix: removing syserrortext as it breaks when commas are embedded 2022-02-02 19:35:54 +00:00
Allan Bowe
64f53acce2 Merge pull request #153 from sasjs/mcf_fmtclass
Mcf fmtclass
2022-02-01 19:50:36 +02:00
munja
2e790f69a1 fix: removing view due to potential for vbufsize violations 2022-02-01 16:14:37 +01:00
munja
e62011d97e chore: updating variable name to fit doc header 2022-02-01 13:52:08 +01:00
munja
cd8d16d09f chore: updating all.sas 2022-02-01 13:48:48 +01:00
munja
9c61965d4b feat: new macro (mcf_getfmttype) to determine the type (DATE,DATETIME,TIME,CHAR,NUM) of a SAS format 2022-02-01 13:48:23 +01:00
21 changed files with 731 additions and 163 deletions

9
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: npm
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 3
allow:
- dependency-type: "production"

View File

@@ -196,6 +196,8 @@ When contributing to this library, it is therefore important to ensure that all
We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major (breaking) release becomes necessary: We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major (breaking) release becomes necessary:
* mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything) * mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything)
* `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed)
* mcf_xxx macros to have `wrap=` option defaulted to YES for convenience
## Star Gazing ## Star Gazing

366
all.sas
View File

@@ -2106,7 +2106,10 @@ Usage:
%if %length(&mac)>0 %then %put NOTE- called by &mac; %if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg; %put NOTE - &msg;
%if %symexist(_SYSINCLUDEFILEDEVICE) %then %do; %if %symexist(_SYSINCLUDEFILEDEVICE)
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
and "&SYSPROCESSNAME " ne "Compute Server "
%then %do;
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do; %if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
data &errds; data &errds;
iftrue='1=1'; iftrue='1=1';
@@ -4666,10 +4669,28 @@ quit;
@brief Export a dataset to a CSV file WITH leading blanks @brief Export a dataset to a CSV file WITH leading blanks
@details Export a dataset to a file or fileref, retaining leading blanks. @details Export a dataset to a file or fileref, retaining leading blanks.
When using SASJS headerformat, the input statement is provided in the first
row of the CSV.
Usage: Usage:
%mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv") %mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv")
filename example temp;
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
data; infile example; input;put _infile_; if _n_>5 then stop;run;
data _null_;
infile example;
input;
call symputx('stmnt',_infile_);
stop;
run;
data work.want;
infile example dsd firstobs=2;
input &stmnt;
run;
Why use mp_ds2csv over, say, proc export? Why use mp_ds2csv over, say, proc export?
1. Ability to retain leading blanks (this is a major one) 1. Ability to retain leading blanks (this is a major one)
@@ -4686,17 +4707,24 @@ quit;
@li LABEL - Use the variable label (or name, if blank) @li LABEL - Use the variable label (or name, if blank)
@li NAME - Use the variable name @li NAME - Use the variable name
@li SASJS - Used to create sasjs-formatted input CSVs, eg for use in @li SASJS - Used to create sasjs-formatted input CSVs, eg for use in
mp_testservice.sas mp_testservice.sas. This format will supply an input statement in the
first row, making ingestion by datastep a breeze. Special misisng values
will be prefixed with a period (eg `.A`) to enable ingestion on both SAS 9
and Viya. Dates / Datetimes etc are identified by the format type (lookup
with mcf_getfmttype.sas) and converted to human readable formats (not
numbers).
@param [out] outfile= The output filename - should be quoted. @param [out] outfile= The output filename - should be quoted.
@param [out] outref= (0) The output fileref (takes precedence if provided) @param [out] outref= (0) The output fileref (takes precedence if provided)
@param [in] outencoding= (0) The output encoding to use (unquoted) @param [in] outencoding= (0) The (quoted) output encoding to use, eg `"UTF-8"`
@param [in] termstr= (CRLF) The line seperator to use. For SASJS, will @param [in] termstr= (CRLF) The line seperator to use. For SASJS, will
always be CRLF. Valid values: always be CRLF. Valid values:
@li CRLF @li CRLF
@li LF @li LF
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_getfmttype.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarformat.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mf_getvartype.sas
@@ -4713,7 +4741,7 @@ quit;
,termstr=CRLF ,termstr=CRLF
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local outloc delim i varlist var vcnt vat dsv vcom vmiss; %local outloc delim i varlist var vcnt vat dsv vcom vmiss fmttype vfmt;
%if not %sysfunc(exist(&ds)) %then %do; %if not %sysfunc(exist(&ds)) %then %do;
%put %str(WARN)ING: &ds does not exist; %put %str(WARN)ING: &ds does not exist;
@@ -4723,7 +4751,7 @@ quit;
%if %index(&ds,.)=0 %then %let ds=WORK.&ds; %if %index(&ds,.)=0 %then %let ds=WORK.&ds;
%if &outencoding=0 %then %let outencoding=; %if &outencoding=0 %then %let outencoding=;
%else %let outencoding=encoding="&outencoding"; %else %let outencoding=encoding=&outencoding;
%if &outref=0 %then %let outloc=&outfile; %if &outref=0 %then %let outloc=&outfile;
%else %let outloc=&outref; %else %let outloc=&outref;
@@ -4731,6 +4759,7 @@ quit;
%if &headerformat=SASJS %then %do; %if &headerformat=SASJS %then %do;
%let delim=","; %let delim=",";
%let termstr=CRLF; %let termstr=CRLF;
%mcf_getfmttype(wrap=YES)
%end; %end;
%else %if &dlm=COMMA %then %let delim=","; %else %if &dlm=COMMA %then %let delim=",";
%else %let delim=";"; %else %let delim=";";
@@ -4740,7 +4769,8 @@ quit;
/* first get headers */ /* first get headers */
data _null_; data _null_;
file &outloc &outencoding lrecl=32767 termstr=&termstr; file &outloc &outencoding lrecl=32767 termstr=&termstr;
length header $ 2000 varnm $32 dlm $1; length header $ 2000 varnm vfmt $32 dlm $1 fmttype $8;
call missing(of _all_);
dsid=open("&ds.","i"); dsid=open("&ds.","i");
num=attrn(dsid,"nvars"); num=attrn(dsid,"nvars");
dlm=&delim; dlm=&delim;
@@ -4755,7 +4785,14 @@ data _null_;
%end; %end;
%else %if &headerformat=SASJS %then %do; %else %if &headerformat=SASJS %then %do;
if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.'); if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.');
else header=cats(varnm,':best.'); else do;
vfmt=coalescec(varfmt(dsid,i),'0');
fmttype=mcf_getfmttype(vfmt);
if fmttype='DATE' then header=cats(varnm,':date9.');
else if fmttype='DATETIME' then header=cats(varnm,':E8601DT26.6');
else if fmttype='TIME' then header=cats(varnm,':TIME12.');
else header=cats(varnm,':best.');
end;
%end; %end;
%else %do; %else %do;
%put &sysmacroname: Invalid headerformat value (&headerformat); %put &sysmacroname: Invalid headerformat value (&headerformat);
@@ -4810,14 +4847,29 @@ data _null_;
%let vcom=; %let vcom=;
%end; %end;
%if %mf_getvartype(&ds,&var)=N %then %do; %if %mf_getvartype(&ds,&var)=N %then %do;
%if &headerformat = SASJS %then %do;
%let vcom=&delim;
%let fmttype=%sysfunc(mcf_getfmttype(%mf_getvarformat(&ds,&var)0));
%if &fmttype=DATE %then %let vfmt=DATE9.;
%else %if &fmttype=DATETIME %then %let vfmt=E8601DT26.6;
%else %if &fmttype=TIME %then %let vfmt=TIME12.;
%else %do;
%let vfmt=;
%let vcom=;
%end;
%end;
%else %let vcom=;
/* must use period - in order to work in both 9.4 and Viya 3.5 */ /* must use period - in order to work in both 9.4 and Viya 3.5 */
if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do; if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do;
&vmiss=cats('.',&var); &vmiss=cats('.',&var);
put &vmiss &vat; put &vmiss &vat;
end; end;
else put &var &vat; else put &var &vfmt &vcom &vat;
%end; %end;
%else %do; %else %do;
%if &i ne &vcnt %then %let vcom=&delim;
put &var &&vlen&i &vcom &vat; put &var &&vlen&i &vcom &vat;
%end; %end;
%end; %end;
@@ -5954,8 +6006,7 @@ filename &fref1 clear;
run; run;
%mp_abort( %mp_abort(
mac=&sysmacroname, mac=&sysmacroname,
msg=%str(Filter validation issues. ERR=%superq(SYSERRORTEXT) msg=%str(Filter validation issues.)
, WARN=%superq(SYSWARNINGTEXT) )
) )
%end; %end;
%let syscc=1008; %let syscc=1008;
@@ -7878,9 +7929,10 @@ https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/mcrolref/n1j5tcc0n2xczyn1
this dataset. this dataset.
It will then run an abort cancel FILE to stop the include running, and pass It will then run an abort cancel FILE to stop the include running, and pass
the dataset back. the dataset back.
NOTE - it is NOT possible to read this dataset as part of _this_ macro -
when running abort cancel FILE, ALL macros are closed, so instead it is IMPORTANT NOTE - it is NOT possible to read this dataset as part of _this_
necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of any macro wrappers. macro! When running abort cancel FILE, ALL macros are closed, so instead it
is necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of macro wrappers.
@version 9.4 @version 9.4
@@ -8137,7 +8189,7 @@ options
%put &sysmacroname: Switching to DATASTEP engine; %put &sysmacroname: Switching to DATASTEP engine;
%goto datastep; %goto datastep;
%end; %end;
data &tempds /view=&tempds;set &ds; data &tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */ /* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty proc json out=&jref pretty
@@ -8188,7 +8240,7 @@ options
%end; %end;
other = [best.]; other = [best.];
data &tempds/view=&tempds; data &tempds;
attrib _all_ label=''; attrib _all_ label='';
%do i=1 %to &numcols; %do i=1 %to &numcols;
%if &&typelong&i=char or &fmt=Y %then %do; %if &&typelong&i=char or &fmt=Y %then %do;
@@ -8250,8 +8302,7 @@ options
%end; %end;
proc sql; proc sql;
drop view &tempds; drop table &colinfo, &tempds;
drop table &colinfo;
%if &showmeta=YES %then %do; %if &showmeta=YES %then %do;
data _null_; file &jref encoding='utf-8' mod; data _null_; file &jref encoding='utf-8' mod;
@@ -8517,7 +8568,7 @@ run;
/* do not proceed if no observations can be processed */ /* do not proceed if no observations can be processed */
%mp_abort(iftrue= (%sysfunc(getoption(OBS))=0) %mp_abort(iftrue= (%sysfunc(getoption(OBS))=0)
,mac=&sysmacroname ,mac=&sysmacroname
,msg=%str(options obs = 0. syserrortext=&syserrortext) ,msg=%str(cannot continue when options obs = 0)
) )
%if &ACTION=LOCK %then %do; %if &ACTION=LOCK %then %do;
@@ -10749,17 +10800,19 @@ create table &outds as
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXTS) Either TEXT, ZIP, CSV, EXCEL
@param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute.
@param [out] outname= the name of the file, as downloaded by the browser
@param [out] outref= (_webout) The destination where the file should be
streamed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas @li mf_getplatform.sas
@li mp_binarycopy.sas @li mp_binarycopy.sas
@param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT)
@param inloc= /path/to/file.ext to be sent
@param inref= fileref of file to be sent (if provided, overrides `inloc`)
@param outname= the name of the file, as downloaded by the browser
@author Allan Bowe @author Allan Bowe
@source https://github.com/sasjs/core
**/ **/
@@ -10767,12 +10820,16 @@ create table &outds as
contenttype=TEXT contenttype=TEXT
,inloc= ,inloc=
,inref=0 ,inref=0
,iftrue=%str(1=1)
,outname= ,outname=
,outref=_webout
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let contentype=%upcase(&contenttype); %if not(%eval(%unquote(&iftrue))) %then %return;
%local platform; %let platform=%mf_getplatform();
%let contentype=%upcase(&contenttype);
%let outref=%upcase(&outref);
%local platform; %let platform=%mf_getplatform();
/** /**
* check engine type to avoid the below err message: * check engine type to avoid the below err message:
@@ -10781,20 +10838,20 @@ create table &outds as
%local streamweb; %local streamweb;
%let streamweb=0; %let streamweb=0;
data _null_; data _null_;
set sashelp.vextfl(where=(upcase(fileref)="_WEBOUT")); set sashelp.vextfl(where=(upcase(fileref)="&outref"));
if xengine='STREAM' then call symputx('streamweb',1,'l'); if xengine='STREAM' then call symputx('streamweb',1,'l');
run; run;
%if &contentype=ZIP %then %do; %if &contentype=CSV %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','application/zip'); rc=stpsrv_header('Content-type','application/csv');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/zip' contenttype='application/csv'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
@@ -10807,11 +10864,41 @@ run;
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
contenttype='application/vnd.ms-excel' contenttype='application/vnd.ms-excel'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html";
%end;
%end;
%else %if &contentype=TEXT %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/text'
contentdisp="attachment; filename=&outname";
%end;
%end;
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI"
contenttype="font/%lowcase(&contenttype)";
%end;
%end;
%else %if &contentype=XLSX %then %do; %else %if &contentype=XLSX %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
@@ -10821,54 +10908,35 @@ run;
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
contenttype= contenttype=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=ZIP %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','application/text'); rc=stpsrv_header('Content-type','application/zip');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip'
contenttype='application/text' contenttype='application/zip'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=CSV %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type','application/csv');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/csv'
contentdisp="attachment; filename=&outname";
%end;
%end;
%else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html";
%end;
%end;
%else %do; %else %do;
%put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!; %put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!;
%return; %return;
%end; %end;
%if &inref ne 0 %then %do; %if &inref ne 0 %then %do;
%mp_binarycopy(inref=&inref,outref=_webout) %mp_binarycopy(inref=&inref,outref=&outref)
%end; %end;
%else %do; %else %do;
%mp_binarycopy(inloc="&inloc",outref=_webout) %mp_binarycopy(inloc="&inloc",outref=&outref)
%end; %end;
%mend mp_streamfile; %mend mp_streamfile;
@@ -13861,7 +13929,7 @@ data _null_;
put ' %put &sysmacroname: Switching to DATASTEP engine; '; put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; '; put ' %goto datastep; ';
put ' %end; '; put ' %end; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
@@ -13912,7 +13980,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data &tempds/view=&tempds; '; put ' data &tempds; ';
put ' attrib _all_ label=''''; '; put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
@@ -13974,8 +14042,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop view &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' drop table &colinfo; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' data _null_; file &jref encoding=''utf-8'' mod; ';
@@ -19004,7 +19071,7 @@ data _null_;
put ' %put &sysmacroname: Switching to DATASTEP engine; '; put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; '; put ' %goto datastep; ';
put ' %end; '; put ' %end; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
@@ -19055,7 +19122,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data &tempds/view=&tempds; '; put ' data &tempds; ';
put ' attrib _all_ label=''''; '; put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
@@ -19117,8 +19184,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop view &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' drop table &colinfo; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' data _null_; file &jref encoding=''utf-8'' mod; ';
@@ -23556,6 +23622,123 @@ run;
%mend ml_json; %mend ml_json;
/** /**
@file
@brief Returns the type of the format
@details
Returns the type, eg DATE / DATETIME / TIME (based on hard-coded lookup)
else CHAR / NUM.
This macro may be extended in the future to support custom formats - this
would necessitate a call to `dosubl()` for running a proc format with cntlout.
The function itself takes the following (positional) parameters:
| PARAMETER | DESCRIPTION |
|---|---|
|fmtnm| Format name to be tested. Can be with or without the w.d extension.|
Usage:
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
data _null_;
fmt1=mcf_getfmttype('DATE9.');
fmt2=mcf_getfmttype('DATETIME');
put (fmt:)(=);
run;
%put fmt3=%sysfunc(mcf_getfmttype(TIME9.));
Returns:
> fmt1=DATE fmt2=DATETIME
> fmt3=TIME
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4>
@li mcf_init.sas
<h4> Related Programs </h4>
@li mcf_getfmttype.test.sas
@li mp_init.sas
@todo "Custom Format Lookups" To enable site-specific formats, make
use of a set of SASJS_FMTLIST_(DATATYPE) global variables.
**/
%macro mcf_getfmttype(wrap=NO
,insert_cmplib=DEPRECATED
,lib=WORK
,cat=SASJS
,pkg=UTILS
)/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_getfmttype)=1 %then %return;
%if &wrap=YES %then %do;
proc fcmp outlib=&lib..&cat..&pkg;
%end;
function mcf_getfmttype(fmtnm $) $8;
if substr(fmtnm,1,1)='$' then return('CHAR');
else do;
/* extract NAME */
length fmt $32;
fmt=scan(fmtnm,1,'.');
do while (
substr(fmt,length(fmt),1) in ('1','2','3','4','5','6','7','8','9','0')
);
if length(fmt)=1 then fmt='W';
else fmt=substr(fmt,1,length(fmt)-1);
end;
/* apply lookups */
if cats(fmt) in ('DATETIME','B8601DN','B8601DN','B8601DT','B8601DT'
,'B8601DZ','B8601DZ','DATEAMPM','DTDATE','DTMONYY','DTWKDATX','DTYEAR'
,'DTYYQC','E8601DN','E8601DN','E8601DT','E8601DT','E8601DZ','E8601DZ')
then return('DATETIME');
else if fmt in ('DATE','YYMMDD','B8601DA','B8601DA','DAY','DDMMYY'
,'DDMMYYB','DDMMYYC','DDMMYYD','DDMMYYN','DDMMYYP','DDMMYYS','DDMMYYx'
,'DOWNAME','E8601DA','E8601DA','JULDAY','JULIAN','MMDDYY','MMDDYYB'
,'MMDDYYC','MMDDYYD','MMDDYYN','MMDDYYP','MMDDYYS','MMDDYYx','MMYY'
,'MMYYC','MMYYD','MMYYN','MMYYP','MMYYS','MMYYx','MONNAME','MONTH'
,'MONYY','PDJULG','PDJULI','QTR','QTRR','WEEKDATE','WEEKDATX','WEEKDAY'
,'WEEKU','WEEKV','WEEKW','WORDDATE','WORDDATX','YEAR','YYMM','YYMMC'
,'YYMMD','YYMMDDB','YYMMDDC','YYMMDDD','YYMMDDN','YYMMDDP','YYMMDDS'
,'YYMMDDx','YYMMN','YYMMP','YYMMS','YYMMx','YYMON','YYQ','YYQC','YYQD'
,'YYQN','YYQP','YYQR','YYQRC','YYQRD','YYQRN','YYQRP','YYQRS','YYQRx'
,'YYQS','YYQx','YYQZ') then return('DATE');
else if fmt in ('TIME','B8601LZ','B8601LZ','B8601TM','B8601TM','B8601TZ'
,'B8601TZ','E8601LZ','E8601LZ','E8601TM','E8601TM','E8601TZ','E8601TZ'
,'HHMM','HOUR','MMSS','TIMEAMPM','TOD') then return('TIME');
else return('NUM');
end;
endsub;
%if &wrap=YES %then %do;
quit;
%end;
/* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat));
%end;
%mend mcf_getfmttype;/**
@file @file
@brief Sets up the mcf_xx functions @brief Sets up the mcf_xx functions
@details @details
@@ -23633,12 +23816,12 @@ run;
> outa=3 outb=4 outc=5 outd=0 > outa=3 outb=4 outc=5 outd=0
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -23650,12 +23833,12 @@ run;
**/ **/
%macro mcf_length(wrap=NO %macro mcf_length(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_length)=1 %then %return; %if %mcf_init(mcf_length)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -23677,7 +23860,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;
@@ -23730,12 +23920,12 @@ endsub;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -23747,12 +23937,12 @@ endsub;
**/ **/
%macro mcf_stpsrv_header(wrap=NO %macro mcf_stpsrv_header(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(stpsrv_header)=1 %then %return; %if %mcf_init(stpsrv_header)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -23779,7 +23969,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;
@@ -23817,12 +24014,12 @@ endsub;
run; run;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -23834,12 +24031,12 @@ endsub;
**/ **/
%macro mcf_string2file(wrap=NO %macro mcf_string2file(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_string2file)=1 %then %return; %if %mcf_init(mcf_string2file)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -23866,7 +24063,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;

View File

@@ -66,7 +66,10 @@
%if %length(&mac)>0 %then %put NOTE- called by &mac; %if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg; %put NOTE - &msg;
%if %symexist(_SYSINCLUDEFILEDEVICE) %then %do; %if %symexist(_SYSINCLUDEFILEDEVICE)
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
and "&SYSPROCESSNAME " ne "Compute Server "
%then %do;
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do; %if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
data &errds; data &errds;
iftrue='1=1'; iftrue='1=1';

View File

@@ -3,10 +3,28 @@
@brief Export a dataset to a CSV file WITH leading blanks @brief Export a dataset to a CSV file WITH leading blanks
@details Export a dataset to a file or fileref, retaining leading blanks. @details Export a dataset to a file or fileref, retaining leading blanks.
When using SASJS headerformat, the input statement is provided in the first
row of the CSV.
Usage: Usage:
%mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv") %mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv")
filename example temp;
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
data; infile example; input;put _infile_; if _n_>5 then stop;run;
data _null_;
infile example;
input;
call symputx('stmnt',_infile_);
stop;
run;
data work.want;
infile example dsd firstobs=2;
input &stmnt;
run;
Why use mp_ds2csv over, say, proc export? Why use mp_ds2csv over, say, proc export?
1. Ability to retain leading blanks (this is a major one) 1. Ability to retain leading blanks (this is a major one)
@@ -23,17 +41,24 @@
@li LABEL - Use the variable label (or name, if blank) @li LABEL - Use the variable label (or name, if blank)
@li NAME - Use the variable name @li NAME - Use the variable name
@li SASJS - Used to create sasjs-formatted input CSVs, eg for use in @li SASJS - Used to create sasjs-formatted input CSVs, eg for use in
mp_testservice.sas mp_testservice.sas. This format will supply an input statement in the
first row, making ingestion by datastep a breeze. Special misisng values
will be prefixed with a period (eg `.A`) to enable ingestion on both SAS 9
and Viya. Dates / Datetimes etc are identified by the format type (lookup
with mcf_getfmttype.sas) and converted to human readable formats (not
numbers).
@param [out] outfile= The output filename - should be quoted. @param [out] outfile= The output filename - should be quoted.
@param [out] outref= (0) The output fileref (takes precedence if provided) @param [out] outref= (0) The output fileref (takes precedence if provided)
@param [in] outencoding= (0) The output encoding to use (unquoted) @param [in] outencoding= (0) The (quoted) output encoding to use, eg `"UTF-8"`
@param [in] termstr= (CRLF) The line seperator to use. For SASJS, will @param [in] termstr= (CRLF) The line seperator to use. For SASJS, will
always be CRLF. Valid values: always be CRLF. Valid values:
@li CRLF @li CRLF
@li LF @li LF
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_getfmttype.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarformat.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mf_getvartype.sas
@@ -50,7 +75,7 @@
,termstr=CRLF ,termstr=CRLF
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local outloc delim i varlist var vcnt vat dsv vcom vmiss; %local outloc delim i varlist var vcnt vat dsv vcom vmiss fmttype vfmt;
%if not %sysfunc(exist(&ds)) %then %do; %if not %sysfunc(exist(&ds)) %then %do;
%put %str(WARN)ING: &ds does not exist; %put %str(WARN)ING: &ds does not exist;
@@ -60,7 +85,7 @@
%if %index(&ds,.)=0 %then %let ds=WORK.&ds; %if %index(&ds,.)=0 %then %let ds=WORK.&ds;
%if &outencoding=0 %then %let outencoding=; %if &outencoding=0 %then %let outencoding=;
%else %let outencoding=encoding="&outencoding"; %else %let outencoding=encoding=&outencoding;
%if &outref=0 %then %let outloc=&outfile; %if &outref=0 %then %let outloc=&outfile;
%else %let outloc=&outref; %else %let outloc=&outref;
@@ -68,6 +93,7 @@
%if &headerformat=SASJS %then %do; %if &headerformat=SASJS %then %do;
%let delim=","; %let delim=",";
%let termstr=CRLF; %let termstr=CRLF;
%mcf_getfmttype(wrap=YES)
%end; %end;
%else %if &dlm=COMMA %then %let delim=","; %else %if &dlm=COMMA %then %let delim=",";
%else %let delim=";"; %else %let delim=";";
@@ -77,7 +103,8 @@
/* first get headers */ /* first get headers */
data _null_; data _null_;
file &outloc &outencoding lrecl=32767 termstr=&termstr; file &outloc &outencoding lrecl=32767 termstr=&termstr;
length header $ 2000 varnm $32 dlm $1; length header $ 2000 varnm vfmt $32 dlm $1 fmttype $8;
call missing(of _all_);
dsid=open("&ds.","i"); dsid=open("&ds.","i");
num=attrn(dsid,"nvars"); num=attrn(dsid,"nvars");
dlm=&delim; dlm=&delim;
@@ -92,7 +119,14 @@ data _null_;
%end; %end;
%else %if &headerformat=SASJS %then %do; %else %if &headerformat=SASJS %then %do;
if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.'); if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.');
else header=cats(varnm,':best.'); else do;
vfmt=coalescec(varfmt(dsid,i),'0');
fmttype=mcf_getfmttype(vfmt);
if fmttype='DATE' then header=cats(varnm,':date9.');
else if fmttype='DATETIME' then header=cats(varnm,':E8601DT26.6');
else if fmttype='TIME' then header=cats(varnm,':TIME12.');
else header=cats(varnm,':best.');
end;
%end; %end;
%else %do; %else %do;
%put &sysmacroname: Invalid headerformat value (&headerformat); %put &sysmacroname: Invalid headerformat value (&headerformat);
@@ -147,14 +181,29 @@ data _null_;
%let vcom=; %let vcom=;
%end; %end;
%if %mf_getvartype(&ds,&var)=N %then %do; %if %mf_getvartype(&ds,&var)=N %then %do;
%if &headerformat = SASJS %then %do;
%let vcom=&delim;
%let fmttype=%sysfunc(mcf_getfmttype(%mf_getvarformat(&ds,&var)0));
%if &fmttype=DATE %then %let vfmt=DATE9.;
%else %if &fmttype=DATETIME %then %let vfmt=E8601DT26.6;
%else %if &fmttype=TIME %then %let vfmt=TIME12.;
%else %do;
%let vfmt=;
%let vcom=;
%end;
%end;
%else %let vcom=;
/* must use period - in order to work in both 9.4 and Viya 3.5 */ /* must use period - in order to work in both 9.4 and Viya 3.5 */
if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do; if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do;
&vmiss=cats('.',&var); &vmiss=cats('.',&var);
put &vmiss &vat; put &vmiss &vat;
end; end;
else put &var &vat; else put &var &vfmt &vcom &vat;
%end; %end;
%else %do; %else %do;
%if &i ne &vcnt %then %let vcom=&delim;
put &var &&vlen&i &vcom &vat; put &var &&vlen&i &vcom &vat;
%end; %end;
%end; %end;

View File

@@ -96,8 +96,7 @@ filename &fref1 clear;
run; run;
%mp_abort( %mp_abort(
mac=&sysmacroname, mac=&sysmacroname,
msg=%str(Filter validation issues. ERR=%superq(SYSERRORTEXT) msg=%str(Filter validation issues.)
, WARN=%superq(SYSWARNINGTEXT) )
) )
%end; %end;
%let syscc=1008; %let syscc=1008;

View File

@@ -51,9 +51,10 @@ https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/mcrolref/n1j5tcc0n2xczyn1
this dataset. this dataset.
It will then run an abort cancel FILE to stop the include running, and pass It will then run an abort cancel FILE to stop the include running, and pass
the dataset back. the dataset back.
NOTE - it is NOT possible to read this dataset as part of _this_ macro -
when running abort cancel FILE, ALL macros are closed, so instead it is IMPORTANT NOTE - it is NOT possible to read this dataset as part of _this_
necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of any macro wrappers. macro! When running abort cancel FILE, ALL macros are closed, so instead it
is necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of macro wrappers.
@version 9.4 @version 9.4

View File

@@ -131,7 +131,7 @@
%put &sysmacroname: Switching to DATASTEP engine; %put &sysmacroname: Switching to DATASTEP engine;
%goto datastep; %goto datastep;
%end; %end;
data &tempds /view=&tempds;set &ds; data &tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */ /* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty proc json out=&jref pretty
@@ -182,7 +182,7 @@
%end; %end;
other = [best.]; other = [best.];
data &tempds/view=&tempds; data &tempds;
attrib _all_ label=''; attrib _all_ label='';
%do i=1 %to &numcols; %do i=1 %to &numcols;
%if &&typelong&i=char or &fmt=Y %then %do; %if &&typelong&i=char or &fmt=Y %then %do;
@@ -244,8 +244,7 @@
%end; %end;
proc sql; proc sql;
drop view &tempds; drop table &colinfo, &tempds;
drop table &colinfo;
%if &showmeta=YES %then %do; %if &showmeta=YES %then %do;
data _null_; file &jref encoding='utf-8' mod; data _null_; file &jref encoding='utf-8' mod;

View File

@@ -85,7 +85,7 @@ run;
/* do not proceed if no observations can be processed */ /* do not proceed if no observations can be processed */
%mp_abort(iftrue= (%sysfunc(getoption(OBS))=0) %mp_abort(iftrue= (%sysfunc(getoption(OBS))=0)
,mac=&sysmacroname ,mac=&sysmacroname
,msg=%str(options obs = 0. syserrortext=&syserrortext) ,msg=%str(cannot continue when options obs = 0)
) )
%if &ACTION=LOCK %then %do; %if &ACTION=LOCK %then %do;

View File

@@ -12,17 +12,19 @@
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXTS) Either TEXT, ZIP, CSV, EXCEL
@param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute.
@param [out] outname= the name of the file, as downloaded by the browser
@param [out] outref= (_webout) The destination where the file should be
streamed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas @li mf_getplatform.sas
@li mp_binarycopy.sas @li mp_binarycopy.sas
@param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT)
@param inloc= /path/to/file.ext to be sent
@param inref= fileref of file to be sent (if provided, overrides `inloc`)
@param outname= the name of the file, as downloaded by the browser
@author Allan Bowe @author Allan Bowe
@source https://github.com/sasjs/core
**/ **/
@@ -30,12 +32,16 @@
contenttype=TEXT contenttype=TEXT
,inloc= ,inloc=
,inref=0 ,inref=0
,iftrue=%str(1=1)
,outname= ,outname=
,outref=_webout
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let contentype=%upcase(&contenttype); %if not(%eval(%unquote(&iftrue))) %then %return;
%local platform; %let platform=%mf_getplatform();
%let contentype=%upcase(&contenttype);
%let outref=%upcase(&outref);
%local platform; %let platform=%mf_getplatform();
/** /**
* check engine type to avoid the below err message: * check engine type to avoid the below err message:
@@ -44,20 +50,20 @@
%local streamweb; %local streamweb;
%let streamweb=0; %let streamweb=0;
data _null_; data _null_;
set sashelp.vextfl(where=(upcase(fileref)="_WEBOUT")); set sashelp.vextfl(where=(upcase(fileref)="&outref"));
if xengine='STREAM' then call symputx('streamweb',1,'l'); if xengine='STREAM' then call symputx('streamweb',1,'l');
run; run;
%if &contentype=ZIP %then %do; %if &contentype=CSV %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','application/zip'); rc=stpsrv_header('Content-type','application/csv');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/zip' contenttype='application/csv'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
@@ -70,11 +76,41 @@ run;
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
contenttype='application/vnd.ms-excel' contenttype='application/vnd.ms-excel'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html";
%end;
%end;
%else %if &contentype=TEXT %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/text'
contentdisp="attachment; filename=&outname";
%end;
%end;
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI"
contenttype="font/%lowcase(&contenttype)";
%end;
%end;
%else %if &contentype=XLSX %then %do; %else %if &contentype=XLSX %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
@@ -84,54 +120,35 @@ run;
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
contenttype= contenttype=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=ZIP %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do; %if &platform=SASMETA and &streamweb=1 %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','application/text'); rc=stpsrv_header('Content-type','application/zip');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt' filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip'
contenttype='application/text' contenttype='application/zip'
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%end; %end;
%else %if &contentype=CSV %then %do;
%if &platform=SASMETA and &streamweb=1 %then %do;
data _null_;
rc=stpsrv_header('Content-type','application/csv');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
contenttype='application/csv'
contentdisp="attachment; filename=&outname";
%end;
%end;
%else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html";
%end;
%end;
%else %do; %else %do;
%put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!; %put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!;
%return; %return;
%end; %end;
%if &inref ne 0 %then %do; %if &inref ne 0 %then %do;
%mp_binarycopy(inref=&inref,outref=_webout) %mp_binarycopy(inref=&inref,outref=&outref)
%end; %end;
%else %do; %else %do;
%mp_binarycopy(inloc="&inloc",outref=_webout) %mp_binarycopy(inloc="&inloc",outref=&outref)
%end; %end;
%mend mp_streamfile; %mend mp_streamfile;

118
fcmp/mcf_getfmttype.sas Normal file
View File

@@ -0,0 +1,118 @@
/**
@file
@brief Returns the type of the format
@details
Returns the type, eg DATE / DATETIME / TIME (based on hard-coded lookup)
else CHAR / NUM.
This macro may be extended in the future to support custom formats - this
would necessitate a call to `dosubl()` for running a proc format with cntlout.
The function itself takes the following (positional) parameters:
| PARAMETER | DESCRIPTION |
|---|---|
|fmtnm| Format name to be tested. Can be with or without the w.d extension.|
Usage:
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
data _null_;
fmt1=mcf_getfmttype('DATE9.');
fmt2=mcf_getfmttype('DATETIME');
put (fmt:)(=);
run;
%put fmt3=%sysfunc(mcf_getfmttype(TIME9.));
Returns:
> fmt1=DATE fmt2=DATETIME
> fmt3=TIME
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4>
@li mcf_init.sas
<h4> Related Programs </h4>
@li mcf_getfmttype.test.sas
@li mp_init.sas
@todo "Custom Format Lookups" To enable site-specific formats, make
use of a set of SASJS_FMTLIST_(DATATYPE) global variables.
**/
%macro mcf_getfmttype(wrap=NO
,insert_cmplib=DEPRECATED
,lib=WORK
,cat=SASJS
,pkg=UTILS
)/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_getfmttype)=1 %then %return;
%if &wrap=YES %then %do;
proc fcmp outlib=&lib..&cat..&pkg;
%end;
function mcf_getfmttype(fmtnm $) $8;
if substr(fmtnm,1,1)='$' then return('CHAR');
else do;
/* extract NAME */
length fmt $32;
fmt=scan(fmtnm,1,'.');
do while (
substr(fmt,length(fmt),1) in ('1','2','3','4','5','6','7','8','9','0')
);
if length(fmt)=1 then fmt='W';
else fmt=substr(fmt,1,length(fmt)-1);
end;
/* apply lookups */
if cats(fmt) in ('DATETIME','B8601DN','B8601DN','B8601DT','B8601DT'
,'B8601DZ','B8601DZ','DATEAMPM','DTDATE','DTMONYY','DTWKDATX','DTYEAR'
,'DTYYQC','E8601DN','E8601DN','E8601DT','E8601DT','E8601DZ','E8601DZ')
then return('DATETIME');
else if fmt in ('DATE','YYMMDD','B8601DA','B8601DA','DAY','DDMMYY'
,'DDMMYYB','DDMMYYC','DDMMYYD','DDMMYYN','DDMMYYP','DDMMYYS','DDMMYYx'
,'DOWNAME','E8601DA','E8601DA','JULDAY','JULIAN','MMDDYY','MMDDYYB'
,'MMDDYYC','MMDDYYD','MMDDYYN','MMDDYYP','MMDDYYS','MMDDYYx','MMYY'
,'MMYYC','MMYYD','MMYYN','MMYYP','MMYYS','MMYYx','MONNAME','MONTH'
,'MONYY','PDJULG','PDJULI','QTR','QTRR','WEEKDATE','WEEKDATX','WEEKDAY'
,'WEEKU','WEEKV','WEEKW','WORDDATE','WORDDATX','YEAR','YYMM','YYMMC'
,'YYMMD','YYMMDDB','YYMMDDC','YYMMDDD','YYMMDDN','YYMMDDP','YYMMDDS'
,'YYMMDDx','YYMMN','YYMMP','YYMMS','YYMMx','YYMON','YYQ','YYQC','YYQD'
,'YYQN','YYQP','YYQR','YYQRC','YYQRD','YYQRN','YYQRP','YYQRS','YYQRx'
,'YYQS','YYQx','YYQZ') then return('DATE');
else if fmt in ('TIME','B8601LZ','B8601LZ','B8601TM','B8601TM','B8601TZ'
,'B8601TZ','E8601LZ','E8601LZ','E8601TM','E8601TM','E8601TZ','E8601TZ'
,'HHMM','HOUR','MMSS','TIMEAMPM','TOD') then return('TIME');
else return('NUM');
end;
endsub;
%if &wrap=YES %then %do;
quit;
%end;
/* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat));
%end;
%mend mcf_getfmttype;

View File

@@ -32,12 +32,12 @@
> outa=3 outb=4 outc=5 outd=0 > outa=3 outb=4 outc=5 outd=0
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -49,12 +49,12 @@
**/ **/
%macro mcf_length(wrap=NO %macro mcf_length(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_length)=1 %then %return; %if %mcf_init(mcf_length)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -76,7 +76,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;

View File

@@ -47,12 +47,12 @@
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -64,12 +64,12 @@
**/ **/
%macro mcf_stpsrv_header(wrap=NO %macro mcf_stpsrv_header(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(stpsrv_header)=1 %then %return; %if %mcf_init(stpsrv_header)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -96,7 +96,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;

View File

@@ -32,12 +32,12 @@
run; run;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper. @param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
CMPLIB reference.
@param [out] lib= (work) The output library in which to create the catalog. @param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package. @param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function. @param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_init.sas @li mcf_init.sas
@@ -49,12 +49,12 @@
**/ **/
%macro mcf_string2file(wrap=NO %macro mcf_string2file(wrap=NO
,insert_cmplib=NO ,insert_cmplib=DEPRECATED
,lib=WORK ,lib=WORK
,cat=SASJS ,cat=SASJS
,pkg=UTILS ,pkg=UTILS
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(mcf_string2file)=1 %then %return; %if %mcf_init(mcf_string2file)=1 %then %return;
%if &wrap=YES %then %do; %if &wrap=YES %then %do;
@@ -81,7 +81,14 @@ endsub;
quit; quit;
%end; %end;
%if &insert_cmplib=YES %then %do; /* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat)); options insert=(CMPLIB=(&lib..&cat));
%end; %end;

View File

@@ -164,7 +164,7 @@ data _null_;
put ' %put &sysmacroname: Switching to DATASTEP engine; '; put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; '; put ' %goto datastep; ';
put ' %end; '; put ' %end; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
@@ -215,7 +215,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data &tempds/view=&tempds; '; put ' data &tempds; ';
put ' attrib _all_ label=''''; '; put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
@@ -277,8 +277,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop view &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' drop table &colinfo; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' data _null_; file &jref encoding=''utf-8'' mod; ';

View File

@@ -59,6 +59,7 @@
"tests/sas9only" "tests/sas9only"
], ],
"programFolders": [], "programFolders": [],
"binaryFolders": [],
"deployConfig": { "deployConfig": {
"deployServicePack": true, "deployServicePack": true,
"deployScripts": [] "deployScripts": []

View File

@@ -0,0 +1,39 @@
/**
@file
@brief Testing mcf_getfmttype.sas macro
<h4> SAS Macros </h4>
@li mcf_getfmttype.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%mp_assertscope(SNAPSHOT)
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
%mp_assertscope(COMPARE,ignorelist=SASJS_FUNCTIONS)
%mp_assert(
iftrue=(%sysfunc(mcf_getfmttype(DATE9.))=DATE),
desc=Check DATE format
)
%mp_assert(
iftrue=(%sysfunc(mcf_getfmttype($6))=CHAR),
desc=Check CHAR format
)
%mp_assert(
iftrue=(%sysfunc(mcf_getfmttype(8.))=NUM),
desc=Check NUM format
)
%mp_assert(
iftrue=(%sysfunc(mcf_getfmttype(E8601DT))=DATETIME),
desc=Check DATETIME format
)
/* test 2 - compile again test for warnings */
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
%mp_assert(
iftrue=(&syscc=0),
desc=Check syscc=0 after re-initialisation
)

View File

@@ -93,4 +93,74 @@ run;
iftrue=("&test3b"="PASS"), iftrue=("&test3b"="PASS"),
desc=Checking data row Test 3, desc=Checking data row Test 3,
outds=work.test_results outds=work.test_results
) )
/* test 4 - sasjs with compare */
filename example temp;
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
data _null_; infile example; input;put _infile_; if _n_>5 then stop;run;
data _null_;
infile example;
input;
call symputx('stmnt',_infile_);
stop;
run;
data work.want;
infile example dsd firstobs=2;
input &stmnt;
run;
%mp_assert(
iftrue=(&syscc =0),
desc=Checking syscc prior to compare of sashelp.air,
outds=work.test_results
)
proc compare base=want compare=sashelp.air;
run;
%mp_assert(
iftrue=(&sysinfo le 41),
desc=Checking compare of sashelp.air,
outds=work.test_results
)
/* test 5 - sasjs with time/datetime/date */
filename f2 temp;
data work.test5;
do x=1 to 5;
y=x;
z=x;
end;
format x date9. y datetime19. z time.;
run;
%mp_ds2csv(work.test5,outref=f2,headerformat=SASJS)
data _null_; infile example; input;put _infile_; if _n_>5 then stop;run;
data _null_;
infile f2;
input;
putlog _infile_;
call symputx('stmnt2',_infile_);
stop;
run;
data work.want5;
infile f2 dsd firstobs=2;
input &stmnt2;
putlog _infile_;
run;
%mp_assert(
iftrue=(&syscc=0),
desc=Checking syscc prior to compare of test5,
outds=work.test_results
)
proc compare base=want5 compare=work.test5;
run;
%mp_assert(
iftrue=(&sysinfo le 41),
desc=Checking compare of work.test5,
outds=work.test_results
)

View File

@@ -0,0 +1,28 @@
/**
@file
@brief Testing mp_streamfile.sas macro
@details This is tricky to test as it streams to webout. For now just
check the compilation, and for macro leakage.
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mp_assertscope.sas
@li mp_streamfile.sas
**/
%mp_assertscope(SNAPSHOT)
%mp_streamfile(iftrue=(1=0)
,contenttype=csv,inloc=/some/where.txt
,outname=myfile.txt
)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(&syscc=0),
desc=Checking error condition,
outds=work.test_results
)

View File

@@ -2,8 +2,18 @@
@file @file
@brief term file for tests @brief term file for tests
<h4> SAS Macros </h4>
@li mp_assert.sas
**/ **/
%mp_assert(
iftrue=(&syscc=0),
desc=Checking final error condition,
outds=work.test_results
)
%webout(OPEN) %webout(OPEN)
%webout(OBJ, TEST_RESULTS) %webout(OBJ, TEST_RESULTS)
%webout(CLOSE) %webout(CLOSE)

View File

@@ -308,7 +308,7 @@ data _null_;
put ' %put &sysmacroname: Switching to DATASTEP engine; '; put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; '; put ' %goto datastep; ';
put ' %end; '; put ' %end; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
@@ -359,7 +359,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data &tempds/view=&tempds; '; put ' data &tempds; ';
put ' attrib _all_ label=''''; '; put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
@@ -421,8 +421,7 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop view &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' drop table &colinfo; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' data _null_; file &jref encoding=''utf-8'' mod; ';