]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/modargs.c
Fighting rewinds: Reduce calls to handle_seek
[pulseaudio] / src / pulsecore / modargs.c
index 7ce3dd087c401a4499c741a7001385a42d0f9a1e..e78cdb9a8ca425f842d62389aaae3c88d9e1a6c6 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id$ */
-
 /***
   This file is part of PulseAudio.
 
 /***
   This file is part of PulseAudio.
 
@@ -7,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
@@ -48,11 +46,17 @@ struct entry {
 
 static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
     struct entry *e;
 
 static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
     struct entry *e;
-    
+
     pa_assert(map);
     pa_assert(key);
     pa_assert(value);
 
     pa_assert(map);
     pa_assert(key);
     pa_assert(value);
 
+    if (pa_hashmap_get(map, key)) {
+        pa_xfree(key);
+        pa_xfree(value);
+        return -1;
+    }
+
     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++)
@@ -70,109 +74,167 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co
     e->key = key;
     e->value = value;
     pa_hashmap_put(map, key, e);
     e->key = key;
     e->value = value;
     pa_hashmap_put(map, 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;
+    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_hashmap *map;
 
     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 
 
     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 == '=')
+    if (!args)
+        return (pa_modargs*) map;
+
+    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(map,
+                                      pa_xstrndup(key, key_len),
+                                      pa_xstrdup(""),
+                                      valid_keys) < 0)
+                        goto fail;
+                    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(map,
+                                      pa_xstrndup(key, key_len),
+                                      pa_unescape(pa_xstrndup(value, value_len)),
+                                      valid_keys) < 0)
+                        goto fail;
+                    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(map,
+                                      pa_xstrndup(key, key_len),
+                                      pa_unescape(pa_xstrndup(value, value_len)),
+                                      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
-                        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_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(map,
+                                      pa_xstrndup(key, key_len),
+                                      pa_unescape(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(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
             goto fail;
             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)
+        goto fail;
 
     return (pa_modargs*) map;
 
 fail:
 
 
     return (pa_modargs*) map;
 
 fail:
 
-    if (map)
-        pa_modargs_free((pa_modargs*) map);
+    pa_modargs_free((pa_modargs*) map);
 
     return NULL;
 }
 
 
     return NULL;
 }
 
-static void free_func(void *p, PA_GCC_UNUSED void*userdata) {
+static void free_func(void *p, void*userdata) {
     struct entry *e = p;
     pa_assert(e);
     struct entry *e = p;
     pa_assert(e);
-    
+
     pa_xfree(e->key);
     pa_xfree(e->value);
     pa_xfree(e);
     pa_xfree(e->key);
     pa_xfree(e->value);
     pa_xfree(e);
@@ -225,7 +287,7 @@ int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
     return 0;
 }
 
     return 0;
 }
 
-int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) {
+int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *value) {
     const char *v;
     int r;
 
     const char *v;
     int r;
 
@@ -250,16 +312,20 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
     const char *format;
     uint32_t channels;
     pa_sample_spec ss;
     const char *format;
     uint32_t channels;
     pa_sample_spec ss;
-    
+
     pa_assert(ma);
     pa_assert(rss);
 
     ss = *rss;
     pa_assert(ma);
     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;
 
@@ -295,7 +361,12 @@ 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;
 
@@ -308,8 +379,10 @@ 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;
 
-    if (!pa_channel_map_init_auto(&map, ss.channels, def))
-        map.channels = 0;
+    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;
@@ -322,3 +395,33 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r
 
     return 0;
 }
 
     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 = pa_modargs_get_value(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) {
+    pa_hashmap *map = (pa_hashmap*) ma;
+    struct entry *e;
+
+    if (!(e = pa_hashmap_iterate(map, state, NULL)))
+        return NULL;
+
+    return e->key;
+}