MIDIClock_SlaveTest: first working testcase
[ardour.git] / libs / pbd / pathscanner.cc
1 /*
2     Copyright (C) 1998-99 Paul Barton-Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <cstdlib>
22 #include <cstdio>
23 #include <cstring>
24 #include <vector>
25 #include <dirent.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #include "pbd/error.h"
30 #include "pbd/pathscanner.h"
31 #include "pbd/stl_delete.h"
32
33 using namespace std;
34 using namespace PBD;
35
36 vector<string *> *
37 PathScanner::operator() (const string &dirpath, const string &regexp,
38                          bool match_fullpath, bool return_fullpath, 
39                          long limit, bool recurse)
40
41 {
42         int err;
43         char msg[256];
44
45         if ((err = regcomp (&compiled_pattern, regexp.c_str(),
46                             REG_EXTENDED|REG_NOSUB))) {
47                 
48                 regerror (err, &compiled_pattern,
49                           msg, sizeof (msg));
50                 
51                 error << "Cannot compile soundfile regexp for use (" 
52                       << msg 
53                       << ")" 
54                       << endmsg;
55                 
56                 return 0;
57         }
58         
59         return run_scan (dirpath, &PathScanner::regexp_filter, 
60                          (bool (*)(const string &, void *)) 0,
61                          0,
62                          match_fullpath,
63                          return_fullpath,
64                          limit, recurse);
65 }       
66
67 vector<string *> *
68 PathScanner::run_scan (const string &dirpath, 
69                        bool (PathScanner::*memberfilter)(const string &),
70                        bool (*filter)(const string &, void *),
71                        void *arg,
72                        bool match_fullpath, bool return_fullpath,
73                        long limit,
74                        bool recurse)
75 {
76         return run_scan_internal ((vector<string*>*) 0, dirpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse);
77 }
78         
79 vector<string *> *
80 PathScanner::run_scan_internal (vector<string *> *result,
81                                 const string &dirpath, 
82                                 bool (PathScanner::*memberfilter)(const string &),
83                                 bool (*filter)(const string &, void *),
84                                 void *arg,
85                                 bool match_fullpath, bool return_fullpath,
86                                 long limit,
87                                 bool recurse)
88 {
89         DIR *dir;
90         struct dirent *finfo;
91         char *pathcopy = strdup (dirpath.c_str());
92         char *thisdir;
93         char fullpath[PATH_MAX+1];
94         string search_str;
95         string *newstr;
96         long nfound = 0;
97
98         if ((thisdir = strtok (pathcopy, ":")) == 0 ||
99             strlen (thisdir) == 0) {
100                 free (pathcopy);
101                 return 0;
102         }
103
104         if (result == 0) {
105                 result = new vector<string *>;
106         }
107
108         do {
109
110                 if ((dir = opendir (thisdir)) == 0) {
111                         continue;
112                 }
113                 
114                 while ((finfo = readdir (dir)) != 0) {
115
116                         if ((finfo->d_name[0] == '.' && finfo->d_name[1] == '\0') ||
117                             (finfo->d_name[0] == '.' && finfo->d_name[1] == '.' && finfo->d_name[2] == '\0')) {
118                                 continue;
119                         }
120
121                         snprintf (fullpath, sizeof(fullpath), "%s/%s",
122                                   thisdir, finfo->d_name);
123
124                         struct stat statbuf;
125                         if (stat (fullpath, &statbuf) < 0) {
126                                 continue;
127                         }
128
129                         if (statbuf.st_mode & S_IFDIR && recurse) {
130                                 run_scan_internal (result, fullpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse);
131                         } else {
132                                 
133                                 if (match_fullpath) {
134                                         search_str = fullpath;
135                                 } else {
136                                         search_str = finfo->d_name;
137                                 }
138                                 
139                                 /* handle either type of function ptr */
140                                 
141                                 if (memberfilter) {
142                                         if (!(this->*memberfilter)(search_str)) {
143                                                 continue;
144                                         } 
145                                 } else {
146                                         if (!filter(search_str, arg)) {
147                                                 continue;
148                                         }
149                                 }
150                                 
151                                 if (return_fullpath) {
152                                         newstr = new string (fullpath);
153                                 } else {
154                                         newstr = new string (finfo->d_name);
155                                 } 
156                                 
157                                 result->push_back (newstr);
158                                 nfound++;
159                         }
160                 }
161                 closedir (dir);
162                 
163         } while ((limit < 0 || (nfound < limit)) && (thisdir = strtok (0, ":")));
164
165         free (pathcopy);
166         return result;
167 }
168
169 string *
170 PathScanner::find_first (const string &dirpath,
171                          const string &regexp,
172                          bool match_fullpath,
173                          bool return_fullpath)
174 {
175         vector<string *> *res;
176         string *ret;
177         int err;
178         char msg[256];
179
180         if ((err = regcomp (&compiled_pattern, regexp.c_str(),
181                             REG_EXTENDED|REG_NOSUB))) {
182                 
183                 regerror (err, &compiled_pattern,
184                           msg, sizeof (msg));
185                 
186                 error << "Cannot compile soundfile regexp for use (" << msg << ")" << endmsg;
187
188                 
189                 return 0;
190         }
191         
192         res = run_scan (dirpath, 
193                         &PathScanner::regexp_filter,
194                         (bool (*)(const string &, void *)) 0,
195                         0,
196                         match_fullpath,
197                         return_fullpath, 
198                         1);
199         
200         if (res->size() == 0) {
201                 ret = 0;
202         } else {
203                 ret = res->front();
204         }
205         vector_delete (res);
206         delete res;
207         return ret;
208 }
209
210 string *
211 PathScanner::find_first (const string &dirpath,
212                          bool (*filter)(const string &, void *),
213                          void * /*arg*/,
214                          bool match_fullpath,
215                          bool return_fullpath)
216 {
217         vector<string *> *res;
218         string *ret;
219
220         res = run_scan (dirpath, 
221                         (bool (PathScanner::*)(const string &)) 0,
222                         filter,
223                         0,
224                         match_fullpath,
225                         return_fullpath, 1);
226         
227         if (res->size() == 0) {
228                 ret = 0;
229         } else {
230                 ret = res->front();
231         }
232         vector_delete (res);
233         delete res;
234         return ret;
235 }