DLLIMPORT int cfg_opt_setmulti(cfg_t *cfg, cfg_opt_t *opt, unsigned int nvalues, char **values) { cfg_opt_t old; unsigned int i; if (!opt || !nvalues) return -1; old = *opt; opt->nvalues = 0; opt->values = 0; for (i = 0; i < nvalues; i++) { if (cfg_setopt(cfg, opt, values[i])) continue; /* ouch, revert */ cfg_free_value(opt); opt->nvalues = old.nvalues; opt->values = old.values; return -1; } cfg_free_value(&old); return 0; }
static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t *force_opt) { int state = 0; char *opttitle = 0; cfg_opt_t *opt = 0; cfg_value_t *val = 0; cfg_opt_t funcopt = CFG_STR(0, 0, 0); int num_values = 0; /* number of values found for a list option */ int rc; if(force_state != -1) state = force_state; if(force_opt) opt = force_opt; while(1) { int tok = cfg_yylex(cfg); if(tok == 0) { /* lexer.l should have called cfg_error */ return STATE_ERROR; } if(tok == EOF) { if(state != 0) { cfg_error(cfg, _("premature end of file")); return STATE_ERROR; } return STATE_EOF; } switch(state) { case 0: /* expecting an option name */ if(tok == '}') { if(level == 0) { cfg_error(cfg, _("unexpected closing brace")); return STATE_ERROR; } return STATE_EOF; } if(tok != CFGT_STR) { cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval); return STATE_ERROR; } opt = cfg_getopt(cfg, cfg_yylval); if(opt == 0) return STATE_ERROR; if(opt->type == CFGT_SEC) { if(is_set(CFGF_TITLE, opt->flags)) state = 6; else state = 5; } else if(opt->type == CFGT_FUNC) { state = 7; } else state = 1; break; case 1: /* expecting an equal sign or plus-equal sign */ if(tok == '+') { if(!is_set(CFGF_LIST, opt->flags)) { cfg_error(cfg, _("attempt to append to non-list option '%s'"), opt->name); return STATE_ERROR; } /* Even if the reset flag was set by * cfg_init_defaults, appending to the defaults * should be ok. */ opt->flags &= ~CFGF_RESET; } else if(tok == '=') { /* set the (temporary) reset flag to clear the old * values, since we obviously didn't want to append */ opt->flags |= CFGF_RESET; } else { cfg_error(cfg, _("missing equal sign after option '%s'"), opt->name); return STATE_ERROR; } if(is_set(CFGF_LIST, opt->flags)) { state = 3; num_values = 0; } else state = 2; break; case 2: /* expecting an option value */ if(tok == '}' && is_set(CFGF_LIST, opt->flags)) { state = 0; if(num_values == 0 && is_set(CFGF_RESET, opt->flags)) /* Reset flags was set, and the empty list was * specified. Free all old values. */ cfg_free_value(opt); break; } if(tok != CFGT_STR) { cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval); return STATE_ERROR; } if(cfg_setopt(cfg, opt, cfg_yylval) == 0) return STATE_ERROR; if(opt->validcb && (*opt->validcb)(cfg, opt) != 0) return STATE_ERROR; if(is_set(CFGF_LIST, opt->flags)) { state = 4; ++num_values; } else state = 0; break; case 3: /* expecting an opening brace for a list option */ if(tok != '{') { cfg_error(cfg, _("missing opening brace for option '%s'"), opt->name); return STATE_ERROR; } state = 2; break; case 4: /* expecting a separator for a list option, or * closing (list) brace */ if(tok == ',') state = 2; else if(tok == '}') { state = 0; if(opt->validcb && (*opt->validcb)(cfg, opt) != 0) return STATE_ERROR; } else { cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval); return STATE_ERROR; } break; case 5: /* expecting an opening brace for a section */ if(tok != '{') { cfg_error(cfg, _("missing opening brace for section '%s'"), opt->name); return STATE_ERROR; } val = cfg_setopt(cfg, opt, opttitle); opttitle = 0; if(!val) return STATE_ERROR; val->section->line = cfg->line; rc = cfg_parse_internal(val->section, level+1,-1,0); cfg->line = val->section->line; if(rc != STATE_EOF) return STATE_ERROR; if(opt->validcb && (*opt->validcb)(cfg, opt) != 0) return STATE_ERROR; state = 0; break; case 6: /* expecting a title for a section */ if(tok != CFGT_STR) { cfg_error(cfg, _("missing title for section '%s'"), opt->name); return STATE_ERROR; } else opttitle = strdup(cfg_yylval); state = 5; break; case 7: /* expecting an opening parenthesis for a function */ if(tok != '(') { cfg_error(cfg, _("missing parenthesis for function '%s'"), opt->name); return STATE_ERROR; } state = 8; break; case 8: /* expecting a function parameter or a closing paren */ if(tok == ')') { int ret = call_function(cfg, opt, &funcopt); if(ret != 0) return STATE_ERROR; state = 0; } else if(tok == CFGT_STR) { val = cfg_addval(&funcopt); val->string = strdup(cfg_yylval); state = 9; } else { cfg_error(cfg, _("syntax error in call of function '%s'"), opt->name); return STATE_ERROR; } break; case 9: /* expecting a comma in a function or a closing paren */ if(tok == ')') { int ret = call_function(cfg, opt, &funcopt); if(ret != 0) return STATE_ERROR; state = 0; } else if(tok == ',') state = 8; else { cfg_error(cfg, _("syntax error in call of function '%s'"), opt->name); return STATE_ERROR; } break; default: /* missing state, internal error, abort */ assert(0); } } return STATE_EOF; }
static void cfg_init_defaults(cfg_t *cfg) { int i; for(i = 0; cfg->opts[i].name; i++) { /* libConfuse doesn't handle default values for "simple" options */ if(cfg->opts[i].simple_value || is_set(CFGF_NODEFAULT, cfg->opts[i].flags)) continue; if(cfg->opts[i].type != CFGT_SEC) { cfg->opts[i].flags |= CFGF_DEFINIT; if(is_set(CFGF_LIST, cfg->opts[i].flags) || cfg->opts[i].def.parsed) { int xstate, ret; /* If it's a list, but no default value was given, * keep the option uninitialized. */ if(cfg->opts[i].def.parsed == 0 || cfg->opts[i].def.parsed[0] == 0) continue; /* setup scanning from the string specified for the * "default" value, force the correct state and option */ if(is_set(CFGF_LIST, cfg->opts[i].flags)) /* lists must be surrounded by {braces} */ xstate = 3; else if(cfg->opts[i].type == CFGT_FUNC) xstate = 0; else xstate = 2; cfg_scan_string_begin(cfg->opts[i].def.parsed); do { ret = cfg_parse_internal(cfg, 1, xstate, &cfg->opts[i]); xstate = -1; } while(ret == STATE_CONTINUE); cfg_scan_string_end(); if(ret == STATE_ERROR) { /* * If there was an error parsing the default string, * the initialization of the default value could be * inconsistent or empty. What to do? It's a * programming error and not an end user input * error. Lets print a message and abort... */ fprintf(stderr, "Parse error in default value '%s'" " for option '%s'\n", cfg->opts[i].def.parsed, cfg->opts[i].name); fprintf(stderr, "Check your initialization macros and the" " libConfuse documentation\n"); abort(); } } else { switch(cfg->opts[i].type) { case CFGT_INT: cfg_opt_setnint(&cfg->opts[i], cfg->opts[i].def.number, 0); break; case CFGT_FLOAT: cfg_opt_setnfloat(&cfg->opts[i], cfg->opts[i].def.fpnumber, 0); break; case CFGT_BOOL: cfg_opt_setnbool(&cfg->opts[i], cfg->opts[i].def.boolean, 0); break; case CFGT_STR: cfg_opt_setnstr(&cfg->opts[i], cfg->opts[i].def.string, 0); break; case CFGT_FUNC: case CFGT_PTR: break; default: cfg_error(cfg, "internal error in cfg_init_defaults(%s)", cfg->opts[i].name); break; } } /* The default value should only be returned if no value * is given in the configuration file, so we set the RESET * flag here. When/If cfg_setopt() is called, the value(s) * will be freed and the flag unset. */ cfg->opts[i].flags |= CFGF_RESET; } /* end if cfg->opts[i].type != CFGT_SEC */ else if(!is_set(CFGF_MULTI, cfg->opts[i].flags)) { cfg_setopt(cfg, &cfg->opts[i], 0); cfg->opts[i].flags |= CFGF_DEFINIT; } } }