Browse Source
We want to use the same style of -L n,m argument for 'git log -L' as for git-blame. Refactor the argument parsing of the range arguments from builtin/blame.c to the (new) file that will hold the 'git log -L' logic. To accommodate different data structures in blame and log -L, the file contents are abstracted away; parse_range_arg takes a callback that it uses to get the contents of a line of the (notional) file. The new test is for a case that made me pause during debugging: the 'blame -L with invalid end' test was the only one that noticed an outright failure to parse the end *at all*. So make a more explicit test for that. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
Bo Yang
12 years ago
committed by
Junio C Hamano
7 changed files with 151 additions and 109 deletions
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
- number |
||||
+ |
||||
If <start> or <end> is a number, it specifies an |
||||
absolute line number (lines count from 1). |
||||
+ |
||||
|
||||
- /regex/ |
||||
+ |
||||
This form will use the first line matching the given |
||||
POSIX regex. If <end> is a regex, it will search |
||||
starting at the line given by <start>. |
||||
+ |
||||
|
||||
- +offset or -offset |
||||
+ |
||||
This is only valid for <end> and will specify a number |
||||
of lines before or after the line given by <start>. |
||||
+ |
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
#include "git-compat-util.h" |
||||
#include "line-range.h" |
||||
|
||||
/* |
||||
* Parse one item in the -L option |
||||
*/ |
||||
static const char *parse_loc(const char *spec, nth_line_fn_t nth_line, |
||||
void *data, long lines, long begin, long *ret) |
||||
{ |
||||
char *term; |
||||
const char *line; |
||||
long num; |
||||
int reg_error; |
||||
regex_t regexp; |
||||
regmatch_t match[1]; |
||||
|
||||
/* Allow "-L <something>,+20" to mean starting at <something> |
||||
* for 20 lines, or "-L <something>,-5" for 5 lines ending at |
||||
* <something>. |
||||
*/ |
||||
if (1 < begin && (spec[0] == '+' || spec[0] == '-')) { |
||||
num = strtol(spec + 1, &term, 10); |
||||
if (term != spec + 1) { |
||||
if (spec[0] == '-') |
||||
num = 0 - num; |
||||
if (0 < num) |
||||
*ret = begin + num - 2; |
||||
else if (!num) |
||||
*ret = begin; |
||||
else |
||||
*ret = begin + num; |
||||
return term; |
||||
} |
||||
return spec; |
||||
} |
||||
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(data, 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++ < lines) { |
||||
nline = nth_line(data, 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); |
||||
} |
||||
} |
||||
|
||||
int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, |
||||
void *cb_data, long lines, long *begin, long *end) |
||||
{ |
||||
arg = parse_loc(arg, nth_line_cb, cb_data, lines, 1, begin); |
||||
|
||||
if (*arg == ',') |
||||
arg = parse_loc(arg + 1, nth_line_cb, cb_data, lines, *begin + 1, end); |
||||
|
||||
if (*arg) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
#ifndef LINE_RANGE_H |
||||
#define LINE_RANGE_H |
||||
|
||||
/* |
||||
* Parse one item in an -L begin,end option w.r.t. the notional file |
||||
* object 'cb_data' consisting of 'lines' lines. |
||||
* |
||||
* The 'nth_line_cb' callback is used to determine the start of the |
||||
* line 'lno' inside the 'cb_data'. The caller is expected to already |
||||
* have a suitable map at hand to make this a constant-time lookup. |
||||
* |
||||
* Returns 0 in case of success and -1 if there was an error. The |
||||
* actual range is stored in *begin and *end. The counting starts |
||||
* at 1! In case of error, the caller should show usage message. |
||||
*/ |
||||
|
||||
typedef const char *(*nth_line_fn_t)(void *data, long lno); |
||||
|
||||
extern int parse_range_arg(const char *arg, |
||||
nth_line_fn_t nth_line_cb, |
||||
void *cb_data, long lines, |
||||
long *begin, long *end); |
||||
|
||||
#endif /* LINE_RANGE_H */ |
Loading…
Reference in new issue