summaryrefslogtreecommitdiff
path: root/user/grep.c
diff options
context:
space:
mode:
Diffstat (limited to 'user/grep.c')
-rw-r--r--user/grep.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/user/grep.c b/user/grep.c
new file mode 100644
index 0000000..b5fdfc2
--- /dev/null
+++ b/user/grep.c
@@ -0,0 +1,107 @@
+// Simple grep. Only supports ^ . * $ operators.
+
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+
+char buf[1024];
+int match(char*, char*);
+
+void
+grep(char *pattern, int fd)
+{
+ int n, m;
+ char *p, *q;
+
+ m = 0;
+ while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
+ m += n;
+ buf[m] = '\0';
+ p = buf;
+ while((q = strchr(p, '\n')) != 0){
+ *q = 0;
+ if(match(pattern, p)){
+ *q = '\n';
+ write(1, p, q+1 - p);
+ }
+ p = q+1;
+ }
+ if(p == buf)
+ m = 0;
+ if(m > 0){
+ m -= p - buf;
+ memmove(buf, p, m);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fd, i;
+ char *pattern;
+
+ if(argc <= 1){
+ printf(2, "usage: grep pattern [file ...]\n");
+ exit();
+ }
+ pattern = argv[1];
+
+ if(argc <= 2){
+ grep(pattern, 0);
+ exit();
+ }
+
+ for(i = 2; i < argc; i++){
+ if((fd = open(argv[i], 0)) < 0){
+ printf(1, "grep: cannot open %s\n", argv[i]);
+ exit();
+ }
+ grep(pattern, fd);
+ close(fd);
+ }
+ exit();
+}
+
+// Regexp matcher from Kernighan & Pike,
+// The Practice of Programming, Chapter 9.
+
+int matchhere(char*, char*);
+int matchstar(int, char*, char*);
+
+int
+match(char *re, char *text)
+{
+ if(re[0] == '^')
+ return matchhere(re+1, text);
+ do{ // must look at empty string
+ if(matchhere(re, text))
+ return 1;
+ }while(*text++ != '\0');
+ return 0;
+}
+
+// matchhere: search for re at beginning of text
+int matchhere(char *re, char *text)
+{
+ if(re[0] == '\0')
+ return 1;
+ if(re[1] == '*')
+ return matchstar(re[0], re+2, text);
+ if(re[0] == '$' && re[1] == '\0')
+ return *text == '\0';
+ if(*text!='\0' && (re[0]=='.' || re[0]==*text))
+ return matchhere(re+1, text+1);
+ return 0;
+}
+
+// matchstar: search for c*re at beginning of text
+int matchstar(int c, char *re, char *text)
+{
+ do{ // a * matches zero or more instances
+ if(matchhere(re, text))
+ return 1;
+ }while(*text!='\0' && (*text++==c || c=='.'));
+ return 0;
+}
+