remove global exported variables:
[profile/ivi/pulseaudio.git] / src / modargs.c
1 #include <ctype.h>
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "hashmap.h"
7 #include "modargs.h"
8 #include "idxset.h"
9 #include "sample-util.h"
10 #include "namereg.h"
11 #include "sink.h"
12 #include "source.h"
13
14 struct pa_modargs;
15
16 struct entry {
17     char *key, *value;
18 };
19
20 static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const* valid_keys) {
21     struct entry *e;
22     assert(map && key && value);
23
24     if (valid_keys) {
25         const char*const* v;
26         for (v = valid_keys; *v; v++)
27             if (strcmp(*v, key) == 0)
28                 break;
29
30         if (!*v) {
31             free(key);
32             free(value);
33             return -1;
34         }
35     }
36     
37     e = malloc(sizeof(struct entry));
38     assert(e);
39     e->key = key;
40     e->value = value;
41     pa_hashmap_put(map, key, e);
42     return 0;
43 }
44
45 struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
46     struct pa_hashmap *map = NULL;
47
48     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
49     assert(map);
50
51     if (args) {
52         enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
53         const char *p, *key, *value;
54         size_t key_len, value_len;
55         
56         key = value = NULL;
57         state = WHITESPACE;
58         for (p = args; *p; p++) {
59             switch (state) {
60                 case WHITESPACE:
61                     if (*p == '=')
62                         goto fail;
63                     else if (!isspace(*p)) {
64                         key = p;
65                         state = KEY;
66                         key_len = 1;
67                     }
68                     break;
69                 case KEY:
70                     if (*p == '=')
71                         state = VALUE_START;
72                     else
73                         key_len++;
74                     break;
75                 case  VALUE_START:
76                     if (*p == '\'') {
77                         state = VALUE_TICKS;
78                         value = p+1;
79                         value_len = 0;
80                     } else if (*p == '"') {
81                         state = VALUE_DOUBLE_QUOTES;
82                         value = p+1;
83                         value_len = 0;
84                     } else if (isspace(*p)) {
85                         if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0)
86                             goto fail;
87                         state = WHITESPACE;
88                     } else {
89                         state = VALUE_SIMPLE;
90                         value = p;
91                         value_len = 1;
92                     }
93                     break;
94                 case VALUE_SIMPLE:
95                     if (isspace(*p)) {
96                         if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0)
97                             goto fail;
98                         state = WHITESPACE;
99                     } else
100                         value_len++;
101                     break;
102                 case VALUE_DOUBLE_QUOTES:
103                     if (*p == '"') {
104                         if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0)
105                             goto fail;
106                         state = WHITESPACE;
107                     } else
108                         value_len++;
109                     break;
110                 case VALUE_TICKS:
111                     if (*p == '\'') {
112                         if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0)
113                             goto fail;
114                         state = WHITESPACE;
115                     } else
116                         value_len++;
117                     break;
118             }
119         }
120
121         if (state == VALUE_START) {
122             if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0)
123                 goto fail;
124         } else if (state == VALUE_SIMPLE) {
125             if (add_key_value(map, strndup(key, key_len), strdup(value), valid_keys) < 0)
126                 goto fail;
127         } else if (state != WHITESPACE)
128             goto fail;
129     }
130
131     return (struct pa_modargs*) map;
132
133 fail:
134
135     if (map)
136         pa_modargs_free((struct pa_modargs*) map);
137                       
138     return NULL;
139 }
140
141
142 static void free_func(void *p, void*userdata) {
143     struct entry *e = p;
144     assert(e);
145     free(e->key);
146     free(e->value);
147     free(e);
148 }
149
150 void pa_modargs_free(struct pa_modargs*ma) {
151     struct pa_hashmap *map = (struct pa_hashmap*) ma;
152     pa_hashmap_free(map, free_func, NULL);
153 }
154
155 const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def) {
156     struct pa_hashmap *map = (struct pa_hashmap*) ma;
157     struct entry*e;
158
159     if (!(e = pa_hashmap_get(map, key)))
160         return def;
161
162     return e->value;
163 }
164
165 int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) {
166     const char *v;
167     char *e;
168     unsigned long l;
169     assert(ma && key && value);
170
171     if (!(v = pa_modargs_get_value(ma, key, NULL)))
172         return 0;
173
174     if (!*v)
175         return -1;
176     
177     l = strtoul(v, &e, 0);
178     if (*e)
179         return -1;
180
181     *value = (uint32_t) l;
182     return 0;
183 }
184
185 int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) {
186     const char *format;
187     uint32_t channels;
188     struct pa_sample_spec ss;
189     assert(ma && rss);
190
191     ss = *rss;
192     if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
193         return -1;
194
195     channels = ss.channels;
196     if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0)
197         return -1;
198     ss.channels = (uint8_t) channels;
199
200     if ((format = pa_modargs_get_value(ma, "format", NULL))) {
201         if (strcmp(format, "s16le") == 0)
202             ss.format = PA_SAMPLE_S16LE;
203         else if (strcmp(format, "s16be") == 0)
204             ss.format = PA_SAMPLE_S16BE;
205         else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0)
206             ss.format = PA_SAMPLE_S16NE;
207         else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0)
208             ss.format = PA_SAMPLE_U8;
209         else if (strcmp(format, "float32") == 0)
210             ss.format = PA_SAMPLE_FLOAT32;
211         else if (strcmp(format, "ulaw") == 0)
212             ss.format = PA_SAMPLE_ULAW;
213         else if (strcmp(format, "alaw") == 0)
214             ss.format = PA_SAMPLE_ALAW;
215         else
216             return -1;
217     }
218
219     if (!pa_sample_spec_valid(&ss))
220         return -1;
221
222     *rss = ss;
223     
224     return 0;
225 }
226
227 int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) {
228     const char *t;
229     assert(ma && index);
230     
231     if (!(t = pa_modargs_get_value(ma, "source", NULL)))
232         *index = PA_IDXSET_INVALID;
233     else {
234         struct pa_source *source;
235         if (!(source = pa_namereg_get(c, t, PA_NAMEREG_SOURCE)))
236             return -1;
237
238         *index = source->index;
239     }
240
241     return 0;
242 }
243
244 int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) {
245     const char *t;
246     assert(ma && index);
247
248     if (!(t = pa_modargs_get_value(ma, "sink", NULL)))
249         *index = PA_IDXSET_INVALID;
250     else {
251         struct pa_sink *sink;
252         if (!(sink = pa_namereg_get(c, t, PA_NAMEREG_SINK)))
253             return -1;
254
255         *index = sink->index;
256     }
257
258     return 0;
259 }