Production Ready Macros for SAS Application Developers
https://github.com/sasjs/core
mp_dirlist.sas
Go to the documentation of this file.
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
10 usage:
11
12 %mp_dirlist(path=/some/location, outds=myTable, maxdepth=MAX)
13
14 %mp_dirlist(outds=cwdfileprops, getattrs=YES)
15
16 %mp_dirlist(fref=MYFREF)
17
18 @warning In a Unix environment, the existence of a named pipe will cause this
19 macro to hang. Therefore this tool should be used with caution in a SAS 9 web
20 application, as it can use up all available multibridge sessions if requests
21 are resubmitted.
22 If anyone finds a way to positively identify a named pipe using SAS (without
23 X CMD) do please raise an issue!
24
25
26 @param [in] path= for which to return contents
27 @param [in] fref= Provide a DISK engine fileref as an alternative to PATH
28 @param [in] maxdepth= (0) Set to a positive integer to indicate the level of
29 subdirectory scan recursion - eg 3, to go `./3/levels/deep`. For unlimited
30 recursion, set to MAX.
31 @param [out] outds= the output dataset to create
32 @param [out] getattrs= (NO) If getattrs=YES then the doptname / foptname
33 functions are used to scan all properties - any characters that are not
34 valid in a SAS name (v7) are simply stripped, and the table is transposed
35 so theat each property is a column and there is one file per row. An
36 attempt is made to get all properties whether a file or folder, but some
37 files/folders cannot be accessed, and so not all properties can / will be
38 populated.
39
40
41 @returns outds contains the following variables:
42 - directory (containing folder)
43 - file_or_folder (file / folder)
44 - filepath (path/to/file.name)
45 - filename (just the file name)
46 - ext (.extension)
47 - msg (system message if any issues)
48 - level (depth of folder)
49 - OS SPECIFIC variables, if <code>getattrs=</code> is used.
50
51 <h4> SAS Macros </h4>
52 @li mp_dropmembers.sas
53
54 <h4> Related Macros </h4>
55 @li mp_dirlist.test.sas
56
57 @version 9.2
58 @author Allan Bowe
59**/
60
61%macro mp_dirlist(path=%sysfunc(pathname(work))
62 , fref=0
63 , outds=work.mp_dirlist
64 , getattrs=NO
65 , maxdepth=0
66 , level=0 /* The level of recursion to perform. For internal use only. */
67)/*/STORE SOURCE*/;
68%let getattrs=%upcase(&getattrs)XX;
69
70/* temp table */
71%local out_ds;
72data;run;
73%let out_ds=%str(&syslast);
74
75/* drop main (top) table if it exists */
76%if &level=0 %then %do;
77 %mp_dropmembers(%scan(&outds,-1,.), libref=WORK)
78%end;
79
80data &out_ds(compress=no
81 keep=file_or_folder filepath filename ext msg directory level
82 );
83 length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80
84 ext $20 msg $200;
85 retain level &level;
86 %if &fref=0 %then %do;
87 rc = filename(fref, "&path");
88 %end;
89 %else %do;
90 fref="&fref";
91 rc=0;
92 %end;
93 if rc = 0 then do;
94 did = dopen(fref);
95 directory=dinfo(did,'Directory');
96 if did=0 then do;
97 putlog "NOTE: This directory is empty - " directory;
98 msg=sysmsg();
99 put _all_;
100 stop;
101 end;
102 rc = filename(fref);
103 end;
104 else do;
105 msg=sysmsg();
106 put _all_;
107 stop;
108 end;
109 dnum = dnum(did);
110 do i = 1 to dnum;
111 filename = dread(did, i);
112 filepath=cats(directory,'/',filename);
113 rc = filename(fref2,filepath);
114 midd=dopen(fref2);
115 dmsg=sysmsg();
116 if did > 0 then file_or_folder='folder';
117 rc=dclose(midd);
118 midf=fopen(fref2);
119 fmsg=sysmsg();
120 if midf > 0 then file_or_folder='file';
121 rc=fclose(midf);
122
123 if index(fmsg,'File is in use') or index(dmsg,'is not a directory')
124 then file_or_folder='file';
125 else if index(fmsg,'Insufficient authorization') then file_or_folder='file';
126 else if file_or_folder='' then file_or_folder='locked';
127
128 if file_or_folder='file' then do;
129 ext = prxchange('s/.*\.{1,1}(.*)/$1/', 1, filename);
130 if filename = ext then ext = ' ';
131 end;
132 else do;
133 ext='';
134 file_or_folder='folder';
135 end;
136 output;
137 end;
138 rc = dclose(did);
139 stop;
140run;
141
142%if %substr(&getattrs,1,1)=Y %then %do;
143 data &out_ds;
144 set &out_ds;
145 length infoname infoval $60 fref $8;
146 rc=filename(fref,filepath);
147 drop rc infoname fid i close fref;
148 if file_or_folder='file' then do;
149 fid=fopen(fref);
150 if fid le 0 then do;
151 msg=sysmsg();
152 putlog "Could not open file:" filepath fid= ;
153 sasname='_MCNOTVALID_';
154 output;
155 end;
156 else do i=1 to foptnum(fid);
157 infoname=foptname(fid,i);
158 infoval=finfo(fid,infoname);
159 sasname=compress(infoname, '_', 'adik');
160 if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
161 if upcase(sasname) ne 'FILENAME' then output;
162 end;
163 close=fclose(fid);
164 end;
165 else do;
166 fid=dopen(fref);
167 if fid le 0 then do;
168 msg=sysmsg();
169 putlog "Could not open folder:" filepath fid= ;
170 sasname='_MCNOTVALID_';
171 output;
172 end;
173 else do i=1 to doptnum(fid);
174 infoname=doptname(fid,i);
175 infoval=dinfo(fid,infoname);
176 sasname=compress(infoname, '_', 'adik');
177 if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
178 if upcase(sasname) ne 'FILENAME' then output;
179 end;
180 close=dclose(fid);
181 end;
182 run;
183 proc sort;
184 by filepath sasname;
185 proc transpose data=&out_ds out=&out_ds(drop=_:);
186 id sasname;
187 var infoval;
188 by filepath file_or_folder filename ext ;
189 run;
190%end;
191
192data &out_ds;
193 set &out_ds(where=(filepath ne ''));
194run;
195
196/* update main table */
197proc append base=&outds data=&out_ds;
198run;
199
200/* recursive call */
201%if &maxdepth>&level or &maxdepth=MAX %then %do;
202 data _null_;
203 set &out_ds;
204 where file_or_folder='folder';
205 length code $10000;
206 code=cats('%nrstr(%mp_dirlist(path=',filepath,",outds=&outds"
207 ,",getattrs=&getattrs,level=%eval(&level+1),maxdepth=&maxdepth))");
208 put code=;
209 call execute(code);
210 run;
211%end;
212
213/* tidy up */
214proc sql;
215drop table &out_ds;
216
217%mend mp_dirlist;