Index: usr.bin/grep/file.c =================================================================== --- usr.bin/grep/file.c +++ usr.bin/grep/file.c @@ -197,7 +197,7 @@ } /* 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 */ ret = bufpos; len = p - bufpos; @@ -219,7 +219,7 @@ if (bufrem == 0) /* EOF: return partial line */ break; - if ((p = memchr(bufpos, '\n', bufrem)) == NULL && + if ((p = memchr(bufpos, fileeol, bufrem)) == NULL && filebehave != FILE_MMAP) continue; if (p == NULL) { @@ -322,7 +322,7 @@ goto error2; /* 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; return (f); Index: usr.bin/grep/grep.h =================================================================== --- usr.bin/grep/grep.h +++ usr.bin/grep/grep.h @@ -116,6 +116,7 @@ extern unsigned long long Aflag, Bflag; extern long long mcount; extern long long mlimit; +extern char fileeol; extern char *label; extern const char *color; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; Index: usr.bin/grep/grep.1 =================================================================== --- usr.bin/grep/grep.1 +++ usr.bin/grep/grep.1 @@ -40,7 +40,7 @@ .Sh SYNOPSIS .Nm grep .Bk -words -.Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZ +.Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZz .Op Fl A Ar num .Op Fl B Ar num .Op Fl C Ns Op Ar num @@ -374,7 +374,10 @@ Equivalent to .Fl i . 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 .Nm grep to behave as Index: usr.bin/grep/grep.c =================================================================== --- usr.bin/grep/grep.c +++ usr.bin/grep/grep.c @@ -66,7 +66,7 @@ /* 1*/ "(standard input)", /* 2*/ "cannot read bzip2 compressed file", /* 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", /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", /* 7*/ "\t[--null] [pattern] [file ...]\n", @@ -109,6 +109,7 @@ bool mflag; /* -m x: stop reading the files after x matches */ long long mcount; /* count 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 oflag; /* -o: print only matching part */ bool qflag; /* -q: quiet mode (don't output anything) */ @@ -165,7 +166,7 @@ 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[] = { @@ -215,6 +216,7 @@ {"word-regexp", no_argument, NULL, 'w'}, {"line-regexp", no_argument, NULL, 'x'}, {"xz", no_argument, NULL, 'X'}, + {"null-data", no_argument, NULL, 'z'}, {"decompress", no_argument, NULL, 'Z'}, {NULL, no_argument, NULL, 0} }; @@ -377,6 +379,7 @@ newarg = 1; prevoptind = 1; needpattern = 1; + fileeol = '\n'; eopts = getenv("GREP_OPTIONS"); @@ -598,6 +601,9 @@ case 'X': filebehave = FILE_XZ; break; + case 'z': + fileeol = '\0'; + break; case 'Z': filebehave = FILE_GZIP; break; Index: usr.bin/grep/util.c =================================================================== --- usr.bin/grep/util.c +++ usr.bin/grep/util.c @@ -221,7 +221,7 @@ else break; } - if (ln.len > 0 && ln.dat[ln.len - 1] == '\n') + if (ln.len > 0 && ln.dat[ln.len - 1] == fileeol) --ln.len; ln.line_no++; @@ -492,6 +492,6 @@ } } else { fwrite(line->dat, line->len, 1, stdout); - putchar('\n'); + putchar(fileeol); } }