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  If getattrs=YES then the doptname / foptname functions are used to scan all
7  properties - any characters that are not valid in a SAS name (v7) are simply
8  stripped, and the table is transposed so theat each property is a column
9  and there is one file per row. An attempt is made to get all properties
10  whether a file or folder, but some files/folders cannot be accessed, and so
11  not all properties can / will be populated.
12 
13  Credit for the rename approach:
14  https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-convert-string-to-Legal-SAS-Name/m-p/27375/highlight/true#M5003
15 
16 
17  usage:
18 
19  %mp_dirlist(path=/some/location,outds=myTable)
20 
21  %mp_dirlist(outds=cwdfileprops, getattrs=YES)
22 
23  %mp_dirlist(fref=MYFREF)
24 
25  @warning In a Unix environment, the existence of a named pipe will cause this
26  macro to hang. Therefore this tool should be used with caution in a SAS 9 web
27  application, as it can use up all available multibridge sessions if requests
28  are resubmitted.
29  If anyone finds a way to positively identify a named pipe using SAS (without
30  X CMD) do please raise an issue!
31 
32 
33  @param path= for which to return contents
34  @param fref= Provide a DISK engine fileref as an alternative to PATH
35  @param outds= the output dataset to create
36  @param getattrs= YES/NO (default=NO). Uses doptname and foptname to return
37  all attributes for each file / folder.
38 
39 
40  @returns outds contains the following variables:
41  - directory (containing folder)
42  - file_or_folder (file / folder)
43  - filepath (path/to/file.name)
44  - filename (just the file name)
45  - ext (.extension)
46  - msg (system message if any issues)
47  - OS SPECIFIC variables, if <code>getattrs=</code> is used.
48 
49  @version 9.2
50  @author Allan Bowe
51 **/
52 
53 %macro mp_dirlist(path=%sysfunc(pathname(work))
54  , fref=0
55  , outds=work.mp_dirlist
56  , getattrs=NO
57 )/*/STORE SOURCE*/;
58 %let getattrs=%upcase(&getattrs)XX;
59 
60 data &outds (compress=no keep=file_or_folder filepath filename ext msg directory);
61  length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
62  %if &fref=0 %then %do;
63  rc = filename(fref, "&path");
64  %end;
65  %else %do;
66  fref="&fref";
67  rc=0;
68  %end;
69  if rc = 0 then do;
70  did = dopen(fref);
71  directory=dinfo(did,'Directory');
72  if did=0 then do;
73  putlog "NOTE: This directory is empty - " directory;
74  msg=sysmsg();
75  put _all_;
76  stop;
77  end;
78  rc = filename(fref);
79  end;
80  else do;
81  msg=sysmsg();
82  put _all_;
83  stop;
84  end;
85  dnum = dnum(did);
86  do i = 1 to dnum;
87  filename = dread(did, i);
88  filepath=cats(directory,'/',filename);
89  rc = filename(fref2,filepath);
90  midd=dopen(fref2);
91  dmsg=sysmsg();
92  if did > 0 then file_or_folder='folder';
93  rc=dclose(midd);
94  midf=fopen(fref2);
95  fmsg=sysmsg();
96  if midf > 0 then file_or_folder='file';
97  rc=fclose(midf);
98 
99  if index(fmsg,'File is in use') or index(dmsg,'is not a directory')
100  then file_or_folder='file';
101  else if index(fmsg, 'Insufficient authorization') then file_or_folder='file';
102  else if file_or_folder='' then file_or_folder='locked';
103 
104  if file_or_folder='file' then do;
105  ext = prxchange('s/.*\.{1,1}(.*)/$1/', 1, filename);
106  if filename = ext then ext = ' ';
107  end;
108  else do;
109  ext='';
110  file_or_folder='folder';
111  end;
112  output;
113  end;
114  rc = dclose(did);
115  stop;
116 run;
117 
118 %if %substr(&getattrs,1,1)=Y %then %do;
119  data &outds;
120  set &outds;
121  length infoname infoval $60 fref $8;
122  rc=filename(fref,filepath);
123  drop rc infoname fid i close fref;
124  if file_or_folder='file' then do;
125  fid=fopen(fref);
126  if fid le 0 then do;
127  msg=sysmsg();
128  putlog "Could not open file:" filepath fid= ;
129  sasname='_MCNOTVALID_';
130  output;
131  end;
132  else do i=1 to foptnum(fid);
133  infoname=foptname(fid,i);
134  infoval=finfo(fid,infoname);
135  sasname=compress(infoname, '_', 'adik');
136  if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
137  if upcase(sasname) ne 'FILENAME' then output;
138  end;
139  close=fclose(fid);
140  end;
141  else do;
142  fid=dopen(fref);
143  if fid le 0 then do;
144  msg=sysmsg();
145  putlog "Could not open folder:" filepath fid= ;
146  sasname='_MCNOTVALID_';
147  output;
148  end;
149  else do i=1 to doptnum(fid);
150  infoname=doptname(fid,i);
151  infoval=dinfo(fid,infoname);
152  sasname=compress(infoname, '_', 'adik');
153  if anydigit(sasname)=1 then sasname=substr(sasname,anyalpha(sasname));
154  if upcase(sasname) ne 'FILENAME' then output;
155  end;
156  close=dclose(fid);
157  end;
158  run;
159  proc sort;
160  by filepath sasname;
161  proc transpose data=&outds out=&outds(drop=_:);
162  id sasname;
163  var infoval;
164  by filepath file_or_folder filename ext ;
165  run;
166 %end;
167 %mend;