1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-25 04:01:20 +00:00

Compare commits

...

15 Commits

Author SHA1 Message Date
Allan Bowe
a69db2ebfb Merge pull request #76 from sasjs/mp_appendfile
feat: mp_appendfile macro for appending 2 or more files together
2021-09-27 14:50:55 +03:00
Allan Bowe
d72ca7cb24 fix: warning in mp_assertcolvals from outobs sql option 2021-09-27 12:30:28 +01:00
Allan Bowe
52dfa7b8f7 feat: mp_appendfile macro for appending 2 or more files together 2021-09-27 11:46:19 +01:00
Allan Bowe
dae03c5730 fix: adding SYSSCPL to mp_abort and webout macros 2021-09-24 17:31:42 +01:00
Allan Bowe
14efe5d3fd chore: removing copyright notice (copy paste error) 2021-09-22 21:10:00 +01:00
Allan Bowe
653244d737 Merge pull request #75 from sasjs/mp_getcols
Mp getcols macro
2021-09-22 19:34:25 +03:00
Allan Bowe
086831b3f5 chore: updating all.sas 2021-09-22 17:20:02 +01:00
Allan Bowe
6eca585fc1 feat: new mp_getcols macro 2021-09-22 17:19:49 +01:00
Allan Bowe
f6ba36fc28 feat: adding more info to result description in mp_assertcolvals 2021-09-22 17:19:29 +01:00
Allan Bowe
7406288d79 fix: mp_gsubfile() now works with multiline files (and we have a multiline test to go with it) 2021-09-16 18:30:17 +01:00
Allan Bowe
2e7fcbe5b8 fix: prevening truncation of _debug in mp_abort.sas and more reliable way to fetch syswarningtext and syserrortext 2021-09-16 14:04:50 +01:00
Allan Bowe
3e7b9f8c14 chore: fixing example in header for mp_gsubfile() 2021-09-16 13:54:27 +01:00
Allan Bowe
e9189ccc06 Merge pull request #74 from sasjs/gsub
feat: adding mp_gsubfile.sas - a SAS macro that uses Lua to perform a…
2021-09-14 19:13:15 +03:00
Allan Bowe
8c00d715c2 chore: formatting 2021-09-14 16:08:30 +01:00
Allan Bowe
d47a369cdf feat: adding mp_gsubfile.sas - a SAS macro that uses Lua to perform a full text find and replace of an entire file. Not restricted by number of characters (only memory). IIncludes a test. 2021-09-14 16:07:12 +01:00
18 changed files with 675 additions and 17 deletions

262
all.sas
View File

@@ -1806,7 +1806,7 @@ Usage:
/* send response in SASjs JSON format */
data _null_;
file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 debug $8;
length msg $32767 ;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
@@ -1837,13 +1837,16 @@ Usage:
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
syserrortext=quote(trim(symget('syserrortext')));
put ",""SYSERRORTEXT"" : " syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
syswarningtext=quote(trim(symget('syswarningtext')));
put ",""SYSWARNINGTEXT"" : " syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
if debug ge '"131"' then put '>>weboutEND<<';
@@ -1853,7 +1856,7 @@ Usage:
%if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
data _null_;
putlog 'stpsrvset program error and syscc';
putlog 'stpsrvset program err and syscc';
rc=stpsrvset('program error', 0);
call symputx("syscc",0,"g");
run;
@@ -1899,6 +1902,62 @@ Usage:
%mend mp_abort;
/** @endcond *//**
@file
@brief Append (concatenate) two or more files.
@details Will append one more more `appendrefs` (filerefs) to a `baseref`.
Uses a binary mechanism, so will work with any file type. For that reason -
use with care! And supply your own trailing carriage returns in each file..
Usage:
filename tmp1 temp;
filename tmp2 temp;
filename tmp3 temp;
data _null_; file tmp1; put 'base file';
data _null_; file tmp2; put 'append1';
data _null_; file tmp3; put 'append2';
run;
%mp_appendfile(baseref=tmp1, appendrefs=tmp2 tmp3)
@param [in] baseref= Fileref of the base file (should exist)
@param [in] appendrefs= One or more filerefs to be appended to the base
fileref. Space separated.
@version 9.2
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mp_abort.sas
@li mp_binarycopy.sas
**/
%macro mp_appendfile(
baseref=0,
appendrefs=0
)/*/STORE SOURCE*/;
%mp_abort(iftrue= (&baseref=0)
,mac=&sysmacroname
,msg=%str(Baseref NOT specified!)
)
%mp_abort(iftrue= (&appendrefs=0)
,mac=&sysmacroname
,msg=%str(Appendrefs NOT specified!)
)
%local i;
%do i=1 %to %sysfunc(countw(&appendrefs));
%mp_abort(iftrue= (&syscc>0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc)
)
%mp_binarycopy(inref=%scan(&appendrefs,&i), outref=&baseref, mode=APPEND)
%end;
%mend mp_appendfile;/**
@file
@brief Generic assertion
@details Useful in the context of writing sasjs tests. The results of the
@@ -2129,6 +2188,7 @@ Usage:
<h4> SAS Macros </h4>
@li mf_existds.sas
@li mf_getuniquename.sas
@li mf_nobs.sas
@li mp_abort.sas
@@ -2214,6 +2274,26 @@ Usage:
select count(*) into: orig from &lib..&ds;
quit;
%local notfound tmp1 tmp2;
%let tmp1=%mf_getuniquename();
%let tmp2=%mf_getuniquename();
/* this is a bit convoluted - but using sql outobs=10 throws warnings */
proc sql noprint;
create view &tmp1 as
select distinct &col
from &lib..&ds
where &col not in (
select &ccol from &clib..&cds
);
data &tmp2;
set &tmp1;
if _n_>10 then stop;
run;
proc sql;
select distinct &col into: notfound separated by ' ' from &tmp2;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc after macro query)
@@ -2224,7 +2304,7 @@ Usage:
test_description=symget('desc');
test_result='FAIL';
test_comments="&sysmacroname: &lib..&ds..&col has &result values "
!!"not in &clib..&cds..&ccol ";
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
%if &test=ANYVAL %then %do;
if &result < &orig then test_result='PASS';
%end;
@@ -4228,6 +4308,70 @@ filename &fref1 clear;
%mend mp_filtervalidate;
/**
@file
@brief Creates a dataset with column metadata.
@details This macro takes the `proc contents` output and "tidies it up" in the
following ways:
@li Blank labels are filled in with column names
@li Formats are reconstructed with default values
@li Types such as DATE / TIME / DATETIME are inferred from the formats
Example usage:
%mp_getcols(sashelp.airline,outds=work.myds)
@param ds The dataset from which to obtain column metadata
@param outds= (work.cols) The output dataset to create. Sample data:
|NAME $|LENGTH 8|VARNUM 8|LABEL $|FORMAT $49|TYPE $1 |DDTYPE $|
|---|---|---|---|---|---|---|
|AIR|8|2|international airline travel (thousands)|8.|N|NUMERIC|
|DATE|8|1|DATE|MONYY.|N|DATE|
|REGION|3|3|REGION|$3.|C|CHARACTER|
<h4> Related Macros </h4>
@li mf_getvarlist.sas
@li mm_getcols.sas
@version 9.2
@author Allan Bowe
**/
%macro mp_getcols(ds, outds=work.cols);
proc contents noprint data=&ds
out=_data_ (keep=name type length label varnum format:);
run;
data &outds(keep=name type length varnum format label ddtype);
set &syslast(rename=(format=format2 type=type2));
name=upcase(name);
if type2=2 then do;
length format $49.;
if format2='' then format=cats('$',length,'.');
else if formatl=0 then format=cats(format2,'.');
else format=cats(format2,formatl,'.');
type='C';
ddtype='CHARACTER';
end;
else do;
if format2='' then format=cats(length,'.');
else if formatl=0 then format=cats(format2,'.');
else if formatd=0 then format=cats(format2,formatl,'.');
else format=cats(format2,formatl,'.',formatd);
type='N';
if format=:'DATETIME' then ddtype='DATETIME';
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
or format=:'MONYY'
then ddtype='DATE';
else if format=:'TIME' then ddtype='TIME';
else ddtype='NUMERIC';
end;
if label='' then label=name;
run;
%mend mp_getcols;/**
@file mp_getconstraints.sas
@brief Get constraint details at column level
@details Useful for capturing constraints before they are dropped / reapplied
@@ -5092,6 +5236,59 @@ create table &outds (rename=(
run;
%mend mp_getmaxvarlengths;/**
@file
@brief Performs a text substitution on a file
@details Makes use of the GSUB function in LUA to perform a text substitution
in a file - either in-place, or writing to a new location. The benefit of
using LUA is that the entire file can be loaded into a single variable,
thereby side stepping the 32767 character limit in a data step.
Usage:
%let file=%sysfunc(pathname(work))/file.txt;
%let str=replace/me;
%let rep=with/this;
data _null_;
file "&file";
put "&str";
run;
%mp_gsubfile(file=&file, patternvar=str, replacevar=rep)
data _null_;
infile "&file";
input;
list;
run;
@param file= (0) The file to perform the substitution on
@param patternvar= A macro variable containing the Lua
[pattern](https://www.lua.org/pil/20.2.html) to search for. Due to the use
of special (magic) characters in Lua patterns, it is safer to pass the NAME
of the macro variable containing the string, rather than the value itself.
@param replacevar= The name of the macro variable containing the replacement
_string_.
@param outfile= (0) The file to write the output to. If zero, then the file
is overwritten in-place.
<h4> SAS Macros </h4>
@li ml_gsubfile.sas
<h4> Related Macros </h4>
@li mp_gsubfile.test.sas
@version 9.4
@author Allan Bowe
**/
%macro mp_gsubfile(file=0,
patternvar=,
replacevar=,
outfile=0
)/*/STORE SOURCE*/;
%ml_gsubfile()
%mend mp_gsubfile;
/**
@file mp_guesspk.sas
@brief Guess the primary key of a table
@details Tries to guess the primary key of a table based on the following logic:
@@ -5975,14 +6172,14 @@ select distinct lowcase(memname)
We take the standard definition one step further by embedding the informat
in the table header row, like so:
|var1:$|var2:best.|var3:date9.|
|var1:$32|var2:best.|var3:date9.|
|---|---|---|
|some text|42|01JAN1960|
|blah|1|31DEC1999|
Which resolves to:
|var1:$|var2:best.|var3:date9.|
|var1:$32|var2:best.|var3:date9.|
|---|---|---|
|some text|42|01JAN1960|
|blah|1|31DEC1999|
@@ -7571,6 +7768,7 @@ alter table &libds modify &var char(&len);
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
**/
@@ -9930,6 +10128,7 @@ data _null_;
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
@@ -13425,6 +13624,7 @@ run;
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
@@ -14896,6 +15096,7 @@ data _null_;
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
@@ -18735,6 +18936,7 @@ filename &fref1 clear;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
@@ -18749,6 +18951,50 @@ filename &fref1 clear;
%end;
%mend mv_webout;
/**
@file ml_gsubfile.sas
@brief Compiles the gsubfile.lua lua file
@details Writes gsubfile.lua to the work directory
and then includes it.
Usage:
%ml_gsubfile()
**/
%macro ml_gsubfile();
data _null_;
file "%sysfunc(pathname(work))/ml_gsubfile.lua";
put 'local fpath, outpath, file, fcontent ';
put ' ';
put '-- configure in / out paths ';
put 'fpath = sas.symget("file") ';
put 'outpath = sas.symget("outfile") ';
put 'if ( outpath == 0 ) ';
put 'then ';
put ' outpath=fpath ';
put 'end ';
put ' ';
put '-- open file and perform the substitution ';
put 'file = io.open(fpath,"r") ';
put 'fcontent = file:read("*all") ';
put 'file:close() ';
put 'fcontent = string.gsub( ';
put ' fcontent, ';
put ' sas.symget(sas.symget("patternvar")), ';
put ' sas.symget(sas.symget("replacevar")) ';
put ') ';
put ' ';
put '-- write the file back out ';
put 'file = io.open(outpath, "w+") ';
put 'io.output(file) ';
put 'io.write(fcontent) ';
put 'io.close(file) ';
run;
%inc "%sysfunc(pathname(work))/ml_gsubfile.lua" /source2;
%mend ml_gsubfile;
/**
@file ml_json.sas
@brief Compiles the json.lua lua file
@@ -19140,7 +19386,7 @@ data _null_;
put '-- JSON.LUA ENDS HERE ';
run;
%inc "%sysfunc(pathname(work))/ml_json.lua";
%inc "%sysfunc(pathname(work))/ml_json.lua" /source2;
%mend ml_json;
/**

View File

@@ -158,7 +158,7 @@
/* send response in SASjs JSON format */
data _null_;
file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 debug $8;
length msg $32767 ;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
@@ -189,13 +189,16 @@
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
syserrortext=quote(trim(symget('syserrortext')));
put ",""SYSERRORTEXT"" : " syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
syswarningtext=quote(trim(symget('syswarningtext')));
put ",""SYSWARNINGTEXT"" : " syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
if debug ge '"131"' then put '>>weboutEND<<';
@@ -205,7 +208,7 @@
%if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
data _null_;
putlog 'stpsrvset program error and syscc';
putlog 'stpsrvset program err and syscc';
rc=stpsrvset('program error', 0);
call symputx("syscc",0,"g");
run;

57
base/mp_appendfile.sas Normal file
View File

@@ -0,0 +1,57 @@
/**
@file
@brief Append (concatenate) two or more files.
@details Will append one more more `appendrefs` (filerefs) to a `baseref`.
Uses a binary mechanism, so will work with any file type. For that reason -
use with care! And supply your own trailing carriage returns in each file..
Usage:
filename tmp1 temp;
filename tmp2 temp;
filename tmp3 temp;
data _null_; file tmp1; put 'base file';
data _null_; file tmp2; put 'append1';
data _null_; file tmp3; put 'append2';
run;
%mp_appendfile(baseref=tmp1, appendrefs=tmp2 tmp3)
@param [in] baseref= Fileref of the base file (should exist)
@param [in] appendrefs= One or more filerefs to be appended to the base
fileref. Space separated.
@version 9.2
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mp_abort.sas
@li mp_binarycopy.sas
**/
%macro mp_appendfile(
baseref=0,
appendrefs=0
)/*/STORE SOURCE*/;
%mp_abort(iftrue= (&baseref=0)
,mac=&sysmacroname
,msg=%str(Baseref NOT specified!)
)
%mp_abort(iftrue= (&appendrefs=0)
,mac=&sysmacroname
,msg=%str(Appendrefs NOT specified!)
)
%local i;
%do i=1 %to %sysfunc(countw(&appendrefs));
%mp_abort(iftrue= (&syscc>0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc)
)
%mp_binarycopy(inref=%scan(&appendrefs,&i), outref=&baseref, mode=APPEND)
%end;
%mend mp_appendfile;

View File

@@ -30,6 +30,7 @@
<h4> SAS Macros </h4>
@li mf_existds.sas
@li mf_getuniquename.sas
@li mf_nobs.sas
@li mp_abort.sas
@@ -115,6 +116,26 @@
select count(*) into: orig from &lib..&ds;
quit;
%local notfound tmp1 tmp2;
%let tmp1=%mf_getuniquename();
%let tmp2=%mf_getuniquename();
/* this is a bit convoluted - but using sql outobs=10 throws warnings */
proc sql noprint;
create view &tmp1 as
select distinct &col
from &lib..&ds
where &col not in (
select &ccol from &clib..&cds
);
data &tmp2;
set &tmp1;
if _n_>10 then stop;
run;
proc sql;
select distinct &col into: notfound separated by ' ' from &tmp2;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc after macro query)
@@ -125,7 +146,7 @@
test_description=symget('desc');
test_result='FAIL';
test_comments="&sysmacroname: &lib..&ds..&col has &result values "
!!"not in &clib..&cds..&ccol ";
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
%if &test=ANYVAL %then %do;
if &result < &orig then test_result='PASS';
%end;

65
base/mp_getcols.sas Normal file
View File

@@ -0,0 +1,65 @@
/**
@file
@brief Creates a dataset with column metadata.
@details This macro takes the `proc contents` output and "tidies it up" in the
following ways:
@li Blank labels are filled in with column names
@li Formats are reconstructed with default values
@li Types such as DATE / TIME / DATETIME are inferred from the formats
Example usage:
%mp_getcols(sashelp.airline,outds=work.myds)
@param ds The dataset from which to obtain column metadata
@param outds= (work.cols) The output dataset to create. Sample data:
|NAME $|LENGTH 8|VARNUM 8|LABEL $|FORMAT $49|TYPE $1 |DDTYPE $|
|---|---|---|---|---|---|---|
|AIR|8|2|international airline travel (thousands)|8.|N|NUMERIC|
|DATE|8|1|DATE|MONYY.|N|DATE|
|REGION|3|3|REGION|$3.|C|CHARACTER|
<h4> Related Macros </h4>
@li mf_getvarlist.sas
@li mm_getcols.sas
@version 9.2
@author Allan Bowe
**/
%macro mp_getcols(ds, outds=work.cols);
proc contents noprint data=&ds
out=_data_ (keep=name type length label varnum format:);
run;
data &outds(keep=name type length varnum format label ddtype);
set &syslast(rename=(format=format2 type=type2));
name=upcase(name);
if type2=2 then do;
length format $49.;
if format2='' then format=cats('$',length,'.');
else if formatl=0 then format=cats(format2,'.');
else format=cats(format2,formatl,'.');
type='C';
ddtype='CHARACTER';
end;
else do;
if format2='' then format=cats(length,'.');
else if formatl=0 then format=cats(format2,'.');
else if formatd=0 then format=cats(format2,formatl,'.');
else format=cats(format2,formatl,'.',formatd);
type='N';
if format=:'DATETIME' then ddtype='DATETIME';
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
or format=:'MONYY'
then ddtype='DATE';
else if format=:'TIME' then ddtype='TIME';
else ddtype='NUMERIC';
end;
if label='' then label=name;
run;
%mend mp_getcols;

53
base/mp_gsubfile.sas Normal file
View File

@@ -0,0 +1,53 @@
/**
@file
@brief Performs a text substitution on a file
@details Makes use of the GSUB function in LUA to perform a text substitution
in a file - either in-place, or writing to a new location. The benefit of
using LUA is that the entire file can be loaded into a single variable,
thereby side stepping the 32767 character limit in a data step.
Usage:
%let file=%sysfunc(pathname(work))/file.txt;
%let str=replace/me;
%let rep=with/this;
data _null_;
file "&file";
put "&str";
run;
%mp_gsubfile(file=&file, patternvar=str, replacevar=rep)
data _null_;
infile "&file";
input;
list;
run;
@param file= (0) The file to perform the substitution on
@param patternvar= A macro variable containing the Lua
[pattern](https://www.lua.org/pil/20.2.html) to search for. Due to the use
of special (magic) characters in Lua patterns, it is safer to pass the NAME
of the macro variable containing the string, rather than the value itself.
@param replacevar= The name of the macro variable containing the replacement
_string_.
@param outfile= (0) The file to write the output to. If zero, then the file
is overwritten in-place.
<h4> SAS Macros </h4>
@li ml_gsubfile.sas
<h4> Related Macros </h4>
@li mp_gsubfile.test.sas
@version 9.4
@author Allan Bowe
**/
%macro mp_gsubfile(file=0,
patternvar=,
replacevar=,
outfile=0
)/*/STORE SOURCE*/;
%ml_gsubfile()
%mend mp_gsubfile;

View File

@@ -14,14 +14,14 @@
We take the standard definition one step further by embedding the informat
in the table header row, like so:
|var1:$|var2:best.|var3:date9.|
|var1:$32|var2:best.|var3:date9.|
|---|---|---|
|some text|42|01JAN1960|
|blah|1|31DEC1999|
Which resolves to:
|var1:$|var2:best.|var3:date9.|
|var1:$32|var2:best.|var3:date9.|
|---|---|---|
|some text|42|01JAN1960|
|blah|1|31DEC1999|

View File

@@ -22,7 +22,7 @@ for file in files:
for line in infile:
ml.write(" put '" + line.rstrip().replace("'","''") + " ';\n")
ml.write("run;\n\n")
ml.write("%inc \"%sysfunc(pathname(work))/" + name + ".lua\";\n\n")
ml.write("%inc \"%sysfunc(pathname(work))/" + name + ".lua\" /source2;\n\n")
ml.write("%mend " + name + ";\n")
ml.close()

25
lua/gsubfile.lua Normal file
View File

@@ -0,0 +1,25 @@
local fpath, outpath, file, fcontent
-- configure in / out paths
fpath = sas.symget("file")
outpath = sas.symget("outfile")
if ( outpath == 0 )
then
outpath=fpath
end
-- open file and perform the substitution
file = io.open(fpath,"r")
fcontent = file:read("*all")
file:close()
fcontent = string.gsub(
fcontent,
sas.symget(sas.symget("patternvar")),
sas.symget(sas.symget("replacevar"))
)
-- write the file back out
file = io.open(outpath, "w+")
io.output(file)
io.write(fcontent)
io.close(file)

44
lua/ml_gsubfile.sas Normal file
View File

@@ -0,0 +1,44 @@
/**
@file ml_gsubfile.sas
@brief Compiles the gsubfile.lua lua file
@details Writes gsubfile.lua to the work directory
and then includes it.
Usage:
%ml_gsubfile()
**/
%macro ml_gsubfile();
data _null_;
file "%sysfunc(pathname(work))/ml_gsubfile.lua";
put 'local fpath, outpath, file, fcontent ';
put ' ';
put '-- configure in / out paths ';
put 'fpath = sas.symget("file") ';
put 'outpath = sas.symget("outfile") ';
put 'if ( outpath == 0 ) ';
put 'then ';
put ' outpath=fpath ';
put 'end ';
put ' ';
put '-- open file and perform the substitution ';
put 'file = io.open(fpath,"r") ';
put 'fcontent = file:read("*all") ';
put 'file:close() ';
put 'fcontent = string.gsub( ';
put ' fcontent, ';
put ' sas.symget(sas.symget("patternvar")), ';
put ' sas.symget(sas.symget("replacevar")) ';
put ') ';
put ' ';
put '-- write the file back out ';
put 'file = io.open(outpath, "w+") ';
put 'io.output(file) ';
put 'io.write(fcontent) ';
put 'io.close(file) ';
run;
%inc "%sysfunc(pathname(work))/ml_gsubfile.lua" /source2;
%mend ml_gsubfile;

View File

@@ -389,6 +389,6 @@ data _null_;
put '-- JSON.LUA ENDS HERE ';
run;
%inc "%sysfunc(pathname(work))/ml_json.lua";
%inc "%sysfunc(pathname(work))/ml_json.lua" /source2;
%mend ml_json;

View File

@@ -385,6 +385,7 @@ data _null_;
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';

View File

@@ -155,6 +155,7 @@
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;

View File

@@ -0,0 +1,41 @@
/**
@file
@brief Testing mp_appendfile.sas macro
<h4> SAS Macros </h4>
@li mp_appendfile.sas
@li mp_assert.sas
**/
filename tmp1 temp;
filename tmp2 temp;
filename tmp3 temp;
data _null_; file tmp1; put 'base file';
data _null_; file tmp2; put 'append1';
data _null_; file tmp3; put 'append2';
run;
%mp_appendfile(baseref=tmp1, appendrefs=tmp2 tmp3)
data _null_;
infile tmp1;
input;
put _infile_;
call symputx(cats('check',_n_),_infile_);
run;
%global check1 check2 check3;
%mp_assert(
iftrue=("&check1"="base file"),
desc=Line 1 of file tmp1 is correct,
outds=work.test_results
)
%mp_assert(
iftrue=("&check2"="append1"),
desc=Line 2 of file tmp1 is correct,
outds=work.test_results
)
%mp_assert(
iftrue=("&check3"="append2"),
desc=Line 3 of file tmp1 is correct,
outds=work.test_results
)

View File

@@ -0,0 +1,33 @@
/**
@file
@brief Testing mp_getcols macro
<h4> SAS Macros </h4>
@li mp_getcols.sas
@li mp_assertcolvals.sas
@li mp_assertdsobs.sas
**/
/* valid filter */
%mp_getcols(sashelp.airline,outds=work.info)
%mp_assertdsobs(work.info,
desc=Has 3 records,
test=EQUALS 3,
outds=work.test_results
)
data work.check;
length val $10;
do val='NUMERIC','DATE','CHARACTER';
output;
end;
run;
%mp_assertcolvals(work.info.ddtype,
checkvals=work.check.val,
desc=All values have a match,
test=ALLVALS
)

View File

@@ -0,0 +1,66 @@
/**
@file
@brief Testing mp_gsubfile.sas macro
<h4> SAS Macros </h4>
@li mp_gsubfile.sas
@li mp_assert.sas
**/
/**
* test 1 - simple replace
*/
%global str1;
%let file=%sysfunc(pathname(work))/file.txt;
%let pat=replace/me;
%let str=with/this;
data _null_;
file "&file";
put "&pat";
run;
%mp_gsubfile(file=&file, patternvar=pat, replacevar=str)
data _null_;
infile "&file";
input;
call symputx('str1',_infile_);
run;
%mp_assert(
iftrue=("&str1"="&str"),
desc=Check that simple replacement was successful,
outds=work.test_results
)
/**
* test 2 - replace from additional line
*/
%global str2 strcheck2 strcheck2b;
%let file2=%sysfunc(pathname(work))/file2.txt;
%let pat2=replace/me;
%let str2=with/this;
data _null_;
file "&file2";
put 'line1';output;
put "&pat2";output;
put "&pat2";output;
run;
%mp_gsubfile(file=&file2, patternvar=pat2, replacevar=str2)
data _null_;
infile "&file2";
input;
if _n_=2 then call symputx('strcheck2',_infile_);
if _n_=3 then call symputx('strcheck2b',_infile_);
putlog _infile_;
run;
%mp_assert(
iftrue=("&strcheck2"="&str2"),
desc=Check that multi line replacement was successful (line2),
outds=work.test_results
)
%mp_assert(
iftrue=("&strcheck2b"="&str2"),
desc=Check that multi line replacement was successful (line3),
outds=work.test_results
)

View File

@@ -590,6 +590,7 @@ data _null_;
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';

View File

@@ -215,6 +215,7 @@
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;