Merge commit 'origin/master-tx'
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / modargs.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <pulse/xmalloc.h>
31
32 #include <pulsecore/hashmap.h>
33 #include <pulsecore/idxset.h>
34 #include <pulsecore/sample-util.h>
35 #include <pulsecore/namereg.h>
36 #include <pulsecore/sink.h>
37 #include <pulsecore/source.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/macro.h>
40
41 #include "modargs.h"
42
43 struct entry {
44     char *key, *value;
45 };
46
47 static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
48     struct entry *e;
49
50     pa_assert(map);
51     pa_assert(key);
52     pa_assert(value);
53
54     if (pa_hashmap_get(map, key)) {
55         pa_xfree(key);
56         pa_xfree(value);
57         return -1;
58     }
59
60     if (valid_keys) {
61         const char*const* v;
62         for (v = valid_keys; *v; v++)
63             if (strcmp(*v, key) == 0)
64                 break;
65
66         if (!*v) {
67             pa_xfree(key);
68             pa_xfree(value);
69             return -1;
70         }
71     }
72
73     e = pa_xnew(struct entry, 1);
74     e->key = key;
75     e->value = value;
76     pa_hashmap_put(map, key, e);
77
78     return 0;
79 }
80
81 pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
82     enum {
83         WHITESPACE,
84         KEY,
85         VALUE_START,
86         VALUE_SIMPLE,
87         VALUE_SIMPLE_ESCAPED,
88         VALUE_DOUBLE_QUOTES,
89         VALUE_DOUBLE_QUOTES_ESCAPED,
90         VALUE_TICKS,
91         VALUE_TICKS_ESCAPED
92     } state;
93
94     const char *p, *key = NULL, *value = NULL;
95     size_t key_len = 0, value_len = 0;
96     pa_hashmap *map;
97
98     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
99
100     if (!args)
101         return (pa_modargs*) map;
102
103     state = WHITESPACE;
104
105     for (p = args; *p; p++) {
106         switch (state) {
107
108             case WHITESPACE:
109                 if (*p == '=')
110                     goto fail;
111                 else if (!isspace(*p)) {
112                     key = p;
113                     state = KEY;
114                     key_len = 1;
115                 }
116                 break;
117
118             case KEY:
119                 if (*p == '=')
120                     state = VALUE_START;
121                 else if (isspace(*p))
122                     goto fail;
123                 else
124                     key_len++;
125                 break;
126
127             case  VALUE_START:
128                 if (*p == '\'') {
129                     state = VALUE_TICKS;
130                     value = p+1;
131                     value_len = 0;
132                 } else if (*p == '"') {
133                     state = VALUE_DOUBLE_QUOTES;
134                     value = p+1;
135                     value_len = 0;
136                 } else if (isspace(*p)) {
137                     if (add_key_value(map,
138                                       pa_xstrndup(key, key_len),
139                                       pa_xstrdup(""),
140                                       valid_keys) < 0)
141                         goto fail;
142                     state = WHITESPACE;
143                 } else if (*p == '\\') {
144                     state = VALUE_SIMPLE_ESCAPED;
145                     value = p;
146                     value_len = 1;
147                 } else {
148                     state = VALUE_SIMPLE;
149                     value = p;
150                     value_len = 1;
151                 }
152                 break;
153
154             case VALUE_SIMPLE:
155                 if (isspace(*p)) {
156                     if (add_key_value(map,
157                                       pa_xstrndup(key, key_len),
158                                       pa_unescape(pa_xstrndup(value, value_len)),
159                                       valid_keys) < 0)
160                         goto fail;
161                     state = WHITESPACE;
162                 } else if (*p == '\\') {
163                     state = VALUE_SIMPLE_ESCAPED;
164                     value_len++;
165                 } else
166                     value_len++;
167                 break;
168
169             case VALUE_SIMPLE_ESCAPED:
170                 state = VALUE_SIMPLE;
171                 value_len++;
172                 break;
173
174             case VALUE_DOUBLE_QUOTES:
175                 if (*p == '"') {
176                     if (add_key_value(map,
177                                       pa_xstrndup(key, key_len),
178                                       pa_unescape(pa_xstrndup(value, value_len)),
179                                       valid_keys) < 0)
180                         goto fail;
181                     state = WHITESPACE;
182                 } else if (*p == '\\') {
183                     state = VALUE_DOUBLE_QUOTES_ESCAPED;
184                     value_len++;
185                 } else
186                     value_len++;
187                 break;
188
189             case VALUE_DOUBLE_QUOTES_ESCAPED:
190                 state = VALUE_DOUBLE_QUOTES;
191                 value_len++;
192                 break;
193
194             case VALUE_TICKS:
195                 if (*p == '\'') {
196                     if (add_key_value(map,
197                                       pa_xstrndup(key, key_len),
198                                       pa_unescape(pa_xstrndup(value, value_len)),
199                                       valid_keys) < 0)
200                         goto fail;
201                     state = WHITESPACE;
202                 } else if (*p == '\\') {
203                     state = VALUE_TICKS_ESCAPED;
204                     value_len++;
205                 } else
206                     value_len++;
207                 break;
208
209             case VALUE_TICKS_ESCAPED:
210                 state = VALUE_TICKS;
211                 value_len++;
212                 break;
213         }
214     }
215
216     if (state == VALUE_START) {
217         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
218             goto fail;
219     } else if (state == VALUE_SIMPLE) {
220         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0)
221             goto fail;
222     } else if (state != WHITESPACE)
223         goto fail;
224
225     return (pa_modargs*) map;
226
227 fail:
228
229     pa_modargs_free((pa_modargs*) map);
230
231     return NULL;
232 }
233
234 static void free_func(void *p, void*userdata) {
235     struct entry *e = p;
236     pa_assert(e);
237
238     pa_xfree(e->key);
239     pa_xfree(e->value);
240     pa_xfree(e);
241 }
242
243 void pa_modargs_free(pa_modargs*ma) {
244     pa_hashmap *map = (pa_hashmap*) ma;
245     pa_hashmap_free(map, free_func, NULL);
246 }
247
248 const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) {
249     pa_hashmap *map = (pa_hashmap*) ma;
250     struct entry*e;
251
252     if (!(e = pa_hashmap_get(map, key)))
253         return def;
254
255     return e->value;
256 }
257
258 int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
259     const char *v;
260
261     pa_assert(ma);
262     pa_assert(key);
263     pa_assert(value);
264
265     if (!(v = pa_modargs_get_value(ma, key, NULL)))
266         return 0;
267
268     if (pa_atou(v, value) < 0)
269         return -1;
270
271     return 0;
272 }
273
274 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
275     const char *v;
276
277     pa_assert(ma);
278     pa_assert(key);
279     pa_assert(value);
280
281     if (!(v = pa_modargs_get_value(ma, key, NULL)))
282         return 0;
283
284     if (pa_atoi(v, value) < 0)
285         return -1;
286
287     return 0;
288 }
289
290 int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *value) {
291     const char *v;
292     int r;
293
294     pa_assert(ma);
295     pa_assert(key);
296     pa_assert(value);
297
298     if (!(v = pa_modargs_get_value(ma, key, NULL)))
299         return 0;
300
301     if (!*v)
302         return -1;
303
304     if ((r = pa_parse_boolean(v)) < 0)
305         return -1;
306
307     *value = r;
308     return 0;
309 }
310
311 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
312     const char *format;
313     uint32_t channels;
314     pa_sample_spec ss;
315
316     pa_assert(ma);
317     pa_assert(rss);
318
319     ss = *rss;
320     if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0 ||
321         ss.rate <= 0 ||
322         ss.rate > PA_RATE_MAX)
323         return -1;
324
325     channels = ss.channels;
326     if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0 ||
327         channels <= 0 ||
328         channels >= PA_CHANNELS_MAX)
329         return -1;
330     ss.channels = (uint8_t) channels;
331
332     if ((format = pa_modargs_get_value(ma, "format", NULL)))
333         if ((ss.format = pa_parse_sample_format(format)) < 0)
334             return -1;
335
336     if (!pa_sample_spec_valid(&ss))
337         return -1;
338
339     *rss = ss;
340
341     return 0;
342 }
343
344 int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
345     pa_channel_map map;
346     const char *cm;
347
348     pa_assert(ma);
349     pa_assert(rmap);
350
351     map = *rmap;
352
353     if ((cm = pa_modargs_get_value(ma, name ? name : "channel_map", NULL)))
354         if (!pa_channel_map_parse(&map, cm))
355             return -1;
356
357     if (!pa_channel_map_valid(&map))
358         return -1;
359
360     *rmap = map;
361     return 0;
362 }
363
364 int pa_modargs_get_sample_spec_and_channel_map(
365         pa_modargs *ma,
366         pa_sample_spec *rss,
367         pa_channel_map *rmap,
368         pa_channel_map_def_t def) {
369
370     pa_sample_spec ss;
371     pa_channel_map map;
372
373     pa_assert(ma);
374     pa_assert(rss);
375     pa_assert(rmap);
376
377     ss = *rss;
378
379     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
380         return -1;
381
382     map = *rmap;
383
384     if (ss.channels != map.channels)
385         pa_channel_map_init_extend(&map, ss.channels, def);
386
387     if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
388         return -1;
389
390     if (map.channels != ss.channels)
391         return -1;
392
393     *rmap = map;
394     *rss = ss;
395
396     return 0;
397 }
398
399 int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa_update_mode_t m) {
400     const char *v;
401     pa_proplist *n;
402
403     pa_assert(ma);
404     pa_assert(name);
405     pa_assert(p);
406
407     if (!(v = pa_modargs_get_value(ma, name, NULL)))
408         return 0;
409
410     if (!(n = pa_proplist_from_string(v)))
411         return -1;
412
413     pa_proplist_update(p, m, n);
414     pa_proplist_free(n);
415
416     return 0;
417 }