@sasjs/utils 2.48.2 → 2.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fs/generateCompileProgram.d.ts +1 -0
- package/fs/generateCompileProgram.js +154 -0
- package/fs/generateCompileProgram.js.map +1 -0
- package/fs/hash.d.ts +22 -0
- package/fs/hash.js +225 -0
- package/fs/hash.js.map +1 -0
- package/fs/index.d.ts +3 -0
- package/fs/index.js +13 -0
- package/fs/index.js.map +1 -0
- package/fs/internal/helper.d.ts +4 -0
- package/fs/internal/helper.js +125 -0
- package/fs/internal/helper.js.map +1 -0
- package/fs/sync.d.ts +6 -0
- package/fs/sync.js +208 -0
- package/fs/sync.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/macros/mf_abort.sas +27 -0
- package/macros/mf_dedup.sas +53 -0
- package/macros/mf_deletefile.sas +31 -0
- package/macros/mf_existds.sas +30 -0
- package/macros/mf_existfeature.sas +59 -0
- package/macros/mf_existfileref.sas +33 -0
- package/macros/mf_existfunction.sas +37 -0
- package/macros/mf_existvar.sas +39 -0
- package/macros/mf_existvarlist.sas +56 -0
- package/macros/mf_fmtdttm.sas +42 -0
- package/macros/mf_getapploc.sas +78 -0
- package/macros/mf_getattrc.sas +34 -0
- package/macros/mf_getattrn.sas +34 -0
- package/macros/mf_getengine.sas +54 -0
- package/macros/mf_getfilesize.sas +64 -0
- package/macros/mf_getfmtlist.sas +61 -0
- package/macros/mf_getfmtname.sas +44 -0
- package/macros/mf_getkeyvalue.sas +32 -0
- package/macros/mf_getplatform.sas +75 -0
- package/macros/mf_getquotedstr.sas +57 -0
- package/macros/mf_getschema.sas +43 -0
- package/macros/mf_getuniquefileref.sas +60 -0
- package/macros/mf_getuniquelibref.sas +57 -0
- package/macros/mf_getuniquename.sas +22 -0
- package/macros/mf_getuser.sas +44 -0
- package/macros/mf_getvalue.sas +36 -0
- package/macros/mf_getvarcount.sas +49 -0
- package/macros/mf_getvarformat.sas +72 -0
- package/macros/mf_getvarlen.sas +56 -0
- package/macros/mf_getvarlist.sas +74 -0
- package/macros/mf_getvarnum.sas +58 -0
- package/macros/mf_getvartype.sas +52 -0
- package/macros/mf_getxengine.sas +43 -0
- package/macros/mf_increment.sas +29 -0
- package/macros/mf_isblank.sas +27 -0
- package/macros/mf_isdir.sas +34 -0
- package/macros/mf_isint.sas +36 -0
- package/macros/mf_islibds.sas +40 -0
- package/macros/mf_loc.sas +29 -0
- package/macros/mf_mkdir.sas +67 -0
- package/macros/mf_mval.sas +19 -0
- package/macros/mf_nobs.sas +26 -0
- package/macros/mf_trimstr.sas +50 -0
- package/macros/mf_uid.sas +21 -0
- package/macros/mf_verifymacvars.sas +72 -0
- package/macros/mf_wordsinstr1andstr2.sas +53 -0
- package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
- package/macros/mf_writefile.sas +67 -0
- package/macros/mp_abort.sas +301 -0
- package/macros/mp_appendfile.sas +57 -0
- package/macros/mp_applyformats.sas +181 -0
- package/macros/mp_assert.sas +56 -0
- package/macros/mp_assertcols.sas +145 -0
- package/macros/mp_assertcolvals.sas +168 -0
- package/macros/mp_assertdsobs.sas +121 -0
- package/macros/mp_assertscope.sas +147 -0
- package/macros/mp_base64copy.sas +117 -0
- package/macros/mp_binarycopy.sas +79 -0
- package/macros/mp_chop.sas +194 -0
- package/macros/mp_cleancsv.sas +78 -0
- package/macros/mp_cntlout.sas +85 -0
- package/macros/mp_copyfolder.sas +84 -0
- package/macros/mp_coretable.sas +73 -0
- package/macros/mp_createconstraints.sas +70 -0
- package/macros/mp_createwebservice.sas +32 -0
- package/macros/mp_csv2ds.sas +140 -0
- package/macros/mp_deleteconstraints.sas +52 -0
- package/macros/mp_deletefolder.sas +70 -0
- package/macros/mp_dictionary.sas +52 -0
- package/macros/mp_dirlist.sas +263 -0
- package/macros/mp_distinctfmtvalues.sas +50 -0
- package/macros/mp_dropmembers.sas +46 -0
- package/macros/mp_ds2cards.sas +291 -0
- package/macros/mp_ds2csv.sas +212 -0
- package/macros/mp_ds2ddl.sas +30 -0
- package/macros/mp_ds2fmtds.sas +105 -0
- package/macros/mp_ds2inserts.sas +180 -0
- package/macros/mp_ds2md.sas +103 -0
- package/macros/mp_ds2squeeze.sas +120 -0
- package/macros/mp_dsmeta.sas +110 -0
- package/macros/mp_filtercheck.sas +251 -0
- package/macros/mp_filtergenerate.sas +105 -0
- package/macros/mp_filterstore.sas +254 -0
- package/macros/mp_filtervalidate.sas +105 -0
- package/macros/mp_getcols.sas +67 -0
- package/macros/mp_getconstraints.sas +115 -0
- package/macros/mp_getdbml.sas +335 -0
- package/macros/mp_getddl.sas +400 -0
- package/macros/mp_getformats.sas +124 -0
- package/macros/mp_getmaxvarlengths.sas +130 -0
- package/macros/mp_getpk.sas +281 -0
- package/macros/mp_gsubfile.sas +58 -0
- package/macros/mp_guesspk.sas +332 -0
- package/macros/mp_hashdataset.sas +91 -0
- package/macros/mp_hashdirectory.sas +162 -0
- package/macros/mp_include.sas +106 -0
- package/macros/mp_init.sas +76 -0
- package/macros/mp_jsonout.sas +406 -0
- package/macros/mp_lib2cards.sas +78 -0
- package/macros/mp_lib2inserts.sas +77 -0
- package/macros/mp_loadformat.sas +303 -0
- package/macros/mp_lockanytable.sas +243 -0
- package/macros/mp_lockfilecheck.sas +103 -0
- package/macros/mp_makedata.sas +107 -0
- package/macros/mp_md5.sas +58 -0
- package/macros/mp_perflog.sas +43 -0
- package/macros/mp_prevobs.sas +88 -0
- package/macros/mp_recursivejoin.sas +90 -0
- package/macros/mp_replace.sas +151 -0
- package/macros/mp_reseterror.sas +27 -0
- package/macros/mp_resetoption.sas +39 -0
- package/macros/mp_retainedkey.sas +247 -0
- package/macros/mp_runddl.sas +49 -0
- package/macros/mp_searchcols.sas +103 -0
- package/macros/mp_searchdata.sas +131 -0
- package/macros/mp_setkeyvalue.sas +55 -0
- package/macros/mp_sortinplace.sas +122 -0
- package/macros/mp_stackdiffs.sas +592 -0
- package/macros/mp_storediffs.sas +230 -0
- package/macros/mp_stprequests.sas +74 -0
- package/macros/mp_streamfile.sas +212 -0
- package/macros/mp_testjob.sas +92 -0
- package/macros/mp_testservice.sas +39 -0
- package/macros/mp_testwritespeedlibrary.sas +59 -0
- package/macros/mp_tree.sas +71 -0
- package/macros/mp_unzip.sas +90 -0
- package/macros/mp_updatevarlength.sas +93 -0
- package/macros/mp_validatecol.sas +97 -0
- package/macros/mp_wait4file.sas +35 -0
- package/macros/mp_webin.sas +59 -0
- package/macros/mp_zip.sas +85 -0
- package/package.json +5 -2
- package/scripts/copySASjsCore.ts +36 -0
- package/types/hash.d.ts +9 -0
- package/types/hash.js +3 -0
- package/types/hash.js.map +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/types/index.js.map +1 -1
- package/utils/index.d.ts +1 -1
- package/utils/index.js +2 -1
- package/utils/index.js.map +1 -1
- package/utils/utils.d.ts +1 -0
- package/utils/utils.js +7 -1
- package/utils/utils.js.map +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Copy any file using binary input / output streams
|
|
4
|
+
@details Reads in a file byte by byte and writes it back out. Is an
|
|
5
|
+
os-independent method to copy files. In case of naming collision, the
|
|
6
|
+
default filerefs can be modified.
|
|
7
|
+
Note that if you have a new enough version of SAS, and you don't need features
|
|
8
|
+
such as APPEND, you may be better of using the fcopy() function instead.
|
|
9
|
+
|
|
10
|
+
%mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout)
|
|
11
|
+
|
|
12
|
+
To append to a file, use the mode option, eg:
|
|
13
|
+
|
|
14
|
+
filename tmp1 temp;
|
|
15
|
+
filename tmp2 temp;
|
|
16
|
+
data _null_;
|
|
17
|
+
file tmp1;
|
|
18
|
+
put 'stacking';
|
|
19
|
+
run;
|
|
20
|
+
|
|
21
|
+
%mp_binarycopy(inref=tmp1, outref=tmp2, mode=APPEND)
|
|
22
|
+
%mp_binarycopy(inref=tmp1, outref=tmp2, mode=APPEND)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@param [in] inloc quoted "path/and/filename.ext" of the file to be copied
|
|
26
|
+
@param [out] outloc quoted "path/and/filename.ext" of the file to be created
|
|
27
|
+
@param [in] inref (____in) If provided, this fileref will take precedence over
|
|
28
|
+
the `inloc` parameter
|
|
29
|
+
@param [out] outref (____in) If provided, this fileref will take precedence
|
|
30
|
+
over the `outloc` parameter. It must already exist!
|
|
31
|
+
@param [in] mode (CREATE) Valid values:
|
|
32
|
+
@li CREATE - Create the file (even if it already exists)
|
|
33
|
+
@li APPEND - Append to the file (don't overwrite)
|
|
34
|
+
@param iftrue= (1=1) Supply a condition for which the macro should be executed
|
|
35
|
+
|
|
36
|
+
@returns nothing
|
|
37
|
+
|
|
38
|
+
@version 9.2
|
|
39
|
+
|
|
40
|
+
**/
|
|
41
|
+
|
|
42
|
+
%macro mp_binarycopy(
|
|
43
|
+
inloc= /* full path and filename of the object to be copied */
|
|
44
|
+
,outloc= /* full path and filename of object to be created */
|
|
45
|
+
,inref=____in /* override default to use own filerefs */
|
|
46
|
+
,outref=____out /* override default to use own filerefs */
|
|
47
|
+
,mode=CREATE
|
|
48
|
+
,iftrue=%str(1=1)
|
|
49
|
+
)/*/STORE SOURCE*/;
|
|
50
|
+
%local mod;
|
|
51
|
+
|
|
52
|
+
%if not(%eval(%unquote(&iftrue))) %then %return;
|
|
53
|
+
|
|
54
|
+
%if &mode=APPEND %then %let mod=mod;
|
|
55
|
+
|
|
56
|
+
/* these IN and OUT filerefs can point to anything */
|
|
57
|
+
%if &inref = ____in %then %do;
|
|
58
|
+
filename &inref &inloc lrecl=1048576 ;
|
|
59
|
+
%end;
|
|
60
|
+
%if &outref=____out %then %do;
|
|
61
|
+
filename &outref &outloc lrecl=1048576 &mod;
|
|
62
|
+
%end;
|
|
63
|
+
|
|
64
|
+
/* copy the file byte-for-byte */
|
|
65
|
+
data _null_;
|
|
66
|
+
infile &inref lrecl=1 recfm=n;
|
|
67
|
+
file &outref &mod recfm=n;
|
|
68
|
+
input sourcechar $char1. @@;
|
|
69
|
+
format sourcechar hex2.;
|
|
70
|
+
put sourcechar char1. @@;
|
|
71
|
+
run;
|
|
72
|
+
|
|
73
|
+
%if &inref = ____in %then %do;
|
|
74
|
+
filename &inref clear;
|
|
75
|
+
%end;
|
|
76
|
+
%if &outref=____out %then %do;
|
|
77
|
+
filename &outref clear;
|
|
78
|
+
%end;
|
|
79
|
+
%mend mp_binarycopy;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Splits a file of ANY SIZE by reference to a search string.
|
|
4
|
+
@details Provide a fileref and a search string to chop off part of a file.
|
|
5
|
+
|
|
6
|
+
Works by reading in the file byte by byte, then marking the beginning and end
|
|
7
|
+
of each matched string, before finally doing the chop.
|
|
8
|
+
|
|
9
|
+
Choose whether to keep the FIRST or the LAST section of the file. Optionally,
|
|
10
|
+
use an OFFSET to fix the precise chop point.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
|
|
14
|
+
%let src="%sysfunc(pathname(work))/file.txt";
|
|
15
|
+
%let str=Chop here!;
|
|
16
|
+
%let out1="%sysfunc(pathname(work))/file1.txt";
|
|
17
|
+
%let out2="%sysfunc(pathname(work))/file2.txt";
|
|
18
|
+
%let out3="%sysfunc(pathname(work))/file3.txt";
|
|
19
|
+
%let out4="%sysfunc(pathname(work))/file4.txt";
|
|
20
|
+
|
|
21
|
+
data _null_;
|
|
22
|
+
file &src;
|
|
23
|
+
put "startsection&str.endsection";
|
|
24
|
+
run;
|
|
25
|
+
|
|
26
|
+
%mp_chop(&src, matchvar=str, keep=FIRST, outfile=&out1)
|
|
27
|
+
%mp_chop(&src, matchvar=str, keep=LAST, outfile=&out2)
|
|
28
|
+
%mp_chop(&src, matchvar=str, keep=FIRST, matchpoint=END, outfile=&out3)
|
|
29
|
+
%mp_chop(&src, matchvar=str, keep=LAST, matchpoint=END, outfile=&out4)
|
|
30
|
+
|
|
31
|
+
filename results (&out1 &out2 &out3 &out4);
|
|
32
|
+
data _null_;
|
|
33
|
+
infile results;
|
|
34
|
+
input;
|
|
35
|
+
list;
|
|
36
|
+
run;
|
|
37
|
+
|
|
38
|
+
Results:
|
|
39
|
+
@li `startsection`
|
|
40
|
+
@li `Chop here!endsection`
|
|
41
|
+
@li `startsectionChop here!`
|
|
42
|
+
@li `endsection`
|
|
43
|
+
|
|
44
|
+
For more examples, see mp_chop.test.sas
|
|
45
|
+
|
|
46
|
+
@param [in] infile The QUOTED path to the file on which to perform the chop
|
|
47
|
+
@param [in] matchvar= Macro variable NAME containing the string to split by
|
|
48
|
+
@param [in] matchpoint= (START) Valid values:
|
|
49
|
+
@li START - chop at the beginning of the string in `matchvar`.
|
|
50
|
+
@li END - chop at the end of the string in `matchvar`.
|
|
51
|
+
@param [in] offset= (0) An adjustment to the precise chop location, by
|
|
52
|
+
by reference to the `matchpoint`. Should be a positive or negative integer.
|
|
53
|
+
@param [in] keep= (FIRST) Valid values:
|
|
54
|
+
@li FIRST - keep the section of the file before the chop
|
|
55
|
+
@li LAST - keep the section of the file after the chop
|
|
56
|
+
@param [in] mdebug= (0) Set to 1 to provide macro debugging
|
|
57
|
+
@param outfile= (0) Optional QUOTED path to the adjusted output file (avoids
|
|
58
|
+
overwriting the first file).
|
|
59
|
+
|
|
60
|
+
<h4> SAS Macros </h4>
|
|
61
|
+
@li mf_getuniquefileref.sas
|
|
62
|
+
@li mf_getuniquename.sas
|
|
63
|
+
|
|
64
|
+
<h4> Related Macros </h4>
|
|
65
|
+
@li mp_abort.sas
|
|
66
|
+
@li mp_gsubfile.sas
|
|
67
|
+
@li mp_replace.sas
|
|
68
|
+
@li mp_chop.test.sas
|
|
69
|
+
|
|
70
|
+
@version 9.4
|
|
71
|
+
@author Allan Bowe
|
|
72
|
+
|
|
73
|
+
**/
|
|
74
|
+
|
|
75
|
+
%macro mp_chop(infile,
|
|
76
|
+
matchvar=,
|
|
77
|
+
matchpoint=START,
|
|
78
|
+
keep=FIRST,
|
|
79
|
+
offset=0,
|
|
80
|
+
mdebug=0,
|
|
81
|
+
outfile=0
|
|
82
|
+
)/*/STORE SOURCE*/;
|
|
83
|
+
|
|
84
|
+
%local fref0 dttm ds1 outref;
|
|
85
|
+
%let fref0=%mf_getuniquefileref();
|
|
86
|
+
%let ds1=%mf_getuniquename(prefix=allchars);
|
|
87
|
+
%let ds2=%mf_getuniquename(prefix=startmark);
|
|
88
|
+
|
|
89
|
+
%if &outfile=0 %then %let outfile=&infile;
|
|
90
|
+
|
|
91
|
+
%mp_abort(iftrue= (%length(%superq(&matchvar))=0)
|
|
92
|
+
,mac=mp_chop.sas
|
|
93
|
+
,msg=%str(&matchvar is an empty variable)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
/* START */
|
|
97
|
+
%let dttm=%sysfunc(datetime());
|
|
98
|
+
|
|
99
|
+
filename &fref0 &infile lrecl=1 recfm=n;
|
|
100
|
+
|
|
101
|
+
/* create dataset with one char per row */
|
|
102
|
+
data &ds1;
|
|
103
|
+
infile &fref0;
|
|
104
|
+
input sourcechar $char1. @@;
|
|
105
|
+
format sourcechar hex2.;
|
|
106
|
+
run;
|
|
107
|
+
|
|
108
|
+
/* get start & stop position of first matchvar string (one row, two vars) */
|
|
109
|
+
data &ds2;
|
|
110
|
+
/* set find string to length in bytes to cover trailing spaces */
|
|
111
|
+
length string $ %length(%superq(&matchvar));
|
|
112
|
+
string =symget("&matchvar");
|
|
113
|
+
drop string;
|
|
114
|
+
|
|
115
|
+
firstchar=char(string,1);
|
|
116
|
+
findlen=lengthm(string); /* <- for trailing bytes */
|
|
117
|
+
|
|
118
|
+
do _N_=1 to nobs;
|
|
119
|
+
set &ds1 nobs=nobs point=_N_;
|
|
120
|
+
if sourcechar=firstchar then do;
|
|
121
|
+
pos=1;
|
|
122
|
+
s=0;
|
|
123
|
+
do point=_N_ to min(_N_ + findlen -1,nobs);
|
|
124
|
+
set &ds1 point=point;
|
|
125
|
+
if sourcechar=char(string, pos) then s + 1;
|
|
126
|
+
else goto _leave_;
|
|
127
|
+
pos+1;
|
|
128
|
+
end;
|
|
129
|
+
_leave_:
|
|
130
|
+
if s=findlen then do;
|
|
131
|
+
START =_N_;
|
|
132
|
+
_N_ =_N_+ s - 1;
|
|
133
|
+
STOP =_N_;
|
|
134
|
+
output;
|
|
135
|
+
/* matched! */
|
|
136
|
+
stop;
|
|
137
|
+
end;
|
|
138
|
+
end;
|
|
139
|
+
end;
|
|
140
|
+
stop;
|
|
141
|
+
keep START STOP;
|
|
142
|
+
run;
|
|
143
|
+
|
|
144
|
+
%local split;
|
|
145
|
+
%let split=0;
|
|
146
|
+
data _null_;
|
|
147
|
+
set &ds2;
|
|
148
|
+
if "&matchpoint"='START' then do;
|
|
149
|
+
if "&keep"='FIRST' then mp=start;
|
|
150
|
+
else if "&keep"='LAST' then mp=start-1;
|
|
151
|
+
end;
|
|
152
|
+
else if "&matchpoint"='END' then do;
|
|
153
|
+
if "&keep"='FIRST' then mp=stop+1;
|
|
154
|
+
else if "&keep"='LAST' then mp=stop;
|
|
155
|
+
end;
|
|
156
|
+
split=mp+&offset;
|
|
157
|
+
call symputx('split',split,'l');
|
|
158
|
+
%if &mdebug=1 %then %do;
|
|
159
|
+
put (_all_)(=);
|
|
160
|
+
%put &=offset;
|
|
161
|
+
%end;
|
|
162
|
+
run;
|
|
163
|
+
%if &split=0 %then %do;
|
|
164
|
+
%put &sysmacroname: No match found in &infile for string %superq(&matchvar);
|
|
165
|
+
%return;
|
|
166
|
+
%end;
|
|
167
|
+
|
|
168
|
+
data _null_;
|
|
169
|
+
file &outfile recfm=n;
|
|
170
|
+
set &ds1;
|
|
171
|
+
%if &keep=FIRST %then %do;
|
|
172
|
+
if _n_ ge &split then stop;
|
|
173
|
+
%end;
|
|
174
|
+
%else %do;
|
|
175
|
+
if _n_ gt &split;
|
|
176
|
+
%end;
|
|
177
|
+
put sourcechar char1.;
|
|
178
|
+
run;
|
|
179
|
+
|
|
180
|
+
%if &mdebug=0 %then %do;
|
|
181
|
+
filename &fref0 clear;
|
|
182
|
+
%end;
|
|
183
|
+
%else %do;
|
|
184
|
+
data _null_;
|
|
185
|
+
infile &outfile lrecl=32767;
|
|
186
|
+
input;
|
|
187
|
+
list;
|
|
188
|
+
if _n_>50 then stop;
|
|
189
|
+
run;
|
|
190
|
+
%end;
|
|
191
|
+
/* END */
|
|
192
|
+
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
|
|
193
|
+
|
|
194
|
+
%mend mp_chop;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Fixes embedded cr / lf / crlf in CSV
|
|
4
|
+
@details CSVs will sometimes contain lf or crlf within quotes (eg when
|
|
5
|
+
saved by excel). When the termstr is ALSO lf or crlf that can be tricky
|
|
6
|
+
to process using SAS defaults.
|
|
7
|
+
This macro converts any csv to follow the convention of a windows excel file,
|
|
8
|
+
applying CRLF line endings and converting embedded cr and crlf to lf.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
|
|
12
|
+
fileref mycsv "/path/your/csv";
|
|
13
|
+
%mp_cleancsv(in=mycsv,out=/path/new.csv)
|
|
14
|
+
|
|
15
|
+
@param in= (NOTPROVIDED) Provide path or fileref to input csv. If a period is
|
|
16
|
+
found, it is assumed to be a file.
|
|
17
|
+
@param out= (NOTPROVIDED) Output path or fileref to output csv. If a period
|
|
18
|
+
is found, it is assumed to be a file.
|
|
19
|
+
@param qchar= ('22'x) Quote char - hex code 22 is the double quote.
|
|
20
|
+
|
|
21
|
+
@version 9.2
|
|
22
|
+
@author Allan Bowe
|
|
23
|
+
@cond
|
|
24
|
+
**/
|
|
25
|
+
|
|
26
|
+
%macro mp_cleancsv(in=NOTPROVIDED,out=NOTPROVIDED,qchar='22'x);
|
|
27
|
+
%if "&in"="NOTPROVIDED" or "&out"="NOTPROVIDED" %then %do;
|
|
28
|
+
%put %str(ERR)OR: Please provide valid input (&in) & output (&out) locations;
|
|
29
|
+
%return;
|
|
30
|
+
%end;
|
|
31
|
+
|
|
32
|
+
/* presence of a period(.) indicates a physical location */
|
|
33
|
+
%if %index(&in,.) %then %let in="&in";
|
|
34
|
+
%if %index(&out,.) %then %let out="&out";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* convert all cr and crlf within quotes to lf
|
|
38
|
+
* convert all other cr or lf to crlf
|
|
39
|
+
*/
|
|
40
|
+
data _null_;
|
|
41
|
+
infile &in recfm=n ;
|
|
42
|
+
file &out recfm=n;
|
|
43
|
+
retain isq iscrlf 0 qchar &qchar;
|
|
44
|
+
input inchar $char1. ;
|
|
45
|
+
if inchar=qchar then isq = mod(isq+1,2);
|
|
46
|
+
if isq then do;
|
|
47
|
+
/* inside a quote change cr and crlf to lf */
|
|
48
|
+
if inchar='0D'x then do;
|
|
49
|
+
put '0A'x;
|
|
50
|
+
input inchar $char1.;
|
|
51
|
+
if inchar ne '0A'x then do;
|
|
52
|
+
put inchar $char1.;
|
|
53
|
+
if inchar=qchar then isq = mod(isq+1,2);
|
|
54
|
+
end;
|
|
55
|
+
end;
|
|
56
|
+
else put inchar $char1.;
|
|
57
|
+
end;
|
|
58
|
+
else do;
|
|
59
|
+
/* outside a quote, change cr and lf to crlf */
|
|
60
|
+
if inchar='0D'x then do;
|
|
61
|
+
crblank:
|
|
62
|
+
put '0D0A'x;
|
|
63
|
+
input inchar $char1.;
|
|
64
|
+
if inchar='0D'x then do;
|
|
65
|
+
/* multiple CR indicates CR formatted file with blank lines */
|
|
66
|
+
goto crblank;
|
|
67
|
+
end;
|
|
68
|
+
else if inchar ne '0A'x then do;
|
|
69
|
+
put inchar $char1.;
|
|
70
|
+
if inchar=qchar then isq = mod(isq+1,2);
|
|
71
|
+
end;
|
|
72
|
+
end;
|
|
73
|
+
else if inchar='0A'x then put '0D0A'x;
|
|
74
|
+
else put inchar $char1.;
|
|
75
|
+
end;
|
|
76
|
+
run;
|
|
77
|
+
%mend mp_cleancsv;
|
|
78
|
+
/** @endcond */
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_cntlout.sas
|
|
3
|
+
@brief Creates a cntlout dataset in a consistent format
|
|
4
|
+
@details The dataset produced by proc format in the cntlout option will vary
|
|
5
|
+
according to its contents.
|
|
6
|
+
|
|
7
|
+
When dealing with formats from an ETL perspective (eg in [Data Controller for
|
|
8
|
+
SAS](https://datacontroller.io)), it is important that the output dataset
|
|
9
|
+
has a consistent model (and compariable values).
|
|
10
|
+
|
|
11
|
+
This macro makes use of mddl_sas_cntlout.sas to provide the consistent model,
|
|
12
|
+
and will left-align the start and end values when dealing with numeric ranges
|
|
13
|
+
to enable consistency when checking for differences.
|
|
14
|
+
|
|
15
|
+
usage:
|
|
16
|
+
|
|
17
|
+
%mp_cntlout(libcat=yourlib.cat,cntlout=work.formatexport)
|
|
18
|
+
|
|
19
|
+
@param [in] libcat The library.catalog reference
|
|
20
|
+
@param [in] fmtlist= (0) provide a space separated list of specific formats to
|
|
21
|
+
extract
|
|
22
|
+
@param [in] iftrue= (1=1) A condition under which the macro should be executed
|
|
23
|
+
@param [out] cntlout= (work.fmtextract) Libds reference for the output dataset
|
|
24
|
+
|
|
25
|
+
<h4> SAS Macros </h4>
|
|
26
|
+
@li mddl_sas_cntlout.sas
|
|
27
|
+
@li mf_getuniquename.sas
|
|
28
|
+
|
|
29
|
+
<h4> Related Macros </h4>
|
|
30
|
+
@li mf_getvarformat.sas
|
|
31
|
+
@li mp_getformats.sas
|
|
32
|
+
@li mp_loadformat.sas
|
|
33
|
+
@li mp_ds2fmtds.sas
|
|
34
|
+
|
|
35
|
+
@version 9.2
|
|
36
|
+
@author Allan Bowe
|
|
37
|
+
@cond
|
|
38
|
+
**/
|
|
39
|
+
|
|
40
|
+
%macro mp_cntlout(
|
|
41
|
+
iftrue=(1=1)
|
|
42
|
+
,libcat=
|
|
43
|
+
,cntlout=work.fmtextract
|
|
44
|
+
,fmtlist=0
|
|
45
|
+
)/*/STORE SOURCE*/;
|
|
46
|
+
%local ddlds cntlds i;
|
|
47
|
+
|
|
48
|
+
%if not(%eval(%unquote(&iftrue))) %then %return;
|
|
49
|
+
|
|
50
|
+
%let ddlds=%mf_getuniquename();
|
|
51
|
+
%let cntlds=%mf_getuniquename();
|
|
52
|
+
|
|
53
|
+
%mddl_sas_cntlout(libds=&ddlds)
|
|
54
|
+
|
|
55
|
+
%if %index(&libcat,-)>0 and %scan(&libcat,2,-)=FC %then %do;
|
|
56
|
+
%let libcat=%scan(&libcat,1,-);
|
|
57
|
+
%end;
|
|
58
|
+
|
|
59
|
+
proc format lib=&libcat cntlout=&cntlds;
|
|
60
|
+
%if "&fmtlist" ne "0" %then %do;
|
|
61
|
+
select
|
|
62
|
+
%do i=1 %to %sysfunc(countw(&fmtlist));
|
|
63
|
+
%scan(&fmtlist,&i,%str( ))
|
|
64
|
+
%end;
|
|
65
|
+
;
|
|
66
|
+
%end;
|
|
67
|
+
run;
|
|
68
|
+
|
|
69
|
+
data &cntlout;
|
|
70
|
+
if 0 then set &ddlds;
|
|
71
|
+
set &cntlds;
|
|
72
|
+
if type="N" then do;
|
|
73
|
+
start=cats(start);
|
|
74
|
+
end=cats(end);
|
|
75
|
+
end;
|
|
76
|
+
run;
|
|
77
|
+
proc sort;
|
|
78
|
+
by fmtname start;
|
|
79
|
+
run;
|
|
80
|
+
|
|
81
|
+
proc sql;
|
|
82
|
+
drop table &ddlds,&cntlds;
|
|
83
|
+
|
|
84
|
+
%mend mp_cntlout;
|
|
85
|
+
/** @endcond */
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief A macro to recursively copy a directory
|
|
4
|
+
@details Performs a recursive directory listing then works from top to bottom
|
|
5
|
+
copying files and creating subdirectories.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
|
|
9
|
+
%let rootdir=%sysfunc(pathname(work))/demo;
|
|
10
|
+
%let copydir=%sysfunc(pathname(work))/demo_copy;
|
|
11
|
+
%mf_mkdir(&rootdir)
|
|
12
|
+
%mf_mkdir(&rootdir/subdir)
|
|
13
|
+
%mf_mkdir(&rootdir/subdir/subsubdir)
|
|
14
|
+
data "&rootdir/subdir/example.sas7bdat";
|
|
15
|
+
run;
|
|
16
|
+
|
|
17
|
+
%mp_copyfolder(&rootdir,©dir)
|
|
18
|
+
|
|
19
|
+
@param [in] source Unquoted path to the folder to copy from.
|
|
20
|
+
@param [out] target Unquoted path to the folder to copy to.
|
|
21
|
+
@param [in] copymax=(MAX) Set to a positive integer to indicate the level of
|
|
22
|
+
subdirectory copy recursion - eg 3, to go `./3/levels/deep`. For unlimited
|
|
23
|
+
recursion, set to MAX.
|
|
24
|
+
|
|
25
|
+
<h4> SAS Macros </h4>
|
|
26
|
+
@li mf_getuniquename.sas
|
|
27
|
+
@li mf_isdir.sas
|
|
28
|
+
@li mf_mkdir.sas
|
|
29
|
+
@li mp_abort.sas
|
|
30
|
+
@li mp_dirlist.sas
|
|
31
|
+
|
|
32
|
+
<h4> Related Macros </h4>
|
|
33
|
+
@li mp_copyfolder.test.sas
|
|
34
|
+
|
|
35
|
+
**/
|
|
36
|
+
|
|
37
|
+
%macro mp_copyfolder(source,target,copymax=MAX);
|
|
38
|
+
|
|
39
|
+
%mp_abort(iftrue=(%mf_isdir(&source)=0)
|
|
40
|
+
,mac=&sysmacroname
|
|
41
|
+
,msg=%str(Source dir does not exist (&source))
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
%mf_mkdir(&target)
|
|
45
|
+
|
|
46
|
+
%mp_abort(iftrue=(%mf_isdir(&target)=0)
|
|
47
|
+
,mac=&sysmacroname
|
|
48
|
+
,msg=%str(Target dir could not be created (&target))
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
/* prep temp table */
|
|
52
|
+
%local tempds;
|
|
53
|
+
%let tempds=%mf_getuniquename();
|
|
54
|
+
|
|
55
|
+
/* recursive directory listing */
|
|
56
|
+
%mp_dirlist(path=&source,outds=work.&tempds,maxdepth=©max)
|
|
57
|
+
|
|
58
|
+
/* create folders and copy content */
|
|
59
|
+
data _null_;
|
|
60
|
+
length msg $200;
|
|
61
|
+
call missing(msg);
|
|
62
|
+
set work.&tempds;
|
|
63
|
+
if _n_ = 1 then dpos+sum(length(directory),2);
|
|
64
|
+
filepath2="&target/"!!substr(filepath,dpos);
|
|
65
|
+
if file_or_folder='folder' then call execute('%mf_mkdir('!!filepath2!!')');
|
|
66
|
+
else do;
|
|
67
|
+
length fref1 fref2 $8;
|
|
68
|
+
rc1=filename(fref1,filepath,'disk','recfm=n');
|
|
69
|
+
rc2=filename(fref2,filepath2,'disk','recfm=n');
|
|
70
|
+
if fcopy(fref1,fref2) ne 0 then do;
|
|
71
|
+
msg=sysmsg();
|
|
72
|
+
putlog "%str(ERR)OR: Unable to copy " filepath " to " filepath2;
|
|
73
|
+
putlog msg=;
|
|
74
|
+
end;
|
|
75
|
+
end;
|
|
76
|
+
rc=filename(fref1);
|
|
77
|
+
rc=filename(fref2);
|
|
78
|
+
run;
|
|
79
|
+
|
|
80
|
+
/* tidy up */
|
|
81
|
+
proc sql;
|
|
82
|
+
drop table work.&tempds;
|
|
83
|
+
|
|
84
|
+
%mend mp_copyfolder;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Create the permanent Core tables
|
|
4
|
+
@details Several macros in the [core](https://github.com/sasjs/core) library
|
|
5
|
+
make use of permanent tables. To avoid duplication in definitions, this
|
|
6
|
+
macro provides a central location for managing the corresponding DDL.
|
|
7
|
+
|
|
8
|
+
Note - this macro is likely to be deprecated in future in favour of a
|
|
9
|
+
dedicated "datamodel" folder (prefix mddl)
|
|
10
|
+
|
|
11
|
+
Any corresponding data would go in a seperate repo, to avoid this one
|
|
12
|
+
ballooning in size!
|
|
13
|
+
|
|
14
|
+
Example usage:
|
|
15
|
+
|
|
16
|
+
%mp_coretable(LOCKTABLE,libds=work.locktable)
|
|
17
|
+
|
|
18
|
+
@param [in] table_ref The type of table to create. Example values:
|
|
19
|
+
@li DIFFTABLE
|
|
20
|
+
@li FILTER_DETAIL
|
|
21
|
+
@li FILTER_SUMMARY
|
|
22
|
+
@li LOCKANYTABLE
|
|
23
|
+
@li MAXKEYTABLE
|
|
24
|
+
@param [in] libds= (0) The library.dataset reference used to create the table.
|
|
25
|
+
If not provided, then the DDL is simply printed to the log.
|
|
26
|
+
|
|
27
|
+
<h4> SAS Macros </h4>
|
|
28
|
+
@li mddl_dc_difftable.sas
|
|
29
|
+
@li mddl_dc_filterdetail.sas
|
|
30
|
+
@li mddl_dc_filtersummary.sas
|
|
31
|
+
@li mddl_dc_locktable.sas
|
|
32
|
+
@li mddl_dc_maxkeytable.sas
|
|
33
|
+
@li mf_getuniquename.sas
|
|
34
|
+
|
|
35
|
+
<h4> Related Macros </h4>
|
|
36
|
+
@li mp_filterstore.sas
|
|
37
|
+
@li mp_lockanytable.sas
|
|
38
|
+
@li mp_retainedkey.sas
|
|
39
|
+
@li mp_storediffs.sas
|
|
40
|
+
@li mp_stackdiffs.sas
|
|
41
|
+
|
|
42
|
+
@version 9.2
|
|
43
|
+
@author Allan Bowe
|
|
44
|
+
|
|
45
|
+
**/
|
|
46
|
+
|
|
47
|
+
%macro mp_coretable(table_ref,libds=0
|
|
48
|
+
)/*/STORE SOURCE*/;
|
|
49
|
+
%local outds ;
|
|
50
|
+
%let outds=%sysfunc(ifc(&libds=0,%mf_getuniquename(),&libds));
|
|
51
|
+
proc sql;
|
|
52
|
+
%if &table_ref=DIFFTABLE %then %do;
|
|
53
|
+
%mddl_dc_difftable(libds=&outds)
|
|
54
|
+
%end;
|
|
55
|
+
%else %if &table_ref=LOCKTABLE %then %do;
|
|
56
|
+
%mddl_dc_locktable(libds=&outds)
|
|
57
|
+
%end;
|
|
58
|
+
%else %if &table_ref=FILTER_SUMMARY %then %do;
|
|
59
|
+
%mddl_dc_filtersummary(libds=&outds)
|
|
60
|
+
%end;
|
|
61
|
+
%else %if &table_ref=FILTER_DETAIL %then %do;
|
|
62
|
+
%mddl_dc_filterdetail(libds=&outds)
|
|
63
|
+
%end;
|
|
64
|
+
%else %if &table_ref=MAXKEYTABLE %then %do;
|
|
65
|
+
%mddl_dc_maxkeytable(libds=&outds)
|
|
66
|
+
%end;
|
|
67
|
+
|
|
68
|
+
%if &libds=0 %then %do;
|
|
69
|
+
proc sql;
|
|
70
|
+
describe table &syslast;
|
|
71
|
+
drop table &syslast;
|
|
72
|
+
%end;
|
|
73
|
+
%mend mp_coretable;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_createconstraints.sas
|
|
3
|
+
@brief Creates constraints
|
|
4
|
+
@details Takes the output from mp_getconstraints.sas as input
|
|
5
|
+
|
|
6
|
+
proc sql;
|
|
7
|
+
create table work.example(
|
|
8
|
+
TX_FROM float format=datetime19.,
|
|
9
|
+
DD_TYPE char(16),
|
|
10
|
+
DD_SOURCE char(2048),
|
|
11
|
+
DD_SHORTDESC char(256),
|
|
12
|
+
constraint pk primary key(tx_from, dd_type,dd_source),
|
|
13
|
+
constraint unq unique(tx_from, dd_type),
|
|
14
|
+
constraint nnn not null(DD_SHORTDESC)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
%mp_getconstraints(lib=work,ds=example,outds=work.constraints)
|
|
18
|
+
%mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES)
|
|
19
|
+
%mp_createconstraints(inds=work.constraints,outds=created,execute=YES)
|
|
20
|
+
|
|
21
|
+
@param inds= (work.mp_getconstraints) The input table containing the
|
|
22
|
+
constraint info
|
|
23
|
+
@param outds= (work.mp_createconstraints) A table containing the create
|
|
24
|
+
statements (create_statement column)
|
|
25
|
+
@param execute= (NO) To actually create, use YES.
|
|
26
|
+
|
|
27
|
+
<h4> Related Files </h4>
|
|
28
|
+
@li mp_getconstraints.sas
|
|
29
|
+
|
|
30
|
+
@version 9.2
|
|
31
|
+
@author Allan Bowe
|
|
32
|
+
|
|
33
|
+
**/
|
|
34
|
+
|
|
35
|
+
%macro mp_createconstraints(inds=mp_getconstraints
|
|
36
|
+
,outds=work.mp_createconstraints
|
|
37
|
+
,execute=NO
|
|
38
|
+
)/*/STORE SOURCE*/;
|
|
39
|
+
|
|
40
|
+
proc sort data=&inds out=&outds;
|
|
41
|
+
by libref table_name constraint_name;
|
|
42
|
+
run;
|
|
43
|
+
|
|
44
|
+
data &outds;
|
|
45
|
+
set &outds;
|
|
46
|
+
by libref table_name constraint_name;
|
|
47
|
+
length create_statement $500;
|
|
48
|
+
if _n_=1 and "&execute"="YES" then call execute('proc sql;');
|
|
49
|
+
if first.constraint_name then do;
|
|
50
|
+
if constraint_type='PRIMARY' then type='PRIMARY KEY';
|
|
51
|
+
else type=constraint_type;
|
|
52
|
+
create_statement=catx(" ","alter table",libref,".",table_name
|
|
53
|
+
,"add constraint",constraint_name,type,"(");
|
|
54
|
+
if last.constraint_name then
|
|
55
|
+
create_statement=cats(create_statement,column_name,");");
|
|
56
|
+
else create_statement=cats(create_statement,column_name,",");
|
|
57
|
+
if "&execute"="YES" then call execute(create_statement);
|
|
58
|
+
end;
|
|
59
|
+
else if last.constraint_name then do;
|
|
60
|
+
create_statement=cats(column_name,");");
|
|
61
|
+
if "&execute"="YES" then call execute(create_statement);
|
|
62
|
+
end;
|
|
63
|
+
else do;
|
|
64
|
+
create_statement=cats(column_name,",");
|
|
65
|
+
if "&execute"="YES" then call execute(create_statement);
|
|
66
|
+
end;
|
|
67
|
+
output;
|
|
68
|
+
run;
|
|
69
|
+
|
|
70
|
+
%mend mp_createconstraints;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_createwebservice.sas
|
|
3
|
+
@brief Create a web service in SAS 9, Viya or SASjs Server
|
|
4
|
+
@details This is actually a wrapper for mx_createwebservice.sas, remaining
|
|
5
|
+
for legacy purposes. For new apps, use mx_createwebservice.sas.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
<h4> SAS Macros </h4>
|
|
9
|
+
@li mx_createwebservice.sas
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
**/
|
|
13
|
+
|
|
14
|
+
%macro mp_createwebservice(path=HOME
|
|
15
|
+
,name=initService
|
|
16
|
+
,precode=
|
|
17
|
+
,code=ft15f001
|
|
18
|
+
,desc=This service was created by the mp_createwebservice macro
|
|
19
|
+
,replace=YES
|
|
20
|
+
,mdebug=0
|
|
21
|
+
)/*/STORE SOURCE*/;
|
|
22
|
+
|
|
23
|
+
%mx_createwebservice(path=&path
|
|
24
|
+
,name=&name
|
|
25
|
+
,precode=&precode
|
|
26
|
+
,code=&code
|
|
27
|
+
,desc=&desc
|
|
28
|
+
,replace=&replace
|
|
29
|
+
,mdebug=&mdebug
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
%mend mp_createwebservice;
|