]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/modargs.c
hashmap: Use pa_free_cb_t instead of pa_free2_cb_t
[pulseaudio] / src / pulsecore / modargs.c
index 9e60125e8e7c629a3ba6755f0193fc6da4ad166f..d48a2c8e147cd7aa90cb96d2f7e5cb21ba39d098 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
 
   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
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 
 #include <pulsecore/hashmap.h>
 #include <pulsecore/idxset.h>
 
 #include <pulsecore/hashmap.h>
 #include <pulsecore/idxset.h>
-#include <pulsecore/sample-util.h>
-#include <pulsecore/namereg.h>
-#include <pulsecore/sink.h>
-#include <pulsecore/source.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/macro.h>
 
 #include "modargs.h"
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/macro.h>
 
 #include "modargs.h"
 
+struct pa_modargs {
+    pa_hashmap *raw;
+    pa_hashmap *unescaped;
+};
+
 struct entry {
     char *key, *value;
 };
 
 struct entry {
     char *key, *value;
 };
 
-static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
+static int add_key_value(pa_modargs *ma, char *key, char *value, const char* const valid_keys[]) {
     struct entry *e;
     struct entry *e;
+    char *raw;
 
 
-    pa_assert(map);
+    pa_assert(ma);
+    pa_assert(ma->raw);
+    pa_assert(ma->unescaped);
     pa_assert(key);
     pa_assert(value);
 
     pa_assert(key);
     pa_assert(value);
 
-    if (pa_hashmap_get(map, key)) {
+    if (pa_hashmap_get(ma->unescaped, key)) {
         pa_xfree(key);
         pa_xfree(value);
         return -1;
         pa_xfree(key);
         pa_xfree(value);
         return -1;
@@ -60,7 +64,7 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co
     if (valid_keys) {
         const char*const* v;
         for (v = valid_keys; *v; v++)
     if (valid_keys) {
         const char*const* v;
         for (v = valid_keys; *v; v++)
-            if (strcmp(*v, key) == 0)
+            if (pa_streq(*v, key))
                 break;
 
         if (!*v) {
                 break;
 
         if (!*v) {
@@ -70,120 +74,180 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co
         }
     }
 
         }
     }
 
+    raw = pa_xstrdup(value);
+
     e = pa_xnew(struct entry, 1);
     e->key = key;
     e = pa_xnew(struct entry, 1);
     e->key = key;
-    e->value = value;
-    pa_hashmap_put(map, key, e);
+    e->value = pa_unescape(value);
+    pa_hashmap_put(ma->unescaped, key, e);
+
+    if (pa_streq(raw, value))
+        pa_xfree(raw);
+    else {
+        e = pa_xnew(struct entry, 1);
+        e->key = pa_xstrdup(key);
+        e->value = raw;
+        pa_hashmap_put(ma->raw, key, e);
+    }
 
     return 0;
 }
 
 pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
 
     return 0;
 }
 
 pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
-    pa_hashmap *map = NULL;
-
-    map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-    if (args) {
-        enum {
-            WHITESPACE,
-            KEY,
-            VALUE_START,
-            VALUE_SIMPLE,
-            VALUE_DOUBLE_QUOTES,
-            VALUE_TICKS
-        } state;
-
-        const char *p, *key, *value;
-        size_t key_len = 0, value_len = 0;
-
-        key = value = NULL;
-        state = WHITESPACE;
-        for (p = args; *p; p++) {
-            switch (state) {
-                case WHITESPACE:
-                    if (*p == '=')
+    enum {
+        WHITESPACE,
+        KEY,
+        VALUE_START,
+        VALUE_SIMPLE,
+        VALUE_SIMPLE_ESCAPED,
+        VALUE_DOUBLE_QUOTES,
+        VALUE_DOUBLE_QUOTES_ESCAPED,
+        VALUE_TICKS,
+        VALUE_TICKS_ESCAPED
+    } state;
+
+    const char *p, *key = NULL, *value = NULL;
+    size_t key_len = 0, value_len = 0;
+    pa_modargs *ma = pa_xnew(pa_modargs, 1);
+
+    ma->raw = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    ma->unescaped = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
+    if (!args)
+        return ma;
+
+    state = WHITESPACE;
+
+    for (p = args; *p; p++) {
+        switch (state) {
+
+            case WHITESPACE:
+                if (*p == '=')
+                    goto fail;
+                else if (!isspace(*p)) {
+                    key = p;
+                    state = KEY;
+                    key_len = 1;
+                }
+                break;
+
+            case KEY:
+                if (*p == '=')
+                    state = VALUE_START;
+                else if (isspace(*p))
+                    goto fail;
+                else
+                    key_len++;
+                break;
+
+            case VALUE_START:
+                if (*p == '\'') {
+                    state = VALUE_TICKS;
+                    value = p+1;
+                    value_len = 0;
+                } else if (*p == '"') {
+                    state = VALUE_DOUBLE_QUOTES;
+                    value = p+1;
+                    value_len = 0;
+                } else if (isspace(*p)) {
+                    if (add_key_value(ma,
+                                      pa_xstrndup(key, key_len),
+                                      pa_xstrdup(""),
+                                      valid_keys) < 0)
                         goto fail;
                         goto fail;
-                    else if (!isspace(*p)) {
-                        key = p;
-                        state = KEY;
-                        key_len = 1;
-                    }
-                    break;
-                case KEY:
-                    if (*p == '=')
-                        state = VALUE_START;
-                    else if (isspace(*p))
+                    state = WHITESPACE;
+                } else if (*p == '\\') {
+                    state = VALUE_SIMPLE_ESCAPED;
+                    value = p;
+                    value_len = 1;
+                } else {
+                    state = VALUE_SIMPLE;
+                    value = p;
+                    value_len = 1;
+                }
+                break;
+
+            case VALUE_SIMPLE:
+                if (isspace(*p)) {
+                    if (add_key_value(ma,
+                                      pa_xstrndup(key, key_len),
+                                      pa_xstrndup(value, value_len),
+                                      valid_keys) < 0)
                         goto fail;
                         goto fail;
-                    else
-                        key_len++;
-                    break;
-                case  VALUE_START:
-                    if (*p == '\'') {
-                        state = VALUE_TICKS;
-                        value = p+1;
-                        value_len = 0;
-                    } else if (*p == '"') {
-                        state = VALUE_DOUBLE_QUOTES;
-                        value = p+1;
-                        value_len = 0;
-                    } else if (isspace(*p)) {
-                        if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
-                            goto fail;
-                        state = WHITESPACE;
-                    } else {
-                        state = VALUE_SIMPLE;
-                        value = p;
-                        value_len = 1;
-                    }
-                    break;
-                case VALUE_SIMPLE:
-                    if (isspace(*p)) {
-                        if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
-                            goto fail;
-                        state = WHITESPACE;
-                    } else
-                        value_len++;
-                    break;
-                case VALUE_DOUBLE_QUOTES:
-                    if (*p == '"') {
-                        if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
-                            goto fail;
-                        state = WHITESPACE;
-                    } else
-                        value_len++;
-                    break;
-                case VALUE_TICKS:
-                    if (*p == '\'') {
-                        if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
-                            goto fail;
-                        state = WHITESPACE;
-                    } else
-                        value_len++;
-                    break;
-            }
+                    state = WHITESPACE;
+                } else if (*p == '\\') {
+                    state = VALUE_SIMPLE_ESCAPED;
+                    value_len++;
+                } else
+                    value_len++;
+                break;
+
+            case VALUE_SIMPLE_ESCAPED:
+                state = VALUE_SIMPLE;
+                value_len++;
+                break;
+
+            case VALUE_DOUBLE_QUOTES:
+                if (*p == '"') {
+                    if (add_key_value(ma,
+                                      pa_xstrndup(key, key_len),
+                                      pa_xstrndup(value, value_len),
+                                      valid_keys) < 0)
+                        goto fail;
+                    state = WHITESPACE;
+                } else if (*p == '\\') {
+                    state = VALUE_DOUBLE_QUOTES_ESCAPED;
+                    value_len++;
+                } else
+                    value_len++;
+                break;
+
+            case VALUE_DOUBLE_QUOTES_ESCAPED:
+                state = VALUE_DOUBLE_QUOTES;
+                value_len++;
+                break;
+
+            case VALUE_TICKS:
+                if (*p == '\'') {
+                    if (add_key_value(ma,
+                                      pa_xstrndup(key, key_len),
+                                      pa_xstrndup(value, value_len),
+                                      valid_keys) < 0)
+                        goto fail;
+                    state = WHITESPACE;
+                } else if (*p == '\\') {
+                    state = VALUE_TICKS_ESCAPED;
+                    value_len++;
+                } else
+                    value_len++;
+                break;
+
+            case VALUE_TICKS_ESCAPED:
+                state = VALUE_TICKS;
+                value_len++;
+                break;
         }
         }
+    }
 
 
-        if (state == VALUE_START) {
-            if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
-                goto fail;
-        } else if (state == VALUE_SIMPLE) {
-            if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0)
-                goto fail;
-        } else if (state != WHITESPACE)
+    if (state == VALUE_START) {
+        if (add_key_value(ma, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
             goto fail;
             goto fail;
-    }
+    } else if (state == VALUE_SIMPLE) {
+        if (add_key_value(ma, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0)
+            goto fail;
+    } else if (state != WHITESPACE)
+        goto fail;
 
 
-    return (pa_modargs*) map;
+    return ma;
 
 fail:
 
 
 fail:
 
-    if (map)
-        pa_modargs_free((pa_modargs*) map);
+    pa_modargs_free(ma);
 
     return NULL;
 }
 
 
     return NULL;
 }
 
-static void free_func(void *p, void*userdata) {
+static void free_func(void *p) {
     struct entry *e = p;
     pa_assert(e);
 
     struct entry *e = p;
     pa_assert(e);
 
@@ -193,25 +257,41 @@ static void free_func(void *p, void*userdata) {
 }
 
 void pa_modargs_free(pa_modargs*ma) {
 }
 
 void pa_modargs_free(pa_modargs*ma) {
-    pa_hashmap *map = (pa_hashmap*) ma;
-    pa_hashmap_free(map, free_func, NULL);
+    pa_assert(ma);
+
+    pa_hashmap_free(ma->raw, free_func);
+    pa_hashmap_free(ma->unescaped, free_func);
+    pa_xfree(ma);
 }
 
 const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) {
 }
 
 const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) {
-    pa_hashmap *map = (pa_hashmap*) ma;
     struct entry*e;
 
     struct entry*e;
 
-    if (!(e = pa_hashmap_get(map, key)))
+    pa_assert(ma);
+    pa_assert(key);
+
+    if (!(e = pa_hashmap_get(ma->unescaped, key)))
         return def;
 
     return e->value;
 }
 
         return def;
 
     return e->value;
 }
 
-int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
-    const char *v;
+static const char *modargs_get_value_raw(pa_modargs *ma, const char *key, const char *def) {
+    struct entry*e;
 
     pa_assert(ma);
     pa_assert(key);
 
     pa_assert(ma);
     pa_assert(key);
+
+    if (!(e = pa_hashmap_get(ma->raw, key)))
+        if (!(e = pa_hashmap_get(ma->unescaped, key)))
+            return def;
+
+    return e->value;
+}
+
+int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
+    const char *v;
+
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
@@ -226,8 +306,6 @@ int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
     const char *v;
 
 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
     const char *v;
 
-    pa_assert(ma);
-    pa_assert(key);
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
@@ -243,8 +321,6 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *val
     const char *v;
     int r;
 
     const char *v;
     int r;
 
-    pa_assert(ma);
-    pa_assert(key);
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
     pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
@@ -260,20 +336,51 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *val
     return 0;
 }
 
     return 0;
 }
 
+int pa_modargs_get_value_double(pa_modargs *ma, const char *key, double *value) {
+    const char *v;
+
+    pa_assert(value);
+
+    if (!(v = pa_modargs_get_value(ma, key, NULL)))
+        return 0;
+
+    if (pa_atod(v, value) < 0)
+        return -1;
+
+    return 0;
+}
+
+int pa_modargs_get_value_volume(pa_modargs *ma, const char *key, pa_volume_t *value) {
+    const char *v;
+
+    pa_assert(value);
+
+    if (!(v = pa_modargs_get_value(ma, key, NULL)))
+        return 0;
+
+    if (pa_parse_volume(v, value) < 0)
+        return -1;
+
+    return 0;
+}
+
 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
     const char *format;
     uint32_t channels;
     pa_sample_spec ss;
 
 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
     const char *format;
     uint32_t channels;
     pa_sample_spec ss;
 
-    pa_assert(ma);
     pa_assert(rss);
 
     ss = *rss;
     pa_assert(rss);
 
     ss = *rss;
-    if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
+    if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0 ||
+        ss.rate <= 0 ||
+        ss.rate > PA_RATE_MAX)
         return -1;
 
     channels = ss.channels;
         return -1;
 
     channels = ss.channels;
-    if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0)
+    if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0 ||
+        channels <= 0 ||
+        channels >= PA_CHANNELS_MAX)
         return -1;
     ss.channels = (uint8_t) channels;
 
         return -1;
     ss.channels = (uint8_t) channels;
 
@@ -289,11 +396,23 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
     return 0;
 }
 
     return 0;
 }
 
+int pa_modargs_get_alternate_sample_rate(pa_modargs *ma, uint32_t *alternate_rate) {
+    pa_assert(ma);
+    pa_assert(alternate_rate);
+
+    if ((pa_modargs_get_value_u32(ma, "alternate_rate", alternate_rate)) < 0 ||
+        *alternate_rate <= 0 ||
+        *alternate_rate > PA_RATE_MAX ||
+        !((*alternate_rate % 4000 == 0) || (*alternate_rate % 11025 == 0)))
+        return -1;
+
+    return 0;
+}
+
 int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
     pa_channel_map map;
     const char *cm;
 
 int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
     pa_channel_map map;
     const char *cm;
 
-    pa_assert(ma);
     pa_assert(rmap);
 
     map = *rmap;
     pa_assert(rmap);
 
     map = *rmap;
@@ -309,11 +428,15 @@ int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map
     return 0;
 }
 
     return 0;
 }
 
-int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap, pa_channel_map_def_t def) {
+int pa_modargs_get_sample_spec_and_channel_map(
+        pa_modargs *ma,
+        pa_sample_spec *rss,
+        pa_channel_map *rmap,
+        pa_channel_map_def_t def) {
+
     pa_sample_spec ss;
     pa_channel_map map;
 
     pa_sample_spec ss;
     pa_channel_map map;
 
-    pa_assert(ma);
     pa_assert(rss);
     pa_assert(rmap);
 
     pa_assert(rss);
     pa_assert(rmap);
 
@@ -322,16 +445,54 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r
     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
         return -1;
 
     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
         return -1;
 
-    pa_channel_map_init_extend(&map, ss.channels, def);
+    map = *rmap;
+
+    if (ss.channels != map.channels)
+        pa_channel_map_init_extend(&map, ss.channels, def);
 
     if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
         return -1;
 
 
     if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
         return -1;
 
-    if (map.channels != ss.channels)
-        return -1;
+    if (map.channels != ss.channels) {
+        if (!pa_modargs_get_value(ma, "channels", NULL))
+            ss.channels = map.channels;
+        else
+            return -1;
+    }
 
     *rmap = map;
     *rss = ss;
 
     return 0;
 }
 
     *rmap = map;
     *rss = ss;
 
     return 0;
 }
+
+int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa_update_mode_t m) {
+    const char *v;
+    pa_proplist *n;
+
+    pa_assert(ma);
+    pa_assert(name);
+    pa_assert(p);
+
+    if (!(v = modargs_get_value_raw(ma, name, NULL)))
+        return 0;
+
+    if (!(n = pa_proplist_from_string(v)))
+        return -1;
+
+    pa_proplist_update(p, m, n);
+    pa_proplist_free(n);
+
+    return 0;
+}
+
+const char *pa_modargs_iterate(pa_modargs *ma, void **state) {
+    struct entry *e;
+
+    pa_assert(ma);
+
+    if (!(e = pa_hashmap_iterate(ma->unescaped, state, NULL)))
+        return NULL;
+
+    return e->key;
+}