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:
parent
9ad04f7ac0
commit
cf9dd707cc
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user