You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.8 KiB
C
151 lines
3.8 KiB
C
/*
|
|
* trie.c: Trie implementation for storing values
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "trie.h"
|
|
#include "config.h"
|
|
|
|
static struct trie *trie_base;
|
|
|
|
static int indexof(char c) {
|
|
// ASCII only!
|
|
if ('A' <= c && c <= 'Z') {
|
|
return (c - 'A');
|
|
} else if ('0' <= c && c <= '9') {
|
|
return (c - '0' + 26);
|
|
} else if (c == '_') {
|
|
return 36;
|
|
} else {
|
|
// Something weird happened
|
|
syslog(cfg_log_facility|LOG_NOTICE, "trie: weird character: %c", c);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static char charof(int i) {
|
|
//ASCII again
|
|
if (i <= 25){
|
|
return ('A' + i);
|
|
} else if (26 <= i && i <= 35) {
|
|
return ('0' + i - 26);
|
|
} else if (i == 36) {
|
|
return '_';
|
|
} else {
|
|
syslog(cfg_log_facility|LOG_NOTICE, "trie: weird character index: %d", i);
|
|
return '\0';
|
|
}
|
|
}
|
|
|
|
static bool trie_set_deep(char string[], int64_t val, struct trie *vertex) {
|
|
// Recursive function to find and set a value
|
|
if (string[0] = '\0') {
|
|
vertex -> val = val;
|
|
vertex -> defined = true;
|
|
return true;
|
|
} else {
|
|
int chld_index = indexof(string[0]);
|
|
if (chld_index == -1) {
|
|
return false; //and don't save anything
|
|
} else if (vertex -> children[chld_index] == NULL) {
|
|
vertex -> children[chld_index] = (struct trie *) calloc(1, sizeof(struct trie));
|
|
if (vertex -> children[chld_index] == NULL) {
|
|
syslog(cfg_log_facility | LOG_ERR, "trie: could not allocate space: %m");
|
|
return false;
|
|
}
|
|
}
|
|
return trie_set_deep(string+1, val, vertex->children[chld_index]);
|
|
}
|
|
}
|
|
|
|
bool trie_set(char string[], int64_t val) {
|
|
if (trie_base == NULL) {
|
|
trie_base = (struct trie *) calloc(1, sizeof(struct trie));
|
|
if(trie_base == NULL) {
|
|
syslog(cfg_log_facility | LOG_ERR, "trie: could not allocate any space: %m");
|
|
return false;
|
|
}
|
|
}
|
|
return trie_set_deep(string, val, trie_base);
|
|
}
|
|
|
|
static struct trie_retval trie_lookup_deep(char string[], struct trie *vertex) {
|
|
if (string[0] == '\0') {
|
|
return (struct trie_retval) {vertex -> val, vertex -> defined};
|
|
} else {
|
|
int chld_index = indexof(string[0]);
|
|
if (chld_index == -1 || vertex -> children[chld_index] == NULL) {
|
|
return (struct trie_retval) {0, false};
|
|
} else {
|
|
return trie_lookup_deep(string + 1, vertex->children[chld_index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct trie_retval trie_lookup(char string[]) {
|
|
if (trie_base == NULL) {
|
|
return (struct trie_retval) {0, false};
|
|
} else return trie_lookup_deep(string, trie_base);
|
|
}
|
|
|
|
bool trie_load(void) {
|
|
FILE *f = fopen(cfg_trie_file, "r");
|
|
if (f == NULL) {
|
|
syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m");
|
|
return false;
|
|
}
|
|
|
|
//FIXME: This is bad.
|
|
int64_t val;
|
|
char name[cfg_var_name_max_len+1];
|
|
int status;
|
|
while ((status = fscanf(f, "%s %d\n", name, &val)) != EOF) {
|
|
if (status != 2) {
|
|
syslog(cfg_log_facility | LOG_ERR, "trie: fscanf matched bad number of items: %d", status);
|
|
return false;
|
|
}
|
|
if(trie_set(name, val) == false) {
|
|
syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %d", name, val);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool trie_dfs(char prefix[], int prefixlen, FILE *f, struct trie *vertex) {
|
|
if (vertex == NULL) {// Very special case;
|
|
return true;
|
|
} else {
|
|
bool retval = true;
|
|
if (vertex -> defined) {
|
|
prefix[prefixlen] = '\0';
|
|
fprintf(f, "%s %d\n", prefix, vertex -> val);
|
|
}
|
|
for (int i = 0; i<37; i++) {
|
|
if (vertex -> children[i] != NULL) {
|
|
prefix[prefixlen] = charof(i);
|
|
retval &= trie_dfs(prefix, prefixlen + 1, f, vertex -> children[i]);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
bool trie_save(void) {
|
|
FILE *f = fopen(cfg_trie_file, "w");
|
|
if (f == NULL) {
|
|
syslog(cfg_log_facility | LOG_CRIT, "trie: could not open file to save trie in: %m");
|
|
return false;
|
|
}
|
|
|
|
// DFS, write every found variable into f
|
|
char prefix[cfg_var_name_max_len +1];
|
|
prefix[cfg_var_name_max_len +1] = '\0';
|
|
int prefixlen = 0;
|
|
|
|
return trie_dfs(prefix, prefixlen, f, trie_base);
|
|
}
|