63cc779dd49af5c26724fc898c57583e2a4bb5bb
[profile/ivi/pulseaudio.git] / src / polypcore / modargs.c
1 /* $Id$ */
2
3 /***
4   This file is part of polypaudio.
5  
6   polypaudio 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 of the License,
9   or (at your option) any later version.
10  
11   polypaudio 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 polypaudio; 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 <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <polyp/xmalloc.h>
32
33 #include <polypcore/hashmap.h>
34 #include <polypcore/idxset.h>
35 #include <polypcore/sample-util.h>
36 #include <polypcore/namereg.h>
37 #include <polypcore/sink.h>
38 #include <polypcore/source.h>
39 #include <polypcore/util.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     assert(map && key && value);
50
51     if (valid_keys) {
52         const char*const* v;
53         for (v = valid_keys; *v; v++)
54             if (strcmp(*v, key) == 0)
55                 break;
56
57         if (!*v) {
58             pa_xfree(key);
59             pa_xfree(value);
60             return -1;
61         }
62     }
63     
64     e = pa_xmalloc(sizeof(struct entry));
65     e->key = key;
66     e->value = value;
67     pa_hashmap_put(map, key, e);
68     return 0;
69 }
70
71 pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
72     pa_hashmap *map = NULL;
73
74     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
75     assert(map);
76
77     if (args) {
78         enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
79         const char *p, *key, *value;
80         size_t key_len = 0, value_len = 0;
81         
82         key = value = NULL;
83         state = WHITESPACE;
84         for (p = args; *p; p++) {
85             switch (state) {
86                 case WHITESPACE:
87                     if (*p == '=')
88                         goto fail;
89                     else if (!isspace(*p)) {
90                         key = p;
91                         state = KEY;
92                         key_len = 1;
93                     }
94                     break;
95                 case KEY:
96                     if (*p == '=')
97                         state = VALUE_START;
98                     else
99                         key_len++;
100                     break;
101                 case  VALUE_START:
102                     if (*p == '\'') {
103                         state = VALUE_TICKS;
104                         value = p+1;
105                         value_len = 0;
106                     } else if (*p == '"') {
107                         state = VALUE_DOUBLE_QUOTES;
108                         value = p+1;
109                         value_len = 0;
110                     } else if (isspace(*p)) {
111                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
112                             goto fail;
113                         state = WHITESPACE;
114                     } else {
115                         state = VALUE_SIMPLE;
116                         value = p;
117                         value_len = 1;
118                     }
119                     break;
120                 case VALUE_SIMPLE:
121                     if (isspace(*p)) {
122                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
123                             goto fail;
124                         state = WHITESPACE;
125                     } else
126                         value_len++;
127                     break;
128                 case VALUE_DOUBLE_QUOTES:
129                     if (*p == '"') {
130                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
131                             goto fail;
132                         state = WHITESPACE;
133                     } else
134                         value_len++;
135                     break;
136                 case VALUE_TICKS:
137                     if (*p == '\'') {
138                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
139                             goto fail;
140                         state = WHITESPACE;
141                     } else
142                         value_len++;
143                     break;
144             }
145         }
146
147         if (state == VALUE_START) {
148             if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
149                 goto fail;
150         } else if (state == VALUE_SIMPLE) {
151             if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0)
152                 goto fail;
153         } else if (state != WHITESPACE)
154             goto fail;
155     }
156
157     return (pa_modargs*) map;
158
159 fail:
160
161     if (map)
162         pa_modargs_free((pa_modargs*) map);
163                       
164     return NULL;
165 }
166
167
168 static void free_func(void *p, PA_GCC_UNUSED void*userdata) {
169     struct entry *e = p;
170     assert(e);
171     pa_xfree(e->key);
172     pa_xfree(e->value);
173     pa_xfree(e);
174 }
175
176 void pa_modargs_free(pa_modargs*ma) {
177     pa_hashmap *map = (pa_hashmap*) ma;
178     pa_hashmap_free(map, free_func, NULL);
179 }
180
181 const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) {
182     pa_hashmap *map = (pa_hashmap*) ma;
183     struct entry*e;
184
185     if (!(e = pa_hashmap_get(map, key)))
186         return def;
187
188     return e->value;
189 }
190
191 int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
192     const char *v;
193     assert(ma && key && value);
194
195     if (!(v = pa_modargs_get_value(ma, key, NULL)))
196         return 0;
197
198     if (pa_atou(v, value) < 0)
199         return -1;
200
201     return 0;
202 }
203
204 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
205     const char *v;
206     assert(ma && key && value);
207
208     if (!(v = pa_modargs_get_value(ma, key, NULL)))
209         return 0;
210
211     if (pa_atoi(v, value) < 0)
212         return -1;
213             
214     return 0;
215 }
216
217 int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) {
218     const char *v;
219     int r;
220     assert(ma && key && value);
221
222     if (!(v = pa_modargs_get_value(ma, key, NULL)))
223         return 0;
224
225     if (!*v)
226         return -1;
227
228     if ((r = pa_parse_boolean(v)) < 0)
229         return -1;
230
231     *value = r;
232     return 0;
233 }
234
235 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
236     const char *format;
237     uint32_t channels;
238     pa_sample_spec ss;
239     assert(ma && rss);
240
241 /*    DEBUG_TRAP;*/
242     
243     ss = *rss;
244     if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
245         return -1;
246
247     channels = ss.channels;
248     if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0)
249         return -1;
250     ss.channels = (uint8_t) channels;
251
252     if ((format = pa_modargs_get_value(ma, "format", NULL)))
253         if ((ss.format = pa_parse_sample_format(format)) < 0)
254             return -1;
255
256     if (!pa_sample_spec_valid(&ss))
257         return -1;
258
259     *rss = ss;
260     
261     return 0;
262 }
263
264 int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) {
265     pa_channel_map map;
266     const char *cm;
267     
268     assert(ma);
269     assert(rmap);
270
271     map = *rmap;
272
273     if ((cm = pa_modargs_get_value(ma, "channel_map", NULL)))
274         if (!pa_channel_map_parse(&map, cm))
275             return -1;
276
277     if (!pa_channel_map_valid(&map))
278         return -1;
279
280     *rmap = map;
281     return 0;
282 }
283
284 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) {
285     pa_sample_spec ss;
286     pa_channel_map map;
287     
288     assert(ma);
289     assert(rss);
290     assert(rmap);
291
292     ss = *rss;
293
294     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
295         return -1;
296
297     if (!pa_channel_map_init_auto(&map, ss.channels, def))
298         map.channels = 0;
299
300     if (pa_modargs_get_channel_map(ma, &map) < 0)
301         return -1;
302
303     if (map.channels != ss.channels)
304         return -1;
305
306     *rmap = map;
307     *rss = ss;
308
309     return 0;
310 }