/* * tree.c * * This file provides the implementation of a konf_tree class */ #include "private.h" #include "lub/argv.h" #include "lub/string.h" #include "lub/ctype.h" #include #include #include #include #include #include /*--------------------------------------------------------- */ static int konf_tree_compare(const void *first, const void *second) { const konf_tree_t *f = (const konf_tree_t *)first; const konf_tree_t *s = (const konf_tree_t *)second; /* Priority check */ if (f->priority != s->priority) return (f->priority - s->priority); /* Sequence check */ if (f->seq_num != s->seq_num) return (f->seq_num - s->seq_num); /* Sub-sequence check */ if (f->sub_num != s->sub_num) return (f->sub_num - s->sub_num); /* Line check */ return strcmp(f->line, s->line); } /*--------------------------------------------------------- */ static void konf_tree_init(konf_tree_t * this, const char *line, unsigned short priority) { /* set up defaults */ this->line = strdup(line); this->priority = priority; this->seq_num = 0; this->sub_num = KONF_ENTRY_OK; this->splitter = BOOL_TRUE; this->depth = -1; /* initialise the list of commands for this conf */ this->list = lub_list_new(konf_tree_compare, konf_tree_delete); } /*--------------------------------------------------------- */ static void konf_tree_fini(konf_tree_t * this) { lub_list_free_all(this->list); free(this->line); } /*--------------------------------------------------------- */ konf_tree_t *konf_tree_new(const char *line, unsigned short priority) { konf_tree_t *this = malloc(sizeof(konf_tree_t)); if (this) konf_tree_init(this, line, priority); return this; } /*--------------------------------------------------------- */ void konf_tree_delete(void *data) { konf_tree_t *this = (konf_tree_t *)data; konf_tree_fini(this); free(this); } /*--------------------------------------------------------- */ void konf_tree_fprintf(konf_tree_t *this, FILE *stream, const char *pattern, int top_depth, int depth, bool_t seq, bool_t splitter, unsigned char prev_pri_hi) { konf_tree_t *conf; lub_list_node_t *iter; unsigned char pri = 0; regex_t regexp; if (this->line && (*(this->line) != '\0') && (this->depth > top_depth) && ((depth < 0 ) || (this->depth <= (top_depth + depth)))) { char *space = NULL; unsigned int space_num = this->depth - top_depth - 1; if (space_num > 0) { space = malloc(space_num + 1); memset(space, ' ', space_num); space[space_num] = '\0'; } if (splitter && (0 == this->depth) && (this->splitter || (konf_tree__get_priority_hi(this) != prev_pri_hi))) fprintf(stream, "!\n"); fprintf(stream, "%s", space ? space : ""); if (seq && (konf_tree__get_seq_num(this) != 0)) fprintf(stream, "%u ", konf_tree__get_seq_num(this)); fprintf(stream, "%s\n", this->line); free(space); } /* regexp compilation */ if (pattern) if (regcomp(®exp, pattern, REG_EXTENDED | REG_ICASE) != 0) return; /* iterate child elements */ for(iter = lub_list__get_head(this->list); iter; iter = lub_list_node__get_next(iter)) { conf = (konf_tree_t *)lub_list_node__get_data(iter); if (pattern && (0 != regexec(®exp, conf->line, 0, NULL, 0))) continue; /* Don't check pattern for child elements */ konf_tree_fprintf(conf, stream, NULL, top_depth, depth, seq, splitter, pri); pri = konf_tree__get_priority_hi(conf); } if (pattern) regfree(®exp); } /*-------------------------------------------------------- */ static int normalize_seq(konf_tree_t * this, unsigned short priority, lub_list_node_t *start) { unsigned short cnt = 1; konf_tree_t *conf = NULL; lub_list_node_t *iter; unsigned short cur_pri; if (start) { lub_list_node_t *prev; iter = start; if ((prev = lub_list_node__get_prev(iter))) { conf = (konf_tree_t *)lub_list_node__get_data(prev); if (konf_tree__get_priority(conf) == priority) cnt = konf_tree__get_seq_num(conf) + 1; } } else { iter = lub_list__get_head(this->list); } /* If list is empty */ if (!iter) return 0; /* Iterate and renum */ do { conf = (konf_tree_t *)lub_list_node__get_data(iter); cur_pri = konf_tree__get_priority(conf); if (cur_pri > priority) break; if (cur_pri < priority) continue; if (konf_tree__get_seq_num(conf) == 0) continue; konf_tree__set_seq_num(conf, cnt++); } while ((iter = lub_list_node__get_next(iter))); return 0; } /*--------------------------------------------------------- */ konf_tree_t *konf_tree_new_conf(konf_tree_t * this, const char *line, unsigned short priority, bool_t seq, unsigned short seq_num) { lub_list_node_t *node; /* Allocate the memory for a new child element */ konf_tree_t *newconf = konf_tree_new(line, priority); assert(newconf); /* Sequence */ if (seq) { konf_tree__set_seq_num(newconf, seq_num ? seq_num : 0xffff); konf_tree__set_sub_num(newconf, KONF_ENTRY_NEW); } /* Insert it into the list */ node = lub_list_add(this->list, newconf); if (seq) { normalize_seq(this, priority, node); konf_tree__set_sub_num(newconf, KONF_ENTRY_OK); } return newconf; } /*--------------------------------------------------------- */ konf_tree_t *konf_tree_find_conf(konf_tree_t * this, const char *line, unsigned short priority, unsigned short seq_num) { konf_tree_t *conf; lub_list_node_t *iter; int check_pri = 0; /* If list is empty */ if (!(iter = lub_list__get_tail(this->list))) return NULL; if ((0 != priority) && (0 != seq_num)) check_pri = 1; /* Iterate non-empty tree */ do { conf = (konf_tree_t *)lub_list_node__get_data(iter); if (check_pri) { if (priority < conf->priority) continue; if (priority > conf->priority) break; if (seq_num < conf->seq_num) continue; if (seq_num > conf->seq_num) break; } if (!strcmp(conf->line, line)) return conf; } while ((iter = lub_list_node__get_prev(iter))); return NULL; } /*--------------------------------------------------------- */ int konf_tree_del_pattern(konf_tree_t *this, const char *line, bool_t unique, const char *pattern, unsigned short priority, bool_t seq, unsigned short seq_num) { int res = 0; konf_tree_t *conf; lub_list_node_t *iter; lub_list_node_t *tmp; regex_t regexp; int del_cnt = 0; /* how many strings were deleted */ if (seq && (0 == priority)) return -1; /* Is tree empty? */ if (!(iter = lub_list__get_head(this->list))) return 0; /* Compile regular expression */ if (regcomp(®exp, pattern, REG_EXTENDED | REG_ICASE) != 0) return -1; /* Iterate configuration tree */ tmp = lub_list_node_new(NULL); do { conf = (konf_tree_t *)lub_list_node__get_data(iter); if ((0 != priority) && (priority != conf->priority)) continue; if (seq && (seq_num != 0) && (seq_num != conf->seq_num)) continue; if (seq && (0 == seq_num) && (0 == conf->seq_num)) continue; if (0 != regexec(®exp, conf->line, 0, NULL, 0)) continue; if (unique && line && !strcmp(conf->line, line)) { res++; continue; } lub_list_del(this->list, iter); konf_tree_delete(conf); lub_list_node_copy(tmp, iter); lub_list_node_free(iter); iter = tmp; del_cnt++; } while ((iter = lub_list_node__get_next(iter))); lub_list_node_free(tmp); regfree(®exp); if (seq && (del_cnt != 0)) normalize_seq(this, priority, NULL); return res; } /*--------------------------------------------------------- */ unsigned short konf_tree__get_priority(const konf_tree_t * this) { return this->priority; } /*--------------------------------------------------------- */ unsigned char konf_tree__get_priority_hi(const konf_tree_t * this) { return (unsigned char)(this->priority >> 8); } /*--------------------------------------------------------- */ unsigned char konf_tree__get_priority_lo(const konf_tree_t * this) { return (unsigned char)(this->priority & 0xff); } /*--------------------------------------------------------- */ bool_t konf_tree__get_splitter(const konf_tree_t * this) { return this->splitter; } /*--------------------------------------------------------- */ void konf_tree__set_splitter(konf_tree_t *this, bool_t splitter) { this->splitter = splitter; } /*--------------------------------------------------------- */ unsigned short konf_tree__get_seq_num(const konf_tree_t * this) { return this->seq_num; } /*--------------------------------------------------------- */ void konf_tree__set_seq_num(konf_tree_t * this, unsigned short seq_num) { this->seq_num = seq_num; } /*--------------------------------------------------------- */ unsigned short konf_tree__get_sub_num(const konf_tree_t * this) { return this->sub_num; } /*--------------------------------------------------------- */ void konf_tree__set_sub_num(konf_tree_t * this, unsigned short sub_num) { this->sub_num = sub_num; } /*--------------------------------------------------------- */ const char * konf_tree__get_line(const konf_tree_t * this) { return this->line; } /*--------------------------------------------------------- */ void konf_tree__set_depth(konf_tree_t * this, int depth) { this->depth = depth; } /*--------------------------------------------------------- */ int konf_tree__get_depth(const konf_tree_t * this) { return this->depth; }