aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/grep/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/grep/main.c')
-rw-r--r--src/cmd/grep/main.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/cmd/grep/main.c b/src/cmd/grep/main.c
new file mode 100644
index 00000000..f2a6e040
--- /dev/null
+++ b/src/cmd/grep/main.c
@@ -0,0 +1,260 @@
+#define EXTERN
+#include "grep.h"
+
+char *validflags = "bchiLlnsv";
+void
+usage(void)
+{
+ fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, status;
+
+ ARGBEGIN {
+ default:
+ if(utfrune(validflags, ARGC()) == nil)
+ usage();
+ flags[ARGC()]++;
+ break;
+
+ case 'e':
+ flags['e']++;
+ lineno = 0;
+ str2top(ARGF());
+ break;
+
+ case 'f':
+ flags['f']++;
+ filename = ARGF();
+ rein = Bopen(filename, OREAD);
+ if(rein == 0) {
+ fprint(2, "grep: can't open %s: %r\n", filename);
+ exits("open");
+ }
+ lineno = 1;
+ str2top(filename);
+ break;
+ } ARGEND
+
+ if(flags['f'] == 0 && flags['e'] == 0) {
+ if(argc <= 0)
+ usage();
+ str2top(argv[0]);
+ argc--;
+ argv++;
+ }
+
+ follow = mal(maxfollow*sizeof(*follow));
+ state0 = initstate(topre.beg);
+
+ Binit(&bout, 1, OWRITE);
+ switch(argc) {
+ case 0:
+ status = search(0, 0);
+ break;
+ case 1:
+ status = search(argv[0], 0);
+ break;
+ default:
+ status = 0;
+ for(i=0; i<argc; i++)
+ status |= search(argv[i], Hflag);
+ break;
+ }
+ if(status)
+ exits(0);
+ exits("no matches");
+}
+
+int
+search(char *file, int flag)
+{
+ State *s, *ns;
+ int c, fid, eof, nl, empty;
+ long count, lineno, n;
+ uchar *elp, *lp, *bol;
+
+ if(file == 0) {
+ file = "stdin";
+ fid = 0;
+ flag |= Bflag;
+ } else
+ fid = open(file, OREAD);
+
+ if(fid < 0) {
+ fprint(2, "grep: can't open %s: %r\n", file);
+ return 0;
+ }
+
+ if(flags['b'])
+ flag ^= Bflag; /* dont buffer output */
+ if(flags['c'])
+ flag |= Cflag; /* count */
+ if(flags['h'])
+ flag &= ~Hflag; /* do not print file name in output */
+ if(flags['i'])
+ flag |= Iflag; /* fold upper-lower */
+ if(flags['l'])
+ flag |= Llflag; /* print only name of file if any match */
+ if(flags['L'])
+ flag |= LLflag; /* print only name of file if any non match */
+ if(flags['n'])
+ flag |= Nflag; /* count only */
+ if(flags['s'])
+ flag |= Sflag; /* status only */
+ if(flags['v'])
+ flag |= Vflag; /* inverse match */
+
+ s = state0;
+ lineno = 0;
+ count = 0;
+ eof = 0;
+ empty = 1;
+ nl = 0;
+ lp = u.buf;
+ bol = lp;
+
+loop0:
+ n = lp-bol;
+ if(n > sizeof(u.pre))
+ n = sizeof(u.pre);
+ memmove(u.buf-n, bol, n);
+ bol = u.buf-n;
+ n = read(fid, u.buf, sizeof(u.buf));
+ /* if file has no final newline, simulate one to emit matches to last line */
+ if(n > 0) {
+ empty = 0;
+ nl = u.buf[n-1]=='\n';
+ } else {
+ if(n < 0){
+ fprint(2, "grep: read error on %s: %r\n", file);
+ return count != 0;
+ }
+ if(!eof && !nl && !empty) {
+ u.buf[0] = '\n';
+ n = 1;
+ eof = 1;
+ }
+ }
+ if(n <= 0) {
+ close(fid);
+ if(flag & Cflag) {
+ if(flag & Hflag)
+ Bprint(&bout, "%s:", file);
+ Bprint(&bout, "%ld\n", count);
+ }
+ if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
+ Bprint(&bout, "%s\n", file);
+ Bflush(&bout);
+ return count != 0;
+ }
+ lp = u.buf;
+ elp = lp+n;
+ if(flag & Iflag)
+ goto loopi;
+
+/*
+ * normal character loop
+ */
+loop:
+ c = *lp;
+ ns = s->next[c];
+ if(ns == 0) {
+ increment(s, c);
+ goto loop;
+ }
+// if(flags['2'])
+// if(s->match)
+// print("%d: %.2x**\n", s, c);
+// else
+// print("%d: %.2x\n", s, c);
+ lp++;
+ s = ns;
+ if(c == '\n') {
+ lineno++;
+ if(!!s->match == !(flag&Vflag)) {
+ count++;
+ if(flag & (Cflag|Sflag|Llflag|LLflag))
+ goto cont;
+ if(flag & Hflag)
+ Bprint(&bout, "%s:", file);
+ if(flag & Nflag)
+ Bprint(&bout, "%ld: ", lineno);
+ /* suppress extra newline at EOF unless we are labeling matches with file name */
+ Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
+ if(flag & Bflag)
+ Bflush(&bout);
+ }
+ if((lineno & Flshcnt) == 0)
+ Bflush(&bout);
+ cont:
+ bol = lp;
+ }
+ if(lp != elp)
+ goto loop;
+ goto loop0;
+
+/*
+ * character loop for -i flag
+ * for speed
+ */
+loopi:
+ c = *lp;
+ if(c >= 'A' && c <= 'Z')
+ c += 'a'-'A';
+ ns = s->next[c];
+ if(ns == 0) {
+ increment(s, c);
+ goto loopi;
+ }
+ lp++;
+ s = ns;
+ if(c == '\n') {
+ lineno++;
+ if(!!s->match == !(flag&Vflag)) {
+ count++;
+ if(flag & (Cflag|Sflag|Llflag|LLflag))
+ goto conti;
+ if(flag & Hflag)
+ Bprint(&bout, "%s:", file);
+ if(flag & Nflag)
+ Bprint(&bout, "%ld: ", lineno);
+ /* suppress extra newline at EOF unless we are labeling matches with file name */
+ Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
+ if(flag & Bflag)
+ Bflush(&bout);
+ }
+ if((lineno & Flshcnt) == 0)
+ Bflush(&bout);
+ conti:
+ bol = lp;
+ }
+ if(lp != elp)
+ goto loopi;
+ goto loop0;
+}
+
+State*
+initstate(Re *r)
+{
+ State *s;
+ int i;
+
+ addcase(r);
+ if(flags['1'])
+ reprint("r", r);
+ nfollow = 0;
+ gen++;
+ fol1(r, Cbegin);
+ follow[nfollow++] = r;
+ qsort(follow, nfollow, sizeof(*follow), fcmp);
+
+ s = sal(nfollow);
+ for(i=0; i<nfollow; i++)
+ s->re[i] = follow[i];
+ return s;
+}