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