aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-01-30 22:07:58 -0600
committerRob Landley <rob@landley.net>2016-01-30 22:07:58 -0600
commit36aed25f3f54f7871d5810adfe99d96944e0afb4 (patch)
tree1d5a073c5bbb799128aadb086adef06deafb34e8
parentb97d8211fa5c382f32e9a9f606a8566bd2ec09fb (diff)
downloadtoybox-36aed25f3f54f7871d5810adfe99d96944e0afb4.tar.gz
Add grep -B -C
-rwxr-xr-xtests/grep.test5
-rw-r--r--toys/posix/grep.c58
2 files changed, 50 insertions, 13 deletions
diff --git a/tests/grep.test b/tests/grep.test
index be8bc85c..aa11c704 100755
--- a/tests/grep.test
+++ b/tests/grep.test
@@ -100,3 +100,8 @@ testing "grep backref" 'grep -e "a\(b\)" -e "b\(c\)\1"' "bcc\nab\n" \
testing "grep -A" "grep -A 2 yes" "yes\nno\nno\n--\nyes\nno\nno\nyes\nno\n" \
"" "yes\nno\nno\nno\nyes\nno\nno\nyes\nno"
+testing "grep -B" "grep -B 1 yes" "no\nyes\n--\nno\nyes\nno\nyes\n" \
+ "" "no\nno\nno\nyes\nno\nno\nyes\nno\nyes"
+testing "grep -C" "grep -C 1 yes" \
+ "yes\nno\n--\nno\nyes\nno\nno\nyes\nno\nyes\nno\n" \
+ "" "yes\nno\nno\nno\nyes\nno\nno\nyes\nno\nyes\nno\nno"
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index 2e0558f3..92d723bb 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -6,7 +6,7 @@
*
* TODO: -ABC
-USE_GREP(NEWTOY(grep, "A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
+USE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
@@ -24,12 +24,12 @@ config GREP
-f File containing regular expressions to match.
match type:
- -A NUM lines after match
- -E extended regex syntax -F fixed (match literal string)
- -i case insensitive -m stop after this many lines matched
- -r recursive (on dir) -v invert match
- -w whole word (implies -E) -x whole line
- -z input NUL terminated
+ -A Show NUM lines after -B Show NUM lines before match
+ -C NUM lines context (A+B) -E extended regex syntax
+ -F fixed (literal match) -i case insensitive
+ -m match MAX many lines -r recursive (on dir)
+ -v invert match -w whole word (implies -E)
+ -x whole line -z input NUL terminated
display modes: (default: matched line)
-c count of matching lines -l show matching filenames
@@ -60,13 +60,16 @@ GLOBALS(
struct arg_list *f;
struct arg_list *e;
long a;
+ long b;
+ long c;
)
// Show matches in one file
static void do_grep(int fd, char *name)
{
+ struct double_list *dlb = 0;
FILE *file = fdopen(fd, "r");
- long offset = 0, after = 0;
+ long offset = 0, after = 0, before = 0;
int lcount = 0, mcount = 0;
char *bars = 0, indelim = '\n' * !(toys.optflags&FLAG_z),
outdelim = '\n' * !(toys.optflags&FLAG_Z);
@@ -166,6 +169,7 @@ static void do_grep(int fd, char *name)
matches.rm_so = 0;
} else if (rc) break;
+ // At least one line we didn't print since match while -ABC active
if (bars) {
xputs(bars);
bars = 0;
@@ -190,8 +194,18 @@ static void do_grep(int fd, char *name)
printf("%ld:", offset + (start-line) +
((toys.optflags & FLAG_o) ? matches.rm_so : 0));
if (!(toys.optflags & FLAG_o)) {
+ while (dlb) {
+ struct double_list *dl = dlist_pop(&dlb);
+
+ xprintf("%s%c", dl->data, outdelim);
+ free(dl->data);
+ free(dl);
+ before--;
+ }
+
+ while (before) xprintf("%s%c", line, outdelim);
xprintf("%s%c", line, outdelim);
- if (TT.a) after = TT.a;
+ if (TT.a) after = TT.a+1;
} else {
xprintf("%.*s%c", (int)(matches.rm_eo-matches.rm_so),
start+matches.rm_so, outdelim);
@@ -204,11 +218,26 @@ static void do_grep(int fd, char *name)
offset += len;
if (mmatch) mcount++;
- else if (after) {
- if (after>0) {
+ else {
+ int discard = (after || TT.b);
+
+ if (after && --after) {
xprintf("%s%c", line, outdelim);
- if (!--after) after = -1;
- } else bars = "--";
+ discard = 0;
+ }
+ if (discard && TT.b) {
+ dlist_add(&dlb, line);
+ line = 0;
+ if (++before>TT.b) {
+ struct double_list *dl;
+
+ dl = dlist_pop(&dlb);
+ free(dl->data);
+ free(dl);
+ before--;
+ } else discard = 0;
+ }
+ if (discard && mcount) bars = "--";
}
free(line);
@@ -306,6 +335,9 @@ void grep_main(void)
{
char **ss = toys.optargs;
+ if (!TT.a) TT.a = TT.c;
+ if (!TT.b) TT.b = TT.c;
+
// Handle egrep and fgrep
if (*toys.which->name == 'e') toys.optflags |= FLAG_E;
if (*toys.which->name == 'f') toys.optflags |= FLAG_F;