00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "globPattern.h"
00020
00021
00022
00023
00024
00025
00026
00027
00028 bool GlobPattern::
00029 has_glob_characters() const {
00030 string::const_iterator pi;
00031 pi = _pattern.begin();
00032 while (pi != _pattern.end()) {
00033 switch (*pi) {
00034 case '*':
00035 case '?':
00036 case '[':
00037 return true;
00038
00039 case '\\':
00040 ++pi;
00041 if (pi == _pattern.end()) {
00042 return false;
00043 }
00044 }
00045 ++pi;
00046 }
00047 return false;
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 int GlobPattern::
00069 match_files(vector_string &results, const Filename &cwd) {
00070 string prefix, pattern, suffix;
00071
00072 string source = _pattern;
00073 if (!source.empty() && source[0] == '/') {
00074
00075 prefix = "/";
00076 source = source.substr(1);
00077 }
00078
00079 size_t slash = source.find('/');
00080 if (slash == string::npos) {
00081 pattern = source;
00082 } else {
00083 pattern = source.substr(0, slash);
00084 suffix = source.substr(slash + 1);
00085 }
00086
00087 GlobPattern glob(pattern);
00088 return glob.r_match_files(prefix, suffix, results, cwd);
00089 }
00090
00091
00092
00093
00094
00095
00096 int GlobPattern::
00097 r_match_files(const Filename &prefix, const string &suffix,
00098 vector_string &results, const Filename &cwd) {
00099 string next_pattern, next_suffix;
00100
00101 size_t slash = suffix.find('/');
00102 if (slash == string::npos) {
00103 next_pattern = suffix;
00104 } else {
00105 next_pattern = suffix.substr(0, slash);
00106 next_suffix = suffix.substr(slash + 1);
00107 }
00108
00109 Filename parent_dir;
00110 if (prefix.is_local() && !cwd.empty()) {
00111 parent_dir = Filename(cwd, prefix);
00112 } else {
00113 parent_dir = prefix;
00114 }
00115
00116 GlobPattern next_glob(next_pattern);
00117
00118 if (!has_glob_characters()) {
00119
00120
00121 if (suffix.empty()) {
00122
00123 Filename single_filename(parent_dir, _pattern);
00124 if (single_filename.exists()) {
00125 results.push_back(Filename(prefix, _pattern));
00126 return 1;
00127 }
00128 return 0;
00129 }
00130
00131 return next_glob.r_match_files(Filename(prefix, _pattern),
00132 next_suffix, results, cwd);
00133
00134 }
00135
00136
00137
00138
00139 vector_string dir_files;
00140 if (!parent_dir.scan_directory(dir_files)) {
00141
00142 return 0;
00143 }
00144
00145
00146
00147 int num_matched = 0;
00148
00149 vector_string::const_iterator fi;
00150 for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
00151 const string &local_file = (*fi);
00152 if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
00153 if (matches(local_file)) {
00154
00155 if (suffix.empty()) {
00156 results.push_back(Filename(prefix, local_file));
00157 num_matched++;
00158 } else {
00159 num_matched += next_glob.r_match_files(Filename(prefix, local_file),
00160 next_suffix, results, cwd);
00161 }
00162 }
00163 }
00164 }
00165
00166 return num_matched;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 bool GlobPattern::
00178 matches_substr(string::const_iterator pi, string::const_iterator pend,
00179 string::const_iterator ci, string::const_iterator cend) const {
00180
00181
00182 if (pi == pend || ci == cend) {
00183
00184
00185
00186 if ((ci == cend) && (pi + 1 == pend) && (*pi) == '*') {
00187 return true;
00188 }
00189 return (pi == pend && ci == cend);
00190 }
00191
00192 switch (*pi) {
00193
00194 case '*':
00195
00196
00197
00198
00199
00200 return
00201 matches_substr(pi, pend, ci + 1, cend) ||
00202 matches_substr(pi + 1, pend, ci, cend);
00203
00204 case '?':
00205
00206
00207 return matches_substr(pi + 1, pend, ci + 1, cend);
00208
00209 case '[':
00210
00211 ++pi;
00212 if ((*pi) == '!') {
00213 ++pi;
00214 if (matches_set(pi, pend, *ci)) {
00215 return false;
00216 }
00217 } else {
00218 if (!matches_set(pi, pend, *ci)) {
00219 return false;
00220 }
00221 }
00222 if (pi == pend) {
00223
00224 return false;
00225 }
00226 return matches_substr(pi + 1, pend, ci + 1, cend);
00227
00228 case '\\':
00229
00230 ++pi;
00231 if (pi == pend) {
00232 return false;
00233 }
00234
00235
00236 default:
00237
00238 if ((*pi) != (*ci)) {
00239 return false;
00240 }
00241 return matches_substr(pi + 1, pend, ci + 1, cend);
00242 }
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 bool GlobPattern::
00257 matches_set(string::const_iterator &pi, string::const_iterator pend,
00258 char ch) const {
00259 bool matched = false;
00260
00261 while (pi != pend && (*pi) != ']') {
00262 if ((*pi) == '\\') {
00263
00264 ++pi;
00265 if (pi == pend) {
00266 return false;
00267 }
00268 }
00269
00270 if (ch == (*pi)) {
00271 matched = true;
00272 }
00273
00274
00275 char start = (*pi);
00276 ++pi;
00277 if (pi != pend && (*pi) == '-') {
00278 ++pi;
00279 if (pi != pend && (*pi) != ']') {
00280
00281
00282 if ((*pi) == '\\') {
00283
00284 ++pi;
00285 if (pi == pend) {
00286 return false;
00287 }
00288 }
00289
00290 char end = (*pi);
00291 ++pi;
00292
00293 if (ch >= start && ch <= end) {
00294 matched = true;
00295 }
00296 } else {
00297
00298 if (ch == '-') {
00299 matched = true;
00300 }
00301 }
00302 }
00303 }
00304
00305 return matched;
00306 }
00307
00308
00309