#include "gbos.h" /* grep [-v][-i][-n] PAT [file]: print the lines of a file (or stdin) that * contain the substring PAT. Plain substring matching, no regex - '.' and '*' * are literal characters. -v inverts the match, -i folds case, -n prefixes * each hit with its line number. * * NB: no statics here. A program's _DATA area starts at $A000, which is also * where the shell leaves the command line (usr/sh.c ARGV0), so statics would * eat argv. Locals live on the task stack below $BFFF and are always safe. */ #define MAXLINE 80 /* two terminal rows; longer lines are clipped */ static char fold(char c, unsigned char ic) { if (ic && c >= 'A' && c <= 'Z') return (char)(c + 32); return c; } /* is pat[] present anywhere in line[0..len)? */ static unsigned char contains(char *line, unsigned char len, char *pat, unsigned char ic) { unsigned char i, j; if (!pat[0]) return 1; /* empty pattern matches all */ for (i = 0; i < len; i++) { for (j = 0;; j++) { if (!pat[j]) return 1; /* ran out of pattern: a hit */ if (i + j >= len) break; /* ran out of line: no hit here */ if (fold(line[i + j], ic) != fold(pat[j], ic)) break; } } return 0; } void main(void) { char *argv[8]; char line[MAXLINE]; unsigned char argc = argv_parse(argv, 8); unsigned char inv = hasflag(argv, argc, 'v') ? 1 : 0; unsigned char ic = hasflag(argv, argc, 'i') ? 1 : 0; unsigned char num = hasflag(argv, argc, 'n') ? 1 : 0; unsigned char i, len = 0, hits = 0, fd = NOFD; unsigned int lineno = 0; char *pat = 0, *fname = 0; int ch; /* first non-flag word is the pattern, second (if any) is the file */ for (i = 0; i < argc; i++) { if (argv[i][0] == '-') continue; if (!pat) pat = argv[i]; else { fname = argv[i]; break; } } if (!pat) { puts("usage: grep [-vin] PAT [file]"); nl(); sexit(2); } if (fname) { fd = open(fname, O_READ); if (fd == EISDIR) { puts("grep: is a directory"); nl(); sexit(2); } if (fd == NOFD) { puts("grep: no such file"); nl(); sexit(2); } } for (;;) { if (fd == NOFD) { char c = readc(); ch = (c == EOF) ? -1 : c; } else ch = fgetc(fd); if (ch == '\r') continue; /* CRLF: the LF ends the line */ if (ch >= 0 && ch != '\n') { /* ordinary character */ if (len < MAXLINE) line[len++] = (char)ch; continue; } if (ch < 0 && len == 0) break; /* EOF, nothing pending */ lineno++; if (contains(line, len, pat, ic) != inv) { if (num) { putu(lineno); putc(':'); } writes(line, len); /* one batched render */ nl(); hits = 1; } len = 0; if (ch < 0) break; /* EOF after a final partial line */ } if (fd != NOFD) close(fd); sexit(hits ? 0 : 1); /* grep(1) exit convention */ }