[pulseaudio-commits] 6 commits - src/daemon src/modules src/pulse src/pulsecore src/utils

Tanu Kaskinen tanuk at kemper.freedesktop.org
Fri Jun 29 03:31:12 PDT 2012


 src/daemon/daemon-conf.c                               |  222 +++---
 src/modules/alsa/alsa-mixer.c                          |  594 ++++++-----------
 src/modules/alsa/alsa-mixer.h                          |    1 
 src/modules/alsa/mixer/paths/analog-output.conf.common |    4 
 src/modules/module-augment-properties.c                |   62 -
 src/pulse/client-conf.c                                |    2 
 src/pulsecore/conf-parser.c                            |  223 +++---
 src/pulsecore/conf-parser.h                            |   48 +
 src/pulsecore/protocol-native.c                        |    4 
 src/utils/pactl.c                                      |    9 
 10 files changed, 542 insertions(+), 627 deletions(-)

New commits:
commit 5f62cf8f409d02984abe574545bc86556b2e94fb
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Apr 13 14:48:30 2012 +0300

    pactl: Print card port properties with the "list" command.

diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 3a5066c..61d0727 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -571,6 +571,8 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
+    pa_xfree(pl);
+
     if (i->profiles) {
         pa_card_profile_info *p;
 
@@ -592,6 +594,11 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
             printf(_("\t\t%s: %s (priority: %u%s)\n"), (*p)->name, (*p)->description, (*p)->priority,
                 get_available_str_ynonly((*p)->available));
 
+            if (!pa_proplist_isempty((*p)->proplist)) {
+                printf(_("\t\t\tProperties:\n\t\t\t\t%s\n"), pl = pa_proplist_to_string_sep((*p)->proplist, "\n\t\t\t\t"));
+                pa_xfree(pl);
+            }
+
             if (pr) {
                 printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name));
                 pr++;
@@ -603,8 +610,6 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
             }
         }
     }
-
-    pa_xfree(pl);
 }
 
 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {

commit ed1085f82be72311f3d7c3e0e6645d6f1c6f946e
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Apr 13 14:48:29 2012 +0300

    native: Send the actual port proplists with card info.

diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index c24254a..e59bf7e 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -3264,7 +3264,6 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
 
     if (card->ports) {
         pa_device_port* port;
-        pa_proplist* proplist = pa_proplist_new(); /* For now - push an empty proplist */
 
         pa_tagstruct_putu32(t, pa_hashmap_size(card->ports));
 
@@ -3274,7 +3273,7 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
             pa_tagstruct_putu32(t, port->priority);
             pa_tagstruct_putu32(t, port->available);
             pa_tagstruct_putu8(t, /* FIXME: port->direction */ (port->is_input ? PA_DIRECTION_INPUT : 0) | (port->is_output ? PA_DIRECTION_OUTPUT : 0));
-            pa_tagstruct_put_proplist(t, proplist);
+            pa_tagstruct_put_proplist(t, port->proplist);
 
             if (port->profiles) {
                 void* state2;
@@ -3285,7 +3284,6 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
                 pa_tagstruct_putu32(t, 0);
         }
 
-        pa_proplist_free(proplist);
     } else
         pa_tagstruct_putu32(t, 0);
 }

commit 88052dbdb97e5e4c58ab6eed0c1eb80b77916ef5
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Apr 13 14:48:28 2012 +0300

    alsa-mixer: Add support for defining port property lists in the path configuration files.

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index b82d8e8..63370da 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -518,6 +518,7 @@ void pa_alsa_path_free(pa_alsa_path *p) {
         setting_free(s);
     }
 
+    pa_proplist_free(p->proplist);
     pa_xfree(p->name);
     pa_xfree(p->description);
     pa_xfree(p);
@@ -2388,6 +2389,7 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa
     p = pa_xnew0(pa_alsa_path, 1);
     n = pa_path_get_filename(fname);
     p->name = pa_xstrndup(n, strcspn(n, "."));
+    p->proplist = pa_proplist_new();
     p->direction = direction;
 
     items[0].data = &p->priority;
@@ -2399,7 +2401,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, NULL, p);
+    r = pa_config_parse(fn, NULL, items, p->proplist, p);
     pa_xfree(fn);
 
     if (r < 0)
@@ -4380,13 +4382,19 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
     pa_hashmap *extra,
     pa_core *core) {
 
-    pa_device_port * p = pa_hashmap_get(ports, name);
+    pa_device_port *p;
+
+    pa_assert(path);
+
+    p = pa_hashmap_get(ports, name);
+
     if (!p) {
         pa_alsa_port_data *data;
 
         p = pa_device_port_new(core, name, description, sizeof(pa_alsa_port_data));
         pa_assert(p);
         pa_hashmap_put(ports, p->name, p);
+        pa_proplist_update(p->proplist, PA_UPDATE_REPLACE, path->proplist);
 
         data = PA_DEVICE_PORT_DATA(p);
         data->path = path;
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index fdcff76..6b12a7f 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -181,6 +181,7 @@ struct pa_alsa_path {
     char *name;
     char *description;
     unsigned priority;
+    pa_proplist *proplist;
 
     pa_bool_t probed:1;
     pa_bool_t supported:1;
diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common
index 160f222..d591686 100644
--- a/src/modules/alsa/mixer/paths/analog-output.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-output.conf.common
@@ -57,6 +57,10 @@
 ; priority = ...                         # Priority for this path
 ; description = ...
 ;
+; [Properties]                           # Property list for this path. The list is merged into the port property list.
+; <key> = <value>                        # Each property is defined on its own line.
+; ...
+;
 ; [Option ...:...]                       # For each option of an enumeration or switch element
 ;                                        # that shall be exposed as a sink/source port. Needs to
 ;                                        # be named after the Element, followed by a colon, followed

commit d3bced8bee825c7d7c1228296bc1cfb42a030c71
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Fri Apr 13 14:48:27 2012 +0300

    conf-parser: Add support for parsing property lists.

diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index a8d64f9..d5fba33 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 9f47c5e..b82d8e8 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)
@@ -4128,7 +4128,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 3c4811d..6bba2b3 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 781fdf9..8988daf 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);

commit 7449f6d9e5bdfdce6c1e5a25c919856971b3aebd
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Apr 13 14:48:26 2012 +0300

    conf-parser: Pass parser state in a struct also for parse callbacks.
    
    As suggested by Maarten Bosmans:
    http://article.gmane.org/gmane.comp.audio.pulseaudio.general/12079

diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index dd2e7b6..a8d64f9 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -263,48 +263,45 @@ int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string)
     return 0;
 }
 
-static int parse_log_target(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_log_target(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
+
+    pa_assert(state);
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    c = state->data;
 
-    if (pa_daemon_conf_set_log_target(c, rvalue) < 0) {
-        pa_log(_("[%s:%u] Invalid log target '%s'."), filename, line, rvalue);
+    if (pa_daemon_conf_set_log_target(c, state->rvalue) < 0) {
+        pa_log(_("[%s:%u] Invalid log target '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
     return 0;
 }
 
-static int parse_log_level(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_log_level(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
+
+    pa_assert(state);
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    c = state->data;
 
-    if (pa_daemon_conf_set_log_level(c, rvalue) < 0) {
-        pa_log(_("[%s:%u] Invalid log level '%s'."), filename, line, rvalue);
+    if (pa_daemon_conf_set_log_level(c, state->rvalue) < 0) {
+        pa_log(_("[%s:%u] Invalid log level '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
     return 0;
 }
 
-static int parse_resample_method(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_resample_method(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
+
+    pa_assert(state);
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    c = state->data;
 
-    if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) {
-        pa_log(_("[%s:%u] Invalid resample method '%s'."), filename, line, rvalue);
+    if (pa_daemon_conf_set_resample_method(c, state->rvalue) < 0) {
+        pa_log(_("[%s:%u] Invalid resample method '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -312,22 +309,21 @@ static int parse_resample_method(const char *filename, unsigned line, const char
 }
 
 #ifdef HAVE_SYS_RESOURCE_H
-static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    struct pa_rlimit *r = data;
+static int parse_rlimit(pa_config_parser_state *state) {
+    struct pa_rlimit *r;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(r);
+    pa_assert(state);
 
-    if (rvalue[strspn(rvalue, "\t ")] == 0) {
+    r = state->data;
+
+    if (state->rvalue[strspn(state->rvalue, "\t ")] == 0) {
         /* Empty string */
         r->is_set = 0;
         r->value = 0;
     } else {
         int32_t k;
-        if (pa_atoi(rvalue, &k) < 0) {
-            pa_log(_("[%s:%u] Invalid rlimit '%s'."), filename, line, rvalue);
+        if (pa_atoi(state->rvalue, &k) < 0) {
+            pa_log(_("[%s:%u] Invalid rlimit '%s'."), state->filename, state->lineno, state->rvalue);
             return -1;
         }
         r->is_set = k >= 0;
@@ -338,17 +334,16 @@ static int parse_rlimit(const char *filename, unsigned line, const char *section
 }
 #endif
 
-static int parse_sample_format(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_sample_format(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     pa_sample_format_t f;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
 
-    if ((f = pa_parse_sample_format(rvalue)) < 0) {
-        pa_log(_("[%s:%u] Invalid sample format '%s'."), filename, line, rvalue);
+    c = state->data;
+
+    if ((f = pa_parse_sample_format(state->rvalue)) < 0) {
+        pa_log(_("[%s:%u] Invalid sample format '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -356,18 +351,17 @@ static int parse_sample_format(const char *filename, unsigned line, const char *
     return 0;
 }
 
-static int parse_sample_rate(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_sample_rate(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     uint32_t r;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
 
-    if (pa_atou(rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
+    c = state->data;
+
+    if (pa_atou(state->rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
         !((r % 4000 == 0) || (r % 11025 == 0))) {
-        pa_log(_("[%s:%u] Invalid sample rate '%s'."), filename, line, rvalue);
+        pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -375,18 +369,17 @@ static int parse_sample_rate(const char *filename, unsigned line, const char *se
     return 0;
 }
 
-static int parse_alternate_sample_rate(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_alternate_sample_rate(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     uint32_t r;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
 
-    if (pa_atou(rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
+    c = state->data;
+
+    if (pa_atou(state->rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
         !((r % 4000==0) || (r % 11025 == 0))) {
-        pa_log(_("[%s:%u] Invalid sample rate '%s'."), filename, line, rvalue);
+        pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -400,17 +393,16 @@ struct channel_conf_info {
     pa_bool_t default_channel_map_set;
 };
 
-static int parse_sample_channels(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    struct channel_conf_info *i = data;
+static int parse_sample_channels(pa_config_parser_state *state) {
+    struct channel_conf_info *i;
     int32_t n;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    i = state->data;
 
-    if (pa_atoi(rvalue, &n) < 0 || n > (int32_t) PA_CHANNELS_MAX || n <= 0) {
-        pa_log(_("[%s:%u] Invalid sample channels '%s'."), filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &n) < 0 || n > (int32_t) PA_CHANNELS_MAX || n <= 0) {
+        pa_log(_("[%s:%u] Invalid sample channels '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -419,16 +411,15 @@ static int parse_sample_channels(const char *filename, unsigned line, const char
     return 0;
 }
 
-static int parse_channel_map(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    struct channel_conf_info *i = data;
+static int parse_channel_map(pa_config_parser_state *state) {
+    struct channel_conf_info *i;
+
+    pa_assert(state);
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    i = state->data;
 
-    if (!pa_channel_map_parse(&i->conf->default_channel_map, rvalue)) {
-        pa_log(_("[%s:%u] Invalid channel map '%s'."), filename, line, rvalue);
+    if (!pa_channel_map_parse(&i->conf->default_channel_map, state->rvalue)) {
+        pa_log(_("[%s:%u] Invalid channel map '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -436,17 +427,16 @@ static int parse_channel_map(const char *filename, unsigned line, const char *se
     return 0;
 }
 
-static int parse_fragments(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_fragments(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     int32_t n;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    c = state->data;
 
-    if (pa_atoi(rvalue, &n) < 0 || n < 2) {
-        pa_log(_("[%s:%u] Invalid number of fragments '%s'."), filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &n) < 0 || n < 2) {
+        pa_log(_("[%s:%u] Invalid number of fragments '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -454,17 +444,16 @@ static int parse_fragments(const char *filename, unsigned line, const char *sect
     return 0;
 }
 
-static int parse_fragment_size_msec(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_fragment_size_msec(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     int32_t n;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    c = state->data;
 
-    if (pa_atoi(rvalue, &n) < 0 || n < 1) {
-        pa_log(_("[%s:%u] Invalid fragment size '%s'."), filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &n) < 0 || n < 1) {
+        pa_log(_("[%s:%u] Invalid fragment size '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -472,17 +461,16 @@ static int parse_fragment_size_msec(const char *filename, unsigned line, const c
     return 0;
 }
 
-static int parse_nice_level(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_nice_level(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
     int32_t level;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    c = state->data;
 
-    if (pa_atoi(rvalue, &level) < 0 || level < -20 || level > 19) {
-        pa_log(_("[%s:%u] Invalid nice level '%s'."), filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &level) < 0 || level < -20 || level > 19) {
+        pa_log(_("[%s:%u] Invalid nice level '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -490,21 +478,22 @@ static int parse_nice_level(const char *filename, unsigned line, const char *sec
     return 0;
 }
 
-static int parse_rtprio(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+static int parse_rtprio(pa_config_parser_state *state) {
+#if !defined(OS_IS_WIN32) && defined(HAVE_SCHED_H)
+    pa_daemon_conf *c;
+    int32_t rtprio;
+#endif
+
+    pa_assert(state);
+
 #ifdef OS_IS_WIN32
-    pa_log("[%s:%u] Realtime priority not available on win32.", filename, line);
+    pa_log("[%s:%u] Realtime priority not available on win32.", state->filename, state->lineno);
 #else
 # ifdef HAVE_SCHED_H
-    pa_daemon_conf *c = data;
-    int32_t rtprio;
+    c = state->data;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
-
-    if (pa_atoi(rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) {
-        pa_log("[%s:%u] Invalid realtime priority '%s'.", filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) {
+        pa_log("[%s:%u] Invalid realtime priority '%s'.", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -516,16 +505,15 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section
 }
 
 #ifdef HAVE_DBUS
-static int parse_server_type(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    pa_daemon_conf *c = data;
+static int parse_server_type(pa_config_parser_state *state) {
+    pa_daemon_conf *c;
+
+    pa_assert(state);
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    c = state->data;
 
-    if (pa_daemon_conf_set_local_server_type(c, rvalue) < 0) {
-        pa_log(_("[%s:%u] Invalid server type '%s'."), filename, line, rvalue);
+    if (pa_daemon_conf_set_local_server_type(c, state->rvalue) < 0) {
+        pa_log(_("[%s:%u] Invalid server type '%s'."), state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 1b2207b..9f47c5e 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1784,78 +1784,66 @@ finish:
     return o;
 }
 
-static int element_parse_switch(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_switch(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
 
-    pa_assert(p);
+    pa_assert(state);
+
+    p = state->userdata;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Switch makes no sense in '%s'", filename, line, section);
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Switch makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "ignore"))
+    if (pa_streq(state->rvalue, "ignore"))
         e->switch_use = PA_ALSA_SWITCH_IGNORE;
-    else if (pa_streq(rvalue, "mute"))
+    else if (pa_streq(state->rvalue, "mute"))
         e->switch_use = PA_ALSA_SWITCH_MUTE;
-    else if (pa_streq(rvalue, "off"))
+    else if (pa_streq(state->rvalue, "off"))
         e->switch_use = PA_ALSA_SWITCH_OFF;
-    else if (pa_streq(rvalue, "on"))
+    else if (pa_streq(state->rvalue, "on"))
         e->switch_use = PA_ALSA_SWITCH_ON;
-    else if (pa_streq(rvalue, "select"))
+    else if (pa_streq(state->rvalue, "select"))
         e->switch_use = PA_ALSA_SWITCH_SELECT;
     else {
-        pa_log("[%s:%u] Switch invalid of '%s'", filename, line, section);
+        pa_log("[%s:%u] Switch invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int element_parse_volume(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_volume(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
 
-    pa_assert(p);
+    pa_assert(state);
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Volume makes no sense in '%s'", filename, line, section);
+    p = state->userdata;
+
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Volume makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "ignore"))
+    if (pa_streq(state->rvalue, "ignore"))
         e->volume_use = PA_ALSA_VOLUME_IGNORE;
-    else if (pa_streq(rvalue, "merge"))
+    else if (pa_streq(state->rvalue, "merge"))
         e->volume_use = PA_ALSA_VOLUME_MERGE;
-    else if (pa_streq(rvalue, "off"))
+    else if (pa_streq(state->rvalue, "off"))
         e->volume_use = PA_ALSA_VOLUME_OFF;
-    else if (pa_streq(rvalue, "zero"))
+    else if (pa_streq(state->rvalue, "zero"))
         e->volume_use = PA_ALSA_VOLUME_ZERO;
     else {
         uint32_t constant;
 
-        if (pa_atou(rvalue, &constant) >= 0) {
+        if (pa_atou(state->rvalue, &constant) >= 0) {
             e->volume_use = PA_ALSA_VOLUME_CONSTANT;
             e->constant_volume = constant;
         } else {
-            pa_log("[%s:%u] Volume invalid of '%s'", filename, line, section);
+            pa_log("[%s:%u] Volume invalid of '%s'", state->filename, state->lineno, state->section);
             return -1;
         }
     }
@@ -1863,59 +1851,47 @@ static int element_parse_volume(
     return 0;
 }
 
-static int element_parse_enumeration(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_enumeration(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
 
-    pa_assert(p);
+    pa_assert(state);
+
+    p = state->userdata;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Enumeration makes no sense in '%s'", filename, line, section);
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Enumeration makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "ignore"))
+    if (pa_streq(state->rvalue, "ignore"))
         e->enumeration_use = PA_ALSA_ENUMERATION_IGNORE;
-    else if (pa_streq(rvalue, "select"))
+    else if (pa_streq(state->rvalue, "select"))
         e->enumeration_use = PA_ALSA_ENUMERATION_SELECT;
     else {
-        pa_log("[%s:%u] Enumeration invalid of '%s'", filename, line, section);
+        pa_log("[%s:%u] Enumeration invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int option_parse_priority(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int option_parse_priority(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_option *o;
     uint32_t prio;
 
-    pa_assert(p);
+    pa_assert(state);
 
-    if (!(o = option_get(p, section))) {
-        pa_log("[%s:%u] Priority makes no sense in '%s'", filename, line, section);
+    p = state->userdata;
+
+    if (!(o = option_get(p, state->section))) {
+        pa_log("[%s:%u] Priority makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_atou(rvalue, &prio) < 0) {
-        pa_log("[%s:%u] Priority invalid of '%s'", filename, line, section);
+    if (pa_atou(state->rvalue, &prio) < 0) {
+        pa_log("[%s:%u] Priority invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
@@ -1923,72 +1899,60 @@ static int option_parse_priority(
     return 0;
 }
 
-static int option_parse_name(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int option_parse_name(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_option *o;
 
-    pa_assert(p);
+    pa_assert(state);
+
+    p = state->userdata;
 
-    if (!(o = option_get(p, section))) {
-        pa_log("[%s:%u] Name makes no sense in '%s'", filename, line, section);
+    if (!(o = option_get(p, state->section))) {
+        pa_log("[%s:%u] Name makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     pa_xfree(o->name);
-    o->name = pa_xstrdup(rvalue);
+    o->name = pa_xstrdup(state->rvalue);
 
     return 0;
 }
 
-static int element_parse_required(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_required(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
     pa_alsa_option *o;
     pa_alsa_jack *j;
     pa_alsa_required_t req;
 
-    pa_assert(p);
+    pa_assert(state);
+
+    p = state->userdata;
 
-    e = element_get(p, section, TRUE);
-    o = option_get(p, section);
-    j = jack_get(p, section);
+    e = element_get(p, state->section, TRUE);
+    o = option_get(p, state->section);
+    j = jack_get(p, state->section);
     if (!e && !o && !j) {
-        pa_log("[%s:%u] Required makes no sense in '%s'", filename, line, section);
+        pa_log("[%s:%u] Required makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "ignore"))
+    if (pa_streq(state->rvalue, "ignore"))
         req = PA_ALSA_REQUIRED_IGNORE;
-    else if (pa_streq(rvalue, "switch") && e)
+    else if (pa_streq(state->rvalue, "switch") && e)
         req = PA_ALSA_REQUIRED_SWITCH;
-    else if (pa_streq(rvalue, "volume") && e)
+    else if (pa_streq(state->rvalue, "volume") && e)
         req = PA_ALSA_REQUIRED_VOLUME;
-    else if (pa_streq(rvalue, "enumeration"))
+    else if (pa_streq(state->rvalue, "enumeration"))
         req = PA_ALSA_REQUIRED_ENUMERATION;
-    else if (pa_streq(rvalue, "any"))
+    else if (pa_streq(state->rvalue, "any"))
         req = PA_ALSA_REQUIRED_ANY;
     else {
-        pa_log("[%s:%u] Required invalid of '%s'", filename, line, section);
+        pa_log("[%s:%u] Required invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(lvalue, "required-absent")) {
+    if (pa_streq(state->lvalue, "required-absent")) {
         if (e)
             e->required_absent = req;
         if (o)
@@ -1996,7 +1960,7 @@ static int element_parse_required(
         if (j)
             j->required_absent = req;
     }
-    else if (pa_streq(lvalue, "required-any")) {
+    else if (pa_streq(state->lvalue, "required-any")) {
         if (e) {
             e->required_any = req;
             e->path->has_req_any |= (req != PA_ALSA_REQUIRED_IGNORE);
@@ -2023,57 +1987,47 @@ static int element_parse_required(
     return 0;
 }
 
-static int element_parse_direction(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_direction(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
 
-    pa_assert(p);
+    pa_assert(state);
+
+    p = state->userdata;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Direction makes no sense in '%s'", filename, line, section);
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Direction makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "playback"))
+    if (pa_streq(state->rvalue, "playback"))
         e->direction = PA_ALSA_DIRECTION_OUTPUT;
-    else if (pa_streq(rvalue, "capture"))
+    else if (pa_streq(state->rvalue, "capture"))
         e->direction = PA_ALSA_DIRECTION_INPUT;
     else {
-        pa_log("[%s:%u] Direction invalid of '%s'", filename, line, section);
+        pa_log("[%s:%u] Direction invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int element_parse_direction_try_other(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_direction_try_other(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
     int yes;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Direction makes no sense in '%s'", filename, line, section);
+    pa_assert(state);
+
+    p = state->userdata;
+
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Direction makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if ((yes = pa_parse_boolean(rvalue)) < 0) {
-        pa_log("[%s:%u] Direction invalid of '%s'", filename, line, section);
+    if ((yes = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] Direction invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
@@ -2081,26 +2035,22 @@ static int element_parse_direction_try_other(
     return 0;
 }
 
-static int element_parse_volume_limit(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_volume_limit(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
     long volume_limit;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] volume-limit makes no sense in '%s'", filename, line, section);
+    pa_assert(state);
+
+    p = state->userdata;
+
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] volume-limit makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_atol(rvalue, &volume_limit) < 0 || volume_limit < 0) {
-        pa_log("[%s:%u] Invalid value for volume-limit", filename, line);
+    if (pa_atol(state->rvalue, &volume_limit) < 0 || volume_limit < 0) {
+        pa_log("[%s:%u] Invalid value for volume-limit", state->filename, state->lineno);
         return -1;
     }
 
@@ -2141,40 +2091,36 @@ static pa_channel_position_mask_t parse_mask(const char *m) {
     return v;
 }
 
-static int element_parse_override_map(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int element_parse_override_map(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_element *e;
-    const char *state = NULL;
+    const char *split_state = NULL;
     unsigned i = 0;
     char *n;
 
-    if (!(e = element_get(p, section, TRUE))) {
-        pa_log("[%s:%u] Override map makes no sense in '%s'", filename, line, section);
+    pa_assert(state);
+
+    p = state->userdata;
+
+    if (!(e = element_get(p, state->section, TRUE))) {
+        pa_log("[%s:%u] Override map makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    while ((n = pa_split(rvalue, ",", &state))) {
+    while ((n = pa_split(state->rvalue, ",", &split_state))) {
         pa_channel_position_mask_t m;
 
         if (!*n)
             m = 0;
         else {
             if ((m = parse_mask(n)) == 0) {
-                pa_log("[%s:%u] Override map '%s' invalid in '%s'", filename, line, n, section);
+                pa_log("[%s:%u] Override map '%s' invalid in '%s'", state->filename, state->lineno, n, state->section);
                 pa_xfree(n);
                 return -1;
             }
         }
 
-        if (pa_streq(lvalue, "override-map.1"))
+        if (pa_streq(state->lvalue, "override-map.1"))
             e->masks[i++][0] = m;
         else
             e->masks[i++][1] = m;
@@ -2189,40 +2135,36 @@ static int element_parse_override_map(
     return 0;
 }
 
-static int jack_parse_state(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_path *p = userdata;
+static int jack_parse_state(pa_config_parser_state *state) {
+    pa_alsa_path *p;
     pa_alsa_jack *j;
     pa_port_available_t pa;
 
-    if (!(j = jack_get(p, section))) {
-        pa_log("[%s:%u] state makes no sense in '%s'", filename, line, section);
+    pa_assert(state);
+
+    p = state->userdata;
+
+    if (!(j = jack_get(p, state->section))) {
+        pa_log("[%s:%u] state makes no sense in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "yes"))
+    if (pa_streq(state->rvalue, "yes"))
 	pa = PA_PORT_AVAILABLE_YES;
-    else if (pa_streq(rvalue, "no"))
+    else if (pa_streq(state->rvalue, "no"))
 	pa = PA_PORT_AVAILABLE_NO;
-    else if (pa_streq(rvalue, "unknown"))
+    else if (pa_streq(state->rvalue, "unknown"))
 	pa = PA_PORT_AVAILABLE_UNKNOWN;
     else {
-        pa_log("[%s:%u] state must be 'yes','no' or 'unknown' in '%s'", filename, line, section);
+        pa_log("[%s:%u] state must be 'yes', 'no' or 'unknown' in '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(lvalue, "state.unplugged"))
+    if (pa_streq(state->lvalue, "state.unplugged"))
         j->state_unplugged = pa;
     else {
         j->state_plugged = pa;
-        pa_assert(pa_streq(lvalue, "state.plugged"));
+        pa_assert(pa_streq(state->lvalue, "state.plugged"));
     }
 
     return 0;
@@ -3427,268 +3369,214 @@ static pa_alsa_decibel_fix *decibel_fix_get(pa_alsa_profile_set *ps, const char
     return db_fix;
 }
 
-static int mapping_parse_device_strings(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_device_strings(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(m = mapping_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    if (!(m = mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
     pa_xstrfreev(m->device_strings);
-    if (!(m->device_strings = pa_split_spaces_strv(rvalue))) {
-        pa_log("[%s:%u] Device string list empty of '%s'", filename, line, section);
+    if (!(m->device_strings = pa_split_spaces_strv(state->rvalue))) {
+        pa_log("[%s:%u] Device string list empty of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int mapping_parse_channel_map(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_channel_map(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(m = mapping_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    if (!(m = mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if (!(pa_channel_map_parse(&m->channel_map, rvalue))) {
-        pa_log("[%s:%u] Channel map invalid of '%s'", filename, line, section);
+    if (!(pa_channel_map_parse(&m->channel_map, state->rvalue))) {
+        pa_log("[%s:%u] Channel map invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int mapping_parse_paths(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_paths(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(m = mapping_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    if (!(m = mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if (pa_streq(lvalue, "paths-input")) {
+    if (pa_streq(state->lvalue, "paths-input")) {
         pa_xstrfreev(m->input_path_names);
-        m->input_path_names = pa_split_spaces_strv(rvalue);
+        m->input_path_names = pa_split_spaces_strv(state->rvalue);
     } else {
         pa_xstrfreev(m->output_path_names);
-        m->output_path_names = pa_split_spaces_strv(rvalue);
+        m->output_path_names = pa_split_spaces_strv(state->rvalue);
     }
 
     return 0;
 }
 
-static int mapping_parse_element(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_element(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
 
-    if (!(m = mapping_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    ps = state->userdata;
+
+    if (!(m = mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if (pa_streq(lvalue, "element-input")) {
+    if (pa_streq(state->lvalue, "element-input")) {
         pa_xstrfreev(m->input_element);
-        m->input_element = pa_split_spaces_strv(rvalue);
+        m->input_element = pa_split_spaces_strv(state->rvalue);
     } else {
         pa_xstrfreev(m->output_element);
-        m->output_element = pa_split_spaces_strv(rvalue);
+        m->output_element = pa_split_spaces_strv(state->rvalue);
     }
 
     return 0;
 }
 
-static int mapping_parse_direction(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_direction(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(m = mapping_get(ps, section))) {
-        pa_log("[%s:%u] Section name %s invalid.", filename, line, section);
+    if (!(m = mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if (pa_streq(rvalue, "input"))
+    if (pa_streq(state->rvalue, "input"))
         m->direction = PA_ALSA_DIRECTION_INPUT;
-    else if (pa_streq(rvalue, "output"))
+    else if (pa_streq(state->rvalue, "output"))
         m->direction = PA_ALSA_DIRECTION_OUTPUT;
-    else if (pa_streq(rvalue, "any"))
+    else if (pa_streq(state->rvalue, "any"))
         m->direction = PA_ALSA_DIRECTION_ANY;
     else {
-        pa_log("[%s:%u] Direction %s invalid.", filename, line, rvalue);
+        pa_log("[%s:%u] Direction %s invalid.", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
     return 0;
 }
 
-static int mapping_parse_description(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_description(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_profile *p;
     pa_alsa_mapping *m;
 
-    pa_assert(ps);
+    pa_assert(state);
 
-    if ((m = mapping_get(ps, section))) {
+    ps = state->userdata;
+
+    if ((m = mapping_get(ps, state->section))) {
         pa_xfree(m->description);
-        m->description = pa_xstrdup(rvalue);
-    } else if ((p = profile_get(ps, section))) {
+        m->description = pa_xstrdup(state->rvalue);
+    } else if ((p = profile_get(ps, state->section))) {
         pa_xfree(p->description);
-        p->description = pa_xstrdup(rvalue);
+        p->description = pa_xstrdup(state->rvalue);
     } else {
-        pa_log("[%s:%u] Section name %s invalid.", filename, line, section);
+        pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int mapping_parse_priority(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int mapping_parse_priority(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_profile *p;
     pa_alsa_mapping *m;
     uint32_t prio;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (pa_atou(rvalue, &prio) < 0) {
-        pa_log("[%s:%u] Priority invalid of '%s'", filename, line, section);
+    if (pa_atou(state->rvalue, &prio) < 0) {
+        pa_log("[%s:%u] Priority invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
-    if ((m = mapping_get(ps, section)))
+    if ((m = mapping_get(ps, state->section)))
         m->priority = prio;
-    else if ((p = profile_get(ps, section)))
+    else if ((p = profile_get(ps, state->section)))
         p->priority = prio;
     else {
-        pa_log("[%s:%u] Section name %s invalid.", filename, line, section);
+        pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
         return -1;
     }
 
     return 0;
 }
 
-static int profile_parse_mappings(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int profile_parse_mappings(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_profile *p;
 
-    pa_assert(ps);
+    pa_assert(state);
 
-    if (!(p = profile_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    ps = state->userdata;
+
+    if (!(p = profile_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if (pa_streq(lvalue, "input-mappings")) {
+    if (pa_streq(state->lvalue, "input-mappings")) {
         pa_xstrfreev(p->input_mapping_names);
-        p->input_mapping_names = pa_split_spaces_strv(rvalue);
+        p->input_mapping_names = pa_split_spaces_strv(state->rvalue);
     } else {
         pa_xstrfreev(p->output_mapping_names);
-        p->output_mapping_names = pa_split_spaces_strv(rvalue);
+        p->output_mapping_names = pa_split_spaces_strv(state->rvalue);
     }
 
     return 0;
 }
 
-static int profile_parse_skip_probe(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int profile_parse_skip_probe(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_profile *p;
     int b;
 
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(p = profile_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    if (!(p = profile_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if ((b = pa_parse_boolean(rvalue)) < 0) {
-        pa_log("[%s:%u] Skip probe invalid of '%s'", filename, line, section);
+    if ((b = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] Skip probe invalid of '%s'", state->filename, state->lineno, state->section);
         return -1;
     }
 
@@ -3697,16 +3585,8 @@ static int profile_parse_skip_probe(
     return 0;
 }
 
-static int decibel_fix_parse_db_values(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    pa_alsa_profile_set *ps = userdata;
+static int decibel_fix_parse_db_values(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
     pa_alsa_decibel_fix *db_fix;
     char **items;
     char *item;
@@ -3718,19 +3598,17 @@ static int decibel_fix_parse_db_values(
     unsigned prev_step = 0;
     double prev_db = 0;
 
-    pa_assert(filename);
-    pa_assert(section);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(ps);
+    pa_assert(state);
+
+    ps = state->userdata;
 
-    if (!(db_fix = decibel_fix_get(ps, section))) {
-        pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+    if (!(db_fix = decibel_fix_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
         return -1;
     }
 
-    if (!(items = pa_split_spaces_strv(rvalue))) {
-        pa_log("[%s:%u] Value missing", pa_strnull(filename), line);
+    if (!(items = pa_split_spaces_strv(state->rvalue))) {
+        pa_log("[%s:%u] Value missing", state->filename, state->lineno);
         return -1;
     }
 
@@ -3747,13 +3625,13 @@ static int decibel_fix_parse_db_values(
 
         if (d == s) {
             /* item started with colon. */
-            pa_log("[%s:%u] No step value found in %s", filename, line, item);
+            pa_log("[%s:%u] No step value found in %s", state->filename, state->lineno, item);
             goto fail;
         }
 
         if (!*d || !*(d + 1)) {
             /* No colon found, or it was the last character in item. */
-            pa_log("[%s:%u] No dB value found in %s", filename, line, item);
+            pa_log("[%s:%u] No dB value found in %s", state->filename, state->lineno, item);
             goto fail;
         }
 
@@ -3762,22 +3640,22 @@ static int decibel_fix_parse_db_values(
         *d++ = '\0';
 
         if (pa_atou(s, &step) < 0) {
-            pa_log("[%s:%u] Invalid step value: %s", filename, line, s);
+            pa_log("[%s:%u] Invalid step value: %s", state->filename, state->lineno, s);
             goto fail;
         }
 
         if (pa_atod(d, &db) < 0) {
-            pa_log("[%s:%u] Invalid dB value: %s", filename, line, d);
+            pa_log("[%s:%u] Invalid dB value: %s", state->filename, state->lineno, d);
             goto fail;
         }
 
         if (step <= prev_step && i != 1) {
-            pa_log("[%s:%u] Step value %u not greater than the previous value %u", filename, line, step, prev_step);
+            pa_log("[%s:%u] Step value %u not greater than the previous value %u", state->filename, state->lineno, step, prev_step);
             goto fail;
         }
 
         if (db < prev_db && i != 1) {
-            pa_log("[%s:%u] Decibel value %0.2f less than the previous value %0.2f", filename, line, db, prev_db);
+            pa_log("[%s:%u] Decibel value %0.2f less than the previous value %0.2f", state->filename, state->lineno, db, prev_db);
             goto fail;
         }
 
diff --git a/src/modules/module-augment-properties.c b/src/modules/module-augment-properties.c
index f280eae..3c4811d 100644
--- a/src/modules/module-augment-properties.c
+++ b/src/modules/module-augment-properties.c
@@ -78,19 +78,15 @@ static void rule_free(struct rule *r) {
     pa_xfree(r);
 }
 
-static int parse_properties(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    struct rule *r = userdata;
+static int parse_properties(pa_config_parser_state *state) {
+    struct rule *r;
     pa_proplist *n;
 
-    if (!(n = pa_proplist_from_string(rvalue)))
+    pa_assert(state);
+
+    r = state->userdata;
+
+    if (!(n = pa_proplist_from_string(state->rvalue)))
         return -1;
 
     if (r->proplist) {
@@ -102,20 +98,16 @@ static int parse_properties(
     return 0;
 }
 
-static int parse_categories(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
-    struct rule *r = userdata;
-    const char *state = NULL;
+static int parse_categories(pa_config_parser_state *state) {
+    struct rule *r;
+    const char *split_state = NULL;
     char *c;
 
-    while ((c = pa_split(rvalue, ";", &state))) {
+    pa_assert(state);
+
+    r = state->userdata;
+
+    while ((c = pa_split(state->rvalue, ";", &split_state))) {
 
         if (pa_streq(c, "Game")) {
             pa_xfree(r->role);
@@ -131,27 +123,13 @@ static int parse_categories(
     return 0;
 }
 
-static int check_type(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
+static int check_type(pa_config_parser_state *state) {
+    pa_assert(state);
 
-    return pa_streq(rvalue, "Application") ? 0 : -1;
+    return pa_streq(state->rvalue, "Application") ? 0 : -1;
 }
 
-static int catch_all(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const char *lvalue,
-        const char *rvalue,
-        void *data,
-        void *userdata) {
-
+static int catch_all(pa_config_parser_state *state) {
     return 0;
 }
 
diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c
index 41849c2..95c21f0 100644
--- a/src/pulsecore/conf-parser.c
+++ b/src/pulsecore/conf-parser.c
@@ -39,20 +39,8 @@
 #define WHITESPACE " \t\n"
 #define COMMENTS "#;\n"
 
-struct parser_state {
-    const char *filename;
-    unsigned lineno;
-    char *section;
-    const pa_config_item *item_table;
-    char buf[4096];
-    void *userdata;
-
-    char *lvalue;
-    char *rvalue;
-};
-
 /* Run the user supplied parser for an assignment */
-static int next_assignment(struct parser_state *state) {
+static int next_assignment(pa_config_parser_state *state) {
     const pa_config_item *item;
 
     pa_assert(state);
@@ -68,7 +56,9 @@ static int next_assignment(struct parser_state *state) {
         if (item->section && !pa_streq(state->section, item->section))
             continue;
 
-        return item->parse(state->filename, state->lineno, state->section, state->lvalue, state->rvalue, item->data, state->userdata);
+        state->data = item->data;
+
+        return item->parse(state);
     }
 
     pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", state->filename, state->lineno, state->lvalue, pa_strna(state->section));
@@ -77,7 +67,7 @@ static int next_assignment(struct parser_state *state) {
 }
 
 /* Parse a variable assignment line */
-static int parse_line(struct parser_state *state) {
+static int parse_line(pa_config_parser_state *state) {
     char *c;
 
     state->lvalue = state->buf + strspn(state->buf, WHITESPACE);
@@ -141,7 +131,7 @@ static int parse_line(struct parser_state *state) {
 int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) {
     int r = -1;
     pa_bool_t do_close = !f;
-    struct parser_state state;
+    pa_config_parser_state state;
 
     pa_assert(filename);
     pa_assert(t);
@@ -188,17 +178,16 @@ finish:
     return r;
 }
 
-int pa_config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    int *i = data;
+int pa_config_parse_int(pa_config_parser_state *state) {
+    int *i;
     int32_t k;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    i = state->data;
 
-    if (pa_atoi(rvalue, &k) < 0) {
-        pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+    if (pa_atoi(state->rvalue, &k) < 0) {
+        pa_log("[%s:%u] Failed to parse numeric value: %s", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -206,17 +195,16 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *section
     return 0;
 }
 
-int pa_config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    unsigned *u = data;
+int pa_config_parse_unsigned(pa_config_parser_state *state) {
+    unsigned *u;
     uint32_t k;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    u = state->data;
 
-    if (pa_atou(rvalue, &k) < 0) {
-        pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+    if (pa_atou(state->rvalue, &k) < 0) {
+        pa_log("[%s:%u] Failed to parse numeric value: %s", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -224,17 +212,16 @@ int pa_config_parse_unsigned(const char *filename, unsigned line, const char *se
     return 0;
 }
 
-int pa_config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    size_t *i = data;
+int pa_config_parse_size(pa_config_parser_state *state) {
+    size_t *i;
     uint32_t k;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    i = state->data;
 
-    if (pa_atou(rvalue, &k) < 0) {
-        pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+    if (pa_atou(state->rvalue, &k) < 0) {
+        pa_log("[%s:%u] Failed to parse numeric value: %s", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -242,17 +229,16 @@ int pa_config_parse_size(const char *filename, unsigned line, const char *sectio
     return 0;
 }
 
-int pa_config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+int pa_config_parse_bool(pa_config_parser_state *state) {
     int k;
-    pa_bool_t *b = data;
+    pa_bool_t *b;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    b = state->data;
 
-    if ((k = pa_parse_boolean(rvalue)) < 0) {
-        pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
+    if ((k = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -261,22 +247,16 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *sectio
     return 0;
 }
 
-int pa_config_parse_not_bool(
-        const char *filename, unsigned line,
-        const char *section,
-        const char *lvalue, const char *rvalue,
-        void *data, void *userdata) {
-
+int pa_config_parse_not_bool(pa_config_parser_state *state) {
     int k;
-    pa_bool_t *b = data;
+    pa_bool_t *b;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    b = state->data;
 
-    if ((k = pa_parse_boolean(rvalue)) < 0) {
-        pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
+    if ((k = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue);
         return -1;
     }
 
@@ -285,15 +265,14 @@ int pa_config_parse_not_bool(
     return 0;
 }
 
-int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    char **s = data;
+int pa_config_parse_string(pa_config_parser_state *state) {
+    char **s;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    s = state->data;
 
     pa_xfree(*s);
-    *s = *rvalue ? pa_xstrdup(rvalue) : NULL;
+    *s = *state->rvalue ? pa_xstrdup(state->rvalue) : NULL;
     return 0;
 }
diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h
index c6c8a14..1344121 100644
--- a/src/pulsecore/conf-parser.h
+++ b/src/pulsecore/conf-parser.h
@@ -27,7 +27,9 @@
 /* An abstract parser for simple, line based, shallow configuration
  * files consisting of variable assignments only. */
 
-typedef int (*pa_config_parser_cb_t)(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+typedef struct pa_config_parser_state pa_config_parser_state;
+
+typedef int (*pa_config_parser_cb_t)(pa_config_parser_state *state);
 
 /* Wraps info for parsing a specific configuration variable */
 typedef struct pa_config_item {
@@ -37,17 +39,31 @@ typedef struct pa_config_item {
     const char *section;
 } pa_config_item;
 
+struct pa_config_parser_state {
+    const char *filename;
+    unsigned lineno;
+    char *section;
+    char *lvalue;
+    char *rvalue;
+    void *data; /* The data pointer of the current pa_config_item. */
+    void *userdata; /* The pointer that was given to pa_config_parse(). */
+
+    /* Private data to be used only by conf-parser.c. */
+    const pa_config_item *item_table;
+    char buf[4096];
+};
+
 /* 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);
 
 /* 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);
-int pa_config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int pa_config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int pa_config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int pa_config_parse_not_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int pa_config_parse_int(pa_config_parser_state *state);
+int pa_config_parse_unsigned(pa_config_parser_state *state);
+int pa_config_parse_size(pa_config_parser_state *state);
+int pa_config_parse_bool(pa_config_parser_state *state);
+int pa_config_parse_not_bool(pa_config_parser_state *state);
+int pa_config_parse_string(pa_config_parser_state *state);
 
 #endif

commit 9a1647500c0b2b79e381bb38ae75841a7ad4be9f
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Fri Apr 13 14:48:25 2012 +0300

    conf-parser: Pass parser state in a struct instead of function parameters.
    
    I don't like long function parameter lists, and I plan to
    add some more state data to the parser which would make the
    parameter lists even longer without this refactoring.

diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c
index 7152955..41849c2 100644
--- a/src/pulsecore/conf-parser.c
+++ b/src/pulsecore/conf-parser.c
@@ -39,104 +39,109 @@
 #define WHITESPACE " \t\n"
 #define COMMENTS "#;\n"
 
+struct parser_state {
+    const char *filename;
+    unsigned lineno;
+    char *section;
+    const pa_config_item *item_table;
+    char buf[4096];
+    void *userdata;
+
+    char *lvalue;
+    char *rvalue;
+};
+
 /* Run the user supplied parser for an assignment */
-static int next_assignment(
-        const char *filename,
-        unsigned line,
-        const char *section,
-        const pa_config_item *t,
-        const char *lvalue,
-        const char *rvalue,
-        void *userdata) {
+static int next_assignment(struct parser_state *state) {
+    const pa_config_item *item;
 
-    pa_assert(filename);
-    pa_assert(t);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
+    pa_assert(state);
 
-    for (; t->parse; t++) {
+    for (item = state->item_table; item->parse; item++) {
 
-        if (t->lvalue && !pa_streq(lvalue, t->lvalue))
+        if (item->lvalue && !pa_streq(state->lvalue, item->lvalue))
             continue;
 
-        if (t->section && !section)
+        if (item->section && !state->section)
             continue;
 
-        if (t->section && !pa_streq(section, t->section))
+        if (item->section && !pa_streq(state->section, item->section))
             continue;
 
-        return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
+        return item->parse(state->filename, state->lineno, state->section, state->lvalue, state->rvalue, item->data, state->userdata);
     }
 
-    pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", filename, line, lvalue, pa_strna(section));
+    pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", state->filename, state->lineno, state->lvalue, pa_strna(state->section));
 
     return -1;
 }
 
 /* Parse a variable assignment line */
-static int parse_line(const char *filename, unsigned line, char **section, const pa_config_item *t, char *l, void *userdata) {
-    char *e, *c, *b;
+static int parse_line(struct parser_state *state) {
+    char *c;
 
-    b = l+strspn(l, WHITESPACE);
+    state->lvalue = state->buf + strspn(state->buf, WHITESPACE);
 
-    if ((c = strpbrk(b, COMMENTS)))
+    if ((c = strpbrk(state->lvalue, COMMENTS)))
         *c = 0;
 
-    if (!*b)
+    if (!*state->lvalue)
         return 0;
 
-    if (pa_startswith(b, ".include ")) {
+    if (pa_startswith(state->lvalue, ".include ")) {
         char *path = NULL, *fn;
         int r;
 
-        fn = pa_strip(b+9);
+        fn = pa_strip(state->lvalue + 9);
         if (!pa_is_path_absolute(fn)) {
             const char *k;
-            if ((k = strrchr(filename, '/'))) {
-                char *dir = pa_xstrndup(filename, k-filename);
+            if ((k = strrchr(state->filename, '/'))) {
+                char *dir = pa_xstrndup(state->filename, k - state->filename);
                 fn = path = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", dir, fn);
                 pa_xfree(dir);
             }
         }
 
-        r = pa_config_parse(fn, NULL, t, userdata);
+        r = pa_config_parse(fn, NULL, state->item_table, state->userdata);
         pa_xfree(path);
         return r;
     }
 
-    if (*b == '[') {
+    if (*state->lvalue == '[') {
         size_t k;
 
-        k = strlen(b);
+        k = strlen(state->lvalue);
         pa_assert(k > 0);
 
-        if (b[k-1] != ']') {
-            pa_log("[%s:%u] Invalid section header.", filename, line);
+        if (state->lvalue[k-1] != ']') {
+            pa_log("[%s:%u] Invalid section header.", state->filename, state->lineno);
             return -1;
         }
 
-        pa_xfree(*section);
-        *section = pa_xstrndup(b+1, k-2);
+        pa_xfree(state->section);
+        state->section = pa_xstrndup(state->lvalue + 1, k-2);
         return 0;
     }
 
-    if (!(e = strchr(b, '='))) {
-        pa_log("[%s:%u] Missing '='.", filename, line);
+    if (!(state->rvalue = strchr(state->lvalue, '='))) {
+        pa_log("[%s:%u] Missing '='.", state->filename, state->lineno);
         return -1;
     }
 
-    *e = 0;
-    e++;
+    *state->rvalue = 0;
+    state->rvalue++;
+
+    state->lvalue = pa_strip(state->lvalue);
+    state->rvalue = pa_strip(state->rvalue);
 
-    return next_assignment(filename, line, *section, t, pa_strip(b), pa_strip(e), userdata);
+    return next_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 r = -1;
-    unsigned line = 0;
     pa_bool_t do_close = !f;
-    char *section = NULL;
+    struct parser_state state;
 
     pa_assert(filename);
     pa_assert(t);
@@ -152,10 +157,13 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
         goto finish;
     }
 
-    while (!feof(f)) {
-        char l[4096];
+    pa_zero(state);
+    state.filename = filename;
+    state.item_table = t;
+    state.userdata = userdata;
 
-        if (!fgets(l, sizeof(l), f)) {
+    while (!feof(f)) {
+        if (!fgets(state.buf, sizeof(state.buf), f)) {
             if (feof(f))
                 break;
 
@@ -163,14 +171,16 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
             goto finish;
         }
 
-        if (parse_line(filename, ++line, &section, t, l, userdata) < 0)
+        state.lineno++;
+
+        if (parse_line(&state) < 0)
             goto finish;
     }
 
     r = 0;
 
 finish:
-    pa_xfree(section);
+    pa_xfree(state.section);
 
     if (do_close && f)
         fclose(f);



More information about the pulseaudio-commits mailing list