1
0
Fork 0

Refactor, complete trie, extract growing array

master
LEdoian 7 years ago
parent d54692a622
commit c9692341e7

@ -6,15 +6,17 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include <stdint.h>
const int cfg_log_facility = LOG_CRON; const int cfg_log_facility = LOG_CRON;
const char cfg_log_ident[] = "kairos"; const char cfg_log_ident[] = "kairos";
const int cfg_log_opt = LOG_PID | LOG_NDELAY; const int cfg_log_opt = LOG_PID | LOG_NDELAY;
const char cfg_trie_file[] = "/home/ledoian/.kairos/trie"; const char cfg_trie_file[] = "/home/ledoian/.kairos/trie";
const char cfg_tasks_file[] = "/home/ledoian/.kairos/tasks"; const char cfg_task_file[] = "/home/ledoian/.kairos/tasks";
const char cfg_socket[] = "/tmp/kairos.sock"; const char cfg_socket[] = "/tmp/kairos.sock";
const int cfg_sock_maxclients = 16; const uint32_t cfg_sock_maxclients = 16;
const int cfg_var_name_max_len = 16; const uint64_t cfg_var_name_max_len = 16;
#endif #endif

@ -2,15 +2,22 @@
* main.c: the daemon itself * main.c: the daemon itself
*/ */
#include <unistd.h>
#include <syslog.h> #include <syslog.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include "config.h" #include "config.h"
#include "trie.h" #include "trie.h"
#include "tasks.h" #include "task.h"
#include "daemonize.h"
void shutdown(int sigval); void term_handle(int sigval);
bool process(int fd);
static int sockfd; static int sockfd;
@ -20,25 +27,28 @@ int main (void) {
daemonize(0); daemonize(0);
// Load saved state -- variable values and tasks // Load saved state -- variable values and tasks
trie_load(); trie_load(cfg_trie_file);
tasks_load(); task_load(cfg_task_file);
// Set basic signal handlers // Set basic signal handlers
sigset_t empty;
sigemptyset(&empty); // Shall not fail
struct sigaction *term_sigh = (struct sigaction *) malloc(sizeof(struct sigaction)); struct sigaction *term_sigh = (struct sigaction *) malloc(sizeof(struct sigaction));
term_sigh -> sa_handler = &shutdown; term_sigh -> sa_handler = &term_handle;
term_sigh -> sa_mask = 0; term_sigh -> sa_mask = empty;
term_sigh -> sa_flags = 0; term_sigh -> sa_flags = 0;
sigaction(SIGTERM, term_sigh, NULL); sigaction(SIGTERM, term_sigh, NULL);
struct sigaction *chld_sigh = (struct sigaction *) malloc(sizeof(struct sigaction)); struct sigaction *chld_sigh = (struct sigaction *) malloc(sizeof(struct sigaction));
chld_sigh -> sa_handler = SIG_IGN; // We don't care for children chld_sigh -> sa_handler = SIG_IGN; // We don't care for children
chld_sigh -> sa_mask = 0; chld_sigh -> sa_mask = empty;
chld_sigh -> sa_flags = SA_NOCLDWAIT; chld_sigh -> sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD, chld_sigh, NULL); sigaction(SIGCHLD, chld_sigh, NULL);
// Setup a socket to listen on // Setup a socket to listen on
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr; struct sockaddr_un addr;
socklen_t addrsize = sizeof(struct sockaddr_un);
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket)); memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket));
bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
@ -49,7 +59,7 @@ int main (void) {
// Main loop: (everything else is handled by process() and signal handlers). // Main loop: (everything else is handled by process() and signal handlers).
while (true) { while (true) {
int fd = accept(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); int fd = accept(sockfd, (struct sockaddr *) &addr, &addrsize);
process(fd); process(fd);
} }
@ -57,9 +67,13 @@ int main (void) {
return 5; return 5;
} }
void shutdown (int signum) { void term_handle (int signum) {
trie_save(); trie_save(cfg_trie_file);
tasks_save(); task_save(cfg_task_file);
close(sockfd); close(sockfd);
unlink(cfg_socket); unlink(cfg_socket);
exit(0);
return;
} }
bool process(int fd) {}

@ -31,7 +31,7 @@ bool daemonize(uint32_t flags) {
syslog(cfg_log_facility | LOG_WARNING, "daemonize: getrlimit failed: %m"); syslog(cfg_log_facility | LOG_WARNING, "daemonize: getrlimit failed: %m");
retval = false; retval = false;
} }
for (rlim_t fd = 3; fd < maxfd.rlim_cur; fd++) { for (unsigned int fd = 3; fd < maxfd.rlim_cur; fd++) {
char tries = 0; char tries = 0;
while(close(fd) == -1) { // Try 3 times to close fd, retry only if interrupted while(close(fd) == -1) { // Try 3 times to close fd, retry only if interrupted
unless (errno == EINTR) { unless (errno == EINTR) {

@ -15,21 +15,21 @@ bool daemonize(uint32_t flags);
// except the first one // except the first one
// some of them will never be used // some of them will never be used
#define NODAEMONIZE 1<<0 /*Do not daemonize at all*/ #define NODAEMONIZE (1<<0) /*Do not daemonize at all*/
#define NOCLOSEFD 1<<1 #define NOCLOSEFD (1<<1)
#define NORSTSIG 1<<2 #define NORSTSIG (1<<2)
#define NORSTSIGMASK 1<<3 #define NORSTSIGMASK (1<<3)
#define NOSANITY 1<<4 // Sanitizing not implemented #define NOSANITY (1<<4) // Sanitizing not implemented
#define NOBGFORK 1<<5 #define NOBGFORK (1<<5)
#define NOSETSID 1<<6 #define NOSETSID (1<<6)
#define NOSECONDFORK 1<<7 #define NOSECONDFORK (1<<7)
#define NOEXITCHLD 1<<8 // Not implemented -- always exit #define NOEXITCHLD (1<<8) // Not implemented -- always exit
#define NOCONNECTIO 1<<9 #define NOCONNECTIO (1<<9)
#define NORSTUMASK 1<<10 #define NORSTUMASK (1<<10)
#define NOCHANGEWD 1<<11 #define NOCHANGEWD (1<<11)
#define NOPIDFILE 1<<12 // Creating PID file not implemented #define NOPIDFILE (1<<12) // Creating PID file not implemented
#define NOPRIVDROP 1<<13 // Not needed #define NOPRIVDROP (1<<13) // Not needed
#define NONOTIFY 1<<14 // Not implemented -- always notify #define NONOTIFY (1<<14) // Not implemented -- always notify
#define NOPARENTEXIT 1<<15 // Not implemented -- always exit #define NOPARENTEXIT (1<<15) // Not implemented -- always exit
#endif #endif

@ -0,0 +1,61 @@
/*
* grow.c: generic growing array implementation
*/
#include <syslog.h>
#include "grow.h"
#include "config.h"
struct grow *grow_init(bool dealloc) {
struct grow *g = malloc(sizeof(struct grow));
if (g == NULL) {
syslog(cfg_log_facility | LOG_ERR, "grow: Could not initialize growing array: %m");
return NULL;
}
g -> arr = NULL;
g -> elems = 0;
g -> alloc = 0;
g -> active_elems = 0;
g -> dealloc = dealloc;
return g;
}
bool grow_push (void *val, struct grow *g) {
if (g -> alloc <= g -> elems) {
uint64_t new_size = g -> alloc == 0? 1 : 2* (g -> alloc);
void **new_arr = realloc(g -> arr, new_size * sizeof(void *));
if (new_arr == NULL) {
syslog(cfg_log_facility | LOG_ERR, "grow: could not resize growinging array: %m");
return false;
} else {
g -> arr = new_arr;
g -> alloc = new_size;
}
}
g -> arr[g -> elems] = val;
g -> elems++;
g -> active_elems++;
return true;
}
void *grow_pop (struct grow *g) {
if (g -> elems == 0) {
return NULL;
} else {
g -> elems--;
g -> active_elems--;
return g -> arr[g -> elems + 1];
}
}
void grow_drop (struct grow *g) {
if (g -> dealloc == true) {
for(uint64_t i = 0; i < g -> elems; i++) {
free(g->arr[i]);
}
}
free(g -> arr);
free(g);
return;
}

@ -0,0 +1,25 @@
/*
* grow.h: declaration of generic growing array
*/
#ifndef GROW_H
#define GROW_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
struct grow {
void **arr;
uint64_t elems;
uint64_t alloc;
uint64_t active_elems;
bool dealloc;
};
struct grow *grow_init(bool dealloc);
bool grow_push (void *val, struct grow *g);
void *grow_pop (struct grow *g);
void grow_drop (struct grow *g);
#endif

267
rpn.c

@ -2,39 +2,268 @@
* rpn.c: evalutor of RPN formulas * rpn.c: evalutor of RPN formulas
*/ */
#include <stdint.h>
#include <syslog.h> #include <syslog.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "config.h" #include "config.h"
#include "rpn.h" #include "rpn.h"
#include "trie.h" #include "trie.h"
#include "grow.h"
// Growing stack implementation // Wrapper functions between grow's void*s and our struct trie_retvals
struct grow { bool stack_push (struct trie_retval val, struct grow *stack) {
struct trie_retval *arr; struct trie_retval *p_val = (struct trie_retval *) malloc(sizeof(struct trie_retval));
int64_t elems; if (p_val == NULL) {
int64_t alloc; syslog(cfg_log_facility | LOG_ERR, "rpn: stack_push: malloc failed: %m");
return false;
}
*p_val = val;
return grow_push((void *)p_val, stack);
}
struct trie_retval stack_pop(struct grow *stack) {
struct trie_retval *p_val = (struct trie_retval *) grow_pop(stack);
struct trie_retval val = *p_val;
free(p_val);
return val;
} }
static struct grow *grow_init(void) { static uint64_t parse_var_name(char str[], char *out[]) {
struct grow *g = malloc(sizeof(struct grow)); uint64_t off;
if (g == NULL) { for (off = 0;
syslog(cfg_log_facility | LOG_ERR, "rpn: Could not initialize growing array: %m"); ('A' <= str[off] && str[off] <= 'Z')
return NULL; || ('0' <= str[off] && str[off] <= '9')
|| str[off] == '_'
; off++) {
if (off < cfg_var_name_max_len) {
(*out)[off] = str[off];
} else {
syslog(cfg_log_facility | LOG_NOTICE, "rpn: variable name too long, trucating char '%c'", str[off]);
}
} }
g -> arr = NULL; // off is pointing past end of variable name;
g -> elems = 0; (*out)[off] = '\0';
g -> alloc = 0; return off - 1; //last character of variable name
return g;
} }
static bool grow_push (int64_t val, struct grow *stack) { static uint64_t do_cmd(char str[], struct grow *stack) {
if (stack -> alloc <= stack -> elems) { // Check whether a command exists and if so, perform it
stack if(0){
//alignment of others
//Bonus unconditional jump for compiling with -O0, maybe
} else if (strncmp("def", str, 3) == 0) {
struct trie_retval arg = stack_pop(stack);
if (arg.def) { // true might not be 1, I am not sure.
stack_push((struct trie_retval) {1, true, NULL}, stack);
} else {
stack_push((struct trie_retval) {0, true, NULL}, stack);
}
return 2;
} else if (strncmp("swap", str, 4) == 0) {
struct trie_retval arg1 = stack_pop(stack);
struct trie_retval arg2 = stack_pop(stack);
stack_push(arg1, stack);
stack_push(arg2, stack);
return 3;
} else if (strncmp("dup", str, 3) == 0) {
struct trie_retval arg = stack_pop(stack);
stack_push(arg, stack);
stack_push(arg, stack);
return 2;
} else if (strncmp("del", str, 3) == 0) {
stack_pop(stack);
return 2;
} else {
syslog(cfg_log_facility | LOG_NOTICE, "rpn: Unknown command starting with '%c'", str[0]);
return 0;
} }
} }
bool rpn_eval (char rpn[]) { static bool rpn_eval_modify (char rpn[], bool modify, bool assoc, uint64_t task) {
uint64_t rpnoff;
struct grow *stack = grow_init(true);
char buf[cfg_var_name_max_len + 1];
int64_t val = 0;
// Sign of val==0
bool val_neg = false;
//definition of temporary variables, because of switch's goto-y behavior
struct trie_retval arg;
struct trie_retval arg1;
struct trie_retval arg2;
// this leads to dangerous code -- it is not clear, what are the values.
// but it has to be done this way due to how C switch works
// parse the RPN
for (rpnoff=0; rpn[rpnoff] != '\0' && rpn[rpnoff] != '?'; rpn++) {
switch (rpn[rpnoff]) {
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
; //Label...
int digit = rpn[rpnoff] - '0';
val = val * 10 + digit;
if (val >= 0 && val_neg == true) {
val *= -1;
}
if (rpn[rpnoff+1] < '0' || '9' < rpn[rpnoff+1]) { //ASCII
// end of number
stack_push((struct trie_retval) {val, true, NULL}, stack);
val = 0;
val_neg = false;
}
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
rpnoff += parse_var_name(rpn + rpnoff, &buf);
stack_push(trie_lookup(buf),stack);
if (modify) {
if (assoc){
trie_assoc(buf, task);
} else {
trie_unassoc(buf, task);
}
}
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
rpnoff += do_cmd(rpn + rpnoff, stack);
break;
case '+':
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val + arg2.val, true, NULL}, stack);
break;
case '-': // May be unary or binary
if ('0' <= rpn[rpnoff+1] && rpn[rpnoff] <= '9') {
// Unary
// It's shame two's complement doesn't have -0, it would help here
val_neg = true;
} else {
// Binary
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val - arg2.val, true, NULL}, stack);
}
break;
case '*':
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val * arg2.val, true, NULL}, stack);
break;
case '/':
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val / arg2.val, true, NULL}, stack);
break;
case '%': //Modulo
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val % arg2.val, true, NULL}, stack);
break;
case '^': //Bit XOR
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val ^ arg2.val, true, NULL}, stack);
break;
case '~': //Bit NOT
; //Label...
arg = stack_pop(stack);
stack_push((struct trie_retval) {~(arg.val), true, NULL}, stack);
break;
case '!': //Logical NOT
; //Label...
arg = stack_pop(stack);
if (arg.val != 0) {
stack_push((struct trie_retval) {0,true, NULL}, stack);
} else {
stack_push((struct trie_retval) {1,true, NULL}, stack);
}
break;
case '=': //Equality
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val == arg2.val, true, NULL}, stack);
break;
case '>': //(mind the operand order)
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val > arg2.val, true, NULL}, stack);
break;
case '<': //(mind the operand order)
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
stack_push((struct trie_retval) {arg1.val < arg2.val, true, NULL}, stack);
break;
case '|': //Bit or logical OR
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
if (rpn[rpnoff+1] == '|') {
// Logical OR
rpnoff++;
stack_push((struct trie_retval) {arg1.val || arg2.val, true, NULL}, stack);
} else {
// Bit OR
stack_push((struct trie_retval) {arg1.val | arg2.val, true, NULL}, stack);
}
break;
case '&': //Bit or logical AND
; //Label...
arg1 = stack_pop(stack);
arg2 = stack_pop(stack);
if (rpn[rpnoff+1] == '&') {
// Logical AND
rpnoff++;
stack_push((struct trie_retval) {arg1.val && arg2.val, true, NULL}, stack);
} else {
// Bit AND
stack_push((struct trie_retval) {arg1.val & arg2.val, true, NULL}, stack);
}
break;
case ' ':
break;
default:
syslog(cfg_log_facility | LOG_NOTICE, "rpn: Unexpected char: %c", rpn[rpnoff]);
break;
}
}
// Return the variable at top of the stack and discard stack
struct trie_retval retval = stack_pop(stack);
grow_drop(stack);
if (retval.def == false || retval.val == 0) {
return false;
} else {
return true;
}
}
/*
* Mathematics is the art of giving the same name to different things.
* - Henri Poincaré
* Programming is the art of giving different names to the same thing.
* - Obvious from the code below.
* (except maybe it is not called art)
*/
bool rpn_eval(char rpn[]) {
return rpn_eval_modify(rpn, false, false, 0);
}
bool rpn_eval_assoc(char rpn[], uint64_t task) {
return rpn_eval_modify(rpn, true, true, task);
}
bool rpn_eval_unassoc(char rpn[], uint64_t task) {
return rpn_eval_modify(rpn, true, false, task);
} }

@ -6,7 +6,10 @@
#define RPN_H #define RPN_H
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
bool rpn_eval (char rpn[]); bool rpn_eval (char rpn[]);
bool rpn_eval_assoc (char rpn[], uint64_t task);
bool rpn_eval_unassoc (char rpn[], uint64_t task);
#endif #endif

@ -0,0 +1,7 @@
/*
* task.c: task management
*/
#include "task.h"

@ -0,0 +1,41 @@
/*
* task.h: declares functions for manipulation with tasks
*/
#ifndef TASK_H
#define TASK_H
#include <stdbool.h>
#include <time.h>
#include <stdbool.h>
#include <stdint.h>
struct task {
// Time info
struct itimerspec times;
timer_t timerid;
// Command to run
char **argv; //NULL terminated list of NUL terminated strings
// Formula to be checked when running
char *formula; // in RPN, NUL terminated
bool run; // dynamic programming
// Disabling/enabling
bool enabled;
};
bool task_add(struct task t);
bool task_disable(uint64_t id);
bool task_enable(uint64_t id);
bool task_delete(uint64_t id);
struct grow *task_list(void);
struct task task_details(uint64_t id);
void task_recalc(uint64_t id);
bool task_load(void);
bool task_save(void);
#endif

179
trie.c

@ -9,8 +9,9 @@
#include "trie.h" #include "trie.h"
#include "config.h" #include "config.h"
#include "task.h"
static struct trie *trie_base; static struct trie *trie_base = NULL;
static int indexof(char c) { static int indexof(char c) {
// ASCII only! // ASCII only!
@ -41,28 +42,41 @@ static char charof(int i) {
} }
} }
static bool trie_set_deep(char string[], int64_t val, struct trie *vertex) { static struct trie *trie_find_vertex(char string[], struct trie *vertex, bool create) {
// Recursive function to find and set a value if (vertex == NULL) {
if (string[0] = '\0') { if (create == false) {
vertex -> val = val; return NULL;
vertex -> defined = true; } else {
return true; vertex = (struct trie *) calloc(1, sizeof(struct trie));
if (vertex == NULL) {
syslog(cfg_log_facility | LOG_ERR, "trie: could not allocate space: %m");
return NULL;
}
}
}
if (string[0] == '\0') {
return vertex;
} else { } else {
int chld_index = indexof(string[0]); int chld_index = indexof(string[0]);
if (chld_index == -1) { if (chld_index == -1) {
return false; //and don't save anything return NULL;
} else if (vertex -> children[chld_index] == NULL) { } else if (vertex -> children[chld_index] == NULL) {
vertex -> children[chld_index] = (struct trie *) calloc(1, sizeof(struct trie)); if (create == false) {
if (vertex -> children[chld_index] == NULL) { return NULL;
syslog(cfg_log_facility | LOG_ERR, "trie: could not allocate space: %m"); } else {
return false; 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 NULL;
}
} }
} }
return trie_set_deep(string+1, val, vertex->children[chld_index]); return trie_find_vertex(string+1, vertex->children[chld_index], create);
} }
} }
bool trie_set(char string[], int64_t val) {
static bool trie_redefine (char string[], int64_t val, bool def){
if (trie_base == NULL) { if (trie_base == NULL) {
trie_base = (struct trie *) calloc(1, sizeof(struct trie)); trie_base = (struct trie *) calloc(1, sizeof(struct trie));
if(trie_base == NULL) { if(trie_base == NULL) {
@ -70,30 +84,44 @@ bool trie_set(char string[], int64_t val) {
return false; return false;
} }
} }
return trie_set_deep(string, val, trie_base); struct trie *v = trie_find_vertex(string, trie_base, def);
} if (v == NULL && def == true) {
//Something is wrong, but it is already logged
static struct trie_retval trie_lookup_deep(char string[], struct trie *vertex) { return false;
if (string[0] == '\0') {
return (struct trie_retval) {vertex -> val, vertex -> defined};
} else { } else {
int chld_index = indexof(string[0]); v -> val = val;
if (chld_index == -1 || vertex -> children[chld_index] == NULL) { v -> def = def;
return (struct trie_retval) {0, false}; //Recalculate tasks
} else { if (v -> tasks != NULL) {
return trie_lookup_deep(string + 1, vertex->children[chld_index]); for (uint64_t i = 0; i < v -> tasks -> elems; i++) {
if (v -> tasks -> arr[i] != NULL) {
uint64_t id = *(uint64_t *)(v -> tasks -> arr[i]);
task_recalc(id);
}
}
} }
return true;
} }
} }
bool trie_set(char string[], int64_t val) {
return trie_redefine(string, val, true);
}
bool trie_unset(char string[]) {
return trie_redefine(string, 0, false);
}
struct trie_retval trie_lookup(char string[]) { struct trie_retval trie_lookup(char string[]) {
if (trie_base == NULL) { struct trie *v = trie_find_vertex(string, trie_base, false);
return (struct trie_retval) {0, false}; if (v == NULL) {
} else return trie_lookup_deep(string, trie_base); return (struct trie_retval) {0, false, NULL};
} else {
return (struct trie_retval) {v -> val, v -> def, v->tasks};
}
} }
bool trie_load(void) { bool trie_load(const char fn[]) {
FILE *f = fopen(cfg_trie_file, "r"); FILE *f = fopen(fn, "r");
if (f == NULL) { if (f == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m"); syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m");
return false; return false;
@ -103,48 +131,117 @@ bool trie_load(void) {
int64_t val; int64_t val;
char name[cfg_var_name_max_len+1]; char name[cfg_var_name_max_len+1];
int status; int status;
while ((status = fscanf(f, "%s %d\n", name, &val)) != EOF) { while ((status = fscanf(f, "%s %ld\n", name, &val)) != EOF) {
if (status != 2) { if (status != 2) {
syslog(cfg_log_facility | LOG_ERR, "trie: fscanf matched bad number of items: %d", status); syslog(cfg_log_facility | LOG_ERR, "trie: fscanf matched bad number of items: %d", status);
return false; return false;
} }
if(trie_set(name, val) == false) { if(trie_set(name, val) == false) {
syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %d", name, val); syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %ld", name, val);
} }
} }
return true; return true;
} }
static bool trie_dfs(char prefix[], int prefixlen, FILE *f, struct trie *vertex) { static bool trie_dfs(char prefix[], int prefixlen, struct grow *list, struct trie *vertex) {
if (vertex == NULL) {// Very special case; if (vertex == NULL) {// Very special case;
return true; return true;
} else { } else {
bool retval = true; bool retval = true;
if (vertex -> defined) { if (vertex -> def) {
prefix[prefixlen] = '\0'; prefix[prefixlen] = '\0';
fprintf(f, "%s %d\n", prefix, vertex -> val); // Add to list
struct trie_list *l = malloc(sizeof(struct trie_list));
l -> val = vertex -> val;
l -> name = malloc((prefixlen + 1) * sizeof(char));
strcpy(l->name, prefix);
grow_push(l, list);
} }
for (int i = 0; i<37; i++) { for (int i = 0; i<37; i++) {
if (vertex -> children[i] != NULL) { if (vertex -> children[i] != NULL) {
prefix[prefixlen] = charof(i); prefix[prefixlen] = charof(i);
retval &= trie_dfs(prefix, prefixlen + 1, f, vertex -> children[i]); retval &= trie_dfs(prefix, prefixlen + 1, list, vertex -> children[i]);
} }
} }
return retval; return retval;
} }
} }
bool trie_save(void) { bool trie_save(const char fn[]) {
FILE *f = fopen(cfg_trie_file, "w"); FILE *f = fopen(fn, "w");
if (f == NULL) { if (f == NULL) {
syslog(cfg_log_facility | LOG_CRIT, "trie: could not open file to save trie in: %m"); syslog(cfg_log_facility | LOG_CRIT, "trie: could not open file to save trie in: %m");
return false; return false;
} }
// DFS, write every found variable into f // DFS
struct grow *list = grow_init(true);
char prefix[cfg_var_name_max_len +1]; char prefix[cfg_var_name_max_len +1];
prefix[cfg_var_name_max_len +1] = '\0'; prefix[cfg_var_name_max_len +1] = '\0';
int prefixlen = 0; trie_dfs(prefix, 0, list, trie_base);
return trie_dfs(prefix, prefixlen, f, trie_base); for (uint64_t i = 0; i < list -> elems; i++) {
struct trie_list l = *(struct trie_list *)(list -> arr[i]);
fprintf(f, "%s %ld\n", l.name, l.val);
}
grow_drop(list);
return true;
}
struct grow *trie_list(void) {
struct grow *list = grow_init(true);
char prefix[cfg_var_name_max_len +1];
prefix[cfg_var_name_max_len +1] = '\0';
trie_dfs(prefix, 0, list, trie_base);
return list;
}
bool trie_assoc(char var[], uint64_t task) {
struct trie *v = trie_find_vertex(var, trie_base, true);
if (v == NULL) {
return false;
} else {
if (v -> tasks == NULL) {
v -> tasks = grow_init(true);
if (v->tasks == NULL) {
return false;
}
}
uint64_t *p_task = malloc(sizeof(uint64_t));
if (p_task == NULL) {
syslog(cfg_log_facility | LOG_ERR, "trie: Could not associate: %m");
return false;
}
*p_task = task;
return grow_push(p_task, v->tasks);
}
}
bool trie_unassoc(char var[], uint64_t task) {
struct trie *v = trie_find_vertex(var, trie_base, false);
if (v == NULL) {
return false; //Was not associated
} else {
if (v -> tasks == NULL) {
return false; //Was not associated
} else {
bool retval = false;
for (uint64_t i = 0; i < v->tasks->elems; i++) {
uint64_t *t = (uint64_t *)(v->tasks->arr[i]);
if (t == NULL) {
continue;
} else if (*t == task) {
// Erase it
v -> tasks -> active_elems--;
free(t);
v->tasks->arr[i] = NULL;
retval = true;
}
}
if (v -> tasks -> active_elems == 0) {
grow_drop(v->tasks);
}
return retval;
}
}
} }

@ -8,13 +8,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
bool trie_load(void); #include "grow.h"
bool trie_save(void);
struct trie { struct trie {
int64_t val; int64_t val;
struct trie *children[37]; //Alphabet: A-Z0-9_ struct trie *children[37]; //Alphabet: A-Z0-9_
bool defined; bool def;
struct grow *tasks;
}; };
enum trie_ret_status {OK, UNDEF}; enum trie_ret_status {OK, UNDEF};
@ -22,9 +22,23 @@ enum trie_ret_status {OK, UNDEF};
struct trie_retval { struct trie_retval {
int64_t val; int64_t val;
bool def; bool def;
struct grow *tasks;
};
struct trie_list {
int64_t val;
char *name;
}; };
struct trie_retval trie_lookup(char string[]); struct trie_retval trie_lookup(char string[]);
bool trie_set (char string[], int64_t val); bool trie_set (char string[], int64_t val);
bool trie_un (char string[]);
struct grow *trie_list(void);
bool trie_assoc(char var[], uint64_t task);
bool trie_unassoc(char var[], uint64_t task);
bool trie_load(const char fn[]);
bool trie_save(const char fn[]);
#endif #endif

Loading…
Cancel
Save