blob: 0d8c96550628f8a33b11285dbd1f47d634b20d6d [file] [log] [blame]
Dima Zavin0fad7d02011-03-24 11:11:06 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "str_params"
18//#define LOG_NDEBUG 0
19
20#define _GNU_SOURCE 1
21#include <errno.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <cutils/hashmap.h>
28#include <cutils/log.h>
29#include <cutils/memory.h>
30
31#include <cutils/str_parms.h>
32
33struct str_parms {
34 Hashmap *map;
35};
36
37
38static bool str_eq(void *key_a, void *key_b)
39{
40 return !strcmp((const char *)key_a, (const char *)key_b);
41}
42
43/* use djb hash unless we find it inadequate */
44static int str_hash_fn(void *str)
45{
46 uint32_t hash = 5381;
47 char *p;
48
49 for (p = str; p && *p; p++)
50 hash = ((hash << 5) + hash) + *p;
51 return (int)hash;
52}
53
54struct str_parms *str_parms_create(void)
55{
56 struct str_parms *str_parms;
57
58 str_parms = calloc(1, sizeof(struct str_parms));
59 if (!str_parms)
60 return NULL;
61
62 str_parms->map = hashmapCreate(5, str_hash_fn, str_eq);
63 if (!str_parms->map)
64 goto err;
65
66 return str_parms;
67
68err:
69 free(str_parms);
70 return NULL;
71}
72
73static bool remove_pair(void *key, void *value, void *context)
74{
75 struct str_parms *str_parms = context;
76
77 hashmapRemove(str_parms->map, key);
78 free(key);
79 free(value);
80 return true;
81}
82
83void str_parms_destroy(struct str_parms *str_parms)
84{
85 hashmapForEach(str_parms->map, remove_pair, str_parms);
86 hashmapFree(str_parms->map);
87 free(str_parms);
88}
89
90struct str_parms *str_parms_create_str(const char *_string)
91{
92 struct str_parms *str_parms;
93 char *str;
94 char *kvpair;
95 char *tmpstr;
96 int items = 0;
97
98 str_parms = str_parms_create();
99 if (!str_parms)
100 goto err_create_str_parms;
101
102 str = strdup(_string);
103 if (!str)
104 goto err_strdup;
105
Steve Block69f4cd72011-10-20 11:54:09 +0100106 ALOGV("%s: source string == '%s'\n", __func__, _string);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700107
108 kvpair = strtok_r(str, ";", &tmpstr);
109 while (kvpair && *kvpair) {
110 char *eq = strchr(kvpair, '='); /* would love strchrnul */
111 char *value;
112 char *key;
113 void *old_val;
114
115 if (eq == kvpair)
116 goto next_pair;
117
118 if (eq) {
119 key = strndup(kvpair, eq - kvpair);
120 if (*(++eq))
121 value = strdup(eq);
122 else
123 value = strdup("");
124 } else {
125 key = strdup(kvpair);
126 value = strdup("");
127 }
128
129 /* if we replaced a value, free it */
130 old_val = hashmapPut(str_parms->map, key, value);
131 if (old_val)
132 free(old_val);
133
134 items++;
135next_pair:
136 kvpair = strtok_r(NULL, ";", &tmpstr);
137 }
138
139 if (!items)
Steve Block69f4cd72011-10-20 11:54:09 +0100140 ALOGV("%s: no items found in string\n", __func__);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700141
142 free(str);
143
144 return str_parms;
145
146err_strdup:
147 str_parms_destroy(str_parms);
148err_create_str_parms:
149 return NULL;
150}
151
152void str_parms_del(struct str_parms *str_parms, const char *key)
153{
154 hashmapRemove(str_parms->map, (void *)key);
155}
156
157int str_parms_add_str(struct str_parms *str_parms, const char *key,
158 const char *value)
159{
160 void *old_val;
Dima Zavin70b93032012-03-12 11:01:16 -0700161 void *tmp_key;
162 void *tmp_val;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700163
Dima Zavin70b93032012-03-12 11:01:16 -0700164 tmp_key = strdup(key);
165 tmp_val = strdup(value);
166 old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700167
168 if (old_val) {
169 free(old_val);
170 } else if (errno == ENOMEM) {
Dima Zavin70b93032012-03-12 11:01:16 -0700171 free(tmp_key);
172 free(tmp_val);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700173 return -ENOMEM;
174 }
175 return 0;
176}
177
178int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
179{
180 char val_str[12];
181 int ret;
182
183 ret = snprintf(val_str, sizeof(val_str), "%d", value);
184 if (ret < 0)
185 return -EINVAL;
186
187 ret = str_parms_add_str(str_parms, key, val_str);
188 return ret;
189}
190
191int str_parms_add_float(struct str_parms *str_parms, const char *key,
192 float value)
193{
194 char val_str[23];
195 int ret;
196
197 ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
198 if (ret < 0)
199 return -EINVAL;
200
201 ret = str_parms_add_str(str_parms, key, val_str);
202 return ret;
203}
204
205int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
206 int len)
207{
208 char *value;
209
210 value = hashmapGet(str_parms->map, (void *)key);
211 if (value)
212 return strlcpy(val, value, len);
213
214 return -ENOENT;
215}
216
217int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
218{
219 char *value;
220 char *end;
221
222 value = hashmapGet(str_parms->map, (void *)key);
223 if (!value)
224 return -ENOENT;
225
226 *val = (int)strtol(value, &end, 0);
227 if (*value != '\0' && *end == '\0')
228 return 0;
229
230 return -EINVAL;
231}
232
233int str_parms_get_float(struct str_parms *str_parms, const char *key,
234 float *val)
235{
236 float out;
237 char *value;
238 char *end;
239
240 value = hashmapGet(str_parms->map, (void *)key);
241 if (!value)
242 return -ENOENT;
243
244 out = strtof(value, &end);
245 if (*value != '\0' && *end == '\0')
246 return 0;
247
248 return -EINVAL;
249}
250
251static bool combine_strings(void *key, void *value, void *context)
252{
253 char **old_str = context;
254 char *new_str;
255 int ret;
256
257 ret = asprintf(&new_str, "%s%s%s=%s",
258 *old_str ? *old_str : "",
259 *old_str ? ";" : "",
260 (char *)key,
261 (char *)value);
262 if (*old_str)
263 free(*old_str);
264
265 if (ret >= 0) {
266 *old_str = new_str;
267 return true;
268 }
269
270 *old_str = NULL;
271 return false;
272}
273
274char *str_parms_to_str(struct str_parms *str_parms)
275{
276 char *str = NULL;
277
278 if (hashmapSize(str_parms->map) > 0)
279 hashmapForEach(str_parms->map, combine_strings, &str);
280 else
281 str = strdup("");
282 return str;
283}
284
285static bool dump_entry(void *key, void *value, void *context)
286{
Steve Blockfe71a612012-01-04 19:19:03 +0000287 ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700288 return true;
289}
290
291void str_parms_dump(struct str_parms *str_parms)
292{
293 hashmapForEach(str_parms->map, dump_entry, str_parms);
294}
295
296#ifdef TEST_STR_PARMS
297static void test_str_parms_str(const char *str)
298{
299 struct str_parms *str_parms;
300 char *out_str;
301 int ret;
302
303 str_parms = str_parms_create_str(str);
304 str_parms_dump(str_parms);
305 out_str = str_parms_to_str(str_parms);
306 str_parms_destroy(str_parms);
Steve Blockfe71a612012-01-04 19:19:03 +0000307 ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700308 free(out_str);
309}
310
311int main(void)
312{
313 struct str_parms *str_parms;
314
315 test_str_parms_str("");
316 test_str_parms_str(";");
317 test_str_parms_str("=");
318 test_str_parms_str("=;");
319 test_str_parms_str("=bar");
320 test_str_parms_str("=bar;");
321 test_str_parms_str("foo=");
322 test_str_parms_str("foo=;");
323 test_str_parms_str("foo=bar");
324 test_str_parms_str("foo=bar;");
325 test_str_parms_str("foo=bar;baz");
326 test_str_parms_str("foo=bar;baz=");
327 test_str_parms_str("foo=bar;baz=bat");
328 test_str_parms_str("foo=bar;baz=bat;");
329
330 return 0;
331}
332#endif