X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fconf-input.c;h=f8d2eb840ce21eb693df10e68fdb0eb9151e4332;hb=1481eca416a467e9952dbc5e4852afe66eaf1256;hp=92acb35d9baf831d377788549343730ba0fc3861;hpb=b541de765129b6bf28c5601bb355779652001150;p=libucw.git diff --git a/ucw/conf-input.c b/ucw/conf-input.c index 92acb35d..f8d2eb84 100644 --- a/ucw/conf-input.c +++ b/ucw/conf-input.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include +#include #include /* Text file parser */ @@ -29,20 +29,20 @@ #include -#define GBUF_TYPE uns +#define GBUF_TYPE uint #define GBUF_PREFIX(x) split_##x #include struct cf_parser_state { const char *name_parse_fb; struct fastbuf *parse_fb; - uns line_num; + uint line_num; char *line; split_t word_buf; - uns words; - uns ends_by_brace; // the line is ended by "{" + uint words; + uint ends_by_brace; // the line is ended by "{" bb_t copy_buf; - uns copied; + uint copied; char line_buf[]; }; @@ -64,7 +64,7 @@ get_line(struct cf_parser_state *p, char **msg) static void append(struct cf_parser_state *p, char *start, char *end) { - uns len = end - start; + uint len = end - start; bb_grow(&p->copy_buf, p->copied + len + 1); memcpy(p->copy_buf.ptr + p->copied, start, len); p->copied += len + 1; @@ -72,7 +72,7 @@ append(struct cf_parser_state *p, char *start, char *end) } static char * -get_word(struct cf_parser_state *p, uns is_command_name) +get_word(struct cf_parser_state *p, uint is_command_name) { char *msg; char *line = p->line; @@ -95,10 +95,10 @@ get_word(struct cf_parser_state *p, uns is_command_name) } else if (*line == '"') { line++; - uns start_copy = p->copied; + uint start_copy = p->copied; while (1) { char *start = line; - uns escape = 0; + uint escape = 0; while (*line) { if (*line == '"' && !escape) break; @@ -122,7 +122,7 @@ get_word(struct cf_parser_state *p, uns is_command_name) line++; char *tmp = stk_str_unesc(p->copy_buf.ptr + start_copy); - uns l = strlen(tmp); + uint l = strlen(tmp); bb_grow(&p->copy_buf, start_copy + l + 1); strcpy(p->copy_buf.ptr + start_copy, tmp); p->copied = start_copy + l + 1; @@ -150,7 +150,7 @@ get_word(struct cf_parser_state *p, uns is_command_name) } static char * -get_token(struct cf_parser_state *p, uns is_command_name, char **err) +get_token(struct cf_parser_state *p, uint is_command_name, char **err) { *err = NULL; while (1) { @@ -171,7 +171,7 @@ get_token(struct cf_parser_state *p, uns is_command_name, char **err) msg(L_WARN, "The line %s:%d following a backslash is empty", p->name_parse_fb ? : "", p->line_num); } else { split_grow(&p->word_buf, p->words+1); - uns start = p->copied; + uint start = p->copied; p->word_buf.ptr[p->words++] = p->copied; *err = get_word(p, is_command_name); return *err ? NULL : p->copy_buf.ptr + start; @@ -203,8 +203,18 @@ split_command(struct cf_parser_state *p) /* Parsing multiple files */ +static int +maybe_commit(struct cf_context *cc) +{ + if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL)) + return 1; + if (!cc->postpone_commit) + cc->everything_committed = 1; + return 0; +} + static char * -parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, uns depth) +parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, uint depth) { struct cf_parser_state *p = cc->parser; if (!p) @@ -215,19 +225,23 @@ parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, un p->line = p->line_buf; *p->line = 0; - char *err; + if (!depth) + cf_init_stack(cc); + + char *err = NULL; while (1) { err = split_command(p); if (err) goto error; if (!p->words) - return NULL; + break; char *name = p->copy_buf.ptr + p->word_buf.ptr[0]; char *pars[p->words-1]; - for (uns i=1; iwords; i++) + for (uint i=1; iwords; i++) pars[i-1] = p->copy_buf.ptr + p->word_buf.ptr[i]; - if (!strcasecmp(name, "include")) + int optional_include = !strcasecmp(name, "optionalinclude"); + if (optional_include || !strcasecmp(name, "include")) { if (p->words != 2) err = "Expecting one filename"; @@ -239,10 +253,12 @@ parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, un goto error; struct fastbuf *new_fb = bopen_try(pars[0], O_RDONLY, 1<<14); if (!new_fb) { + if (optional_include && errno == ENOENT) + continue; err = cf_printf("Cannot open file %s: %m", pars[0]); goto error; } - uns ll = p->line_num; + uint ll = p->line_num; err = parse_fastbuf(cc, stk_strdup(pars[0]), new_fb, depth+1); p->line_num = ll; bclose(new_fb); @@ -282,6 +298,17 @@ parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, un if (err) goto error; } + + if (!depth) + { + if (cf_done_stack(cc)) + err = "Unterminated block"; + else if (maybe_commit(cc)) + err = "Commit failed"; + } + if (!err) + return NULL; + error: if (name_fb) msg(L_ERROR, "File %s, line %d: %s", name_fb, p->line_num, err); @@ -292,40 +319,26 @@ error: return "included from here"; } -static int -done_stack(struct cf_context *cc) -{ - if (cf_check_stack(cc)) - return 1; - if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL)) - return 1; - if (!cc->postpone_commit) - cc->everything_committed = 1; - return 0; -} - static int load_file(struct cf_context *cc, const char *file) { - cf_init_stack(cc); struct fastbuf *fb = bopen_try(file, O_RDONLY, 1<<14); if (!fb) { - msg(L_ERROR, "Cannot open %s: %m", file); + msg(L_ERROR, "Cannot open configuration file %s: %m", file); return 1; } char *err_msg = parse_fastbuf(cc, file, fb, 0); bclose(fb); - return !!err_msg || done_stack(cc); + return !!err_msg; } static int load_string(struct cf_context *cc, const char *string) { - cf_init_stack(cc); struct fastbuf fb; fbbuf_init_read(&fb, (byte *)string, strlen(string), 0); char *msg = parse_fastbuf(cc, NULL, &fb, 0); - return !!msg || done_stack(cc); + return !!msg; } /* Safe loading and reloading */ @@ -340,11 +353,9 @@ struct conf_entry { /* We remember a list of actions to apply upon reload */ }; static void -cf_remember_entry(struct cf_context *cc, uns type, const char *arg) +cf_remember_entry(struct cf_context *cc, uint type, const char *arg) { - if (!cc->need_journal) - return; - if (!cc->postpone_commit) + if (!cc->enable_journal) return; struct conf_entry *ce = cf_malloc(sizeof(*ce)); ce->type = type; @@ -356,14 +367,15 @@ int cf_reload(const char *file) { struct cf_context *cc = cf_get_context(); + ASSERT(cc->enable_journal); cf_journal_swap(); struct cf_journal_item *oldj = cf_journal_new_transaction(1); - uns ec = cc->everything_committed; + uint ec = cc->everything_committed; cc->everything_committed = 0; clist old_entries; clist_move(&old_entries, &cc->conf_entries); - cc->postpone_commit = 1; + cf_open_group(); int err = 0; if (file) @@ -379,9 +391,7 @@ cf_reload(const char *file) cf_remember_entry(cc, ce->type, ce->arg); } - cc->postpone_commit = 0; - if (!err) - err |= done_stack(cc); + err |= cf_close_group(); if (!err) { cf_journal_delete(); @@ -404,7 +414,7 @@ cf_load(const char *file) if (!err) { cf_journal_commit_transaction(1, oldj); cf_remember_entry(cc, CE_FILE, file); - cc->def_loaded = 1; + cc->config_loaded = 1; } else cf_journal_rollback_transaction(1, oldj); return err; @@ -424,92 +434,27 @@ cf_set(const char *string) return err; } -/* Command-line parser */ - -#ifndef CONFIG_UCW_DEFAULT_CONFIG -#define CONFIG_UCW_DEFAULT_CONFIG NULL -#endif -char *cf_def_file = CONFIG_UCW_DEFAULT_CONFIG; - -#ifndef CONFIG_UCW_ENV_VAR_CONFIG -#define CONFIG_UCW_ENV_VAR_CONFIG NULL -#endif -char *cf_env_file = CONFIG_UCW_ENV_VAR_CONFIG; - -static void -load_default(struct cf_context *cc) +void +cf_revert(void) { - if (cc->def_loaded++) - return; - if (cf_def_file) - { - char *env; - if (cf_env_file && (env = getenv(cf_env_file))) - { - if (cf_load(env)) - die("Cannot load config file %s", env); - } - else if (cf_load(cf_def_file)) - die("Cannot load default config %s", cf_def_file); - } - else - { - // We need to create an empty pool and initialize all configuration items - struct cf_journal_item *oldj = cf_journal_new_transaction(1); - cf_init_stack(cc); - done_stack(cc); - cf_journal_commit_transaction(1, oldj); - } + cf_journal_swap(); + cf_journal_delete(); } -static void -final_commit(struct cf_context *cc) +void +cf_open_group(void) { - if (cc->postpone_commit) { - cc->postpone_commit = 0; - if (done_stack(cc)) - die("Cannot commit after the initialization"); - } + struct cf_context *cc = cf_get_context(); + cc->postpone_commit++; } int -cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index) +cf_close_group(void) { - struct cf_context *cc = cf_obtain_context(); - cc->postpone_commit = 1; - - while (1) { - int res = getopt_long (argc, argv, short_opts, long_opts, long_index); - if (res == 'S' || res == 'C' || res == 0x64436667) - { - if (cc->other_options) - die("The -S and -C options must precede all other arguments"); - if (res == 'S') { - load_default(cc); - if (cf_set(optarg)) - die("Cannot set %s", optarg); - } else if (res == 'C') { - if (cf_load(optarg)) - die("Cannot load config file %s", optarg); - } -#ifdef CONFIG_UCW_DEBUG - else { /* --dumpconfig */ - load_default(cc); - final_commit(cc); - struct fastbuf *b = bfdopen(1, 4096); - cf_dump_sections(b); - bclose(b); - exit(0); - } -#endif - } else { - /* unhandled option or end of options */ - if (res != ':' && res != '?') { - load_default(cc); - final_commit(cc); - } - cc->other_options++; - return res; - } - } + struct cf_context *cc = cf_get_context(); + ASSERT(cc->postpone_commit); + if (!--cc->postpone_commit) + return maybe_commit(cc); + else + return 0; }