[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