[Toybox] [patch] add grep

Isaac idunham at lavabit.com
Mon Jul 8 19:08:03 PDT 2013


On Sun, Jul 07, 2013 at 08:02:29PM -0500, Strake wrote:
> # HG changeset patch
> # User Strake
> # Date 1373245375 18000
> # Node ID 29e47cf402a5f81640c4b0a0e38d5f7741bc7ad6
> # Parent  f8db1f6ec4ab6972ee05126aae860e6ea104360e
> add grep
> 
> diff -r f8db1f6ec4ab -r 29e47cf402a5 toys/posix/grep.c
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/toys/posix/grep.c	Sun Jul 07 20:02:55 2013 -0500
> @@ -0,0 +1,100 @@
> +/* grep.c - print lines what match given regular expression
> + *
> + * Copyright 2013 CE Strake <strake888 at gmail.com>
> + *
> + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
> + * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
> +
> +USE_GREP(NEWTOY(grep, "Einvclq", TOYFLAG_BIN))
> +
> +config GREP
> +  bool "grep"
> +  default y
> +  help
> +    usage: grep [-clq] [-Einv] RE [file...]

This is not POSIX conformant yet, and would also break the kernel build.

grep must support multiple regexes:
"Multiple -e and -f options shall be accepted by the grep utility."
grep -e signals that the next argument is a regex.
grep -f <file> means each line in <file> is a regex.

Also you didn't implement -F (exact match), which is specified by POSIX.

Practically speaking, you also will need to support 
grep -h (which outputs only the matching line without the filename)
This is required by the kernel build process.
And as far as I can tell, you don't have a switch to suppress filename
when only one file is specified.

grep -r is frequently used, and that's trivial to implement with dirtree_*.

> +    modes:
> +      default:	print lines from each file what match regular expression RE.
> +      -c:	print the number of matching lines in each file.
> +      -l:	print all matching file names.
> +      -q:	print nil; quit with code 0 when match found.
> +
> +    flags:
> +      -E:	extended RE syntax
> +      -i:	case insensitive
> +      -n:	print line numbers
> +      -v:	invert match
> +*/
> +
> +#define FOR_grep
> +#include "toys.h"
> +#include <regex.h>
> +#include <err.h>
> +
> +/* could be in GLOBALS but so need initialization code */
> +char mode = 0;
> +int c = 1;
> +
> +regex_t re; /* fails in GLOBALS */
> +
> +static void do_grep (int fd, char *name) {
> +  int n = 0, nMatch = 0;
> +  size_t l;
> +  char *x;
> +  FILE *f;
> +
> +  f = fdopen (fd, "r");
> +  if (!f) err (2, "failed to open %s", name);
> +
> +  x = 0;
> +  for (;;) {
> +    if (getline (&x, &l, f) < 0) {
> +      if (feof (f)) break;
> +      err (2, "failed to read");
> +    }
> +    n++; /* start at 1 */
> +
> +    if (regexec (&re, x, 0, 0, 0) == 0) {
> +      c = 0; nMatch++;
> +      switch (mode) {
> +      case 'q':
> +        exit (0);
> +      case 'l':
> +        printf ("%s\n", name);
> +        goto end;
> +      case 'c':
> +        break;
> +      default:
> +        printf ("%s:", name);
> +        if (toys.optflags & FLAG_n) printf ("%d:", n);
> +        fputs (x, stdout);
> +      }
> +    }
> +  }
> +
> +  if (mode == 'c') printf ("%s:%d\n", name, nMatch);
> +
> +end:
> +  free (x);
> +  fclose (f);
> +}
> +
> +void grep_main (void) {
> +  if (toys.optc < 1) errx (2, "no RE");
> +
> +  if (regcomp (&re, toys.optargs[0],
> +               REG_NOSUB |
> +               (toys.optflags & FLAG_E ? REG_EXTENDED : 0) |
> +               (toys.optflags & FLAG_i ? REG_ICASE    : 0)) != 0) {
> +    errx (2, "bad RE");
> +  }
> +
> +  if (toys.optflags & FLAG_c) mode = 'c';
> +  if (toys.optflags & FLAG_l) mode = 'l';
> +  if (toys.optflags & FLAG_q) mode = 'q';
> +
> +  if (toys.optc > 1) loopfiles (toys.optargs + 1, do_grep);
> +  else do_grep (0, "-");
> +
> +  exit (c);
> +}


 1373335683.0


More information about the Toybox mailing list