#include "lexer.h" #include #include #include #include #include #include "ugtests.h" int print(__attribute__((unused)) const char *param, const char *filename) { printf("%s\n", filename); return 1; } int name(const char *param, const char *filename) { const char *f = filename + strlen(filename) - 1; for (; f >= filename && *f != '/'; f--) { continue; } if (*f == '/') f++; return !fnmatch(param, f, FNM_PATHNAME); } int type(const char *param, const char *filename) { // assume that param is valid e.g. single char struct stat s; if (lstat(filename, &s)) { fprintf(stderr, "myfind: Error trying to stat path %s\n", filename); return -1; } switch (*param) { case 'b': return S_ISBLK(s.st_mode); case 'c': return S_ISCHR(s.st_mode); case 'd': return S_ISDIR(s.st_mode); case 'f': return S_ISREG(s.st_mode); case 'l': return S_ISLNK(s.st_mode); case 'p': return S_ISFIFO(s.st_mode); case 's': return S_ISSOCK(s.st_mode); default: fprintf(stderr, "myfind: Error trying to stat path %s\n", filename); return -1; } } int is_newer(const char *param, const char *filename) { struct stat f1; if (lstat(filename, &f1)) { fprintf(stderr, "myfind: Error trying to stat path %s\n", filename); return -1; } struct stat f2; if (lstat(param, &f2)) { fprintf(stderr, "myfind: Error trying to stat path %s\n", param); return -1; } if (f2.st_mtime == f1.st_mtime) { if (f2.st_mtim.tv_nsec >= f1.st_mtim.tv_nsec) return 0; } else if (f2.st_mtime > f1.st_mtime) return 0; return 1; } struct template { char *flag; enum type type; int (*fun)(__attribute__((unused)) const char *, const char *); }; static struct template templates[] = { { .flag = "-print", .type = PRINT, .fun = print }, { .flag = "-name", .type = NAME, .fun = name }, { .flag = "-type", .type = TYPE, .fun = type }, { .flag = "-newer", .type = NEWER, .fun = is_newer }, { .flag = "-group", .type = GROUP, .fun = group_belong }, { .flag = "-user", .type = USER, .fun = user_belong }, { .flag = "-perm", .type = PERM, .fun = perm }, { .flag = "-o", .type = OR, .fun = NULL }, { .flag = "-a", .type = AND, .fun = NULL } }; void init_token(struct ast **tok, struct template temp) { *tok = malloc(sizeof(struct ast)); (*tok)->type = temp.type; if ((*tok)->type == OR || (*tok)->type == AND) { (*tok)->data.children.left = NULL; (*tok)->data.children.right = NULL; } else { (*tok)->data.test.param = NULL; (*tok)->data.test.fun = temp.fun; } } void cleanup(struct ast **tokens, int len) { for (int k = 0; k < len; k++) free(tokens[k]); free(tokens); } void *error(struct ast **tokens, int len, enum type flag) { char *f; switch (flag) { case NAME: f = "-name"; break; case TYPE: f = "-type"; break; case PERM: f = "-perm"; break; case GROUP: f = "-group"; break; case USER: f = "-user"; break; default: f = "-newer"; break; } fprintf(stderr, "myfind: lex: invalid/missing %s argument\n", f); cleanup(tokens, len); return NULL; } struct ast **lex(char **argv, int *len, int *act) { // if error : free tokens struct ast **tokens = malloc((*len * 2 - 1) * sizeof(struct ast *)); *act = 0; int n = 0; for (int i = 0; i < *len; i++, n++) { int j; for (j = 0; j < 9; j++) { if (strcmp(argv[i], templates[j].flag) == 0) { init_token(tokens + n, templates[j]); if (tokens[n]->type == PRINT) *act = 1; // enventual offset & param set // refactor if (tokens[n]->type == NAME || tokens[n]->type == TYPE || tokens[n]->type == NEWER || tokens[n]->type == GROUP || tokens[n]->type == USER || tokens[n]->type == PERM) { struct stat s; if ((i + 1 >= *len) || (tokens[n]->type == TYPE && argv[i + 1][1] != '\0') || (tokens[n]->type == NEWER && lstat(argv[i + 1], &s))) { return error(tokens, n + 1, tokens[n]->type); } tokens[n]->data.test.param = argv[i + 1]; i++; } break; } } if (j == 9) { fprintf(stderr, "myfind: lex: Invalid argument %s\n", argv[i]); cleanup(tokens, n + 1); return NULL; } } *len = n; return tokens; }