void validate_setup(void)
{
	cfg_opt_t *opt = 0;

	static cfg_opt_t action_opts[] = {
		CFG_INT("speed", 0, CFGF_NONE),
		CFG_STR("name", 0, CFGF_NONE),
		CFG_INT("xspeed", 0, CFGF_NONE),
		CFG_END()
	};

	static cfg_opt_t multi_opts[] = {
		CFG_INT_LIST("speeds", 0, CFGF_NONE),
		CFG_SEC("options", action_opts, CFGF_NONE),
		CFG_END()
	};

	cfg_opt_t opts[] = {
		CFG_STR_LIST("ip-address", 0, CFGF_NONE),
		CFG_INT_CB("action", ACTION_NONE, CFGF_NONE, parse_action),
		CFG_SEC("options", action_opts, CFGF_NONE),
		CFG_SEC("multi_options", multi_opts, CFGF_MULTI),
		CFG_END()
	};

	cfg = cfg_init(opts, 0);

	cfg_set_validate_func(cfg, "ip-address", validate_ip);
	fail_unless(cfg_set_validate_func(cfg, "ip-address", validate_ip) == validate_ip);
	opt = cfg_getopt(cfg, "ip-address");
	fail_unless(opt != 0);
	fail_unless(opt->validcb == validate_ip);

	cfg_set_validate_func(cfg, "options", validate_action);
	fail_unless(cfg_set_validate_func(cfg, "options", validate_action) == validate_action);
	opt = cfg_getopt(cfg, "options");
	fail_unless(opt != 0);
	fail_unless(opt->validcb == validate_action);

	cfg_set_validate_func(cfg, "options|speed", validate_speed);
	fail_unless(cfg_set_validate_func(cfg, "options|speed", validate_speed) == validate_speed);
	opt = cfg_getopt(cfg, "options|speed");
	fail_unless(opt != 0);
	fail_unless(opt->validcb == validate_speed);

	cfg_set_validate_func(cfg, "multi_options|speeds", validate_speed);
	fail_unless(cfg_set_validate_func(cfg, "multi_options|speeds", validate_speed) == validate_speed);

	cfg_set_validate_func(cfg, "multi_options|options|xspeed", validate_speed);
	fail_unless(cfg_set_validate_func(cfg, "multi_options|options|xspeed", validate_speed) == validate_speed);

	/* Validate callbacks for *set*() functions, i.e. not when parsing file content */
	cfg_set_validate_func2(cfg, "multi_options|speed", validate_speed2);
	cfg_set_validate_func2(cfg, "multi_options|options|name", validate_name2);
}
Exemple #2
0
/**
 * Start up the configuration system, using the configuration file given
 * to get the current values. If the configuration file given does not exist,
 * go ahead and write out the default config to the file.
 */
gint config_init (const gchar *config_file)
{
	gint ret = 0;

    // Can we use a more descriptive name than tc?
	tc = cfg_init (config_opts, 0);

	if (g_file_test (config_file,
        G_FILE_TEST_IS_REGULAR))
    {
		/* Read in the existing configuration options */
		ret = cfg_parse (tc, config_file);

		if (ret == CFG_PARSE_ERROR) {
			DEBUG_ERROR ("Problem parsing config");
            return ret;
		} else if (ret != CFG_SUCCESS) {
            DEBUG_ERROR ("Problem parsing config.");
            return ret;
        }
	}

    /* Deprecate old config settings
     * This is a lame work around until we get a permenant solution to
     * libconfuse lacking for this functionality
     */
    const gchar *deprecated_tilda_config_options[] = {"show_on_monitor_number"};
    remove_deprecated_config_options(deprecated_tilda_config_options, G_N_ELEMENTS(deprecated_tilda_config_options));

#if VTE_MINOR_VERSION >= 40
    /* Deprecate old config settings
     * This is a lame work around until we get a permenant solution to
     * libconfuse lacking for this functionality
     */
    const gchar *deprecated_vte_config_options[] = {"word_chars", "image", "scroll_background", "use_image"};
    remove_deprecated_config_options (deprecated_vte_config_options, G_N_ELEMENTS(deprecated_vte_config_options));
#else
    if (cfg_getopt(tc, "use_image")->nvalues < 1) {
        cfg_setbool(tc, "use_image", FALSE);
    }
    if (cfg_getopt(tc, "word_chars")->nvalues < 1) {
        cfg_setstr(tc, "word_chars", DEFAULT_WORD_CHARS);
    }
    if (cfg_getopt(tc, "scroll_background")->nvalues < 1) {
        cfg_setbool(tc, "scroll_background", TRUE);
    }
#endif
    #ifndef NO_THREADSAFE
        g_mutex_init(&mutex);
    #endif

	return ret;
}
Exemple #3
0
int Settings::setStringSetting(Node type, int intDeviceId, const std::wstring &name, const std::wstring &value, bool parameter) {
	// already locked
	if (d->cfg == 0) {
		return TELLSTICK_ERROR_PERMISSION_DENIED;
	}
	std::string strType = getNodeString(type);
	cfg_t *cfg_device;
	for (int i = 0; i < cfg_size(d->cfg, strType.c_str()); ++i) {
		cfg_device = cfg_getnsec(d->cfg, strType.c_str(), i);
		if (cfg_getint(cfg_device, "id") == intDeviceId)  {
			std::string newValue = TelldusCore::wideToString(value);
			cfg_t *p = cfg_device;
			if (parameter) {
				p = cfg_getsec(cfg_device, "parameters");
			}
			cfg_opt_t *opt = cfg_getopt(p, TelldusCore::wideToString(name).c_str());
			if (!opt) {
				return TELLSTICK_ERROR_CONFIG_SYNTAX;
			}
			cfg_setstr(p, TelldusCore::wideToString(name).c_str(), newValue.c_str());
			FILE *fp = fopen(CONFIG_FILE, "we");  // e for setting O_CLOEXEC on the file handle
			if (!fp) {
				return TELLSTICK_ERROR_PERMISSION_DENIED;
			}
			cfg_print(d->cfg, fp);
			fclose(fp);
			return TELLSTICK_SUCCESS;
		}
	}
	return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
}
Exemple #4
0
DLLIMPORT int cfg_setmulti(cfg_t *cfg, const char *name, unsigned int nvalues, char **values)
{
	cfg_opt_t *opt = cfg_getopt(cfg, name);

	if (!opt)
		return -1;
	return cfg_opt_setmulti(cfg, opt, nvalues, values);
}
Exemple #5
0
void remove_deprecated_config_options(const gchar *const *deprecated_config_options, guint size) {
    cfg_opt_t *opt;
    for (guint i =0; i < size; i++) {
        opt = cfg_getopt(tc, deprecated_config_options[i]);
        if (opt->nvalues != 0) {
            g_warning("Warning: %s is no longer a valid config option for the current version of Tilda.\n", deprecated_config_options[i]);
            cfg_free_value(opt);
        }
    }
}
Exemple #6
0
DLLIMPORT void cfg_addlist(cfg_t *cfg, const char *name, unsigned int nvalues, ...)
{
	va_list ap;
	cfg_opt_t *opt = cfg_getopt(cfg, name);

	assert(opt && is_set(CFGF_LIST, opt->flags));

	va_start(ap, nvalues);
	cfg_addlist_internal(opt, nvalues, ap);
	va_end(ap);
}
Exemple #7
0
static const char *set(int argc, char *argv[])
{
	if (argc < 3)
		return "Need more args\n";

	if (!cfg_getopt(cfg, argv[1]))
		return "Unknown option\n";

	if (cfg_setmulti(cfg, argv[1], argc - 2, &argv[2]))
		return "Failure\n";

	return "OK\n";
}
void validate_test(void)
{
	char *buf;
	unsigned int i;

	buf = "action = wlak";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "action = walk";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_SUCCESS);

	buf = "action = run" " options { speed = 6 }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "action = jump" " options { speed = 2 name = 'Joe' }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_SUCCESS);

	buf = "action = crawl" " options { speed = -2 name = 'Smith' }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "ip-address = { 0.0.0.0 , 1.2.3.4 , 192.168.0.254 , 10.0.0.255 , 20.30.40.256}";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);
	buf = "ip-address = { 0.0.0.0 , 1.2.3.4 , 192.168.0.254 , 10.0.0.255 , 20.30.40.250}";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_SUCCESS);
	buf = "ip-address = { 1.2.3. }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "action = run" " multi_options { speeds = {1, 2, 3, 4, 5} }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_SUCCESS);
	for (i = 0; i < cfg_size(cfg, "multi_options"); i++) {
		cfg_t *multisec = cfg_getnsec(cfg, "multi_options", i);
		cfg_opt_t *speeds_opt = cfg_getopt(multisec, "speeds");

		fail_unless(speeds_opt != 0);
		fail_unless(speeds_opt->validcb == validate_speed);
	}

	buf = "action = run" " multi_options { speeds = {1, 2, 3, -4, 5} }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "action = run" " multi_options { speeds = {1, 2, 3, 4, 0} }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);

	buf = "action = run" " multi_options { options { xspeed = 3 } }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_SUCCESS);

	buf = "action = run" " multi_options { options { xspeed = -3 } }";
	fail_unless(cfg_parse_buf(cfg, buf) == CFG_PARSE_ERROR);
}
Exemple #9
0
int main(void)
{
	char *comment;
	char *expect = "Now, is it this comment that goes with the option?";
	cfg_t *cfg;
	cfg_opt_t *opt;
	cfg_opt_t section_opts[] = {
		CFG_INT("key", 0, CFGF_NONE),
		CFG_BOOL("bool", 0, CFGF_NONE),
		CFG_STR("option", NULL, CFGF_NONE),
		CFG_END()
	};
	cfg_opt_t opts[] = {
		CFG_STR("option", NULL, CFGF_NONE),
		CFG_SEC("section", section_opts, CFGF_MULTI),
		CFG_END()
	};

	cfg = cfg_init(opts, CFGF_COMMENTS);
	fail_unless(cfg != NULL);

	fail_unless(cfg_parse(cfg, SRC_DIR "/annotate.conf") == CFG_SUCCESS);

	/* Verify the parser read the correct comment for this tricky option */
	opt = cfg_getopt(cfg, "section|option");
	fail_unless(opt != NULL);
	comment = cfg_opt_getcomment(opt);
	fail_unless(comment != NULL);
	fail_unless(strcmp(comment, expect) == 0);

	expect = "But what's the worst poetry in the universe?";
	fail_unless(cfg_opt_setcomment(opt, expect) == CFG_SUCCESS);

	cfg_opt_setnstr(opt, "Paula Nancy Millstone Jennings was a poet who wrote the worst poetry in "
			"the universe. In fact, her poetry is still considered to be the worst in "
			"the Galaxy, closely followed by that of the Azgoths of Kria and the "
			"Vogons, in that order.", 0);

	/* Verify that the comment is not reset when changing option value */
	comment = cfg_opt_getcomment(opt);
	fail_unless(comment != NULL);
	fail_unless(strcmp(comment, expect) == 0);

	cfg_print(cfg, stdout);
	fail_unless(cfg_free(cfg) == CFG_SUCCESS);

	return 0;
}
Exemple #10
0
int validate_action(cfg_t *cfg, cfg_opt_t *opt)
{
	cfg_opt_t *name_opt;
	cfg_t *action_sec = cfg_opt_getnsec(opt, 0);

	fail_unless(action_sec != 0);

	name_opt = cfg_getopt(action_sec, "name");

	fail_unless(name_opt != 0);
	fail_unless(cfg_opt_size(name_opt) == 1);

	if (cfg_opt_getnstr(name_opt, 0) == NULL) {
		/* cfg_error(cfg, "missing required option 'name' in section %s", opt->name); */
		return 1;
	}
	return 0;
}
Exemple #11
0
static const char *subset(int argc, char *argv[])
{
	cfg_t *sub;

	if (argc < 4)
		return "Need more args\n";
	if (argc > 4)
		return "Too many args\n";

	sub = cfg_gettsec(cfg, "sub", argv[1]);
	if (!sub)
		return "No such section\n";

	if (!cfg_getopt(sub, argv[2]))
		return "Unknown option\n";

	if (cfg_setmulti(sub, argv[2], argc - 3, &argv[3]))
		return "Failure\n";

	return "OK\n";
}
Exemple #12
0
void
gimmix_config_save (Conf *conf)
{
	FILE *fp;
	cfg_t *cfg;
	cfg_opt_t *sopts;
	
	cfg_opt_t opts[] = {
		CFG_SIMPLE_STR ("mpd_hostname", NULL),
		CFG_SIMPLE_INT ("mpd_port", 0),
		CFG_SIMPLE_STR ("mpd_password", NULL),
		CFG_SIMPLE_BOOL ("enable_systray", false),
		CFG_SIMPLE_BOOL ("enable_notify", false),
		CFG_END()
	};

	cfg = cfg_init(opts, 0);
	char *rcfile = cfg_tilde_expand ("~/.gimmixrc");
	
	if((fp = fopen(rcfile, "w")))
	{	
		fprintf (fp, "# Gimmix configuration\n");
		fprintf (fp, "\n# MPD hostname (default: localhost)\n");
		if (conf->hostname)
			cfg_setstr(cfg, "mpd_hostname", conf->hostname);
		sopts = cfg_getopt (cfg, "mpd_hostname");
		cfg_opt_print (sopts, fp);

		fprintf (fp, "\n# MPD port (default: 6600)\n");
		if (conf->port > 0)
			cfg_setint(cfg, "mpd_port", conf->port);
		else
			cfg_setint(cfg, "mpd_port", 0);
		sopts = cfg_getopt (cfg, "mpd_port");
		cfg_opt_print (sopts, fp);
		
		fprintf (fp, "\n# MPD password (leave blank for no password) \n");
		if (conf->password)
			cfg_setstr(cfg, "mpd_password", conf->password);
		sopts = cfg_getopt (cfg, "mpd_password");
		cfg_opt_print (sopts, fp);

		fprintf (fp, "\n# Enable/Disable systray icon (Enable = true, Disable = false)\n");
		if (conf->systray_enable == 1)
			cfg_setbool(cfg, "enable_systray", true);
		else
			cfg_setbool(cfg, "enable_systray", false);
		sopts = cfg_getopt (cfg, "enable_systray");
		cfg_opt_print (sopts, fp);
		
		fprintf (fp, "\n# Enable/Disable system tray notifications (Enable = true, Disable = false) \n");
		if (conf->notify_enable == 1)
			cfg_setbool(cfg, "enable_notify", true);
		else
			cfg_setbool(cfg, "enable_notify", false);
		sopts = cfg_getopt (cfg, "enable_notify");
		cfg_opt_print (sopts, fp);

		free (rcfile);
		fclose (fp);
	}
	else
	{	
		fprintf (stderr, "Error while saving config.\n");
	}

	cfg_free_value (opts);
	cfg_free (cfg);
	
	return;
}
Exemple #13
0
DLLIMPORT void cfg_rmtsec(cfg_t *cfg, const char *name, const char *title)
{
	cfg_opt_rmtsec(cfg_getopt(cfg, name), title);
}
Exemple #14
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;
}
Exemple #15
0
DLLIMPORT cfg_t *cfg_gettsec(cfg_t *cfg, const char *name, const char *title)
{
    return cfg_opt_gettsec(cfg_getopt(cfg, name), title);
}
Exemple #16
0
DLLIMPORT cfg_t *cfg_getnsec(cfg_t *cfg, const char *name, unsigned int index)
{
    return cfg_opt_getnsec(cfg_getopt(cfg, name), index);
}
Exemple #17
0
DLLIMPORT double cfg_getnfloat(cfg_t *cfg, const char *name,
                               unsigned int index)
{
    return cfg_opt_getnfloat(cfg_getopt(cfg, name), index);
}
Exemple #18
0
DLLIMPORT unsigned int cfg_size(cfg_t *cfg, const char *name)
{
    return cfg_opt_size(cfg_getopt(cfg, name));
}
Exemple #19
0
DLLIMPORT cfg_print_func_t cfg_set_print_func(cfg_t *cfg, const char *name,
                                              cfg_print_func_t pf)
{
    return cfg_opt_set_print_func(cfg_getopt(cfg, name), pf);
}
Exemple #20
0
DLLIMPORT void cfg_setnstr(cfg_t *cfg, const char *name,
                           const char *value, unsigned int index)
{
    cfg_opt_setnstr(cfg_getopt(cfg, name), value, index);
}
Exemple #21
0
DLLIMPORT void cfg_rmnsec(cfg_t *cfg, const char *name, unsigned int index)
{
	cfg_opt_rmnsec(cfg_getopt(cfg, name), index);
}
Exemple #22
0
/**
 * @brief parses a single rule from a server { vhost { rules { } } } config
 *
 * @param cfg
 *
 * @return
 */
rule_cfg_t *
rule_cfg_parse(cfg_t * cfg) {
    rule_cfg_t * rcfg;
    const char * rname;
    int          i;

    assert(cfg != NULL);

    rname      = cfg_title(cfg);
    assert(rname != NULL);

    rcfg       = rule_cfg_new();
    assert(cfg != NULL);

    rcfg->name = strdup(rname);
    assert(rcfg->name != NULL);

    if (cfg_getstr(cfg, "uri-match")) {
        rcfg->type     = rule_type_exact;
        rcfg->matchstr = strdup(cfg_getstr(cfg, "uri-match"));
    } else if (cfg_getstr(cfg, "uri-gmatch")) {
        rcfg->type     = rule_type_glob;
        rcfg->matchstr = strdup(cfg_getstr(cfg, "uri-gmatch"));
    } else if (cfg_getstr(cfg, "uri-rmatch")) {
        rcfg->type     = rule_type_regex;
        rcfg->matchstr = strdup(cfg_getstr(cfg, "uri-rmatch"));
    } else {
        fprintf(stderr, "Rule %s has no match statement!\n", rname);
        exit(EXIT_FAILURE);
    }

    rcfg->lb_method      = lbstr_to_lbtype(cfg_getstr(cfg, "lb-method"));
    rcfg->headers        = headers_cfg_parse(cfg_getsec(cfg, "headers"));
    rcfg->passthrough    = cfg_getbool(cfg, "passthrough");
    rcfg->allow_redirect = cfg_getbool(cfg, "allow-redirect");

    if (cfg_getopt(cfg, "upstream-read-timeout")) {
        rcfg->up_read_timeout.tv_sec  = cfg_getnint(cfg, "upstream-read-timeout", 0);
        rcfg->up_read_timeout.tv_usec = cfg_getnint(cfg, "upstream-read-timeout", 1);
        rcfg->has_up_read_timeout     = 1;
    }

    if (cfg_getopt(cfg, "upstream-write-timeout")) {
        rcfg->up_write_timeout.tv_sec  = cfg_getnint(cfg, "upstream-write-timeout", 0);
        rcfg->up_write_timeout.tv_usec = cfg_getnint(cfg, "upstream-write-timeout", 1);
        rcfg->has_up_write_timeout     = 1;
    }

    for (i = 0; i < cfg_size(cfg, "downstreams"); i++) {
        lztq_elem * elem;
        char      * ds_name;

        ds_name = strdup(cfg_getnstr(cfg, "downstreams", i));
        assert(ds_name != NULL);

        elem    = lztq_append(rcfg->downstreams, ds_name, strlen(ds_name), free);
        assert(elem != NULL);
    }

    if (rcfg->allow_redirect != 0 && cfg_size(cfg, "redirect-filter")) {
        /*
         * if the redirect option is enabled, optionally an administrator can
         * add a list of allowed hosts it may communicate with.
         */
        int n_filters;

        n_filters = cfg_size(cfg, "redirect-filter");
        assert(n_filters > 0);

        rcfg->redirect_filter = lztq_new();
        assert(rcfg->redirect_filter != NULL);

        for (i = 0; i < n_filters; i++) {
            lztq_elem * elem;
            char      * host_ent;

            host_ent = strdup(cfg_getnstr(cfg, "redirect-filter", i));
            assert(host_ent != NULL);

            elem     = lztq_append(rcfg->redirect_filter, host_ent,
                                   strlen(host_ent), free);
            assert(elem != NULL);
        }
    }

    return rcfg;
} /* rule_cfg_parse */