void add_ignore_pattern(ignores *ig, const char* pattern) { int i; int pattern_len; if ('/' == pattern[0]) { log_debug("Pattern begins with '/', skipping."); return; } /* Strip off the leading ./ so that matches are more likely. */ if (strncmp(pattern, "./", 2) == 0) { pattern += 2; } /* Kill trailing whitespace */ for (pattern_len = strlen(pattern); pattern_len > 0; pattern_len--) { if (!isspace(pattern[pattern_len-1])) { break; } } if (pattern_len == 0) { log_debug("Pattern is empty. Not adding any ignores."); return; } /* TODO: de-dupe these patterns */ if (is_fnmatch(pattern)) { ig->regexes_len++; ig->regexes = ag_realloc(ig->regexes, ig->regexes_len * sizeof(char*)); ig->regexes[ig->regexes_len - 1] = ag_strndup(pattern, pattern_len); log_debug("added regex ignore pattern %s", pattern); } else { /* a balanced binary tree is best for performance, but I'm lazy */ ig->names_len++; ig->names = ag_realloc(ig->names, ig->names_len * sizeof(char*)); for (i = ig->names_len - 1; i > 0; i--) { if (strcmp(pattern, ig->names[i-1]) > 0) { break; } ig->names[i] = ig->names[i-1]; } ig->names[i] = ag_strndup(pattern, pattern_len); log_debug("added literal ignore pattern %s", pattern); } }
void add_ignore_pattern(ignores *ig, const char *pattern) { int i; int pattern_len; /* Strip off the leading dot so that matches are more likely. */ if (strncmp(pattern, "./", 2) == 0) { pattern++; } /* Kill trailing whitespace */ for (pattern_len = strlen(pattern); pattern_len > 0; pattern_len--) { if (!isspace(pattern[pattern_len - 1])) { break; } } if (pattern_len == 0) { log_debug("Pattern is empty. Not adding any ignores."); return; } char ***patterns_p; size_t *patterns_len; if (is_fnmatch(pattern)) { if (pattern[0] == '/') { patterns_p = &(ig->slash_regexes); patterns_len = &(ig->slash_regexes_len); pattern++; pattern_len--; } else { patterns_p = &(ig->regexes); patterns_len = &(ig->regexes_len); } } else { if (pattern[0] == '/') { patterns_p = &(ig->slash_names); patterns_len = &(ig->slash_names_len); pattern++; pattern_len--; } else { patterns_p = &(ig->names); patterns_len = &(ig->names_len); } } ++*patterns_len; char **patterns; /* a balanced binary tree is best for performance, but I'm lazy */ *patterns_p = patterns = ag_realloc(*patterns_p, (*patterns_len) * sizeof(char *)); /* TODO: de-dupe these patterns */ for (i = *patterns_len - 1; i > 0; i--) { if (strcmp(pattern, patterns[i - 1]) > 0) { break; } patterns[i] = patterns[i - 1]; } patterns[i] = ag_strndup(pattern, pattern_len); log_debug("added ignore pattern %s to %s", pattern, ig == root_ignores ? "root ignores" : ig->abs_path); }
void load_svn_ignore_patterns(ignores *ig, const char *path) { FILE *fp = NULL; char *dir_prop_base; ag_asprintf(&dir_prop_base, "%s/%s", path, SVN_DIR_PROP_BASE); fp = fopen(dir_prop_base, "r"); if (fp == NULL) { log_debug("Skipping svn ignore file %s", dir_prop_base); free(dir_prop_base); return; } char *entry = NULL; size_t entry_len = 0; char *key = ag_malloc(32); /* Sane start for max key length. */ size_t key_len = 0; size_t bytes_read = 0; char *entry_line; size_t line_len; int matches; while (fscanf(fp, "K %zu\n", &key_len) == 1) { key = ag_realloc(key, key_len + 1); bytes_read = fread(key, 1, key_len, fp); key[key_len] = '\0'; matches = fscanf(fp, "\nV %zu\n", &entry_len); if (matches != 1) { log_debug("Unable to parse svnignore file %s: fscanf() got %i matches, expected 1.", dir_prop_base, matches); goto cleanup; } if (strncmp(SVN_PROP_IGNORE, key, bytes_read) != 0) { log_debug("key is %s, not %s. skipping %u bytes", key, SVN_PROP_IGNORE, entry_len); /* Not the key we care about. fseek and repeat */ fseek(fp, entry_len + 1, SEEK_CUR); /* +1 to account for newline. yes I know this is hacky */ continue; } /* Aww yeah. Time to ignore stuff */ entry = ag_malloc(entry_len + 1); bytes_read = fread(entry, 1, entry_len, fp); entry[bytes_read] = '\0'; log_debug("entry: %s", entry); break; } if (entry == NULL) { goto cleanup; } char *patterns = entry; size_t patterns_len = strlen(patterns); while (*patterns != '\0' && patterns < (entry + bytes_read)) { for (line_len = 0; line_len < patterns_len; line_len++) { if (patterns[line_len] == '\n') { break; } } if (line_len > 0) { entry_line = ag_strndup(patterns, line_len); add_ignore_pattern(ig, entry_line); free(entry_line); } patterns += line_len + 1; patterns_len -= line_len + 1; } free(entry); cleanup: free(dir_prop_base); free(key); fclose(fp); }
void print_file_matches(const char* path, const char* buf, const int buf_len, const match matches[], const int matches_len) { int line = 1; char **context_prev_lines = NULL; int prev_line = 0; int last_prev_line = 0; int prev_line_offset = 0; int cur_match = 0; /* TODO the line below contains a terrible hack */ int lines_since_last_match = 1000000; /* if I initialize this to INT_MAX it'll overflow */ int lines_to_print = 0; int last_printed_match = 0; char sep = '-'; int i, j; int in_a_match = FALSE; int printing_a_match = FALSE; if (opts.ackmate) { sep = ':'; } print_file_separator(); if (opts.print_heading == TRUE) { print_path(path, '\n'); } context_prev_lines = ag_calloc(sizeof(char*), (opts.before + 1)); for (i = 0; i <= buf_len && (cur_match < matches_len || lines_since_last_match <= opts.after); i++) { if (cur_match < matches_len && i == matches[cur_match].end) { /* We found the end of a match. */ cur_match++; in_a_match = FALSE; } if (cur_match < matches_len && i == matches[cur_match].start) { in_a_match = TRUE; /* We found the start of a match */ if (cur_match > 0 && opts.context && lines_since_last_match > (opts.before + opts.after + 1)) { fprintf(out_fd, "--\n"); } if (lines_since_last_match > 0 && opts.before > 0) { /* TODO: better, but still needs work */ /* print the previous line(s) */ lines_to_print = lines_since_last_match - (opts.after + 1); if (lines_to_print < 0) { lines_to_print = 0; } else if (lines_to_print > opts.before) { lines_to_print = opts.before; } for (j = (opts.before - lines_to_print); j < opts.before; j++) { prev_line = (last_prev_line + j) % opts.before; if (context_prev_lines[prev_line] != NULL) { if (opts.print_heading == 0) { print_path(path, ':'); } print_line_number(line - (opts.before - j), sep); fprintf(out_fd, "%s\n", context_prev_lines[prev_line]); } } } lines_since_last_match = 0; } /* We found the end of a line. */ if (buf[i] == '\n' && opts.before > 0) { if (context_prev_lines[last_prev_line] != NULL) { free(context_prev_lines[last_prev_line]); } /* We don't want to strcpy the \n */ context_prev_lines[last_prev_line] = ag_strndup(&buf[prev_line_offset], i - prev_line_offset); last_prev_line = (last_prev_line + 1) % opts.before; } if (buf[i] == '\n' || i == buf_len) { if (lines_since_last_match == 0) { if (opts.print_heading == 0 && !opts.search_stream) { print_path(path, ':'); } if (opts.ackmate) { /* print headers for ackmate to parse */ print_line_number(line, ';'); for (; last_printed_match < cur_match; last_printed_match++) { fprintf(out_fd, "%i %i", (matches[last_printed_match].start - prev_line_offset), (matches[last_printed_match].end - matches[last_printed_match].start) ); last_printed_match == cur_match - 1 ? fputc(':', out_fd) : fputc(',', out_fd); } j = prev_line_offset; /* print up to current char */ for (; j <= i; j++) { fputc(buf[j], out_fd); } } else { print_line_number(line, ':'); if (opts.column) { fprintf(out_fd, "%i:", (matches[last_printed_match].start - prev_line_offset) + 1); } if (printing_a_match && opts.color) { fprintf(out_fd, "%s", opts.color_match); } for (j = prev_line_offset; j <= i; j++) { if (j == matches[last_printed_match].end && last_printed_match < matches_len) { if (opts.color) { fprintf(out_fd, "%s", color_reset); } printing_a_match = FALSE; last_printed_match++; } if (j == matches[last_printed_match].start && last_printed_match < matches_len) { if (opts.color) { fprintf(out_fd, "%s", opts.color_match); } printing_a_match = TRUE; } /* Don't print the null terminator */ if (j < buf_len) { fputc(buf[j], out_fd); } } if (printing_a_match && opts.color) { fprintf(out_fd, "%s", color_reset); } } } else if (lines_since_last_match <= opts.after && i != buf_len) { /* print context after matching line */ if (opts.print_heading == 0) { print_path(path, ':'); } print_line_number(line, sep); for (j = prev_line_offset; j < i; j++) { fputc(buf[j], out_fd); } fputc('\n', out_fd); } prev_line_offset = i + 1; /* skip the newline */ line++; if (!in_a_match) { lines_since_last_match++; } /* File doesn't end with a newline. Print one so the output is pretty. */ if (i == buf_len && buf[i] != '\n') { fputc('\n', out_fd); } } } for (i = 0; i < opts.before; i++) { if (context_prev_lines[i] != NULL) { free(context_prev_lines[i]); } } free(context_prev_lines); }
void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match_t matches[], const size_t matches_len) { size_t line = 1; char **context_prev_lines = NULL; size_t prev_line = 0; size_t last_prev_line = 0; size_t prev_line_offset = 0; size_t cur_match = 0; size_t lines_since_last_match = INT_MAX; ssize_t lines_to_print = 0; size_t last_printed_match = 0; char sep = '-'; size_t i, j; int in_a_match = FALSE; int printing_a_match = FALSE; if (opts.ackmate || opts.vimgrep) { sep = ':'; } print_file_separator(); if (opts.print_path == PATH_PRINT_DEFAULT) { opts.print_path = PATH_PRINT_TOP; } else if (opts.print_path == PATH_PRINT_DEFAULT_EACH_LINE) { opts.print_path = PATH_PRINT_EACH_LINE; } if (opts.print_path == PATH_PRINT_TOP) { if (opts.print_count) { print_path_count(path, opts.path_sep, matches_len); } else { print_path(path, opts.path_sep); } } context_prev_lines = ag_calloc(sizeof(char *), (opts.before + 1)); for (i = 0; i <= buf_len && (cur_match < matches_len || lines_since_last_match <= opts.after); i++) { if (cur_match < matches_len && i == matches[cur_match].start) { in_a_match = TRUE; /* We found the start of a match */ if (cur_match > 0 && opts.context && lines_since_last_match > (opts.before + opts.after + 1)) { fprintf(out_fd, "--\n"); } if (lines_since_last_match > 0 && opts.before > 0) { /* TODO: better, but still needs work */ /* print the previous line(s) */ lines_to_print = lines_since_last_match - (opts.after + 1); if (lines_to_print < 0) { lines_to_print = 0; } else if ((size_t)lines_to_print > opts.before) { lines_to_print = opts.before; } for (j = (opts.before - lines_to_print); j < opts.before; j++) { prev_line = (last_prev_line + j) % opts.before; if (context_prev_lines[prev_line] != NULL) { if (opts.print_path == PATH_PRINT_EACH_LINE) { print_path(path, ':'); } print_line_number(line - (opts.before - j), sep); fprintf(out_fd, "%s\n", context_prev_lines[prev_line]); } } } lines_since_last_match = 0; } if (cur_match < matches_len && i == matches[cur_match].end) { /* We found the end of a match. */ cur_match++; in_a_match = FALSE; } /* We found the end of a line. */ if (buf[i] == '\n' && opts.before > 0) { if (context_prev_lines[last_prev_line] != NULL) { free(context_prev_lines[last_prev_line]); } /* We don't want to strcpy the \n */ context_prev_lines[last_prev_line] = ag_strndup(&buf[prev_line_offset], i - prev_line_offset); last_prev_line = (last_prev_line + 1) % opts.before; } if (buf[i] == '\n' || i == buf_len) { if (lines_since_last_match == 0) { if (opts.print_path == PATH_PRINT_EACH_LINE && !opts.search_stream) { print_path(path, ':'); } if (opts.ackmate) { /* print headers for ackmate to parse */ print_line_number(line, ';'); for (; last_printed_match < cur_match; last_printed_match++) { /* Don't print negative offsets. This isn't quite right, but not many people use --ackmate */ long start = (long)(matches[last_printed_match].start - prev_line_offset); if (start < 0) { start = 0; } fprintf(out_fd, "%li %li", start, (long)(matches[last_printed_match].end - matches[last_printed_match].start)); last_printed_match == cur_match - 1 ? fputc(':', out_fd) : fputc(',', out_fd); } print_line(buf, i, prev_line_offset); } else if (opts.vimgrep) { for (; last_printed_match < cur_match; last_printed_match++) { print_path(path, sep); print_line_number(line, sep); print_column_number(matches, last_printed_match, prev_line_offset, sep); print_line(buf, i, prev_line_offset); } } else { print_line_number(line, ':'); int printed_match = FALSE; if (opts.column) { print_column_number(matches, last_printed_match, prev_line_offset, ':'); } if (printing_a_match && opts.color) { fprintf(out_fd, "%s", opts.color_match); } for (j = prev_line_offset; j <= i; j++) { if (last_printed_match < matches_len && j == matches[last_printed_match].end) { if (opts.color) { fprintf(out_fd, "%s", color_reset); } printing_a_match = FALSE; last_printed_match++; printed_match = TRUE; if (opts.only_matching) { fputc('\n', out_fd); } } if (last_printed_match < matches_len && j == matches[last_printed_match].start) { if (opts.only_matching && printed_match) { if (opts.print_path == PATH_PRINT_EACH_LINE) { print_path(path, ':'); } print_line_number(line, ':'); if (opts.column) { print_column_number(matches, last_printed_match, prev_line_offset, ':'); } } if (opts.color) { fprintf(out_fd, "%s", opts.color_match); } printing_a_match = TRUE; } /* Don't print the null terminator */ if (j < buf_len) { /* if only_matching is set, print only matches and newlines */ if (!opts.only_matching || printing_a_match) { fputc(buf[j], out_fd); } } } if (printing_a_match && opts.color) { fprintf(out_fd, "%s", color_reset); } } } else if (lines_since_last_match <= opts.after) { /* print context after matching line */ if (opts.print_path == PATH_PRINT_EACH_LINE) { print_path(path, ':'); } print_line_number(line, sep); for (j = prev_line_offset; j < i; j++) { fputc(buf[j], out_fd); } fputc('\n', out_fd); } prev_line_offset = i + 1; /* skip the newline */ line++; if (!in_a_match && lines_since_last_match < INT_MAX) { lines_since_last_match++; } /* File doesn't end with a newline. Print one so the output is pretty. */ if (i == buf_len && buf[i] != '\n' && !opts.search_stream) { fputc('\n', out_fd); } } } for (i = 0; i < opts.before; i++) { if (context_prev_lines[i] != NULL) { free(context_prev_lines[i]); } } free(context_prev_lines); }