~ubuntu-branches/ubuntu/utopic/silversearcher-ag/utopic-proposed

« back to all changes in this revision

Viewing changes to src/ignore.c

  • Committer: Package Import Robot
  • Author(s): Hajime Mizuno
  • Date: 2014-06-15 14:08:20 UTC
  • mfrom: (1.1.5)
  • Revision ID: package-import@ubuntu.com-20140615140820-a3t6lv1x4hp2uz4m
Tags: 0.22.0-1
new upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#include "util.h"
13
13
 
14
14
#ifdef _WIN32
15
 
# include <shlwapi.h>
16
 
# define fnmatch(x, y, z) (!PathMatchSpec(y,x))
 
15
#include <shlwapi.h>
 
16
#define fnmatch(x, y, z) (!PathMatchSpec(y, x))
17
17
#else
18
 
# include <fnmatch.h>
19
 
const int fnmatch_flags = 0 & FNM_PATHNAME;
 
18
#include <fnmatch.h>
 
19
const int fnmatch_flags = FNM_PATHNAME;
20
20
#endif
21
21
 
22
22
/* TODO: build a huge-ass list of files we want to ignore by default (build cache stuff, pyc files, etc) */
67
67
    }
68
68
}
69
69
 
70
 
void add_ignore_pattern(ignores *ig, const char* pattern) {
 
70
void add_ignore_pattern(ignores *ig, const char *pattern) {
71
71
    int i;
72
72
    int pattern_len;
73
73
 
74
 
    /* Strip off the leading ./ so that matches are more likely. */
 
74
    /* Strip off the leading dot so that matches are more likely. */
75
75
    if (strncmp(pattern, "./", 2) == 0) {
76
 
        pattern += 2;
 
76
        pattern++;
77
77
    }
78
78
 
79
79
    /* Kill trailing whitespace */
80
80
    for (pattern_len = strlen(pattern); pattern_len > 0; pattern_len--) {
81
 
        if (!isspace(pattern[pattern_len-1])) {
 
81
        if (!isspace(pattern[pattern_len - 1])) {
82
82
            break;
83
83
        }
84
84
    }
91
91
    /* TODO: de-dupe these patterns */
92
92
    if (is_fnmatch(pattern)) {
93
93
        ig->regexes_len++;
94
 
        ig->regexes = ag_realloc(ig->regexes, ig->regexes_len * sizeof(char*));
95
 
        ig->regexes[ig->regexes_len - 1] = ag_strndup(pattern, pattern_len);
 
94
        ig->regexes = ag_realloc(ig->regexes, ig->regexes_len * sizeof(char *));
 
95
        if (pattern[0] != '/') {
 
96
            ag_asprintf(&(ig->regexes[ig->regexes_len - 1]), "*/%s", pattern);
 
97
        } else {
 
98
            ig->regexes[ig->regexes_len - 1] = ag_strndup(pattern, pattern_len);
 
99
        }
96
100
        log_debug("added regex ignore pattern %s", pattern);
97
101
    } else {
98
102
        /* a balanced binary tree is best for performance, but I'm lazy */
99
103
        ig->names_len++;
100
 
        ig->names = ag_realloc(ig->names, ig->names_len * sizeof(char*));
 
104
        ig->names = ag_realloc(ig->names, ig->names_len * sizeof(char *));
101
105
        for (i = ig->names_len - 1; i > 0; i--) {
102
 
            if (strcmp(pattern, ig->names[i-1]) > 0) {
 
106
            if (strcmp(pattern, ig->names[i - 1]) > 0) {
103
107
                break;
104
108
            }
105
 
            ig->names[i] = ig->names[i-1];
 
109
            ig->names[i] = ig->names[i - 1];
106
110
        }
107
111
        ig->names[i] = ag_strndup(pattern, pattern_len);
108
112
        log_debug("added literal ignore pattern %s", pattern);
126
130
        if (line_len == 0 || line[0] == '\n' || line[0] == '#') {
127
131
            continue;
128
132
        }
129
 
        if (line[line_len-1] == '\n') {
130
 
            line[line_len-1] = '\0'; /* kill the \n */
 
133
        if (line[line_len - 1] == '\n') {
 
134
            line[line_len - 1] = '\0'; /* kill the \n */
131
135
        }
132
136
        add_ignore_pattern(ig, line);
133
137
    }
200
204
        patterns_len -= line_len + 1;
201
205
    }
202
206
    free(entry);
203
 
    cleanup:;
 
207
cleanup:
204
208
    free(dir_prop_base);
205
209
    free(key);
206
210
    fclose(fp);
207
211
}
208
212
 
209
 
static int ackmate_dir_match(const char* dir_name) {
210
 
    int rc = 0;
211
 
 
212
 
    if (opts.ackmate_dir_filter != NULL) {
213
 
        /* we just care about the match, not where the matches are */
214
 
        rc = pcre_exec(opts.ackmate_dir_filter, NULL, dir_name, strlen(dir_name), 0, 0, NULL, 0);
215
 
        if (rc >= 0) {
216
 
            log_debug("file %s ignored because name matches ackmate dir filter pattern", dir_name);
217
 
            return 1;
218
 
        }
 
213
static int ackmate_dir_match(const char *dir_name) {
 
214
    if (opts.ackmate_dir_filter == NULL) {
 
215
        return 0;
219
216
    }
220
 
 
221
 
    return 0;
 
217
    /* we just care about the match, not where the matches are */
 
218
    return pcre_exec(opts.ackmate_dir_filter, NULL, dir_name, strlen(dir_name), 0, 0, NULL, 0);
222
219
}
223
220
 
224
221
static int filename_ignore_search(const ignores *ig, const char *filename) {
225
 
    size_t i;
226
222
    int match_pos;
227
223
 
228
224
    if (strncmp(filename, "./", 2) == 0) {
229
 
        filename += 2;
 
225
        filename++;
230
226
    }
231
227
 
232
228
    match_pos = binary_search(filename, ig->names, 0, ig->names_len);
235
231
        return 1;
236
232
    }
237
233
 
238
 
    if (ackmate_dir_match(filename)) {
239
 
        log_debug("file %s ignored because name matches ackmate regex", filename);
240
 
        return 1;
241
 
    }
242
 
 
243
 
    for (i = 0; i < ig->regexes_len; i++) {
244
 
        if (fnmatch(ig->regexes[i], filename, fnmatch_flags) == 0) {
245
 
            log_debug("file %s ignored because name matches regex pattern %s", filename, ig->regexes[i]);
246
 
            return 1;
247
 
        }
248
 
        log_debug("pattern %s doesn't match file %s", ig->regexes[i], filename);
249
 
    }
250
234
    log_debug("file %s not ignored", filename);
251
235
    return 0;
252
236
}
257
241
    if (filename_ignore_search(ig, filename)) {
258
242
        return 1;
259
243
    }
260
 
    ag_asprintf(&temp, "%s/%s", path, filename);
261
 
    int rv = filename_ignore_search(ig, temp);
 
244
 
 
245
    ag_asprintf(&temp, "%s/%s", path[0] == '.' ? path + 1 : path, filename);
 
246
 
 
247
    if (filename_ignore_search(ig, temp)) {
 
248
        free(temp);
 
249
        return 1;
 
250
    }
 
251
 
 
252
    int rv = 0;
 
253
    size_t i;
 
254
    char *regex;
 
255
    for (i = 0; i < ig->regexes_len; i++) {
 
256
        regex = ig->regexes[i];
 
257
        /* TODO: behave specially if regex doesn't start with a slash
 
258
        if (regex[0] == '/') {
 
259
         */
 
260
        if (fnmatch(regex, temp, fnmatch_flags) == 0) {
 
261
            log_debug("file %s ignored because name matches regex pattern %s", temp, regex);
 
262
            rv = 1;
 
263
            break;
 
264
        }
 
265
        log_debug("pattern %s doesn't match file %s", regex, temp);
 
266
    }
 
267
    if (rv == 0) {
 
268
        rv = ackmate_dir_match(temp);
 
269
    }
262
270
    free(temp);
263
271
    return rv;
264
272
}
266
274
/* This function is REALLY HOT. It gets called for every file */
267
275
int filename_filter(const char *path, const struct dirent *dir, void *baton) {
268
276
    const char *filename = dir->d_name;
 
277
    /* TODO: don't call strlen on filename every time we call filename_filter() */
269
278
    size_t filename_len = strlen(filename);
270
279
    size_t i;
271
 
    scandir_baton_t *scandir_baton = (scandir_baton_t*) baton;
 
280
    scandir_baton_t *scandir_baton = (scandir_baton_t *)baton;
272
281
    const ignores *ig = scandir_baton->ig;
273
282
    const char *base_path = scandir_baton->base_path;
274
 
    size_t base_path_len = strlen(base_path);
 
283
    const size_t base_path_len = scandir_baton->base_path_len;
275
284
    const char *path_start = path;
276
285
    char *temp;
277
286
 
302
311
        /* base_path always ends with "/\0" while path doesn't, so this is safe */
303
312
        path_start = path + i + 2;
304
313
    }
305
 
    log_debug("path_start is %s", path_start);
306
 
 
307
 
    if (path_ignore_search(ig, path_start, filename)) {
308
 
        return 0;
309
 
    }
310
 
 
311
 
    if (is_directory(path, dir) && filename[filename_len - 1] != '/') {
312
 
        ag_asprintf(&temp, "%s/", filename);
313
 
        int rv = path_ignore_search(ig, path_start, temp);
314
 
        free(temp);
315
 
        if (rv) {
316
 
            return 0;
317
 
        }
318
 
    }
319
 
 
320
 
    /* TODO: copy-pasted from above */
321
 
    if (scandir_baton->level == 0) {
322
 
        char *temp2; /* horrible variable name, I know */
323
 
        ag_asprintf(&temp, "/%s", filename);
324
 
        if (path_ignore_search(ig, path_start, temp)) {
325
 
            return 0;
326
 
        }
327
 
 
328
 
        if (is_directory(path, dir) && temp[filename_len - 1] != '/') {
329
 
            ag_asprintf(&temp2, "%s/", temp);
330
 
            int rv = path_ignore_search(ig, path_start, temp2);
331
 
            free(temp2);
 
314
    log_debug("path_start %s filename %s", path_start, filename);
 
315
 
 
316
    while (ig != NULL) {
 
317
        if (path_ignore_search(ig, path_start, filename)) {
 
318
            return 0;
 
319
        }
 
320
 
 
321
        if (is_directory(path, dir) && filename[filename_len - 1] != '/') {
 
322
            ag_asprintf(&temp, "%s/", filename);
 
323
            int rv = path_ignore_search(ig, path_start, temp);
 
324
            free(temp);
332
325
            if (rv) {
333
326
                return 0;
334
327
            }
335
328
        }
336
 
        free(temp);
337
 
    }
338
 
 
339
 
    scandir_baton->level++;
340
 
    if (ig->parent != NULL) {
341
 
        scandir_baton->ig = ig->parent;
342
 
        return filename_filter(path, dir, (void *)scandir_baton);
 
329
        ig = ig->parent;
343
330
    }
344
331
 
345
332
    return 1;