bsdgrep: add -z/--null-data support

-z treats input and output data as sequences of lines terminated by a
zero byte instead of a newline. This brings it more in line with GNU grep
and brings us closer to passing the current tests with BSD grep.

Submitted by:	Kyle Evans <kevans91 at ksu.edu>
Reviewed by:	cem
Relnotes:	Yes
Differential Revision:	https://reviews.freebsd.org/D10101
This commit is contained in:
emaste 2017-04-17 13:14:18 +00:00
parent 9ad04f7ac0
commit cf9dd707cc
5 changed files with 21 additions and 10 deletions

View File

@ -197,7 +197,7 @@ grep_fgetln(struct file *f, size_t *lenp)
} }
/* Look for a newline in the remaining part of the buffer */ /* Look for a newline in the remaining part of the buffer */
if ((p = memchr(bufpos, '\n', bufrem)) != NULL) { if ((p = memchr(bufpos, fileeol, bufrem)) != NULL) {
++p; /* advance over newline */ ++p; /* advance over newline */
ret = bufpos; ret = bufpos;
len = p - bufpos; len = p - bufpos;
@ -219,7 +219,7 @@ grep_fgetln(struct file *f, size_t *lenp)
if (bufrem == 0) if (bufrem == 0)
/* EOF: return partial line */ /* EOF: return partial line */
break; break;
if ((p = memchr(bufpos, '\n', bufrem)) == NULL && if ((p = memchr(bufpos, fileeol, bufrem)) == NULL &&
filebehave != FILE_MMAP) filebehave != FILE_MMAP)
continue; continue;
if (p == NULL) { if (p == NULL) {
@ -322,7 +322,8 @@ grep_open(const char *path)
goto error2; goto error2;
/* Check for binary stuff, if necessary */ /* Check for binary stuff, if necessary */
if (binbehave != BINFILE_TEXT && memchr(bufpos, '\0', bufrem) != NULL) if (binbehave != BINFILE_TEXT && fileeol != '\0' &&
memchr(bufpos, '\0', bufrem) != NULL)
f->binary = true; f->binary = true;
return (f); return (f);

View File

@ -30,7 +30,7 @@
.\" .\"
.\" @(#)grep.1 8.3 (Berkeley) 4/18/94 .\" @(#)grep.1 8.3 (Berkeley) 4/18/94
.\" .\"
.Dd July 28, 2010 .Dd April 17, 2017
.Dt GREP 1 .Dt GREP 1
.Os .Os
.Sh NAME .Sh NAME
@ -40,7 +40,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm grep .Nm grep
.Bk -words .Bk -words
.Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZ .Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZz
.Op Fl A Ar num .Op Fl A Ar num
.Op Fl B Ar num .Op Fl B Ar num
.Op Fl C Ns Op Ar num .Op Fl C Ns Op Ar num
@ -378,7 +378,10 @@ expression are considered to be matching lines.
Equivalent to Equivalent to
.Fl i . .Fl i .
Obsoleted. Obsoleted.
.It Fl Z , Fl z , Fl Fl decompress .It Fl z , Fl Fl null-data
Treat input and output data as sequences of lines terminated by a
zero-byte instead of a newline.
.It Fl Z , Fl Fl decompress
Force Force
.Nm grep .Nm grep
to behave as to behave as

View File

@ -66,7 +66,7 @@ const char *errstr[] = {
/* 1*/ "(standard input)", /* 1*/ "(standard input)",
/* 2*/ "cannot read bzip2 compressed file", /* 2*/ "cannot read bzip2 compressed file",
/* 3*/ "unknown %s option", /* 3*/ "unknown %s option",
/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
/* 7*/ "\t[--null] [pattern] [file ...]\n", /* 7*/ "\t[--null] [pattern] [file ...]\n",
@ -109,6 +109,7 @@ bool lflag; /* -l: only show names of files with matches */
bool mflag; /* -m x: stop reading the files after x matches */ bool mflag; /* -m x: stop reading the files after x matches */
long long mcount; /* count for -m */ long long mcount; /* count for -m */
long long mlimit; /* requested value for -m */ long long mlimit; /* requested value for -m */
char fileeol; /* indicator for eol */
bool nflag; /* -n: show line numbers in front of matching lines */ bool nflag; /* -n: show line numbers in front of matching lines */
bool oflag; /* -o: print only matching part */ bool oflag; /* -o: print only matching part */
bool qflag; /* -q: quiet mode (don't output anything) */ bool qflag; /* -q: quiet mode (don't output anything) */
@ -165,7 +166,7 @@ usage(void)
exit(2); exit(2);
} }
static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy"; static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXyz";
static const struct option long_options[] = static const struct option long_options[] =
{ {
@ -215,6 +216,7 @@ static const struct option long_options[] =
{"word-regexp", no_argument, NULL, 'w'}, {"word-regexp", no_argument, NULL, 'w'},
{"line-regexp", no_argument, NULL, 'x'}, {"line-regexp", no_argument, NULL, 'x'},
{"xz", no_argument, NULL, 'X'}, {"xz", no_argument, NULL, 'X'},
{"null-data", no_argument, NULL, 'z'},
{"decompress", no_argument, NULL, 'Z'}, {"decompress", no_argument, NULL, 'Z'},
{NULL, no_argument, NULL, 0} {NULL, no_argument, NULL, 0}
}; };
@ -384,6 +386,7 @@ main(int argc, char *argv[])
newarg = 1; newarg = 1;
prevoptind = 1; prevoptind = 1;
needpattern = 1; needpattern = 1;
fileeol = '\n';
eopts = getenv("GREP_OPTIONS"); eopts = getenv("GREP_OPTIONS");
@ -605,6 +608,9 @@ main(int argc, char *argv[])
case 'X': case 'X':
filebehave = FILE_XZ; filebehave = FILE_XZ;
break; break;
case 'z':
fileeol = '\0';
break;
case 'Z': case 'Z':
filebehave = FILE_GZIP; filebehave = FILE_GZIP;
break; break;

View File

@ -116,6 +116,7 @@ extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag;
extern unsigned long long Aflag, Bflag; extern unsigned long long Aflag, Bflag;
extern long long mcount; extern long long mcount;
extern long long mlimit; extern long long mlimit;
extern char fileeol;
extern char *label; extern char *label;
extern const char *color; extern const char *color;
extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;

View File

@ -221,7 +221,7 @@ procfile(const char *fn)
else else
break; break;
} }
if (ln.len > 0 && ln.dat[ln.len - 1] == '\n') if (ln.len > 0 && ln.dat[ln.len - 1] == fileeol)
--ln.len; --ln.len;
ln.line_no++; ln.line_no++;
@ -530,6 +530,6 @@ printline(struct str *line, int sep, regmatch_t *matches, int m)
} }
} else { } else {
fwrite(line->dat, line->len, 1, stdout); fwrite(line->dat, line->len, 1, stdout);
putchar('\n'); putchar(fileeol);
} }
} }