]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/conf-parser.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / src / pulsecore / conf-parser.c
index 58ceab9171162309dc10810b066253332fb3e353..200252bb7ad567dd2d180395b5f893d36d385cdc 100644 (file)
@@ -5,7 +5,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 #define COMMENTS "#;\n"
 
 /* Run the user supplied parser for an assignment */
-static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
-    pa_assert(filename);
-    pa_assert(t);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
+static int normal_assignment(pa_config_parser_state *state) {
+    const pa_config_item *item;
+
+    pa_assert(state);
+
+    for (item = state->item_table; item->parse; item++) {
+
+        if (item->lvalue && !pa_streq(state->lvalue, item->lvalue))
+            continue;
+
+        if (item->section && !state->section)
+            continue;
+
+        if (item->section && !pa_streq(state->section, item->section))
+            continue;
+
+        state->data = item->data;
 
-    for (; t->parse; t++)
-        if (!strcmp(lvalue, t->lvalue))
-            return t->parse(filename, line, lvalue, rvalue, t->data, userdata);
+        return item->parse(state);
+    }
 
-    pa_log("[%s:%u] Unknown lvalue '%s'.", filename, line, lvalue);
+    pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", state->filename, state->lineno, state->lvalue, pa_strna(state->section));
 
     return -1;
 }
 
-/* Returns non-zero when c is contained in s */
-static int in_string(char c, const char *s) {
-    pa_assert(s);
+/* Parse a proplist entry. */
+static int proplist_assignment(pa_config_parser_state *state) {
+    pa_assert(state);
+    pa_assert(state->proplist);
 
-    for (; *s; s++)
-        if (*s == c)
-            return 1;
+    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;
 }
 
-/* Remove all whitepsapce from the beginning and the end of *s. *s may
- * be modified. */
-static char *strip(char *s) {
-    char *b = s+strspn(s, WHITESPACE);
-    char *e, *l = NULL;
+/* Parse a variable assignment line */
+static int parse_line(pa_config_parser_state *state) {
+    char *c;
 
-    for (e = b; *e; e++)
-        if (!in_string(*e, WHITESPACE))
-            l = e;
+    state->lvalue = state->buf + strspn(state->buf, WHITESPACE);
 
-    if (l)
-        *(l+1) = 0;
+    if ((c = strpbrk(state->lvalue, COMMENTS)))
+        *c = 0;
 
-    return b;
-}
+    if (!*state->lvalue)
+        return 0;
 
-/* Parse a variable assignment line */
-static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) {
-    char *e, *c, *b = l+strspn(l, WHITESPACE);
+    if (pa_startswith(state->lvalue, ".include ")) {
+        char *path = NULL, *fn;
+        int r;
+
+        fn = pa_strip(state->lvalue + 9);
+        if (!pa_is_path_absolute(fn)) {
+            const char *k;
+            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);
+            }
+        }
 
-    if ((c = strpbrk(b, COMMENTS)))
-        *c = 0;
+        r = pa_config_parse(fn, NULL, state->item_table, state->proplist, state->userdata);
+        pa_xfree(path);
+        return r;
+    }
+
+    if (*state->lvalue == '[') {
+        size_t k;
+
+        k = strlen(state->lvalue);
+        pa_assert(k > 0);
+
+        if (state->lvalue[k-1] != ']') {
+            pa_log("[%s:%u] Invalid section header.", state->filename, state->lineno);
+            return -1;
+        }
+
+        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;
 
-    if (!*b)
         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, t, strip(b), strip(e), userdata);
+    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;
-    unsigned line = 0;
-    int do_close = !f;
+    bool do_close = !f;
+    pa_config_parser_state state;
 
     pa_assert(filename);
     pa_assert(t);
 
-    if (!f && !(f = fopen(filename, "r"))) {
+    pa_zero(state);
+
+    if (!f && !(f = pa_fopen_cloexec(filename, "r"))) {
         if (errno == ENOENT) {
+            pa_log_debug("Failed to open configuration file '%s': %s", filename, pa_cstrerror(errno));
             r = 0;
             goto finish;
         }
 
-        pa_log_warn("Failed to open configuration file '%s': %s",
-            filename, pa_cstrerror(errno));
+        pa_log_warn("Failed to open configuration file '%s': %s", filename, pa_cstrerror(errno));
         goto finish;
     }
 
+    state.filename = filename;
+    state.item_table = t;
+    state.userdata = userdata;
+
+    if (proplist)
+        state.proplist = pa_proplist_new();
+
     while (!feof(f)) {
-        char l[256];
-        if (!fgets(l, sizeof(l), f)) {
+        if (!fgets(state.buf, sizeof(state.buf), f)) {
             if (feof(f))
                 break;
 
-            pa_log_warn("Failed to read configuration file '%s': %s",
-                filename, pa_cstrerror(errno));
+            pa_log_warn("Failed to read configuration file '%s': %s", filename, pa_cstrerror(errno));
             goto finish;
         }
 
-        if (parse_line(filename, ++line, t,  l, userdata) < 0)
+        state.lineno++;
+
+        if (parse_line(&state) < 0)
             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)
         fclose(f);
@@ -148,17 +215,16 @@ finish:
     return r;
 }
 
-int pa_config_parse_int(const char *filename, unsigned line, 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;
     }
 
@@ -166,17 +232,33 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue,
     return 0;
 }
 
-int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    size_t *i = 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(state->rvalue, &k) < 0) {
+        pa_log("[%s:%u] Failed to parse numeric value: %s", state->filename, state->lineno, state->rvalue);
+        return -1;
+    }
+
+    *u = (unsigned) k;
+    return 0;
+}
+
+int pa_config_parse_size(pa_config_parser_state *state) {
+    size_t *i;
+    uint32_t k;
+
+    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;
     }
 
@@ -184,17 +266,16 @@ int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue
     return 0;
 }
 
-int pa_config_parse_bool(const char *filename, unsigned line, 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;
+    bool *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;
     }
 
@@ -203,15 +284,32 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue
     return 0;
 }
 
-int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
-    char **s = data;
+int pa_config_parse_not_bool(pa_config_parser_state *state) {
+    int k;
+    bool *b;
 
-    pa_assert(filename);
-    pa_assert(lvalue);
-    pa_assert(rvalue);
-    pa_assert(data);
+    pa_assert(state);
+
+    b = state->data;
+
+    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;
+    }
+
+    *b = !k;
+
+    return 0;
+}
+
+int pa_config_parse_string(pa_config_parser_state *state) {
+    char **s;
+
+    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;
 }