diff --git a/Makefile b/Makefile index 833db88..339fa4c 100644 --- a/Makefile +++ b/Makefile @@ -145,6 +145,7 @@ UPROGS=\ $U/_mkdir\ $U/_pingpong\ $U/_primes\ + $U/_regexfind\ $U/_rm\ $U/_sh\ $U/_sleep\ diff --git a/user/regexfind.c b/user/regexfind.c new file mode 100644 index 0000000..edeea4c --- /dev/null +++ b/user/regexfind.c @@ -0,0 +1,112 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "kernel/fs.h" +#include "user/user.h" + +int match(char*, char*); + +void +find(char *path, char *pattern) +{ + char buf[512], *p; + int fd; + struct dirent de; + struct stat st; + + if ((fd = open(path, 0)) < 0) { + fprintf(2, "find: cannot find path %s\n", path); + exit(1); + } + + if (fstat(fd, &st) < 0) { + fprintf(2, "find: cannot stat %s\n", path); + close(fd); + exit(1); + } + + if (st.type != T_DIR) { + fprintf(2, "find: %s is not a directory\n", path); + close(fd); + exit(1); + } + + if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){ + fprintf(2, "find: path too long\n"); + close(fd); + exit(1); + } + + strcpy(buf, path); + p = buf + strlen(buf); + *p++ = '/'; + while (read(fd, &de, sizeof(de)) == sizeof(de)) { + if (de.inum == 0 || !strcmp(de.name, ".") || !strcmp(de.name, "..")) + continue; + memmove(p, de.name, DIRSIZ); + p[DIRSIZ] = 0; + if (stat(buf, &st) < 0) { + fprintf(1, "find: cannot stat %s\n", buf); + continue; + } + if (st.type == T_FILE && match(pattern, de.name)) { + fprintf(1, "%s\n", buf); + } else if (st.type == T_DIR) { + find(buf, pattern); + } + } + close(fd); +} + +int +main(int argc, char *argv[]) +{ + if (argc < 2 || argc > 3) { + fprintf(2, "Usage: find (path) [file]\n"); + exit(1); + } else if (argc < 3) { + find(".", argv[1]); + } else { + find(argv[1], argv[2]); + } + + exit(0); +} + +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; +}