From b5430e4d8844f8588034f4c5399e4dc5d6ca5cd9 Mon Sep 17 00:00:00 2001 From: pirofti Date: Sat, 9 Dec 2017 18:38:37 +0000 Subject: [PATCH] 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@. --- usr.bin/grep/grep.1 | 11 ++++++++--- usr.bin/grep/grep.c | 23 ++++++++++++++++++----- usr.bin/grep/grep.h | 9 ++++++--- usr.bin/grep/util.c | 12 +++++++++++- 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 */ -- 2.20.1