mirror of
https://github.com/git/git.git
synced 2024-06-13 13:07:13 +02:00
93 lines
2.0 KiB
C
93 lines
2.0 KiB
C
|
#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;
|
||
|
}
|