@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,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_csv2ds.sas
|
|
3
|
+
@brief Efficient import of arbitrary CSV using a dataset as template
|
|
4
|
+
@details Used to import relevant columns from a large CSV using
|
|
5
|
+
a dataset to provide the types and lengths. Assumes that a header
|
|
6
|
+
row is provided, and datarows start on line 2. Extra columns in
|
|
7
|
+
both the CSV and base dataset are ignored.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
|
|
11
|
+
filename mycsv temp;
|
|
12
|
+
data _null_;
|
|
13
|
+
file mycsv;
|
|
14
|
+
put 'name,age,nickname';
|
|
15
|
+
put 'John,48,Jonny';
|
|
16
|
+
put 'Jennifer,23,Jen';
|
|
17
|
+
run;
|
|
18
|
+
|
|
19
|
+
%mp_csv2ds(inref=mycsv,outds=myds,baseds=sashelp.class)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@param inref= fileref to the CSV
|
|
23
|
+
@param outds= output ds (lib.ds format)
|
|
24
|
+
@param view= Set to YES or NO to determine whether the output should be
|
|
25
|
+
a view or not. Default is NO (not a view).
|
|
26
|
+
@param baseds= Template dataset on which to create the input statement.
|
|
27
|
+
Is used to determine types, lengths, and any informats.
|
|
28
|
+
|
|
29
|
+
@version 9.2
|
|
30
|
+
@author Allan Bowe
|
|
31
|
+
|
|
32
|
+
<h4> SAS Macros </h4>
|
|
33
|
+
@li mp_abort.sas
|
|
34
|
+
@li mf_existds.sas
|
|
35
|
+
|
|
36
|
+
**/
|
|
37
|
+
|
|
38
|
+
%macro mp_csv2ds(inref=0,outds=0,baseds=0,view=NO);
|
|
39
|
+
|
|
40
|
+
%mp_abort(iftrue=( &inref=0 )
|
|
41
|
+
,mac=&sysmacroname
|
|
42
|
+
,msg=%str(the INREF variable must be provided)
|
|
43
|
+
)
|
|
44
|
+
%mp_abort(iftrue=( %superq(outds)=0 )
|
|
45
|
+
,mac=&sysmacroname
|
|
46
|
+
,msg=%str(the OUTDS variable must be provided)
|
|
47
|
+
)
|
|
48
|
+
%mp_abort(iftrue=( &baseds=0 )
|
|
49
|
+
,mac=&sysmacroname
|
|
50
|
+
,msg=%str(the BASEDS variable must be provided)
|
|
51
|
+
)
|
|
52
|
+
%mp_abort(iftrue=( %mf_existds(&baseds)=0 )
|
|
53
|
+
,mac=&sysmacroname
|
|
54
|
+
,msg=%str(the BASEDS dataset (&baseds) needs to be assigned, and to exist)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
/* count rows */
|
|
58
|
+
%local hasheader; %let hasheader=0;
|
|
59
|
+
data _null_;
|
|
60
|
+
if _N_ > 1 then do;
|
|
61
|
+
call symputx('hasheader',1,'l');
|
|
62
|
+
stop;
|
|
63
|
+
end;
|
|
64
|
+
infile &inref;
|
|
65
|
+
input;
|
|
66
|
+
run;
|
|
67
|
+
%mp_abort(iftrue=( &hasheader=0 )
|
|
68
|
+
,mac=&sysmacroname
|
|
69
|
+
,msg=%str(No header row in &inref)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
/* get the variables in the CSV */
|
|
73
|
+
data _data_;
|
|
74
|
+
infile &inref;
|
|
75
|
+
input;
|
|
76
|
+
length name $32;
|
|
77
|
+
do i=1 to countc(_infile_,',')+1;
|
|
78
|
+
name=upcase(scan(_infile_,i,','));
|
|
79
|
+
output;
|
|
80
|
+
end;
|
|
81
|
+
stop;
|
|
82
|
+
run;
|
|
83
|
+
%local csv_vars;%let csv_vars=&syslast;
|
|
84
|
+
|
|
85
|
+
/* get the variables in the dataset */
|
|
86
|
+
proc contents noprint data=&baseds
|
|
87
|
+
out=_data_ (keep=name type length format: informat);
|
|
88
|
+
run;
|
|
89
|
+
%local base_vars; %let base_vars=&syslast;
|
|
90
|
+
|
|
91
|
+
proc sql undo_policy=none;
|
|
92
|
+
create table &csv_vars as
|
|
93
|
+
select a.*
|
|
94
|
+
,b.type
|
|
95
|
+
,b.length
|
|
96
|
+
,b.format
|
|
97
|
+
,b.formatd
|
|
98
|
+
,b.formatl
|
|
99
|
+
,b.informat
|
|
100
|
+
from &csv_vars a
|
|
101
|
+
left join &base_vars b
|
|
102
|
+
on a.name=upcase(b.name)
|
|
103
|
+
order by i;
|
|
104
|
+
|
|
105
|
+
/* prepare the input statement */
|
|
106
|
+
%local instat dropvars;
|
|
107
|
+
data _null_;
|
|
108
|
+
set &syslast end=last;
|
|
109
|
+
length in dropvars $32767;
|
|
110
|
+
retain in dropvars;
|
|
111
|
+
if missing(type) then do;
|
|
112
|
+
informat='$1.';
|
|
113
|
+
dropvars=catx(' ',dropvars,name);
|
|
114
|
+
end;
|
|
115
|
+
else if missing(informat) then do;
|
|
116
|
+
if type=1 then informat='best.';
|
|
117
|
+
else informat=cats('$',length,'.');
|
|
118
|
+
end;
|
|
119
|
+
else informat=cats(informat,'.');
|
|
120
|
+
in=catx(' ',in,name,':',informat);
|
|
121
|
+
if last then do;
|
|
122
|
+
call symputx('instat',in,'l');
|
|
123
|
+
call symputx('dropvars',dropvars,'l');
|
|
124
|
+
end;
|
|
125
|
+
run;
|
|
126
|
+
|
|
127
|
+
/* import the CSV */
|
|
128
|
+
data &outds
|
|
129
|
+
%if %upcase(&view)=YES %then %do;
|
|
130
|
+
/view=&outds
|
|
131
|
+
%end;
|
|
132
|
+
;
|
|
133
|
+
infile &inref dsd firstobs=2;
|
|
134
|
+
input &instat;
|
|
135
|
+
%if %length(&dropvars)>0 %then %do;
|
|
136
|
+
drop &dropvars;
|
|
137
|
+
%end;
|
|
138
|
+
run;
|
|
139
|
+
|
|
140
|
+
%mend mp_csv2ds;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_deleteconstraints.sas
|
|
3
|
+
@brief Delete constraionts
|
|
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
|
+
|
|
20
|
+
@param inds= The input table containing the constraint info
|
|
21
|
+
@param outds= a table containing the drop statements (drop_statement column)
|
|
22
|
+
@param execute= `YES|NO` - default is NO. To actually drop, use YES.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@version 9.2
|
|
26
|
+
@author Allan Bowe
|
|
27
|
+
|
|
28
|
+
**/
|
|
29
|
+
|
|
30
|
+
%macro mp_deleteconstraints(inds=mp_getconstraints
|
|
31
|
+
,outds=mp_deleteconstraints
|
|
32
|
+
,execute=NO
|
|
33
|
+
)/*/STORE SOURCE*/;
|
|
34
|
+
|
|
35
|
+
proc sort data=&inds out=&outds;
|
|
36
|
+
by libref table_name constraint_name;
|
|
37
|
+
run;
|
|
38
|
+
|
|
39
|
+
data &outds;
|
|
40
|
+
set &outds;
|
|
41
|
+
by libref table_name constraint_name;
|
|
42
|
+
length drop_statement $500;
|
|
43
|
+
if _n_=1 and "&execute"="YES" then call execute('proc sql;');
|
|
44
|
+
if first.constraint_name then do;
|
|
45
|
+
drop_statement=catx(" ","alter table",libref,".",table_name
|
|
46
|
+
,"drop constraint",constraint_name,";");
|
|
47
|
+
output;
|
|
48
|
+
if "&execute"="YES" then call execute(drop_statement);
|
|
49
|
+
end;
|
|
50
|
+
run;
|
|
51
|
+
|
|
52
|
+
%mend mp_deleteconstraints;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief A macro to delete a directory
|
|
4
|
+
@details Will delete all folder content (including subfolder content) and
|
|
5
|
+
finally, the folder itself.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
|
|
9
|
+
%let rootdir=%sysfunc(pathname(work))/demo;
|
|
10
|
+
%mf_mkdir(&rootdir)
|
|
11
|
+
%mf_mkdir(&rootdir/subdir)
|
|
12
|
+
%mf_mkdir(&rootdir/subdir/subsubdir)
|
|
13
|
+
data "&rootdir/subdir/example.sas7bdat";
|
|
14
|
+
run;
|
|
15
|
+
|
|
16
|
+
%mp_deletefolder(&rootdir)
|
|
17
|
+
|
|
18
|
+
@param path Unquoted path to the folder to delete.
|
|
19
|
+
|
|
20
|
+
<h4> SAS Macros </h4>
|
|
21
|
+
@li mf_getuniquename.sas
|
|
22
|
+
@li mf_isdir.sas
|
|
23
|
+
@li mp_dirlist.sas
|
|
24
|
+
|
|
25
|
+
<h4> Related Macros </h4>
|
|
26
|
+
@li mp_deletefolder.test.sas
|
|
27
|
+
|
|
28
|
+
**/
|
|
29
|
+
|
|
30
|
+
%macro mp_deletefolder(folder);
|
|
31
|
+
/* proceed if valid directory */
|
|
32
|
+
%if %mf_isdir(&folder)=1 %then %do;
|
|
33
|
+
|
|
34
|
+
/* prep temp table */
|
|
35
|
+
%local tempds;
|
|
36
|
+
%let tempds=%mf_getuniquename();
|
|
37
|
+
|
|
38
|
+
/* recursive directory listing */
|
|
39
|
+
%mp_dirlist(path=&folder,outds=work.&tempds, maxdepth=MAX)
|
|
40
|
+
|
|
41
|
+
/* sort descending level so can delete folder contents before folders */
|
|
42
|
+
proc sort data=work.&tempds;
|
|
43
|
+
by descending level;
|
|
44
|
+
run;
|
|
45
|
+
|
|
46
|
+
/* ensure top level folder is removed at the end */
|
|
47
|
+
proc sql;
|
|
48
|
+
insert into work.&tempds set filepath="&folder";
|
|
49
|
+
|
|
50
|
+
/* delete everything */
|
|
51
|
+
data _null_;
|
|
52
|
+
set work.&tempds end=last;
|
|
53
|
+
length fref $8;
|
|
54
|
+
fref='';
|
|
55
|
+
rc=filename(fref,filepath);
|
|
56
|
+
rc=fdelete(fref);
|
|
57
|
+
if rc then do;
|
|
58
|
+
msg=sysmsg();
|
|
59
|
+
put "&sysmacroname:" / rc= / msg= / filepath=;
|
|
60
|
+
end;
|
|
61
|
+
rc=filename(fref);
|
|
62
|
+
run;
|
|
63
|
+
|
|
64
|
+
/* tidy up */
|
|
65
|
+
proc sql;
|
|
66
|
+
drop table work.&tempds;
|
|
67
|
+
|
|
68
|
+
%end;
|
|
69
|
+
%else %put &sysmacroname: &folder: is not a valid / accessible folder. ;
|
|
70
|
+
%mend mp_deletefolder;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_dictionary.sas
|
|
3
|
+
@brief Creates a portal (libref) into the SQL Dictionary Views
|
|
4
|
+
@details Provide a libref and the macro will create a series of views against
|
|
5
|
+
each view in the special PROC SQL dictionary libref.
|
|
6
|
+
|
|
7
|
+
This is useful if you would like to visualise (navigate) the views in a SAS
|
|
8
|
+
client such as Base SAS, Enterprise Guide, or Studio (or [Data Controller](
|
|
9
|
+
https://datacontroller.io)).
|
|
10
|
+
|
|
11
|
+
It works by extracting the dictionary.dictionaries view into
|
|
12
|
+
YOURLIB.dictionaries, then uses that to create a YOURLIB.{viewName} for every
|
|
13
|
+
other dictionary.view, eg:
|
|
14
|
+
|
|
15
|
+
proc sql;
|
|
16
|
+
create view YOURLIB.columns as select * from dictionary.columns;
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
|
|
20
|
+
libname demo "/lib/directory";
|
|
21
|
+
%mp_dictionary(lib=demo)
|
|
22
|
+
|
|
23
|
+
Or, to just create them in WORK:
|
|
24
|
+
|
|
25
|
+
%mp_dictionary()
|
|
26
|
+
|
|
27
|
+
If you'd just like to browse the dictionary data model, you can also check
|
|
28
|
+
out [this article](https://rawsas.com/dictionary-of-dictionaries/).
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
@param lib= (WORK) The libref in which to create the views
|
|
33
|
+
|
|
34
|
+
<h4> Related Files </h4>
|
|
35
|
+
@li mp_dictionary.test.sas
|
|
36
|
+
|
|
37
|
+
@version 9.2
|
|
38
|
+
@author Allan Bowe
|
|
39
|
+
|
|
40
|
+
**/
|
|
41
|
+
|
|
42
|
+
%macro mp_dictionary(lib=WORK)/*/STORE SOURCE*/;
|
|
43
|
+
%local list i mem;
|
|
44
|
+
proc sql noprint;
|
|
45
|
+
create view &lib..dictionaries as select * from dictionary.dictionaries;
|
|
46
|
+
select distinct memname into: list separated by ' ' from &lib..dictionaries;
|
|
47
|
+
%do i=1 %to %sysfunc(countw(&list,%str( )));
|
|
48
|
+
%let mem=%scan(&list,&i,%str( ));
|
|
49
|
+
create view &lib..&mem as select * from dictionary.&mem;
|
|
50
|
+
%end;
|
|
51
|
+
quit;
|
|
52
|
+
%mend mp_dictionary;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Returns all files and subdirectories within a specified parent
|
|
4
|
+
@details When used with getattrs=NO, is not OS specific (uses dopen / dread).
|
|
5
|
+
|
|
6
|
+
Credit for the rename approach:
|
|
7
|
+
https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-convert-string-to-Legal-SAS-Name/m-p/27375/highlight/true#M5003
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
|
|
11
|
+
%mp_dirlist(path=/some/location, outds=myTable, maxdepth=MAX)
|
|
12
|
+
|
|
13
|
+
%mp_dirlist(outds=cwdfileprops, getattrs=YES)
|
|
14
|
+
|
|
15
|
+
%mp_dirlist(fref=MYFREF)
|
|
16
|
+
|
|
17
|
+
@warning In a Unix environment, the existence of a named pipe will cause this
|
|
18
|
+
macro to hang. Therefore this tool should be used with caution in a SAS 9 web
|
|
19
|
+
application, as it can use up all available multibridge sessions if requests
|
|
20
|
+
are resubmitted.
|
|
21
|
+
If anyone finds a way to positively identify a named pipe using SAS (without
|
|
22
|
+
X CMD) do please raise an issue!
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@param [in] path= (%sysfunc(pathname(work))) Path for which to return contents
|
|
26
|
+
@param [in] fref= (0) Provide a DISK engine fileref as an alternative to PATH
|
|
27
|
+
@param [in] maxdepth= (0) Set to a positive integer to indicate the level of
|
|
28
|
+
subdirectory scan recursion - eg 3, to go `./3/levels/deep`. For unlimited
|
|
29
|
+
recursion, set to MAX.
|
|
30
|
+
@param [in] showparent= (NO) By default, the initial parent directory is not
|
|
31
|
+
part of the results. Set to YES to include it. For this record only,
|
|
32
|
+
directory=filepath.
|
|
33
|
+
@param [out] outds= (work.mp_dirlist) The output dataset to create
|
|
34
|
+
@param [out] getattrs= (NO) If getattrs=YES then the doptname / foptname
|
|
35
|
+
functions are used to scan all properties - any characters that are not
|
|
36
|
+
valid in a SAS name (v7) are simply stripped, and the table is transposed
|
|
37
|
+
so theat each property is a column and there is one file per row. An
|
|
38
|
+
attempt is made to get all properties whether a file or folder, but some
|
|
39
|
+
files/folders cannot be accessed, and so not all properties can / will be
|
|
40
|
+
populated.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@returns outds contains the following variables:
|
|
44
|
+
- directory (containing folder)
|
|
45
|
+
- file_or_folder (file / folder)
|
|
46
|
+
- filepath (path/to/file.name)
|
|
47
|
+
- filename (just the file name)
|
|
48
|
+
- ext (.extension)
|
|
49
|
+
- msg (system message if any issues)
|
|
50
|
+
- level (depth of folder)
|
|
51
|
+
- OS SPECIFIC variables, if <code>getattrs=</code> is used.
|
|
52
|
+
|
|
53
|
+
<h4> SAS Macros </h4>
|
|
54
|
+
@li mf_existds.sas
|
|
55
|
+
@li mf_getvarlist.sas
|
|
56
|
+
@li mf_wordsinstr1butnotstr2.sas
|
|
57
|
+
@li mp_dropmembers.sas
|
|
58
|
+
|
|
59
|
+
<h4> Related Macros </h4>
|
|
60
|
+
@li mp_dirlist.test.sas
|
|
61
|
+
|
|
62
|
+
@version 9.2
|
|
63
|
+
**/
|
|
64
|
+
|
|
65
|
+
%macro mp_dirlist(path=%sysfunc(pathname(work))
|
|
66
|
+
, fref=0
|
|
67
|
+
, outds=work.mp_dirlist
|
|
68
|
+
, getattrs=NO
|
|
69
|
+
, showparent=NO
|
|
70
|
+
, maxdepth=0
|
|
71
|
+
, level=0 /* The level of recursion to perform. For internal use only. */
|
|
72
|
+
)/*/STORE SOURCE*/;
|
|
73
|
+
%let getattrs=%upcase(&getattrs)XX;
|
|
74
|
+
|
|
75
|
+
/* temp table */
|
|
76
|
+
%local out_ds;
|
|
77
|
+
data;run;
|
|
78
|
+
%let out_ds=%str(&syslast);
|
|
79
|
+
|
|
80
|
+
/* drop main (top) table if it exists */
|
|
81
|
+
%if &level=0 %then %do;
|
|
82
|
+
%mp_dropmembers(%scan(&outds,-1,.), libref=WORK)
|
|
83
|
+
%end;
|
|
84
|
+
|
|
85
|
+
data &out_ds(compress=no
|
|
86
|
+
keep=file_or_folder filepath filename ext msg directory level
|
|
87
|
+
);
|
|
88
|
+
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80
|
|
89
|
+
ext $20 msg $200 foption $16;
|
|
90
|
+
if _n_=1 then call missing(of _all_);
|
|
91
|
+
retain level &level;
|
|
92
|
+
%if &fref=0 %then %do;
|
|
93
|
+
rc = filename(fref, "&path");
|
|
94
|
+
%end;
|
|
95
|
+
%else %do;
|
|
96
|
+
fref="&fref";
|
|
97
|
+
rc=0;
|
|
98
|
+
%end;
|
|
99
|
+
if rc = 0 then do;
|
|
100
|
+
did = dopen(fref);
|
|
101
|
+
if did=0 then do;
|
|
102
|
+
putlog "NOTE: This directory is empty, or does not exist - &path";
|
|
103
|
+
msg=sysmsg();
|
|
104
|
+
put msg;
|
|
105
|
+
put _all_;
|
|
106
|
+
stop;
|
|
107
|
+
end;
|
|
108
|
+
/* attribute is OS-dependent - could be "Directory" or "Directory Name" */
|
|
109
|
+
numopts=doptnum(did);
|
|
110
|
+
do i=1 to numopts;
|
|
111
|
+
foption=doptname(did,i);
|
|
112
|
+
if foption=:'Directory' then i=numopts;
|
|
113
|
+
end;
|
|
114
|
+
directory=dinfo(did,foption);
|
|
115
|
+
rc = filename(fref);
|
|
116
|
+
end;
|
|
117
|
+
else do;
|
|
118
|
+
msg=sysmsg();
|
|
119
|
+
put _all_;
|
|
120
|
+
stop;
|
|
121
|
+
end;
|
|
122
|
+
dnum = dnum(did);
|
|
123
|
+
do i = 1 to dnum;
|
|
124
|
+
filename = dread(did, i);
|
|
125
|
+
filepath=cats(directory,'/',filename);
|
|
126
|
+
rc = filename(fref2,filepath);
|
|
127
|
+
midd=dopen(fref2);
|
|
128
|
+
dmsg=sysmsg();
|
|
129
|
+
if did > 0 then file_or_folder='folder';
|
|
130
|
+
rc=dclose(midd);
|
|
131
|
+
midf=fopen(fref2);
|
|
132
|
+
fmsg=sysmsg();
|
|
133
|
+
if midf > 0 then file_or_folder='file';
|
|
134
|
+
rc=fclose(midf);
|
|
135
|
+
|
|
136
|
+
if index(fmsg,'File is in use') or index(dmsg,'is not a directory')
|
|
137
|
+
then file_or_folder='file';
|
|
138
|
+
else if index(fmsg,'Insufficient authorization') then file_or_folder='file';
|
|
139
|
+
else if file_or_folder='' then file_or_folder='locked';
|
|
140
|
+
|
|
141
|
+
if file_or_folder='file' then do;
|
|
142
|
+
ext = prxchange('s/.*\.{1,1}(.*)/$1/', 1, filename);
|
|
143
|
+
if filename = ext then ext = ' ';
|
|
144
|
+
end;
|
|
145
|
+
else do;
|
|
146
|
+
ext='';
|
|
147
|
+
file_or_folder='folder';
|
|
148
|
+
end;
|
|
149
|
+
output;
|
|
150
|
+
end;
|
|
151
|
+
rc = dclose(did);
|
|
152
|
+
%if &showparent=YES and &level=0 %then %do;
|
|
153
|
+
filepath=directory;
|
|
154
|
+
file_or_folder='folder';
|
|
155
|
+
ext='';
|
|
156
|
+
filename=scan(directory,-1,'/\');
|
|
157
|
+
msg='';
|
|
158
|
+
level=&level;
|
|
159
|
+
output;
|
|
160
|
+
%end;
|
|
161
|
+
stop;
|
|
162
|
+
run;
|
|
163
|
+
|
|
164
|
+
%if %substr(&getattrs,1,1)=Y %then %do;
|
|
165
|
+
data &out_ds;
|
|
166
|
+
set &out_ds;
|
|
167
|
+
length infoname infoval $60 fref $8;
|
|
168
|
+
if _n_=1 then call missing(fref);
|
|
169
|
+
rc=filename(fref,filepath);
|
|
170
|
+
drop rc infoname fid i close fref;
|
|
171
|
+
if file_or_folder='file' then do;
|
|
172
|
+
fid=fopen(fref);
|
|
173
|
+
if fid le 0 then do;
|
|
174
|
+
msg=sysmsg();
|
|
175
|
+
putlog "Could not open file:" filepath fid= ;
|
|
176
|
+
sasname='_MCNOTVALID_';
|
|
177
|
+
output;
|
|
178
|
+
end;
|
|
179
|
+
else do i=1 to foptnum(fid);
|
|
180
|
+
infoname=foptname(fid,i);
|
|
181
|
+
infoval=finfo(fid,infoname);
|
|
182
|
+
sasname=compress(infoname, '_', 'adik');
|
|
183
|
+
if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
|
|
184
|
+
if upcase(sasname) ne 'FILENAME' then output;
|
|
185
|
+
end;
|
|
186
|
+
close=fclose(fid);
|
|
187
|
+
end;
|
|
188
|
+
else do;
|
|
189
|
+
fid=dopen(fref);
|
|
190
|
+
if fid le 0 then do;
|
|
191
|
+
msg=sysmsg();
|
|
192
|
+
putlog "Could not open folder:" filepath fid= ;
|
|
193
|
+
sasname='_MCNOTVALID_';
|
|
194
|
+
output;
|
|
195
|
+
end;
|
|
196
|
+
else do i=1 to doptnum(fid);
|
|
197
|
+
infoname=doptname(fid,i);
|
|
198
|
+
infoval=dinfo(fid,infoname);
|
|
199
|
+
sasname=compress(infoname, '_', 'adik');
|
|
200
|
+
if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
|
|
201
|
+
if upcase(sasname) ne 'FILENAME' then output;
|
|
202
|
+
end;
|
|
203
|
+
close=dclose(fid);
|
|
204
|
+
end;
|
|
205
|
+
run;
|
|
206
|
+
proc sort;
|
|
207
|
+
by filepath sasname;
|
|
208
|
+
proc transpose data=&out_ds out=&out_ds(drop=_:);
|
|
209
|
+
id sasname;
|
|
210
|
+
var infoval;
|
|
211
|
+
by filepath file_or_folder filename ext ;
|
|
212
|
+
run;
|
|
213
|
+
%end;
|
|
214
|
+
|
|
215
|
+
data &out_ds;
|
|
216
|
+
set &out_ds(where=(filepath ne ''));
|
|
217
|
+
run;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The above transpose can mean that some updates create additional columns.
|
|
221
|
+
* This necessitates the occasional use of datastep over proc append.
|
|
222
|
+
*/
|
|
223
|
+
%if %mf_existds(&outds) %then %do;
|
|
224
|
+
%local basevars appvars newvars;
|
|
225
|
+
%let basevars=%mf_getvarlist(&outds);
|
|
226
|
+
%let appvars=%mf_getvarlist(&out_ds);
|
|
227
|
+
%let newvars=%length(%mf_wordsinstr1butnotstr2(Str1=&appvars,Str2=&basevars));
|
|
228
|
+
%if &newvars>0 %then %do;
|
|
229
|
+
data &outds;
|
|
230
|
+
set &outds &out_ds;
|
|
231
|
+
run;
|
|
232
|
+
%end;
|
|
233
|
+
%else %do;
|
|
234
|
+
proc append base=&outds data=&out_ds force nowarn;
|
|
235
|
+
run;
|
|
236
|
+
%end;
|
|
237
|
+
%end;
|
|
238
|
+
%else %do;
|
|
239
|
+
proc append base=&outds data=&out_ds;
|
|
240
|
+
run;
|
|
241
|
+
%end;
|
|
242
|
+
|
|
243
|
+
/* recursive call */
|
|
244
|
+
%if &maxdepth>&level or &maxdepth=MAX %then %do;
|
|
245
|
+
data _null_;
|
|
246
|
+
set &out_ds;
|
|
247
|
+
where file_or_folder='folder';
|
|
248
|
+
%if &showparent=YES and &level=0 %then %do;
|
|
249
|
+
if filepath ne directory;
|
|
250
|
+
%end;
|
|
251
|
+
length code $10000;
|
|
252
|
+
code=cats('%nrstr(%mp_dirlist(path=',filepath,",outds=&outds"
|
|
253
|
+
,",getattrs=&getattrs,level=%eval(&level+1),maxdepth=&maxdepth))");
|
|
254
|
+
put code=;
|
|
255
|
+
call execute(code);
|
|
256
|
+
run;
|
|
257
|
+
%end;
|
|
258
|
+
|
|
259
|
+
/* tidy up */
|
|
260
|
+
proc sql;
|
|
261
|
+
drop table &out_ds;
|
|
262
|
+
|
|
263
|
+
%mend mp_dirlist;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Creates a dataset containing distinct _formatted_ values
|
|
4
|
+
@details If no format is supplied, then the original value is used instead.
|
|
5
|
+
There is also a dependency on other macros within the Macro Core library.
|
|
6
|
+
Usage:
|
|
7
|
+
|
|
8
|
+
%mp_distinctfmtvalues(libds=sashelp.class,var=age,outvar=age,outds=test)
|
|
9
|
+
|
|
10
|
+
@param libds input dataset
|
|
11
|
+
@param var variable to get distinct values for
|
|
12
|
+
@param outvar variable to create. Default: `formatted_value`
|
|
13
|
+
@param outds dataset to create. Default: work.mp_distinctfmtvalues
|
|
14
|
+
@param varlen length of variable to create (default 200)
|
|
15
|
+
|
|
16
|
+
@version 9.2
|
|
17
|
+
@author Allan Bowe
|
|
18
|
+
|
|
19
|
+
**/
|
|
20
|
+
|
|
21
|
+
%macro mp_distinctfmtvalues(
|
|
22
|
+
libds=
|
|
23
|
+
,var=
|
|
24
|
+
,outvar=formatted_value
|
|
25
|
+
,outds=work.mp_distinctfmtvalues
|
|
26
|
+
,varlen=2000
|
|
27
|
+
)/*/STORE SOURCE*/;
|
|
28
|
+
|
|
29
|
+
%local fmt vtype;
|
|
30
|
+
%let fmt=%mf_getvarformat(&libds,&var);
|
|
31
|
+
%let vtype=%mf_getvartype(&libds,&var);
|
|
32
|
+
|
|
33
|
+
proc sql;
|
|
34
|
+
create table &outds as
|
|
35
|
+
select distinct
|
|
36
|
+
%if &vtype=C & %trim(&fmt)=%str() %then %do;
|
|
37
|
+
&var
|
|
38
|
+
%end;
|
|
39
|
+
%else %if &vtype=C %then %do;
|
|
40
|
+
put(&var,&fmt)
|
|
41
|
+
%end;
|
|
42
|
+
%else %if %trim(&fmt)=%str() %then %do;
|
|
43
|
+
put(&var,32.)
|
|
44
|
+
%end;
|
|
45
|
+
%else %do;
|
|
46
|
+
put(&var,&fmt)
|
|
47
|
+
%end;
|
|
48
|
+
as &outvar length=&varlen
|
|
49
|
+
from &libds;
|
|
50
|
+
%mend mp_distinctfmtvalues;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Drops tables / views (if they exist) without warnings in the log
|
|
4
|
+
@details Useful for dropping tables when you're not sure they exist, or if
|
|
5
|
+
you are not sure whether they are a dataset or view. Also efficient for
|
|
6
|
+
dropping multiple tables / views.
|
|
7
|
+
|
|
8
|
+
Example usage:
|
|
9
|
+
|
|
10
|
+
proc sql;
|
|
11
|
+
create table data1 as select * from sashelp.class;
|
|
12
|
+
create view view2 as select * from sashelp.class;
|
|
13
|
+
%mp_dropmembers(data1 view2, libref=WORK)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
<h4> SAS Macros </h4>
|
|
17
|
+
@li mf_isblank.sas
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@param [in] list space separated list of datasets / views, WITHOUT libref
|
|
21
|
+
@param [in] libref= (WORK) Note - you can only drop from one library at a time
|
|
22
|
+
@param [in] iftrue= (1=1) Conditionally drop tables, eg if &debug=N
|
|
23
|
+
|
|
24
|
+
@version 9.2
|
|
25
|
+
@author Allan Bowe
|
|
26
|
+
|
|
27
|
+
**/
|
|
28
|
+
|
|
29
|
+
%macro mp_dropmembers(
|
|
30
|
+
list /* space separated list of datasets / views */
|
|
31
|
+
,libref=WORK /* can only drop from a single library at a time */
|
|
32
|
+
,iftrue=%str(1=1)
|
|
33
|
+
)/*/STORE SOURCE*/;
|
|
34
|
+
|
|
35
|
+
%if not(%eval(%unquote(&iftrue))) %then %return;
|
|
36
|
+
|
|
37
|
+
%if %mf_isblank(&list) %then %do;
|
|
38
|
+
%put NOTE: nothing to drop!;
|
|
39
|
+
%return;
|
|
40
|
+
%end;
|
|
41
|
+
|
|
42
|
+
proc datasets lib=&libref nolist;
|
|
43
|
+
delete &list;
|
|
44
|
+
delete &list /mtype=view;
|
|
45
|
+
run;
|
|
46
|
+
%mend mp_dropmembers;
|