From c9692341e7d4fc0eaead6f30f1107bb8ce0d5b3b Mon Sep 17 00:00:00 2001 From: LEdoian Date: Wed, 14 Feb 2018 08:51:14 +0100 Subject: [PATCH] Refactor, complete trie, extract growing array --- config.h | 8 +- main.c => daemon.c | 36 ++++-- daemonize.c | 2 +- daemonize.h | 32 +++--- grow.c | 61 ++++++++++ grow.h | 25 +++++ rpn.c | 269 +++++++++++++++++++++++++++++++++++++++++---- rpn.h | 3 + task.c | 7 ++ task.h | 41 +++++++ trie.c | 179 +++++++++++++++++++++++------- trie.h | 20 +++- 12 files changed, 588 insertions(+), 95 deletions(-) rename main.c => daemon.c (68%) create mode 100644 grow.c create mode 100644 grow.h create mode 100644 task.c create mode 100644 task.h diff --git a/config.h b/config.h index 883a6df..9ebad43 100644 --- a/config.h +++ b/config.h @@ -6,15 +6,17 @@ #ifndef CONFIG_H #define CONFIG_H +#include + const int cfg_log_facility = LOG_CRON; const char cfg_log_ident[] = "kairos"; const int cfg_log_opt = LOG_PID | LOG_NDELAY; 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 int cfg_sock_maxclients = 16; -const int cfg_var_name_max_len = 16; +const uint32_t cfg_sock_maxclients = 16; +const uint64_t cfg_var_name_max_len = 16; #endif diff --git a/main.c b/daemon.c similarity index 68% rename from main.c rename to daemon.c index b307b47..ac3c57b 100644 --- a/main.c +++ b/daemon.c @@ -2,15 +2,22 @@ * main.c: the daemon itself */ +#include #include +#include #include #include +#include +#include +#include #include "config.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; @@ -20,25 +27,28 @@ int main (void) { daemonize(0); // Load saved state -- variable values and tasks - trie_load(); - tasks_load(); + trie_load(cfg_trie_file); + task_load(cfg_task_file); // Set basic signal handlers + sigset_t empty; + sigemptyset(&empty); // Shall not fail struct sigaction *term_sigh = (struct sigaction *) malloc(sizeof(struct sigaction)); - term_sigh -> sa_handler = &shutdown; - term_sigh -> sa_mask = 0; + term_sigh -> sa_handler = &term_handle; + term_sigh -> sa_mask = empty; term_sigh -> sa_flags = 0; sigaction(SIGTERM, term_sigh, NULL); 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_mask = 0; + chld_sigh -> sa_mask = empty; chld_sigh -> sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, chld_sigh, NULL); // Setup a socket to listen on sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr; + socklen_t addrsize = sizeof(struct sockaddr_un); addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket)); 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). while (true) { - int fd = accept(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); + int fd = accept(sockfd, (struct sockaddr *) &addr, &addrsize); process(fd); } @@ -57,9 +67,13 @@ int main (void) { return 5; } -void shutdown (int signum) { - trie_save(); - tasks_save(); +void term_handle (int signum) { + trie_save(cfg_trie_file); + task_save(cfg_task_file); close(sockfd); unlink(cfg_socket); + exit(0); + return; } + +bool process(int fd) {} diff --git a/daemonize.c b/daemonize.c index ea95c6d..fe7a6fe 100644 --- a/daemonize.c +++ b/daemonize.c @@ -31,7 +31,7 @@ bool daemonize(uint32_t flags) { syslog(cfg_log_facility | LOG_WARNING, "daemonize: getrlimit failed: %m"); 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; while(close(fd) == -1) { // Try 3 times to close fd, retry only if interrupted unless (errno == EINTR) { diff --git a/daemonize.h b/daemonize.h index 83d2d9f..6445b2a 100644 --- a/daemonize.h +++ b/daemonize.h @@ -15,21 +15,21 @@ bool daemonize(uint32_t flags); // except the first one // some of them will never be used -#define NODAEMONIZE 1<<0 /*Do not daemonize at all*/ -#define NOCLOSEFD 1<<1 -#define NORSTSIG 1<<2 -#define NORSTSIGMASK 1<<3 -#define NOSANITY 1<<4 // Sanitizing not implemented -#define NOBGFORK 1<<5 -#define NOSETSID 1<<6 -#define NOSECONDFORK 1<<7 -#define NOEXITCHLD 1<<8 // Not implemented -- always exit -#define NOCONNECTIO 1<<9 -#define NORSTUMASK 1<<10 -#define NOCHANGEWD 1<<11 -#define NOPIDFILE 1<<12 // Creating PID file not implemented -#define NOPRIVDROP 1<<13 // Not needed -#define NONOTIFY 1<<14 // Not implemented -- always notify -#define NOPARENTEXIT 1<<15 // Not implemented -- always exit +#define NODAEMONIZE (1<<0) /*Do not daemonize at all*/ +#define NOCLOSEFD (1<<1) +#define NORSTSIG (1<<2) +#define NORSTSIGMASK (1<<3) +#define NOSANITY (1<<4) // Sanitizing not implemented +#define NOBGFORK (1<<5) +#define NOSETSID (1<<6) +#define NOSECONDFORK (1<<7) +#define NOEXITCHLD (1<<8) // Not implemented -- always exit +#define NOCONNECTIO (1<<9) +#define NORSTUMASK (1<<10) +#define NOCHANGEWD (1<<11) +#define NOPIDFILE (1<<12) // Creating PID file not implemented +#define NOPRIVDROP (1<<13) // Not needed +#define NONOTIFY (1<<14) // Not implemented -- always notify +#define NOPARENTEXIT (1<<15) // Not implemented -- always exit #endif diff --git a/grow.c b/grow.c new file mode 100644 index 0000000..128c5eb --- /dev/null +++ b/grow.c @@ -0,0 +1,61 @@ +/* + * grow.c: generic growing array implementation + */ + +#include + +#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; +} diff --git a/grow.h b/grow.h new file mode 100644 index 0000000..714f03d --- /dev/null +++ b/grow.h @@ -0,0 +1,25 @@ +/* + * grow.h: declaration of generic growing array + */ + +#ifndef GROW_H +#define GROW_H + +#include +#include +#include + +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 diff --git a/rpn.c b/rpn.c index b7c2e83..36b82d0 100644 --- a/rpn.c +++ b/rpn.c @@ -2,39 +2,268 @@ * rpn.c: evalutor of RPN formulas */ -#include #include #include +#include #include "config.h" #include "rpn.h" #include "trie.h" +#include "grow.h" -// Growing stack implementation -struct grow { - struct trie_retval *arr; - int64_t elems; - int64_t alloc; +// Wrapper functions between grow's void*s and our struct trie_retvals +bool stack_push (struct trie_retval val, struct grow *stack) { + struct trie_retval *p_val = (struct trie_retval *) malloc(sizeof(struct trie_retval)); + if (p_val == NULL) { + 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) { - struct grow *g = malloc(sizeof(struct grow)); - if (g == NULL) { - syslog(cfg_log_facility | LOG_ERR, "rpn: Could not initialize growing array: %m"); - return NULL; +static uint64_t parse_var_name(char str[], char *out[]) { + uint64_t off; + for (off = 0; + ('A' <= str[off] && str[off] <= 'Z') + || ('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; - g -> elems = 0; - g -> alloc = 0; - return g; + // off is pointing past end of variable name; + (*out)[off] = '\0'; + return off - 1; //last character of variable name } -static bool grow_push (int64_t val, struct grow *stack) { - if (stack -> alloc <= stack -> elems) { - stack +static uint64_t do_cmd(char str[], struct grow *stack) { + // Check whether a command exists and if so, perform it + 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); } diff --git a/rpn.h b/rpn.h index 33d286b..864b942 100644 --- a/rpn.h +++ b/rpn.h @@ -6,7 +6,10 @@ #define RPN_H #include +#include bool rpn_eval (char rpn[]); +bool rpn_eval_assoc (char rpn[], uint64_t task); +bool rpn_eval_unassoc (char rpn[], uint64_t task); #endif diff --git a/task.c b/task.c new file mode 100644 index 0000000..0b513fa --- /dev/null +++ b/task.c @@ -0,0 +1,7 @@ +/* + * task.c: task management + */ + +#include "task.h" + + diff --git a/task.h b/task.h new file mode 100644 index 0000000..ff35454 --- /dev/null +++ b/task.h @@ -0,0 +1,41 @@ +/* + * task.h: declares functions for manipulation with tasks + */ + +#ifndef TASK_H +#define TASK_H + +#include +#include +#include +#include + +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 diff --git a/trie.c b/trie.c index df2069d..49e0cef 100644 --- a/trie.c +++ b/trie.c @@ -9,8 +9,9 @@ #include "trie.h" #include "config.h" +#include "task.h" -static struct trie *trie_base; +static struct trie *trie_base = NULL; static int indexof(char c) { // ASCII only! @@ -41,28 +42,41 @@ static char charof(int i) { } } -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; +static struct trie *trie_find_vertex(char string[], struct trie *vertex, bool create) { + if (vertex == NULL) { + if (create == false) { + return NULL; + } else { + 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 { int chld_index = indexof(string[0]); if (chld_index == -1) { - return false; //and don't save anything + return NULL; } 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; + if (create == false) { + return NULL; + } else { + 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) { trie_base = (struct trie *) calloc(1, sizeof(struct trie)); if(trie_base == NULL) { @@ -70,30 +84,44 @@ bool trie_set(char string[], int64_t val) { 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}; + struct trie *v = trie_find_vertex(string, trie_base, def); + if (v == NULL && def == true) { + //Something is wrong, but it is already logged + return false; } 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]); + v -> val = val; + v -> def = def; + //Recalculate tasks + if (v -> tasks != NULL) { + 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[]) { - if (trie_base == NULL) { - return (struct trie_retval) {0, false}; - } else return trie_lookup_deep(string, trie_base); + struct trie *v = trie_find_vertex(string, trie_base, false); + if (v == NULL) { + return (struct trie_retval) {0, false, NULL}; + } else { + return (struct trie_retval) {v -> val, v -> def, v->tasks}; + } } -bool trie_load(void) { - FILE *f = fopen(cfg_trie_file, "r"); +bool trie_load(const char fn[]) { + FILE *f = fopen(fn, "r"); if (f == NULL) { syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m"); return false; @@ -103,48 +131,117 @@ bool trie_load(void) { int64_t val; char name[cfg_var_name_max_len+1]; 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) { 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); + syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %ld", name, val); } } 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; return true; } else { bool retval = true; - if (vertex -> defined) { + if (vertex -> def) { 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++) { if (vertex -> children[i] != NULL) { 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; } } -bool trie_save(void) { - FILE *f = fopen(cfg_trie_file, "w"); +bool trie_save(const char fn[]) { + FILE *f = fopen(fn, "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 + // DFS + struct grow *list = grow_init(true); char prefix[cfg_var_name_max_len +1]; 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; + } + } } diff --git a/trie.h b/trie.h index 55e4307..7218e94 100644 --- a/trie.h +++ b/trie.h @@ -8,13 +8,13 @@ #include #include -bool trie_load(void); -bool trie_save(void); +#include "grow.h" struct trie { int64_t val; struct trie *children[37]; //Alphabet: A-Z0-9_ - bool defined; + bool def; + struct grow *tasks; }; enum trie_ret_status {OK, UNDEF}; @@ -22,9 +22,23 @@ enum trie_ret_status {OK, UNDEF}; struct trie_retval { int64_t val; bool def; + struct grow *tasks; +}; + +struct trie_list { + int64_t val; + char *name; }; struct trie_retval trie_lookup(char string[]); 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