summaryrefslogtreecommitdiff
path: root/usr.bin/grep
diff options
context:
space:
mode:
authorPaul Irofti <pirofti@cvs.openbsd.org>2017-12-09 18:38:38 +0000
committerPaul Irofti <pirofti@cvs.openbsd.org>2017-12-09 18:38:38 +0000
commitc6fc90ac65c74731083728585a1469b2a8e202f7 (patch)
treeaba74ad9de2ae666ea5b21c36cce747d02e4a09c /usr.bin/grep
parentf5e2ebd23d6511bc869fac986ea5c2f6c8d1b054 (diff)
Add support for the non-standard grep -m extension.
grep -m num stops after a maximum of num matches are found. We support -m0 to match GNU behaviour, but we do not allow negative numbers. Manpage help from jmc@, OK deraadt@.
Diffstat (limited to 'usr.bin/grep')
-rw-r--r--usr.bin/grep/grep.111
-rw-r--r--usr.bin/grep/grep.c23
-rw-r--r--usr.bin/grep/grep.h9
-rw-r--r--usr.bin/grep/util.c12
4 files changed, 43 insertions, 12 deletions
diff --git a/usr.bin/grep/grep.1 b/usr.bin/grep/grep.1
index 6e8d7676df7..44fcf2c4851 100644
--- a/usr.bin/grep/grep.1
+++ b/usr.bin/grep/grep.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: grep.1,v 1.43 2015/01/13 04:45:34 daniel Exp $
+.\" $OpenBSD: grep.1,v 1.44 2017/12/09 18:38:37 pirofti Exp $
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -28,7 +28,7 @@
.\"
.\" @(#)grep.1 8.3 (Berkeley) 4/18/94
.\"
-.Dd $Mdocdate: January 13 2015 $
+.Dd $Mdocdate: December 9 2017 $
.Dt GREP 1
.Os
.Sh NAME
@@ -44,6 +44,7 @@
.Op Fl C Ns Op Ar num
.Op Fl e Ar pattern
.Op Fl f Ar file
+.Op Fl m Ar num
.Op Fl -binary-files Ns = Ns Ar value
.Op Fl -context Ns Op = Ns Ar num
.Op Fl -line-buffered
@@ -216,6 +217,10 @@ Pathnames are listed once per file searched.
If the standard input is searched, the string
.Dq (standard input)
is written.
+.It Fl m Ar num, Fl Fl max-count Ns = Ns Ar num
+Stop after
+.Ar num
+matches.
.It Fl n
Each output line is preceded by its relative line number in the file,
starting at line 1.
@@ -354,7 +359,7 @@ utility is compliant with the
specification.
.Pp
The flags
-.Op Fl AaBbCGHhILoRUVwZ
+.Op Fl AaBbCGHhILmoRUVwZ
are extensions to that specification, and the behaviour of the
.Fl f
flag when used with an empty pattern file is left undefined.
diff --git a/usr.bin/grep/grep.c b/usr.bin/grep/grep.c
index 907246caa5d..401ed503cbb 100644
--- a/usr.bin/grep/grep.c
+++ b/usr.bin/grep/grep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: grep.c,v 1.55 2015/11/28 01:17:12 gsoares Exp $ */
+/* $OpenBSD: grep.c,v 1.56 2017/12/09 18:38:37 pirofti Exp $ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -71,6 +71,9 @@ int cflag; /* -c: only show a count of matching lines */
int hflag; /* -h: don't print filename headers */
int iflag; /* -i: ignore case */
int lflag; /* -l: only show names of files with matches */
+int mflag; /* -m x: stop reading the files after x matches */
+long long mcount; /* count for -m */
+long long mlimit; /* requested value for -m */
int nflag; /* -n: show line numbers in front of matching lines */
int oflag; /* -o: print each match */
int qflag; /* -q: quiet mode (don't output anything) */
@@ -111,15 +114,16 @@ usage(void)
#else
"usage: %s [-abcEFGHhIiLlnoqRsUVvwxZ] [-A num] [-B num] [-C[num]]\n"
#endif
- "\t[-e pattern] [-f file] [--binary-files=value] [--context[=num]]\n"
- "\t[--line-buffered] [pattern] [file ...]\n", __progname);
+ "\t[-e pattern] [-f file] [-m num] [--binary-files=value]\n"
+ "\t[--context[=num]] [--line-buffered] [pattern] [file ...]\n",
+ __progname);
exit(2);
}
#ifdef NOZ
-static const char optstr[] = "0123456789A:B:CEFGHILRUVabce:f:hilnoqrsuvwxy";
+static const char optstr[] = "0123456789A:B:CEFGHILRUVabce:f:hilm:noqrsuvwxy";
#else
-static const char optstr[] = "0123456789A:B:CEFGHILRUVZabce:f:hilnoqrsuvwxy";
+static const char optstr[] = "0123456789A:B:CEFGHILRUVZabce:f:hilm:noqrsuvwxy";
#endif
static const struct option long_options[] =
@@ -147,6 +151,7 @@ static const struct option long_options[] =
{"ignore-case", no_argument, NULL, 'i'},
{"files-without-match", no_argument, NULL, 'L'},
{"files-with-matches", no_argument, NULL, 'l'},
+ {"max-count", required_argument, NULL, 'm'},
{"line-number", no_argument, NULL, 'n'},
{"quiet", no_argument, NULL, 'q'},
{"silent", no_argument, NULL, 'q'},
@@ -376,6 +381,14 @@ main(int argc, char *argv[])
Lflag = 0;
lflag = qflag = 1;
break;
+ case 'm':
+ mflag = 1;
+ mlimit = mcount = strtonum(optarg, 0, LLONG_MAX,
+ &errstr);
+ if (errstr != NULL)
+ errx(2, "invalid max-count %s: %s",
+ optarg, errstr);
+ break;
case 'n':
nflag = 1;
break;
diff --git a/usr.bin/grep/grep.h b/usr.bin/grep/grep.h
index 21b1cab10f8..bbf7f8cd8c8 100644
--- a/usr.bin/grep/grep.h
+++ b/usr.bin/grep/grep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: grep.h,v 1.24 2015/12/14 20:02:07 mmcc Exp $ */
+/* $OpenBSD: grep.h,v 1.25 2017/12/09 18:38:37 pirofti Exp $ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -66,8 +66,8 @@ extern int cflags, eflags;
/* Command line flags */
extern int Aflag, Bflag, Eflag, Fflag, Hflag, Lflag,
Rflag, Zflag,
- bflag, cflag, hflag, iflag, lflag, nflag, oflag, qflag, sflag,
- vflag, wflag, xflag;
+ bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag, qflag,
+ sflag, vflag, wflag, xflag;
extern int binbehave;
extern int first, matchall, patterns, tail, file_err;
@@ -75,6 +75,9 @@ extern char **pattern;
extern fastgrep_t *fg_pattern;
extern regex_t *r_pattern;
+/* For -m max-count */
+extern long long mcount, mlimit;
+
/* For regex errors */
#define RE_ERROR_BUF 512
extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
diff --git a/usr.bin/grep/util.c b/usr.bin/grep/util.c
index 9cfed4c0dae..f7c5407d3e0 100644
--- a/usr.bin/grep/util.c
+++ b/usr.bin/grep/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.57 2017/04/03 16:18:35 tedu Exp $ */
+/* $OpenBSD: util.c,v 1.58 2017/12/09 18:38:37 pirofti Exp $ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -97,6 +97,8 @@ procfile(char *fn)
file_t *f;
int c, t, z, nottext;
+ mcount = mlimit;
+
if (fn == NULL) {
fn = "(standard input)";
f = grep_fdopen(STDIN_FILENO, "r");
@@ -126,6 +128,8 @@ procfile(char *fn)
if (Bflag > 0)
initqueue();
for (c = 0; c == 0 || !(lflag || qflag); ) {
+ if (mflag && mlimit == 0)
+ break;
ln.off += ln.len + 1;
if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL)
break;
@@ -140,6 +144,8 @@ procfile(char *fn)
linesqueued++;
}
c += t;
+ if (mflag && mcount <= 0)
+ break;
}
if (Bflag > 0)
clearqueue();
@@ -224,6 +230,10 @@ print:
if (vflag)
c = !c;
+ /* Count the matches if we have a match limit */
+ if (mflag)
+ mcount -= c;
+
if (c && binbehave == BIN_FILE_BIN && nottext)
return c; /* Binary file */