a320ec8d54deadddd4019e87114c2c37650caeb7
[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 #define strtok_r strtok_s // @john: this should probably go to msvc_extra_headers/ardourext/misc.h.input instead of the current define there
28 #else
29 #include <dirent.h>
30 #include <cstdlib>
31 #include <cstdio>
32 #endif
33 #include <cstring>
34 #include <vector>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #include <glibmm/miscutils.h>
39
40 #include "pbd/error.h"
41 #include "pbd/pathexpand.h"
42 #include "pbd/pathscanner.h"
43
44 using namespace std;
45 using namespace PBD;
46
47 static
48 bool
49 regexp_filter (const string& str, void *arg)
50 {
51         regex_t* pattern = (regex_t*)arg;
52         return regexec (pattern, str.c_str(), 0, 0, 0) == 0;
53 }
54
55 void
56 PathScanner::find_files_matching_regex (vector<string>& result,
57                 const std::string& dirpath,
58                 const std::string& regexp,
59                 bool match_fullpath, bool return_fullpath,
60                 long limit,
61                 bool recurse)
62 {
63         int err;
64         char msg[256];
65         regex_t compiled_pattern;
66
67         if ((err = regcomp (&compiled_pattern, regexp.c_str(),
68                             REG_EXTENDED|REG_NOSUB))) {
69                 
70                 regerror (err, &compiled_pattern,
71                           msg, sizeof (msg));
72                 
73                 error << "Cannot compile soundfile regexp for use (" 
74                       << msg 
75                       << ")" 
76                       << endmsg;
77                 
78                 return;
79         }
80
81         find_files_matching_filter (result, dirpath,
82                                     regexp_filter, &compiled_pattern,
83                                     match_fullpath, return_fullpath,
84                                     limit, recurse);
85
86         regfree (&compiled_pattern);
87 }
88         
89 void
90 PathScanner::find_files_matching_filter (vector<string>& result,
91                                          const string &dirpath,
92                                          bool (*filter)(const string &, void *),
93                                          void *arg,
94                                          bool match_fullpath, bool return_fullpath,
95                                          long limit,
96                                          bool recurse)
97 {
98         DIR *dir;
99         struct dirent *finfo;
100         char *pathcopy = strdup (search_path_expand (dirpath).c_str());
101         char *thisdir;
102         string fullpath;
103         string search_str;
104         long nfound = 0;
105         char *saveptr;
106
107         if ((thisdir = strtok_r (pathcopy, G_SEARCHPATH_SEPARATOR_S, &saveptr)) == 0 ||
108             strlen (thisdir) == 0) {
109                 free (pathcopy);
110                 return;
111         }
112
113         do {
114
115                 if ((dir = opendir (thisdir)) == 0) {
116                         continue;
117                 }
118                 
119                 while ((finfo = readdir (dir)) != 0) {
120
121                         if ((finfo->d_name[0] == '.' && finfo->d_name[1] == '\0') ||
122                             (finfo->d_name[0] == '.' && finfo->d_name[1] == '.' && finfo->d_name[2] == '\0')) {
123                                 continue;
124                         }
125                         
126                         fullpath = Glib::build_filename (thisdir, finfo->d_name);
127
128                         struct stat statbuf;
129                         if (stat (fullpath.c_str(), &statbuf) < 0) {
130                                 continue;
131                         }
132
133                         if (statbuf.st_mode & S_IFDIR && recurse) {
134                                 find_files_matching_filter (result, fullpath, filter, arg, match_fullpath, return_fullpath, limit, recurse);
135                         } else {
136                                 
137                                 if (match_fullpath) {
138                                         search_str = fullpath;
139                                 } else {
140                                         search_str = finfo->d_name;
141                                 }
142                                 
143                                 if (!filter(search_str, arg)) {
144                                         continue;
145                                 }
146
147                                 if (return_fullpath) {
148                                         result.push_back(fullpath);
149                                 } else {
150                                         result.push_back(finfo->d_name);
151                                 } 
152                                 
153                                 nfound++;
154                         }
155                 }
156                 closedir (dir);
157                 
158         } while ((limit < 0 || (nfound < limit)) && (thisdir = strtok_r (0, G_SEARCHPATH_SEPARATOR_S, &saveptr)));
159
160         free (pathcopy);
161         return;
162 }