]>
Commit | Line | Data |
---|---|---|
25ed3412 BY |
1 | #include "git-compat-util.h" |
2 | #include "line-range.h" | |
3 | ||
4 | /* | |
5 | * Parse one item in the -L option | |
6 | */ | |
7 | static const char *parse_loc(const char *spec, nth_line_fn_t nth_line, | |
8 | void *data, long lines, long begin, long *ret) | |
9 | { | |
10 | char *term; | |
11 | const char *line; | |
12 | long num; | |
13 | int reg_error; | |
14 | regex_t regexp; | |
15 | regmatch_t match[1]; | |
16 | ||
17 | /* Allow "-L <something>,+20" to mean starting at <something> | |
18 | * for 20 lines, or "-L <something>,-5" for 5 lines ending at | |
19 | * <something>. | |
20 | */ | |
21 | if (1 < begin && (spec[0] == '+' || spec[0] == '-')) { | |
22 | num = strtol(spec + 1, &term, 10); | |
23 | if (term != spec + 1) { | |
24 | if (spec[0] == '-') | |
25 | num = 0 - num; | |
26 | if (0 < num) | |
27 | *ret = begin + num - 2; | |
28 | else if (!num) | |
29 | *ret = begin; | |
30 | else | |
31 | *ret = begin + num; | |
32 | return term; | |
33 | } | |
34 | return spec; | |
35 | } | |
36 | num = strtol(spec, &term, 10); | |
37 | if (term != spec) { | |
38 | *ret = num; | |
39 | return term; | |
40 | } | |
41 | if (spec[0] != '/') | |
42 | return spec; | |
43 | ||
44 | /* it could be a regexp of form /.../ */ | |
45 | for (term = (char *) spec + 1; *term && *term != '/'; term++) { | |
46 | if (*term == '\\') | |
47 | term++; | |
48 | } | |
49 | if (*term != '/') | |
50 | return spec; | |
51 | ||
52 | /* try [spec+1 .. term-1] as regexp */ | |
53 | *term = 0; | |
54 | begin--; /* input is in human terms */ | |
55 | line = nth_line(data, begin); | |
56 | ||
57 | if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) && | |
58 | !(reg_error = regexec(®exp, line, 1, match, 0))) { | |
59 | const char *cp = line + match[0].rm_so; | |
60 | const char *nline; | |
61 | ||
62 | while (begin++ < lines) { | |
63 | nline = nth_line(data, begin); | |
64 | if (line <= cp && cp < nline) | |
65 | break; | |
66 | line = nline; | |
67 | } | |
68 | *ret = begin; | |
69 | regfree(®exp); | |
70 | *term++ = '/'; | |
71 | return term; | |
72 | } | |
73 | else { | |
74 | char errbuf[1024]; | |
75 | regerror(reg_error, ®exp, errbuf, 1024); | |
76 | die("-L parameter '%s': %s", spec + 1, errbuf); | |
77 | } | |
78 | } | |
79 | ||
80 | int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, | |
81 | void *cb_data, long lines, long *begin, long *end) | |
82 | { | |
83 | arg = parse_loc(arg, nth_line_cb, cb_data, lines, 1, begin); | |
84 | ||
85 | if (*arg == ',') | |
86 | arg = parse_loc(arg + 1, nth_line_cb, cb_data, lines, *begin + 1, end); | |
87 | ||
88 | if (*arg) | |
89 | return -1; | |
90 | ||
91 | return 0; | |
92 | } |