#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <String.h>
#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;
}
|