#include #include #include #include #include #include "triton_p.h" #include "memdebug.h" struct sect_t { struct list_head entry; struct conf_sect_t *sect; }; struct conf_ctx { const char *fname; FILE *file; int line; struct list_head *items; }; static LIST_HEAD(sections); static char *conf_fname; static char* skip_space(char *str); static char* skip_word(char *str); static struct conf_sect_t *find_sect(const char *name); static struct conf_sect_t *create_sect(const char *name); static int sect_add_item(struct conf_ctx *ctx, const char *name, char *val, char *raw); static struct conf_option_t *find_item(struct conf_sect_t *, const char *name); static int load_file(struct conf_ctx *ctx); static char *buf; static struct conf_sect_t *cur_sect; static int __conf_load(struct conf_ctx *ctx, const char *fname) { struct conf_ctx ctx1; int r; ctx1.fname = fname; ctx1.file = fopen(fname, "r"); ctx1.line = 0; ctx1.items = ctx->items; if (!ctx1.file) { perror("conf_file:open"); return -1; } r = load_file(&ctx1); fclose(ctx1.file); return r; } static int load_file(struct conf_ctx *ctx) { char *str, *str2, *raw; int len; while(1) { if (!fgets(buf, 1024, ctx->file)) break; ctx->line++; len = strlen(buf); if (buf[len - 1] == '\n') buf[--len] = 0; while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) buf[--len] = 0; str = skip_space(buf); if (*str == '#' || *str == 0) continue; if (strncmp(str, "$include", 8) == 0) { str = skip_word(str); str = skip_space(str); if (__conf_load(ctx, str)) break; continue; } if (*str == '[') { for (str2 = ++str; *str2 && *str2 != ']'; str2++); if (*str2 != ']') { fprintf(stderr, "conf_file:%s:%i: sintax error\n", ctx->fname, ctx->line); return -1; } if (cur_sect && ctx->items != &cur_sect->items) { fprintf(stderr, "conf_file:%s:%i: cann't open section inside option\n", ctx->fname, ctx->line); return -1; } *str2 = 0; cur_sect = find_sect(str); if (!cur_sect) cur_sect = create_sect(str); ctx->items = &cur_sect->items; continue; } if (*str == '}' && ctx->items != &cur_sect->items) return 0; if (!cur_sect) { fprintf(stderr, "conf_file:%s:%i: no section opened\n", ctx->fname, ctx->line); return -1; } raw = _strdup(str); str2 = skip_word(str); if (*str2 == ' ') { *str2 = 0; ++str2; } str2 = skip_space(str2); if (*str2 == '=' || *str2 == ',') { *str2 = 0; str2 = skip_space(str2 + 1); if (*str2 && *(str2 + 1) && *str2 == '$' && *(str2 + 1) == '{') { char *s; struct conf_option_t *opt; for (s = str2+2; *s && *s != '}'; s++); if (*s == '}') { *s = 0; str2 += 2; } opt = find_item(cur_sect, str2); if (!opt) { fprintf(stderr, "conf_file:%s:%i: parent option not found\n", ctx->fname, ctx->line); return -1; } str2 = opt->val; } } else str2 = NULL; if (sect_add_item(ctx, str, str2, raw)) return -1; } return 0; } /*static void print_items(struct list_head *items, int dep) { struct conf_option_t *opt; int i; list_for_each_entry(opt, items, entry) { for (i = 0; i < dep; i++) printf("\t"); printf("%s=%s\n", opt->name, opt->val); print_items(&opt->items, dep + 1); } } static void print_conf() { struct sect_t *s; list_for_each_entry(s, §ions, entry) { printf("[%s]\n", s->sect->name); print_items(&s->sect->items, 0); } }*/ int conf_load(const char *fname) { int r; struct conf_ctx ctx; if (fname) { if (conf_fname) _free(conf_fname); conf_fname = _strdup(fname); } else fname = conf_fname; buf = _malloc(1024); cur_sect = NULL; ctx.items = NULL; r = __conf_load(&ctx, fname); _free(buf); return r; } static void free_items(struct list_head *items) { struct conf_option_t *opt; while (!list_empty(items)) { opt = list_entry(items->next, typeof(*opt), entry); list_del(&opt->entry); if (opt->val) _free(opt->val); _free(opt->name); _free(opt->raw); free_items(&opt->items); _free(opt); } } int conf_reload(const char *fname) { struct sect_t *sect; int r; LIST_HEAD(sections_bak); list_splice_init(§ions, §ions_bak); cur_sect = NULL; r = conf_load(fname); if (r) list_splice(§ions_bak, §ions); else { while (!list_empty(§ions_bak)) { sect = list_entry(sections_bak.next, typeof(*sect), entry); list_del(§->entry); free_items(§->sect->items); _free((char *)sect->sect->name); _free(sect->sect); _free(sect); } } return r; } static char* skip_space(char *str) { for (; *str && (*str == ' ' || *str == '\t'); str++); return str; } static char* skip_word(char *str) { for (; *str && (*str != ' ' && *str != '\t' && *str != '='); str++); return str; } static struct conf_sect_t *find_sect(const char *name) { struct sect_t *s; list_for_each_entry(s, §ions, entry) if (strcmp(s->sect->name, name) == 0) return s->sect; return NULL; } static struct conf_sect_t *create_sect(const char *name) { struct sect_t *s = _malloc(sizeof(struct sect_t)); s->sect = _malloc(sizeof(struct conf_sect_t)); s->sect->name = (char*)_strdup(name); INIT_LIST_HEAD(&s->sect->items); list_add_tail(&s->entry, §ions); return s->sect; } static int sect_add_item(struct conf_ctx *ctx, const char *name, char *val, char *raw) { struct conf_option_t *opt = _malloc(sizeof(struct conf_option_t)); int r = 0; int len = 0; if (val) { len = strlen(val); if (val[len - 1] == '{') { val[len - 1] = 0; while (len && (val[len - 1] == ' ' || val[len - 1] == '\t')) len--; len = 1; } else len = 0; } opt->name = _strdup(name); opt->val = val ? _strdup(val) : NULL; opt->raw = raw; INIT_LIST_HEAD(&opt->items); list_add_tail(&opt->entry, ctx->items); if (len) { struct list_head *items = ctx->items; ctx->items = &opt->items; r = load_file(ctx); ctx->items = items; } return r; } static struct conf_option_t *find_item(struct conf_sect_t *sect, const char *name) { struct conf_option_t *opt; list_for_each_entry(opt, §->items, entry) { if (strcmp(opt->name, name) == 0) return opt; } return NULL; } __export struct conf_sect_t * conf_get_section(const char *name) { return find_sect(name); } __export char * conf_get_opt(const char *sect, const char *name) { struct conf_option_t *opt; struct conf_sect_t *s = conf_get_section(sect); if (!s) return NULL; opt = find_item(s, name); if (!opt) return NULL; return opt->val; }