grep: add --null flag
authorop <op@openbsd.org>
Sun, 26 Jun 2022 10:57:36 +0000 (10:57 +0000)
committerop <op@openbsd.org>
Sun, 26 Jun 2022 10:57:36 +0000 (10:57 +0000)
makes grep print an ASCII NUL byte after the file name to make the
output unambiguous even in the presence of file names with funny
characters.

A previous iteration of this diff was improved by benno@ and tedu@ and
discussed also with sthen@ and deraadt@.  deraadt@ also improved the
manpage changes in this version of the diff.

OK deraadt@

usr.bin/grep/grep.1
usr.bin/grep/grep.c
usr.bin/grep/grep.h
usr.bin/grep/util.c

index 5cc228d..8701df1 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: grep.1,v 1.50 2019/12/03 08:48:49 kn Exp $
+.\"    $OpenBSD: grep.1,v 1.51 2022/06/26 10:57:36 op 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: December 3 2019 $
+.Dd $Mdocdate: June 26 2022 $
 .Dt GREP 1
 .Os
 .Sh NAME
@@ -49,6 +49,7 @@
 .Op Fl -context Ns Op = Ns Ar num
 .Op Fl -label Ns = Ns Ar name
 .Op Fl -line-buffered
+.Op Fl -null
 .Op Ar pattern
 .Op Ar
 .Ek
@@ -297,6 +298,15 @@ instead of the filename before lines.
 Force output to be line buffered.
 By default, output is line buffered when standard output is a terminal
 and block buffered otherwise.
+.It Fl -null
+Output a zero byte instead of the character that normally follows a
+file name.
+This option makes the output unambiguous, even in the presence of file
+names containing unusual characters like newlines.
+This is similar to the
+.Ar -print0
+option in
+.Xr find 1 .
 .El
 .Sh EXIT STATUS
 The
index f41b5e2..181af7f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: grep.c,v 1.65 2020/07/23 20:19:27 martijn Exp $       */
+/*     $OpenBSD: grep.c,v 1.66 2022/06/26 10:57:36 op Exp $    */
 
 /*-
  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -80,6 +80,7 @@ int    vflag;         /* -v: only show non-matching lines */
 int     wflag;         /* -w: pattern must start and end on word boundaries */
 int     xflag;         /* -x: pattern must match entire line */
 int     lbflag;        /* --line-buffered */
+int     nullflag;      /* --null */
 const char *labelname; /* --label=name */
 
 int binbehave = BIN_FILE_BIN;
@@ -89,6 +90,7 @@ enum {
        HELP_OPT,
        MMAP_OPT,
        LINEBUF_OPT,
+       NULL_OPT,
        LABEL_OPT,
 };
 
@@ -134,6 +136,7 @@ static const struct option long_options[] =
        {"mmap",                no_argument,            NULL, MMAP_OPT},
        {"label",               required_argument,      NULL, LABEL_OPT},
        {"line-buffered",       no_argument,            NULL, LINEBUF_OPT},
+       {"null",                no_argument,            NULL, NULL_OPT},
        {"after-context",       required_argument,      NULL, 'A'},
        {"before-context",      required_argument,      NULL, 'B'},
        {"context",             optional_argument,      NULL, 'C'},
@@ -436,6 +439,9 @@ main(int argc, char *argv[])
                case LINEBUF_OPT:
                        lbflag = 1;
                        break;
+               case NULL_OPT:
+                       nullflag = 1;
+                       break;
                case HELP_OPT:
                default:
                        usage();
index 731bbcc..07c8069 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: grep.h,v 1.28 2021/03/10 21:55:22 millert Exp $       */
+/*     $OpenBSD: grep.h,v 1.29 2022/06/26 10:57:36 op Exp $    */
 
 /*-
  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -68,7 +68,7 @@ extern int     cflags, eflags;
 extern int      Aflag, Bflag, Eflag, Fflag, Hflag, Lflag,
                 Rflag, Zflag,
                 bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag, qflag,
-                sflag, vflag, wflag, xflag;
+                sflag, vflag, wflag, xflag, nullflag;
 extern int      binbehave;
 extern const char *labelname;
 
index 33b1094..d1840b9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: util.c,v 1.65 2022/05/30 16:07:28 dv Exp $    */
+/*     $OpenBSD: util.c,v 1.66 2022/06/26 10:57:36 op Exp $    */
 
 /*-
  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
@@ -172,13 +172,13 @@ procfile(char *fn)
 
        if (cflag) {
                if (!hflag)
-                       printf("%s:", ln.file);
+                       printf("%s%c", ln.file, nullflag ? '\0' : ':');
                printf("%llu%s\n", c, overflow ? "+" : "");
        }
        if (lflag && c != 0)
-               printf("%s\n", fn);
+               printf("%s%c", fn, nullflag ? '\0' : '\n');
        if (Lflag && c == 0)
-               printf("%s\n", fn);
+               printf("%s%c", fn, nullflag ? '\0' : '\n');
        if (c && !cflag && !lflag && !Lflag &&
            binbehave == BIN_FILE_BIN && nottext && !qflag)
                printf("Binary file %s matches\n", fn);
@@ -653,27 +653,32 @@ grep_revstr(unsigned char *str, int len)
 void
 printline(str_t *line, int sep, regmatch_t *pmatch)
 {
-       int n;
+       int n, printsep;
 
        n = 0;
+       printsep = !nullflag;
        if (!hflag) {
                fputs(line->file, stdout);
+               if (nullflag)
+                       putchar(0);
                ++n;
        }
        if (nflag) {
-               if (n)
+               if (n && printsep)
                        putchar(sep);
                printf("%lld", line->line_no);
+               printsep = 1;
                ++n;
        }
        if (bflag) {
-               if (n)
+               if (n && printsep)
                        putchar(sep);
                printf("%lld", (long long)line->off +
                    (pmatch ? pmatch->rm_so : 0));
+               printsep = 1;
                ++n;
        }
-       if (n)
+       if (n && printsep)
                putchar(sep);
        if (pmatch)
                fwrite(line->dat + pmatch->rm_so,