/* * trie.c: Trie implementation for storing values */ #include #include #include #include #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); }