--- src/daemon/daemon-conf.c | 2 +- src/modules/alsa/alsa-mixer.c | 4 +- src/modules/module-augment-properties.c | 2 +- src/pulse/client-conf.c | 2 +- src/pulsecore/conf-parser.c | 46 ++++++++++++++++++++++++++++--- src/pulsecore/conf-parser.h | 17 ++++++++++- 6 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 3ef7f81..4532e9e 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -645,7 +645,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { ci.default_channel_map_set = ci.default_sample_spec_set = FALSE; ci.conf = c; - r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0; + r = f ? pa_config_parse(c->config_file, f, table, NULL, NULL) : 0; if (r >= 0) { diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 36f3351..c646f31 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -2390,7 +2390,7 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa fn = pa_maybe_prefix_path(fname, paths_dir); - r = pa_config_parse(fn, NULL, items, p); + r = pa_config_parse(fn, NULL, items, NULL, p); pa_xfree(fn); if (r < 0) @@ -4123,7 +4123,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel pa_run_from_build_tree() ? PA_BUILDDIR "/modules/alsa/mixer/profile-sets/" : PA_ALSA_PROFILE_SETS_DIR); - r = pa_config_parse(fn, NULL, items, ps); + r = pa_config_parse(fn, NULL, items, NULL, ps); pa_xfree(fn); if (r < 0) diff --git a/src/modules/module-augment-properties.c b/src/modules/module-augment-properties.c index 05f6f0a..d45bcdc 100644 --- a/src/modules/module-augment-properties.c +++ b/src/modules/module-augment-properties.c @@ -228,7 +228,7 @@ static void update_rule(struct rule *r) { table[0].data = &r->application_name; table[1].data = &r->icon_name; - if (pa_config_parse(fn, NULL, table, r) < 0) + if (pa_config_parse(fn, NULL, table, NULL, r) < 0) pa_log_warn("Failed to parse .desktop file %s.", fn); pa_xfree(fn); diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index e2c2aae..3641e3e 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -127,7 +127,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { goto finish; } - r = f ? pa_config_parse(fn, f, table, NULL) : 0; + r = f ? pa_config_parse(fn, f, table, NULL, NULL) : 0; if (!r) r = pa_client_conf_load_cookie(c); diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 41849c2..6602766 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -44,15 +44,17 @@ struct parser_state { unsigned lineno; char *section; const pa_config_item *item_table; + pa_proplist *proplist; char buf[4096]; void *userdata; char *lvalue; char *rvalue; + pa_bool_t in_proplist; }; /* Run the user supplied parser for an assignment */ -static int next_assignment(struct parser_state *state) { +static int normal_assignment(struct parser_state *state) { const pa_config_item *item; pa_assert(state); @@ -76,6 +78,19 @@ static int next_assignment(struct parser_state *state) { return -1; } +/* Parse a proplist entry. */ +static int proplist_assignment(struct parser_state *state) { + pa_assert(state); + pa_assert(state->proplist); + + if (pa_proplist_sets(state->proplist, state->lvalue, state->rvalue) < 0) { + pa_log("[%s:%u] Failed to parse a proplist entry: %s = %s", state->filename, state->lineno, state->lvalue, state->rvalue); + return -1; + } + + return 0; +} + /* Parse a variable assignment line */ static int parse_line(struct parser_state *state) { char *c; @@ -102,7 +117,7 @@ static int parse_line(struct parser_state *state) { } } - r = pa_config_parse(fn, NULL, state->item_table, state->userdata); + r = pa_config_parse(fn, NULL, state->item_table, state->proplist, state->userdata); pa_xfree(path); return r; } @@ -120,6 +135,17 @@ static int parse_line(struct parser_state *state) { pa_xfree(state->section); state->section = pa_xstrndup(state->lvalue + 1, k-2); + + if (pa_streq(state->section, "Property List")) { + if (!state->proplist) { + pa_log("[%s:%u] \"Property List\" section is not allowed in this file.", state->filename, state->lineno); + return -1; + } + + state->in_proplist = TRUE; + } else + state->in_proplist = FALSE; + return 0; } @@ -134,11 +160,14 @@ static int parse_line(struct parser_state *state) { state->lvalue = pa_strip(state->lvalue); state->rvalue = pa_strip(state->rvalue); - return next_assignment(state); + if (state->in_proplist) + return proplist_assignment(state); + else + return normal_assignment(state); } /* Go through the file and parse each line */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, pa_proplist *proplist, void *userdata) { int r = -1; pa_bool_t do_close = !f; struct parser_state state; @@ -162,6 +191,9 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void state.item_table = t; state.userdata = userdata; + if (proplist) + state.proplist = pa_proplist_new(); + while (!feof(f)) { if (!fgets(state.buf, sizeof(state.buf), f)) { if (feof(f)) @@ -177,9 +209,15 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void goto finish; } + if (proplist) + pa_proplist_update(proplist, PA_UPDATE_REPLACE, state.proplist); + r = 0; finish: + if (state.proplist) + pa_proplist_free(state.proplist); + pa_xfree(state.section); if (do_close && f) diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index c6c8a14..9fb0110 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -24,6 +24,8 @@ #include <stdio.h> +#include <pulse/proplist.h> + /* An abstract parser for simple, line based, shallow configuration * files consisting of variable assignments only. */ @@ -39,8 +41,19 @@ typedef struct pa_config_item { /* The configuration file parsing routine. Expects a table of * pa_config_items in *t that is terminated by an item where lvalue is - * NULL */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); + * NULL. + * + * Some configuration files may contain a Property List section, which + * is a bit special. Normally all accepted lvalues must be predefined + * in the pa_config_item table, but in the Property List section the + * pa_config_item table is ignored, and all lvalues are accepted (as + * long as they are valid proplist keys). If the proplist pointer is + * non-NULL, the parser will parse any section named "Property List" as + * properties, and those properties will be merged into the given + * proplist. If proplist is NULL, then sections named "Property List" + * are not allowed at all in the configuration file. + */ +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, pa_proplist *proplist, void *userdata); /* Generic parsers for integers, size_t, booleans and strings */ int pa_config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); -- 1.7.7.3