#include #include #include #include #include #include "filter.h" struct filter_rule parse_exclude_rule(const char *rule) { const size_t len = strlen(rule); const bool open_left = rule[0] == '*'; if (open_left) { if (len < 4 || memcmp(rule, "**/", 3) != 0) { fprintf(stderr, "Error: A filter rule starting with '*' must start with '**/'.\n"); exit(1); } } else { if (rule[0] != '/') { fprintf(stderr, "Error: A filter rule with a non-wildcard left-hand side must start with '/'.\n"); exit(1); } } const bool open_right = len > 0 && rule[len - 1] == '*'; if (open_right) { if (len < 4 || memcmp(rule + len - 3, "/**", 3) != 0) { fprintf(stderr, "Error: A filter rule ending with '*' must end with '/**'.\n"); exit(1); } } const size_t str_start = open_left ? 3 : 1; const size_t str_len = len - str_start - (open_right ? 3 : 0); for (size_t i = 0; i < str_len; i++) { if (rule[str_start + i] == '*') { fprintf(stderr, "Error: Wildcards in the middle of a pattern unsupported.\n"); exit(1); } } char *str = malloc(str_len + 1); memcpy(str, rule + str_start, str_len); str[str_len] = '\0'; return (struct filter_rule){ .ftype = FILTER_EXCLUDE, .ptype = open_left && open_right ? PATTERN_INFIX : open_left ? PATTERN_SUFFIX : open_right ? PATTERN_PREFIX : PATTERN_EQUAL, .str = str, .len = str_len, }; } bool filter_rule_allows(const struct filter_rule rule, const char *path) { assert(rule.ftype == FILTER_EXCLUDE); switch (rule.ptype) { case PATTERN_EQUAL: if (strcmp(path, rule.str) == 0) return false; break; case PATTERN_PREFIX: if (strncmp(path, rule.str, rule.len) == 0 && (path[rule.len] == '/' || path[rule.len] == '\0')) return false; break; case PATTERN_SUFFIX: { const size_t pathlen = strlen(path); if (pathlen >= rule.len && memcmp(path + pathlen - rule.len, rule.str, rule.len) == 0 && (pathlen == rule.len || path[pathlen - rule.len - 1] == '/')) return false; break; } case PATTERN_INFIX: { const size_t pathlen = strlen(path); if (strncmp(path, rule.str, rule.len) == 0 && (path[rule.len] == '\0' || path[rule.len] == '/')) return false; for (size_t i = 0; i < pathlen; i++) { if (path[i] == '/') { if (strncmp(path + i+1, rule.str, rule.len) == 0 && (path[i+1 + rule.len] == '\0' || path[i+1 + rule.len] == '/')) return false; } } break; } } return true; } void filter_rule_debugdump(FILE *stream, const struct filter_rule rule) { const char *ftype_str; switch (rule.ftype) { case FILTER_EXCLUDE: ftype_str = "exclude"; break; default: ftype_str = "?unknown_ftype"; break; } const char *ptype_str; switch (rule.ptype) { case PATTERN_EQUAL: ptype_str = "equal"; break; case PATTERN_PREFIX: ptype_str = "prefix"; break; case PATTERN_SUFFIX: ptype_str = "suffix"; break; case PATTERN_INFIX: ptype_str = "infix"; break; default: ptype_str = "?unknown_ptype"; break; } fprintf(stream, "%s %s <%s>\n", ftype_str, ptype_str, rule.str); }