From: Tanu Kaskinen <tanuk@xxxxxx> --- 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 | 44 ++++++++++++++++++++++++++++--- src/pulsecore/conf-parser.h | 18 +++++++++++-- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index abc1e61..dc5ac66 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -633,7 +633,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 fac5cd9..a3b5944 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -2399,7 +2399,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) @@ -4127,7 +4127,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 2999ece..ae46e2c 100644 --- a/src/modules/module-augment-properties.c +++ b/src/modules/module-augment-properties.c @@ -206,7 +206,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 95c21f0..10b020c 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -40,7 +40,7 @@ #define COMMENTS "#;\n" /* Run the user supplied parser for an assignment */ -static int next_assignment(pa_config_parser_state *state) { +static int normal_assignment(pa_config_parser_state *state) { const pa_config_item *item; pa_assert(state); @@ -66,6 +66,19 @@ static int next_assignment(pa_config_parser_state *state) { return -1; } +/* Parse a proplist entry. */ +static int proplist_assignment(pa_config_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(pa_config_parser_state *state) { char *c; @@ -92,7 +105,7 @@ static int parse_line(pa_config_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; } @@ -110,6 +123,17 @@ static int parse_line(pa_config_parser_state *state) { pa_xfree(state->section); state->section = pa_xstrndup(state->lvalue + 1, k-2); + + if (pa_streq(state->section, "Properties")) { + if (!state->proplist) { + pa_log("[%s:%u] \"Properties\" section is not allowed in this file.", state->filename, state->lineno); + return -1; + } + + state->in_proplist = TRUE; + } else + state->in_proplist = FALSE; + return 0; } @@ -124,11 +148,14 @@ static int parse_line(pa_config_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; pa_config_parser_state state; @@ -152,6 +179,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)) @@ -167,9 +197,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 1344121..7892a07 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. */ @@ -51,12 +53,24 @@ struct pa_config_parser_state { /* Private data to be used only by conf-parser.c. */ const pa_config_item *item_table; char buf[4096]; + pa_proplist *proplist; + pa_bool_t in_proplist; }; /* 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 Properties section, which + * is a bit special. Normally all accepted lvalues must be predefined + * in the pa_config_item table, but in the Properties 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 "Properties" as + * properties, and those properties will be merged into the given + * proplist. If proplist is NULL, then sections named "Properties" + * 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(pa_config_parser_state *state); -- 1.7.10