sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit f526ad099f35bd6a17af6ac23e2844bfb3fe4372
parent 82bff35228af1236a5dd36b1db804937f824ff46
Author: sin <sin@2f30.org>
Date:   Fri Sep 27 16:26:22 +0100

Implement -e support for grep

Diffstat:
grep.1 | 9+++++++++
grep.c | 129++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
2 files changed, 100 insertions(+), 38 deletions(-)
diff --git a/grep.1 b/grep.1 @@ -4,6 +4,8 @@ grep \- search files for a pattern .SH SYNOPSIS .B grep .RB [ \-Ecilnqv ] +.RB [ \-e +.I pattern ] .I pattern .RI [ file ...] .SH DESCRIPTION @@ -25,6 +27,13 @@ matches using extended regex. .B \-c prints only a count of matching lines. .TP +.B \-e pattern +Specify a pattern used during the search of the input: an input +line is selected if it matches any of the specified patterns. +This option is most useful when multiple -e options are used to +specify multiple patterns, or when a pattern begins with a dash +(`-'). +.TP .B \-i matches lines case insensitively. .TP diff --git a/grep.c b/grep.c @@ -10,19 +10,27 @@ enum { Match = 0, NoMatch = 1, Error = 2 }; -static void grep(FILE *, const char *, regex_t *); +static void addpattern(const char *); +static bool grep(FILE *, const char *); static void usage(void); +static bool eflag = false; static bool vflag = false; static bool many; -static bool match = false; static char mode = 0; +static struct plist { + char *pattern; + regex_t preg; + struct plist *next; +} *phead; + int main(int argc, char *argv[]) { + bool match = false; + struct plist *pnode, *tmp; int i, n, flags = REG_NOSUB; - regex_t preg; FILE *fp; ARGBEGIN { @@ -30,6 +38,10 @@ main(int argc, char *argv[]) flags |= REG_EXTENDED; break; case 'c': + case 'e': + addpattern(EARGF(usage())); + eflag = true; + break; case 'l': case 'n': case 'q': @@ -45,57 +57,97 @@ main(int argc, char *argv[]) usage(); } ARGEND; - if(argc == 0) + if(argc == 0 && !eflag) usage(); /* no pattern */ - if((n = regcomp(&preg, argv[0], flags)) != 0) { - char buf[BUFSIZ]; + /* If -e is not specified treat it as if it were */ + if(!eflag) { + addpattern(argv[0]); + argc--; + argv++; + } + + /* Compile regex for all search patterns */ + for(pnode = phead; pnode; pnode = pnode->next) { + if((n = regcomp(&pnode->preg, pnode->pattern, flags)) != 0) { + char buf[BUFSIZ]; - regerror(n, &preg, buf, sizeof buf); - enprintf(Error, "invalid pattern: %s\n", buf); + regerror(n, &pnode->preg, buf, sizeof buf); + enprintf(Error, "invalid pattern: %s\n", buf); + } } many = (argc > 1); - if(argc == 1) - grep(stdin, "<stdin>", &preg); - else for(i = 1; i < argc; i++) { - if(!(fp = fopen(argv[i], "r"))) - enprintf(Error, "fopen %s:", argv[i]); - grep(fp, argv[i], &preg); - fclose(fp); + if(argc == 0) { + match = grep(stdin, "<stdin>"); + } else { + for(i = 0; i < argc; i++) { + if(!(fp = fopen(argv[i], "r"))) + enprintf(Error, "fopen %s:", argv[i]); + if(grep(fp, argv[i])) + match = true; + fclose(fp); + } + } + pnode = phead; + while(pnode) { + tmp = pnode->next; + regfree(&pnode->preg); + free(pnode->pattern); + free(pnode); + pnode = tmp; } return match ? Match : NoMatch; } void -grep(FILE *fp, const char *str, regex_t *preg) +addpattern(const char *pattern) +{ + struct plist *pnode; + + pnode = malloc(sizeof(*pnode)); + if(!pnode) + eprintf("malloc:"); + pnode->pattern = strdup(pattern); + if(!pnode->pattern) + eprintf("strdup:"); + pnode->next = phead; + phead = pnode; +} + +bool +grep(FILE *fp, const char *str) { char *buf = NULL; long n, c = 0; size_t size = 0, len; + struct plist *pnode; + bool match = false; for(n = 1; afgets(&buf, &size, fp); n++) { - if(buf[(len = strlen(buf))-1] == '\n') - buf[--len] = '\0'; - if(regexec(preg, buf, 0, NULL, 0) ^ vflag) - continue; - switch(mode) { - case 'c': - c++; - break; - case 'l': - puts(str); - goto end; - case 'q': - exit(Match); - default: - if(many) - printf("%s:", str); - if(mode == 'n') - printf("%ld:", n); - printf("%s\n", buf); - break; + for(pnode = phead; pnode; pnode = pnode->next) { + if(buf[(len = strlen(buf))-1] == '\n') + buf[--len] = '\0'; + if(regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) + continue; + switch(mode) { + case 'c': + c++; + break; + case 'l': + puts(str); + goto end; + case 'q': + exit(Match); + default: + if(many) + printf("%s:", str); + if(mode == 'n') + printf("%ld:", n); + printf("%s\n", buf); + break; + } + match = true; } - match = true; } if(mode == 'c') printf("%ld\n", c); @@ -103,10 +155,11 @@ end: if(ferror(fp)) enprintf(Error, "%s: read error:", str); free(buf); + return match; } void usage(void) { - enprintf(Error, "usage: %s [-Ecilnqv] pattern [files...]\n", argv0); + enprintf(Error, "usage: %s [-Ecilnqv] [-e pattern] pattern [files...]\n", argv0); }