Merge remote-tracking branch 'remotes/origin/cairocanvas' into windows
[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 #ifdef COMPILER_MSVC
22 #include <stdlib.h>
23 #include <stdio.h>
24 using PBD::readdir;
25 using PBD::opendir;
26 using PBD::closedir;
27 #else
28 #include <dirent.h>
29 #include <cstdlib>
30 #include <cstdio>
31 #endif
32 #include <cstring>
33 #include <vector>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include <glibmm/miscutils.h>
38
39 #include "pbd/error.h"
40 #include "pbd/pathexpand.h"
41 #include "pbd/pathscanner.h"
42 #include "pbd/stl_delete.h"
43
44 using namespace std;
45 using namespace PBD;
46
47 vector<string *> *
48 PathScanner::operator() (const string &dirpath, const string &regexp,
49                          bool match_fullpath, bool return_fullpath, 
50                          long limit, bool recurse)
51
52 {
53         int err;
54         char msg[256];
55
56         if ((err = regcomp (&compiled_pattern, regexp.c_str(),
57                             REG_EXTENDED|REG_NOSUB))) {
58                 
59                 regerror (err, &compiled_pattern,
60                           msg, sizeof (msg));
61                 
62                 error << "Cannot compile soundfile regexp for use (" 
63                       << msg 
64                       << ")" 
65                       << endmsg;
66                 
67                 return 0;
68         }
69         
70         return run_scan (dirpath, &PathScanner::regexp_filter, 
71                          (bool (*)(const string &, void *)) 0,
72                          0,
73                          match_fullpath,
74                          return_fullpath,
75                          limit, recurse);
76 }       
77
78 vector<string *> *
79 PathScanner::run_scan (const string &dirpath, 
80                        bool (PathScanner::*memberfilter)(const string &),
81                        bool (*filter)(const string &, void *),
82                        void *arg,
83                        bool match_fullpath, bool return_fullpath,
84                        long limit,
85                        bool recurse)
86 {
87         return run_scan_internal ((vector<string*>*) 0, dirpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse);
88 }
89         
90 vector<string *> *
91 PathScanner::run_scan_internal (vector<string *> *result,
92                                 const string &dirpath, 
93                                 bool (PathScanner::*memberfilter)(const string &),
94                                 bool (*filter)(const string &, void *),
95                                 void *arg,
96                                 bool match_fullpath, bool return_fullpath,
97                                 long limit,
98                                 bool recurse)
99 {
100         DIR *dir;
101         struct dirent *finfo;
102         char *pathcopy = strdup (search_path_expand (dirpath).c_str());
103         char *thisdir;
104         string fullpath;
105         string search_str;
106         string *newstr;
107         long nfound = 0;
108
109         if ((thisdir = strtok (pathcopy, ":")) == 0 ||
110             strlen (thisdir) == 0) {
111                 free (pathcopy);
112                 return 0;
113         }
114
115         if (result == 0) {
116                 result = new vector<string *>;
117         }
118
119         do {
120
121                 if ((dir = opendir (thisdir)) == 0) {
122                         continue;
123                 }
124                 
125                 while ((finfo = readdir (dir)) != 0) {
126
127                         if ((finfo->d_name[0] == '.' && finfo->d_name[1] == '\0') ||
128                             (finfo->d_name[0] == '.' && finfo->d_name[1] == '.' && finfo->d_name[2] == '\0')) {
129                                 continue;
130                         }
131                         
132                         fullpath = Glib::build_filename (thisdir, finfo->d_name);
133
134                         struct stat statbuf;
135                         if (stat (fullpath.c_str(), &statbuf) < 0) {
136                                 continue;
137                         }
138
139                         if (statbuf.st_mode & S_IFDIR && recurse) {
140                                 run_scan_internal (result, fullpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse);
141                         } else {
142                                 
143                                 if (match_fullpath) {
144                                         search_str = fullpath;
145                                 } else {
146                                         search_str = finfo->d_name;
147                                 }
148                                 
149                                 /* handle either type of function ptr */
150                                 
151                                 if (memberfilter) {
152                                         if (!(this->*memberfilter)(search_str)) {
153                                                 continue;
154                                         } 
155                                 } else {
156                                         if (!filter(search_str, arg)) {
157                                                 continue;
158                                         }
159                                 }
160
161                                 if (return_fullpath) {
162                                         newstr = new string (fullpath);
163                                 } else {
164                                         newstr = new string (finfo->d_name);
165                                 } 
166                                 
167                                 result->push_back (newstr);
168                                 nfound++;
169                         }
170                 }
171                 closedir (dir);
172                 
173         } while ((limit < 0 || (nfound < limit)) && (thisdir = strtok (0, ":")));
174
175         free (pathcopy);
176         return result;
177 }
178
179 string *
180 PathScanner::find_first (const string &dirpath,
181                          const string &regexp,
182                          bool match_fullpath,
183                          bool return_fullpath)
184 {
185         vector<string *> *res;
186         string *ret;
187         int err;
188         char msg[256];
189
190         if ((err = regcomp (&compiled_pattern, regexp.c_str(),
191                             REG_EXTENDED|REG_NOSUB))) {
192                 
193                 regerror (err, &compiled_pattern,
194                           msg, sizeof (msg));
195                 
196                 error << "Cannot compile soundfile regexp for use (" << msg << ")" << endmsg;
197
198                 
199                 return 0;
200         }
201         
202         res = run_scan (dirpath, 
203                         &PathScanner::regexp_filter,
204                         (bool (*)(const string &, void *)) 0,
205                         0,
206                         match_fullpath,
207                         return_fullpath, 
208                         1);
209         
210         if (res->size() == 0) {
211                 ret = 0;
212         } else {
213                 ret = res->front();
214         }
215         vector_delete (res);
216         delete res;
217         return ret;
218 }
219
220 string *
221 PathScanner::find_first (const string &dirpath,
222                          bool (*filter)(const string &, void *),
223                          void * /*arg*/,
224                          bool match_fullpath,
225                          bool return_fullpath)
226 {
227         vector<string *> *res;
228         string *ret;
229
230         res = run_scan (dirpath, 
231                         (bool (PathScanner::*)(const string &)) 0,
232                         filter,
233                         0,
234                         match_fullpath,
235                         return_fullpath, 1);
236         
237         if (res->size() == 0) {
238                 ret = 0;
239         } else {
240                 ret = res->front();
241         }
242         vector_delete (res);
243         delete res;
244         return ret;
245 }