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