#include #include #include #include #include <9p.h> #include #include "common.h" #include "debug.h" #include "string.h" #include "collection.h" #include "function.h" #include "array.h" #include "rule.h" #include "namerule.h" #include "logicalrule.h" #include "regexrule.h" #include "moderule.h" #include "allrule.h" #include "filepath.h" #include "file.h" #include "holemanager.h" #include "filehandle.h" #include "fiddata.h" #include "qidgenerator.h" #include "matcher.h" #include "configyacclex.h" #include "config.h" enum { DEBUG_CONFIG = false }; extern int infd; // extern from lex.yy.c typedef struct Config { int *input; Matcher *matcher; char *absolutepath; Array *stack; } Config; static Config configInstance; Config *config_instance(void) { return &configInstance; } static void config_set_absolutepath(Config *self, char *path) { String *absolute; assert_valid(self); assert_valid(path); free(self->absolutepath); absolute = s_copy(path); filepath_make_absolute(&absolute); self->absolutepath = string_convert_escaped(estrdup_fs(s_to_c(absolute))); s_free(absolute); } void config_set_currentpath(char *path) { assert_valid(path); config_set_absolutepath(config_instance(), path); } typedef Rule *(*rule_parse)(char *rule, char *setting, char *path); static rule_parse ruleParserRegistry[] = { extensionrule_parse, fileregexrule_parse, dirregexrule_parse, regexrule_parse, moderule_parse, allrule_parse }; static Rule *config_parse_rule(Config *self, char *rule, char *setting) { int i; int registrysize = static_array_length(ruleParserRegistry); Rule *result = nil; char *converted; assert_valid(self); converted = string_convert_single_escaped(estrdup_fs(setting), '>', '>'); NOISE(DEBUG_CONFIG, "rule name: %s setting: %s converted: %s path: %s", rule, setting, converted, self->absolutepath); for(i = 0; i < registrysize && result == nil; ++i) { result = ruleParserRegistry[i](rule, converted, self->absolutepath); } free(converted); return result; } static void config_push_and_rule(Config *self) { Rule *first; Rule *second; assert_valid(self); NOISE(DEBUG_CONFIG, "config_push_and_rule with stack size: %d", array_size(self->stack)); second = (Rule *)array_pop(self->stack); first = (Rule *)array_pop(self->stack); array_push(self->stack, andrule_new(first, second, self->absolutepath)); } static void config_push_or_rule(Config *self) { Rule *first; Rule *second; assert_valid(self); NOISE(DEBUG_CONFIG, "config_push_or_rule with stack size: %d", array_size(self->stack)); second = (Rule *)array_pop(self->stack); first = (Rule *)array_pop(self->stack); array_push(self->stack, orrule_new(first, second, self->absolutepath)); } void config_and_setting(void) { config_push_and_rule(config_instance()); } void config_or_setting(void) { config_push_or_rule(config_instance()); } static void config_push_rule(Config *self, Rule *rule) { assert_valid(self); assert_valid(rule); array_push(self->stack, rule); } bool config_push_setting(char *rulename, char *setting) { Rule *rule; assert_valid(rulename); assert_valid(setting); rule = config_parse_rule(config_instance(), rulename, setting); if(rule == nil) { return false; } config_push_rule(config_instance(), rule); return true; } static void config_add_rule(Config *self) { assert_valid(self); NOISE(DEBUG_CONFIG, "entering config_add_rule with stack size: %d", array_size(self->stack)); matcher_add(self->matcher, array_pop(self->stack)); assert(array_isempty(self->stack)); } void config_rule_end(void) { NOISE(DEBUG_CONFIG, "config_rule_end done with rule"); config_add_rule(config_instance()); } static bool config_init(Config *self, Matcher *matcher, char *file) { assert_valid(self); assert_valid(matcher); assert_valid(file); self->input = &infd; *(self->input) = file_open(file, OREAD); if(!fd_isopen(*(self->input))) { ERROR(DEBUG_CONFIG, "config_init failed to open file: %s", file); return false; } self->matcher = matcher; self->absolutepath = nil; self->stack = array_new(); return true; } static void config_destroy(Config *self) { if(self == nil) { return; } array_free_with(self->stack, (functionunary)rule_free); self->stack = nil; free(self->absolutepath); self->absolutepath = nil; self->matcher = nil; file_close(*(self->input)); *(self->input) = INVALID_FD; } static bool config_yyparse(void) { NOISE(DEBUG_CONFIG, "config_yyparse about to call yyparse"); return yyparse() == CONFIG_YACC_SUCCESS; } bool config_parse(Matcher *matcher, char *file) { bool result; assert_valid(matcher); assert_valid(file); if(!config_init(config_instance(), matcher, file)) { return false; } result = config_yyparse(); NOISE(DEBUG_CONFIG, "config_parse done parsing with result: %d", result); config_destroy(config_instance()); return result; }