Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / src / pulsecore / modargs.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2004-2006 Lennart Poettering
7
8   PulseAudio is free software; you can redistribute it and/or modify
9   it under the terms of the GNU Lesser General Public License as published
10   by the Free Software Foundation; either version 2 of the License,
11   or (at your option) any later version.
12
13   PulseAudio is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with PulseAudio; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21   USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <ctype.h>
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <pulse/xmalloc.h>
34
35 #include <pulsecore/hashmap.h>
36 #include <pulsecore/idxset.h>
37 #include <pulsecore/sample-util.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/sink.h>
40 #include <pulsecore/source.h>
41 #include <pulsecore/core-util.h>
42
43 #include "modargs.h"
44
45 struct entry {
46     char *key, *value;
47 };
48
49 static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
50     struct entry *e;
51     assert(map && key && value);
52
53     if (valid_keys) {
54         const char*const* v;
55         for (v = valid_keys; *v; v++)
56             if (strcmp(*v, key) == 0)
57                 break;
58
59         if (!*v) {
60             pa_xfree(key);
61             pa_xfree(value);
62             return -1;
63         }
64     }
65
66     e = pa_xmalloc(sizeof(struct entry));
67     e->key = key;
68     e->value = value;
69     pa_hashmap_put(map, key, e);
70     return 0;
71 }
72
73 pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
74     pa_hashmap *map = NULL;
75
76     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
77     assert(map);
78
79     if (args) {
80         enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
81         const char *p, *key, *value;
82         size_t key_len = 0, value_len = 0;
83
84         key = value = NULL;
85         state = WHITESPACE;
86         for (p = args; *p; p++) {
87             switch (state) {
88                 case WHITESPACE:
89                     if (*p == '=')
90                         goto fail;
91                     else if (!isspace(*p)) {
92                         key = p;
93                         state = KEY;
94                         key_len = 1;
95                     }
96                     break;
97                 case KEY:
98                     if (*p == '=')
99                         state = VALUE_START;
100                     else
101                         key_len++;
102                     break;
103                 case  VALUE_START:
104                     if (*p == '\'') {
105                         state = VALUE_TICKS;
106                         value = p+1;
107                         value_len = 0;
108                     } else if (*p == '"') {
109                         state = VALUE_DOUBLE_QUOTES;
110                         value = p+1;
111                         value_len = 0;
112                     } else if (isspace(*p)) {
113                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
114                             goto fail;
115                         state = WHITESPACE;
116                     } else {
117                         state = VALUE_SIMPLE;
118                         value = p;
119                         value_len = 1;
120                     }
121                     break;
122                 case VALUE_SIMPLE:
123                     if (isspace(*p)) {
124                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
125                             goto fail;
126                         state = WHITESPACE;
127                     } else
128                         value_len++;
129                     break;
130                 case VALUE_DOUBLE_QUOTES:
131                     if (*p == '"') {
132                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
133                             goto fail;
134                         state = WHITESPACE;
135                     } else
136                         value_len++;
137                     break;
138                 case VALUE_TICKS:
139                     if (*p == '\'') {
140                         if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0)
141                             goto fail;
142                         state = WHITESPACE;
143                     } else
144                         value_len++;
145                     break;
146             }
147         }
148
149         if (state == VALUE_START) {
150             if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0)
151                 goto fail;
152         } else if (state == VALUE_SIMPLE) {
153             if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0)
154                 goto fail;
155         } else if (state != WHITESPACE)
156             goto fail;
157     }
158
159     return (pa_modargs*) map;
160
161 fail:
162
163     if (map)
164         pa_modargs_free((pa_modargs*) map);
165
166     return NULL;
167 }
168
169
170 static void free_func(void *p, PA_GCC_UNUSED void*userdata) {
171     struct entry *e = p;
172     assert(e);
173     pa_xfree(e->key);
174     pa_xfree(e->value);
175     pa_xfree(e);
176 }
177
178 void pa_modargs_free(pa_modargs*ma) {
179     pa_hashmap *map = (pa_hashmap*) ma;
180     pa_hashmap_free(map, free_func, NULL);
181 }
182
183 const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) {
184     pa_hashmap *map = (pa_hashmap*) ma;
185     struct entry*e;
186
187     if (!(e = pa_hashmap_get(map, key)))
188         return def;
189
190     return e->value;
191 }
192
193 int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
194     const char *v;
195     assert(ma && key && value);
196
197     if (!(v = pa_modargs_get_value(ma, key, NULL)))
198         return 0;
199
200     if (pa_atou(v, value) < 0)
201         return -1;
202
203     return 0;
204 }
205
206 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
207     const char *v;
208     assert(ma && key && value);
209
210     if (!(v = pa_modargs_get_value(ma, key, NULL)))
211         return 0;
212
213     if (pa_atoi(v, value) < 0)
214         return -1;
215
216     return 0;
217 }
218
219 int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) {
220     const char *v;
221     int r;
222     assert(ma && key && value);
223
224     if (!(v = pa_modargs_get_value(ma, key, NULL)))
225         return 0;
226
227     if (!*v)
228         return -1;
229
230     if ((r = pa_parse_boolean(v)) < 0)
231         return -1;
232
233     *value = r;
234     return 0;
235 }
236
237 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
238     const char *format;
239     uint32_t channels;
240     pa_sample_spec ss;
241     assert(ma && rss);
242
243 /*    DEBUG_TRAP;*/
244
245     ss = *rss;
246     if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
247         return -1;
248
249     channels = ss.channels;
250     if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0)
251         return -1;
252     ss.channels = (uint8_t) channels;
253
254     if ((format = pa_modargs_get_value(ma, "format", NULL)))
255         if ((ss.format = pa_parse_sample_format(format)) < 0)
256             return -1;
257
258     if (!pa_sample_spec_valid(&ss))
259         return -1;
260
261     *rss = ss;
262
263     return 0;
264 }
265
266 int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) {
267     pa_channel_map map;
268     const char *cm;
269
270     assert(ma);
271     assert(rmap);
272
273     map = *rmap;
274
275     if ((cm = pa_modargs_get_value(ma, "channel_map", NULL)))
276         if (!pa_channel_map_parse(&map, cm))
277             return -1;
278
279     if (!pa_channel_map_valid(&map))
280         return -1;
281
282     *rmap = map;
283     return 0;
284 }
285
286 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) {
287     pa_sample_spec ss;
288     pa_channel_map map;
289
290     assert(ma);
291     assert(rss);
292     assert(rmap);
293
294     ss = *rss;
295
296     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
297         return -1;
298
299     if (!pa_channel_map_init_auto(&map, ss.channels, def))
300         map.channels = 0;
301
302     if (pa_modargs_get_channel_map(ma, &map) < 0)
303         return -1;
304
305     if (map.channels != ss.channels)
306         return -1;
307
308     *rmap = map;
309     *rss = ss;
310
311     return 0;
312 }