[PATCH] grep -A/-B/-Cinfinity to get full context
Just a proof of concept.
Cc: René Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Jakub Narebski wrote:
> If there were more options that use <n> == 0 to actually mean unlimited
> (infinity), perhaps it would be better to extend parseopt to provide for
> such situation, e.g. OPT_INT_INF or something.
Something like this, maybe.
Documentation/technical/api-parse-options.txt | 6 ++++++
builtin/grep.c | 8 ++++++--
grep.c | 8 +++++---
grep.h | 4 ++--
parse-options.c | 21 +++++++++++++++++++++
parse-options.h | 4 ++++
6 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 312e3b2..f152a3f 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -160,6 +160,12 @@ There are some macros to easily define options:
Introduce an option with integer argument.
The integer is put into `int_var`.
+`OPT_INT_INF(short, long, &int_var, inf_val, description)`::
+ Introduce an option with integer argument.
+ The integer is put into `int_var`. If the special value
+ "inf" (or "infinity") is used as an argument, then `inf_val`
+ is put into `int_var`.
+
`OPT_DATE(short, long, &int_var, description)`::
Introduce an option with date argument, see `approxidate()`.
The timestamp is put into `int_var`.
diff --git a/builtin/grep.c b/builtin/grep.c
index 597f76b..9fbc985 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -750,6 +750,10 @@ static int context_callback(const struct option *opt, const char *arg,
grep_opt->pre_context = grep_opt->post_context = 0;
return 0;
}
+ if (!strcasecmp(arg, "inf") || !strcasecmp(arg, "infinity")) {
+ grep_opt->pre_context = grep_opt->post_context = -1;
+ return 0;
+ }
value = strtol(arg, (char **)&endp, 10);
if (*endp) {
return error("switch `%c' expects a numerical value",
@@ -890,9 +894,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_CALLBACK('C', NULL, &opt, "n",
"show <n> context lines before and after matches",
context_callback),
- OPT_INTEGER('B', NULL, &opt.pre_context,
+ OPT_INT_INF('B', NULL, &opt.pre_context, -1,
"show <n> context lines before matches"),
- OPT_INTEGER('A', NULL, &opt.post_context,
+ OPT_INT_INF('A', NULL, &opt.post_context, -1,
"show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback),
diff --git a/grep.c b/grep.c
index 82fb349..793d41f 100644
--- a/grep.c
+++ b/grep.c
@@ -687,7 +687,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
unsigned cur = lno, from = 1, funcname_lno = 0;
int funcname_needed = opt->funcname;
- if (opt->pre_context < lno)
+ if (opt->pre_context >= 0 && opt->pre_context < lno)
from = lno - opt->pre_context;
if (from <= opt->last_shown)
from = opt->last_shown + 1;
@@ -861,7 +861,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
*/
if (try_lookahead
&& !(last_hit
- && lno <= last_hit + opt->post_context)
+ && (opt->post_context < 0
+ || lno <= last_hit + opt->post_context))
&& look_ahead(opt, &left, &lno, &bol))
break;
eol = end_of_line(bol, &left);
@@ -916,7 +917,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
last_hit = lno;
}
else if (last_hit &&
- lno <= last_hit + opt->post_context) {
+ (opt->post_context < 0 ||
+ lno <= last_hit + opt->post_context)) {
/* If the last hit is within the post context,
* we need to show this line.
*/
diff --git a/grep.h b/grep.h
index efa8cff..13aae94 100644
--- a/grep.h
+++ b/grep.h
@@ -95,8 +95,8 @@ struct grep_opt {
char color_selected[COLOR_MAXLEN];
char color_sep[COLOR_MAXLEN];
int regflags;
- unsigned pre_context;
- unsigned post_context;
+ int pre_context;
+ int post_context;
unsigned last_shown;
int show_hunk_mark;
void *priv;
diff --git a/parse-options.c b/parse-options.c
index 0fa79bc..b299125 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -612,6 +612,27 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
return 0;
}
+int parse_opt_infinity_cb(const struct option *opt, const char *arg,
+ int unset)
+{
+ const char *endp;
+
+ if (unset) {
+ *(int *)opt->value = 0;
+ return 0;
+ }
+ if (!arg)
+ return opterror(opt, "expects a numerical value", 0);
+ if (!strcasecmp(arg, "inf") || !strcasecmp(arg, "infinity")) {
+ *(int *)opt->value = opt->defval;
+ return 0;
+ }
+ *(int *)opt->value = strtol(arg, (char **)&endp, 10);
+ if (*endp)
+ return opterror(opt, "expects a numerical value", 0);
+ return 0;
+}
+
int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
int unset)
{
diff --git a/parse-options.h b/parse-options.h
index 7435cdb..6ae041a 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -126,6 +126,9 @@ struct option {
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_UYN(s, l, v, h) { OPTION_CALLBACK, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, &parse_opt_tertiary }
+#define OPT_INT_INF(s, l, v, i, h) \
+ { OPTION_CALLBACK, (s), (l), (v), "n", (h), 0, \
+ parse_opt_infinity_cb, (intptr_t)(i) }
#define OPT_DATE(s, l, v, h) \
{ OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
parse_opt_approxidate_cb }
@@ -193,6 +196,7 @@ extern int parse_options_concat(struct option *dst, size_t, struct option *src);
/*----- some often used options -----*/
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
+extern int parse_opt_infinity_cb(const struct option *, const char *, int);
extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern int parse_opt_with_commit(const struct option *, const char *, int);
--
1.7.2.2.536.g42dab.dirty