summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/grep.c197
2 files changed, 198 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 259f782..fedc7a2 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ LDFLAGS = -s
-include config.mak
-B = cat true false pwd
+B = cat true false pwd grep
UB = strings basename dirname link wc fold iconv
ALL = $(B:%=bin/%) $(UB:%=bin/%)
diff --git a/src/grep.c b/src/grep.c
new file mode 100644
index 0000000..ae5e941
--- /dev/null
+++ b/src/grep.c
@@ -0,0 +1,197 @@
+/*
+ * grep.c
+ * Implementation of POSIX 2008 ls utility
+ * Copyright © 2012 Rich Felker
+ * Licensed under the terms of the GNU General Public License, v2 or later
+ */
+
+#include <stdio.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+struct pattern {
+ struct pattern *next;
+ char *str;
+ regex_t re;
+};
+
+static struct pattern *head, *tail;
+
+static void usage()
+{
+ exit(1);
+}
+
+static void addpats(const char *prog, int mode, const char *src)
+{
+ FILE *f;
+ char *line = 0;
+ ssize_t llen = 0;
+ struct pattern *pat;
+ f = (mode=='f') ? fopen(src, "rb")
+ : fmemopen((void *)src, strlen(src), "rb");
+ if (!f) {
+ fprintf(stderr, "%s: ", prog);
+ perror(mode=='f' ? src : 0);
+ exit(1);
+ }
+ while ((llen = getline(&line, (size_t[]){0}, f)) >= 0) {
+ if (llen && line[llen-1]=='\n')
+ line[--llen] = 0;
+ pat = malloc(sizeof *pat);
+ if (!pat) {
+ perror(prog);
+ exit(1);
+ }
+ pat->str = line;
+ pat->next = 0;
+ if (tail) tail->next = pat;
+ else head = tail = pat;
+ line = 0;
+ llen = 0;
+ }
+ fclose(f);
+}
+
+#define FLAG_E (1U<<0)
+#define FLAG_F (1U<<1)
+#define FLAG_c (1U<<2)
+#define FLAG_i (1U<<7)
+#define FLAG_l (1U<<8)
+#define FLAG_n (1U<<9)
+#define FLAG_q (1U<<10)
+#define FLAG_s (1U<<11)
+#define FLAG_v (1U<<12)
+#define FLAG_x (1U<<13)
+
+int main(int argc, char **argv)
+{
+ static const char *optpat = "EFce:f:ilnqsvx";
+ FILE *f;
+ char *line = 0;
+ ssize_t llen = 0;
+ int b;
+ int multifile;
+ struct pattern *pat;
+ int match, any_matches = 0;
+ long long count, lineno;
+ unsigned flags = 0;
+ const char *filename;
+ int err;
+
+ while ((b=getopt(argc, argv, optpat))!=EOF) {
+ flags |= 1U << strchr(optpat, b)-optpat;
+ if (b-'e'<2U) addpats(argv[0], b, optarg);
+ }
+ if (!argv[optind]) usage();
+ if (!head) addpats(argv[0], 'e', argv[optind++]);
+
+ if (!(flags & FLAG_F)) {
+ int re_opts = (flags & FLAG_E)
+ ? REG_NOSUB|REG_EXTENDED
+ : REG_NOSUB;
+ if (flags & FLAG_i) re_opts |= REG_ICASE;
+ for (pat=head; pat; pat=pat->next) {
+ if (flags & FLAG_x) {
+ char *tmp = malloc(strlen(pat->str)+3);
+ if (!tmp) {
+ perror(argv[0]);
+ exit(1);
+ }
+ sprintf(tmp, "%s%s%s",
+ pat->str[0]=='^'?"":"^", pat->str,
+ pat->str[strlen(pat->str)-1]=='$'?"":"$");
+ free(pat->str);
+ pat->str = tmp;
+ }
+ if ((err=regcomp(&pat->re, pat->str, re_opts))) {
+ char errstr[256];
+ regerror(err, &pat->re, errstr, sizeof errstr);
+ fprintf(stderr, "%s: %s\n", argv[0], errstr);
+ exit(1);
+ }
+ free(pat->str);
+ }
+ }
+
+ if (!argv[optind]) {
+ optind--;
+ filename = "(standard input)";
+ f = stdin;
+ multifile = 0;
+ goto process_stdin;
+ }
+
+ multifile = !!argv[optind+1];
+
+ for (; argv[optind]; optind++) {
+ filename = argv[optind];
+ f = fopen(filename, "rb");
+ if (!f) {
+ if (!(flags & FLAG_s)) {
+ fprintf(stderr, "%s: ", argv[0]);
+ perror(filename);
+ }
+ continue;
+ }
+process_stdin:
+ count = 0;
+ lineno = 0;
+ while ((llen = getline(&line, (size_t[]){0}, f)) >= 0) {
+ lineno++;
+ if (llen && line[llen-1]=='\n')
+ line[--llen] = 0;
+ match = 0;
+ for (pat=head; pat; pat=pat->next) {
+ if (flags & FLAG_F) {
+ if (flags & FLAG_x) {
+ if (!strcmp(line, pat->str)) {
+ match = 1;
+ break;
+ }
+ } else if (strstr(line, pat->str)) {
+ match = 1;
+ break;
+ }
+ } else if (!regexec(&pat->re, line, 0, 0, 0)) {
+ match = 1;
+ break;
+ }
+ }
+ if (flags & FLAG_v) match = !match;
+ if (match) {
+ any_matches = 1;
+ if (flags & FLAG_q) exit(0);
+ if (flags & FLAG_l) {
+ puts(filename);
+ break;
+ }
+ if (flags & FLAG_c) {
+ count++;
+ continue;
+ }
+ if (multifile) {
+ if (flags & FLAG_n)
+ printf("%s:%lld:%s\n", filename, lineno, line);
+ else
+ printf("%s:%s\n", filename, line);
+ } else {
+ if (flags & FLAG_n)
+ printf("%lld:%s\n", lineno, line);
+ else
+ puts(line);
+ }
+ }
+ }
+ if (flags & FLAG_c) {
+ if (multifile)
+ printf("%s:%lld\n", filename, count);
+ else
+ printf("%lld\n", count);
+ }
+ fclose(f);
+ }
+ return !any_matches;
+}