diff options
-rw-r--r-- | builtin-pickaxe.c | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/builtin-pickaxe.c b/builtin-pickaxe.c index f12b2d4544..673185f96d 100644 --- a/builtin-pickaxe.c +++ b/builtin-pickaxe.c @@ -17,6 +17,7 @@ #include <time.h> #include <sys/time.h> +#include <regex.h> static char pickaxe_usage[] = "git-pickaxe [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n" @@ -1533,6 +1534,78 @@ static const char *add_prefix(const char *prefix, const char *path) return prefix_path(prefix, strlen(prefix), path); } +static const char *parse_loc(const char *spec, + struct scoreboard *sb, long lno, + long begin, long *ret) +{ + char *term; + const char *line; + long num; + int reg_error; + regex_t regexp; + regmatch_t match[1]; + + num = strtol(spec, &term, 10); + if (term != spec) { + *ret = num; + return term; + } + if (spec[0] != '/') + return spec; + + /* it could be a regexp of form /.../ */ + for (term = (char*) spec + 1; *term && *term != '/'; term++) { + if (*term == '\\') + term++; + } + if (*term != '/') + return spec; + + /* try [spec+1 .. term-1] as regexp */ + *term = 0; + begin--; /* input is in human terms */ + line = nth_line(sb, begin); + + if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) && + !(reg_error = regexec(®exp, line, 1, match, 0))) { + const char *cp = line + match[0].rm_so; + const char *nline; + + while (begin++ < lno) { + nline = nth_line(sb, begin); + if (line <= cp && cp < nline) + break; + line = nline; + } + *ret = begin; + regfree(®exp); + *term++ = '/'; + return term; + } + else { + char errbuf[1024]; + regerror(reg_error, ®exp, errbuf, 1024); + die("-L parameter '%s': %s", spec + 1, errbuf); + } +} + +static void prepare_blame_range(struct scoreboard *sb, + const char *bottomtop, + long lno, + long *bottom, long *top) +{ + const char *term; + + term = parse_loc(bottomtop, sb, lno, 1, bottom); + if (*term == ',') { + term = parse_loc(term + 1, sb, lno, *bottom + 1, top); + if (*term) + usage(pickaxe_usage); + } + if (*term) + usage(pickaxe_usage); +} + int cmd_pickaxe(int argc, const char **argv, const char *prefix) { struct rev_info revs; @@ -1546,11 +1619,11 @@ int cmd_pickaxe(int argc, const char **argv, const char *prefix) const char *revs_file = NULL; const char *final_commit_name = NULL; char type[10]; + const char *bottomtop = NULL; save_commit_buffer = 0; opt = 0; - bottom = top = 0; seen_dashdash = 0; for (unk = i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -1575,7 +1648,6 @@ int cmd_pickaxe(int argc, const char **argv, const char *prefix) blame_copy_score = parse_score(arg+2); } else if (!strncmp("-L", arg, 2)) { - char *term; if (!arg[2]) { if (++i >= argc) usage(pickaxe_usage); @@ -1583,18 +1655,9 @@ int cmd_pickaxe(int argc, const char **argv, const char *prefix) } else arg += 2; - if (bottom || top) + if (bottomtop) die("More than one '-L n,m' option given"); - bottom = strtol(arg, &term, 10); - if (*term == ',') { - top = strtol(term + 1, &term, 10); - if (*term) - usage(pickaxe_usage); - } - if (bottom && top && top < bottom) { - unsigned long tmp; - tmp = top; top = bottom; bottom = tmp; - } + bottomtop = arg; } else if (!strcmp("--score-debug", arg)) output_option |= OUTPUT_SHOW_SCORE; @@ -1755,6 +1818,13 @@ int cmd_pickaxe(int argc, const char **argv, const char *prefix) num_read_blob++; lno = prepare_lines(&sb); + bottom = top = 0; + if (bottomtop) + prepare_blame_range(&sb, bottomtop, lno, &bottom, &top); + if (bottom && top && top < bottom) { + long tmp; + tmp = top; top = bottom; bottom = tmp; + } if (bottom < 1) bottom = 1; if (top < 1) |