X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/364786ee8c16765da9c634f2293a152744cb2f85..8872c238ba6748c76455ecc6827b83ebcb1dd469:/src/pulsecore/modargs.c diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 4a30f52a..d48a2c8e 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -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 @@ -31,27 +31,31 @@ #include #include -#include -#include -#include -#include #include #include #include "modargs.h" +struct pa_modargs { + pa_hashmap *raw; + pa_hashmap *unescaped; +}; + 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; + char *raw; - pa_assert(map); + pa_assert(ma); + pa_assert(ma->raw); + pa_assert(ma->unescaped); 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; @@ -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 (strcmp(*v, key) == 0) + if (pa_streq(*v, key)) break; if (!*v) { @@ -70,10 +74,21 @@ 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->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; } @@ -84,18 +99,22 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { KEY, VALUE_START, VALUE_SIMPLE, + VALUE_SIMPLE_ESCAPED, VALUE_DOUBLE_QUOTES, - VALUE_TICKS + 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; + pa_modargs *ma = pa_xnew(pa_modargs, 1); - map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + 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 (pa_modargs*) map; + return ma; state = WHITESPACE; @@ -121,7 +140,7 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { key_len++; break; - case VALUE_START: + case VALUE_START: if (*p == '\'') { state = VALUE_TICKS; value = p+1; @@ -131,9 +150,16 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { 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) + if (add_key_value(ma, + 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; @@ -143,52 +169,85 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { case VALUE_SIMPLE: if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + 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_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_xstrndup(value, value_len), valid_keys) < 0) + 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(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + 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) + if (add_key_value(ma, 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) + 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: - pa_modargs_free((pa_modargs*) map); + pa_modargs_free(ma); return NULL; } -static void free_func(void *p, void*userdata) { +static void free_func(void *p) { struct entry *e = p; pa_assert(e); @@ -198,25 +257,41 @@ static void free_func(void *p, void*userdata) { } 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) { - pa_hashmap *map = (pa_hashmap*) ma; 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; } -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); + + 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))) @@ -231,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; - pa_assert(ma); - pa_assert(key); pa_assert(value); if (!(v = pa_modargs_get_value(ma, key, NULL))) @@ -248,8 +321,6 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *val const char *v; int r; - pa_assert(ma); - pa_assert(key); pa_assert(value); if (!(v = pa_modargs_get_value(ma, key, NULL))) @@ -265,12 +336,39 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *val 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; - pa_assert(ma); pa_assert(rss); ss = *rss; @@ -298,11 +396,23 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { 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; - pa_assert(ma); pa_assert(rmap); map = *rmap; @@ -327,7 +437,6 @@ int pa_modargs_get_sample_spec_and_channel_map( pa_sample_spec ss; pa_channel_map map; - pa_assert(ma); pa_assert(rss); pa_assert(rmap); @@ -344,11 +453,46 @@ int pa_modargs_get_sample_spec_and_channel_map( 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; } + +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; +}