blob: 4f23d09c5145f552a21e235102df71b5fcd9fbf7 [file] [log] [blame]
Dima Zavin0fad7d02011-03-24 11:11:06 -07001/*
Elliott Hughesaf98efb2015-04-02 13:36:54 -07002 * Copyright (C) 2011 The Android Open Source Project
Dima Zavin0fad7d02011-03-24 11:11:06 -07003 *
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>
Dima Zavin0fad7d02011-03-24 11:11:06 -070028#include <cutils/memory.h>
Dima Zavin0fad7d02011-03-24 11:11:06 -070029#include <cutils/str_parms.h>
Mark Salyzyn12717162014-04-29 15:49:14 -070030#include <log/log.h>
Dima Zavin0fad7d02011-03-24 11:11:06 -070031
Mark Salyzynba02cd12013-11-22 07:36:45 -080032#define UNUSED __attribute__((unused))
33
Dima Zavin0fad7d02011-03-24 11:11:06 -070034struct str_parms {
35 Hashmap *map;
36};
37
38
39static bool str_eq(void *key_a, void *key_b)
40{
41 return !strcmp((const char *)key_a, (const char *)key_b);
42}
43
44/* use djb hash unless we find it inadequate */
Nick Kralevich73904782015-08-26 10:40:00 -070045#ifdef __clang__
46__attribute__((no_sanitize("integer")))
47#endif
Dima Zavin0fad7d02011-03-24 11:11:06 -070048static int str_hash_fn(void *str)
49{
50 uint32_t hash = 5381;
51 char *p;
52
53 for (p = str; p && *p; p++)
54 hash = ((hash << 5) + hash) + *p;
55 return (int)hash;
56}
57
58struct str_parms *str_parms_create(void)
59{
60 struct str_parms *str_parms;
61
62 str_parms = calloc(1, sizeof(struct str_parms));
63 if (!str_parms)
64 return NULL;
65
66 str_parms->map = hashmapCreate(5, str_hash_fn, str_eq);
67 if (!str_parms->map)
68 goto err;
69
70 return str_parms;
71
72err:
73 free(str_parms);
74 return NULL;
75}
76
Dima Zavinefd75012012-03-14 23:12:40 -070077struct remove_ctxt {
78 struct str_parms *str_parms;
79 const char *key;
80};
81
Dima Zavin0fad7d02011-03-24 11:11:06 -070082static bool remove_pair(void *key, void *value, void *context)
83{
Dima Zavinefd75012012-03-14 23:12:40 -070084 struct remove_ctxt *ctxt = context;
85 bool should_continue;
Dima Zavin0fad7d02011-03-24 11:11:06 -070086
Dima Zavinefd75012012-03-14 23:12:40 -070087 /*
88 * - if key is not supplied, then we are removing all entries,
89 * so remove key and continue (i.e. return true)
90 * - if key is supplied and matches, then remove it and don't
91 * continue (return false). Otherwise, return true and keep searching
92 * for key.
93 *
94 */
95 if (!ctxt->key) {
96 should_continue = true;
97 goto do_remove;
98 } else if (!strcmp(ctxt->key, key)) {
99 should_continue = false;
100 goto do_remove;
101 }
102
103 return true;
104
105do_remove:
106 hashmapRemove(ctxt->str_parms->map, key);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700107 free(key);
108 free(value);
Dima Zavinefd75012012-03-14 23:12:40 -0700109 return should_continue;
110}
111
112void str_parms_del(struct str_parms *str_parms, const char *key)
113{
114 struct remove_ctxt ctxt = {
115 .str_parms = str_parms,
116 .key = key,
117 };
118 hashmapForEach(str_parms->map, remove_pair, &ctxt);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700119}
120
121void str_parms_destroy(struct str_parms *str_parms)
122{
Dima Zavinefd75012012-03-14 23:12:40 -0700123 struct remove_ctxt ctxt = {
124 .str_parms = str_parms,
125 };
126
127 hashmapForEach(str_parms->map, remove_pair, &ctxt);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700128 hashmapFree(str_parms->map);
129 free(str_parms);
130}
131
132struct str_parms *str_parms_create_str(const char *_string)
133{
134 struct str_parms *str_parms;
135 char *str;
136 char *kvpair;
137 char *tmpstr;
138 int items = 0;
139
140 str_parms = str_parms_create();
141 if (!str_parms)
142 goto err_create_str_parms;
143
144 str = strdup(_string);
145 if (!str)
146 goto err_strdup;
147
Steve Block69f4cd72011-10-20 11:54:09 +0100148 ALOGV("%s: source string == '%s'\n", __func__, _string);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700149
150 kvpair = strtok_r(str, ";", &tmpstr);
151 while (kvpair && *kvpair) {
152 char *eq = strchr(kvpair, '='); /* would love strchrnul */
153 char *value;
154 char *key;
155 void *old_val;
156
157 if (eq == kvpair)
158 goto next_pair;
159
160 if (eq) {
161 key = strndup(kvpair, eq - kvpair);
162 if (*(++eq))
163 value = strdup(eq);
164 else
165 value = strdup("");
166 } else {
167 key = strdup(kvpair);
168 value = strdup("");
169 }
170
171 /* if we replaced a value, free it */
172 old_val = hashmapPut(str_parms->map, key, value);
Dima Zavin86bfbe32012-03-14 23:10:06 -0700173 if (old_val) {
Dima Zavin0fad7d02011-03-24 11:11:06 -0700174 free(old_val);
Dima Zavin86bfbe32012-03-14 23:10:06 -0700175 free(key);
176 }
Dima Zavin0fad7d02011-03-24 11:11:06 -0700177
178 items++;
179next_pair:
180 kvpair = strtok_r(NULL, ";", &tmpstr);
181 }
182
183 if (!items)
Steve Block69f4cd72011-10-20 11:54:09 +0100184 ALOGV("%s: no items found in string\n", __func__);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700185
186 free(str);
187
188 return str_parms;
189
190err_strdup:
191 str_parms_destroy(str_parms);
192err_create_str_parms:
193 return NULL;
194}
195
Dima Zavin0fad7d02011-03-24 11:11:06 -0700196int str_parms_add_str(struct str_parms *str_parms, const char *key,
197 const char *value)
198{
Jens Gulind3c8d5b2014-03-06 18:15:43 +0100199 void *tmp_key = NULL;
200 void *tmp_val = NULL;
201 void *old_val = NULL;
202
203 // strdup and hashmapPut both set errno on failure.
204 // Set errno to 0 so we can recognize whether anything went wrong.
205 int saved_errno = errno;
206 errno = 0;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700207
Dima Zavin70b93032012-03-12 11:01:16 -0700208 tmp_key = strdup(key);
Jens Gulind3c8d5b2014-03-06 18:15:43 +0100209 if (tmp_key == NULL) {
210 goto clean_up;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700211 }
Jens Gulind3c8d5b2014-03-06 18:15:43 +0100212
213 tmp_val = strdup(value);
214 if (tmp_val == NULL) {
215 goto clean_up;
216 }
217
218 old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
219 if (old_val == NULL) {
220 // Did hashmapPut fail?
221 if (errno == ENOMEM) {
222 goto clean_up;
223 }
224 // For new keys, hashmap takes ownership of tmp_key and tmp_val.
225 tmp_key = tmp_val = NULL;
226 } else {
227 // For existing keys, hashmap takes ownership of tmp_val.
228 // (It also gives up ownership of old_val.)
229 tmp_val = NULL;
230 }
231
232clean_up:
233 free(tmp_key);
234 free(tmp_val);
235 free(old_val);
236 int result = -errno;
237 errno = saved_errno;
238 return result;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700239}
240
241int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
242{
243 char val_str[12];
244 int ret;
245
246 ret = snprintf(val_str, sizeof(val_str), "%d", value);
247 if (ret < 0)
248 return -EINVAL;
249
250 ret = str_parms_add_str(str_parms, key, val_str);
251 return ret;
252}
253
254int str_parms_add_float(struct str_parms *str_parms, const char *key,
255 float value)
256{
257 char val_str[23];
258 int ret;
259
260 ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
261 if (ret < 0)
262 return -EINVAL;
263
264 ret = str_parms_add_str(str_parms, key, val_str);
265 return ret;
266}
267
Paul McLean55c64072013-12-19 15:47:29 -0800268int str_parms_has_key(struct str_parms *str_parms, const char *key) {
269 return hashmapGet(str_parms->map, (void *)key) != NULL;
270}
271
Dima Zavin0fad7d02011-03-24 11:11:06 -0700272int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
273 int len)
274{
275 char *value;
276
277 value = hashmapGet(str_parms->map, (void *)key);
278 if (value)
279 return strlcpy(val, value, len);
280
281 return -ENOENT;
282}
283
284int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
285{
286 char *value;
287 char *end;
288
289 value = hashmapGet(str_parms->map, (void *)key);
290 if (!value)
291 return -ENOENT;
292
293 *val = (int)strtol(value, &end, 0);
294 if (*value != '\0' && *end == '\0')
295 return 0;
296
297 return -EINVAL;
298}
299
300int str_parms_get_float(struct str_parms *str_parms, const char *key,
301 float *val)
302{
303 float out;
304 char *value;
305 char *end;
306
307 value = hashmapGet(str_parms->map, (void *)key);
308 if (!value)
309 return -ENOENT;
310
311 out = strtof(value, &end);
Mark Salyzyn8e71dde2013-11-22 07:38:46 -0800312 if (*value == '\0' || *end != '\0')
313 return -EINVAL;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700314
Mark Salyzyn8e71dde2013-11-22 07:38:46 -0800315 *val = out;
316 return 0;
Dima Zavin0fad7d02011-03-24 11:11:06 -0700317}
318
319static bool combine_strings(void *key, void *value, void *context)
320{
321 char **old_str = context;
322 char *new_str;
323 int ret;
324
325 ret = asprintf(&new_str, "%s%s%s=%s",
326 *old_str ? *old_str : "",
327 *old_str ? ";" : "",
328 (char *)key,
329 (char *)value);
330 if (*old_str)
331 free(*old_str);
332
333 if (ret >= 0) {
334 *old_str = new_str;
335 return true;
336 }
337
338 *old_str = NULL;
339 return false;
340}
341
342char *str_parms_to_str(struct str_parms *str_parms)
343{
344 char *str = NULL;
345
346 if (hashmapSize(str_parms->map) > 0)
347 hashmapForEach(str_parms->map, combine_strings, &str);
348 else
349 str = strdup("");
350 return str;
351}
352
Mark Salyzynba02cd12013-11-22 07:36:45 -0800353static bool dump_entry(void *key, void *value, void *context UNUSED)
Dima Zavin0fad7d02011-03-24 11:11:06 -0700354{
Steve Blockfe71a612012-01-04 19:19:03 +0000355 ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
Dima Zavin0fad7d02011-03-24 11:11:06 -0700356 return true;
357}
358
359void str_parms_dump(struct str_parms *str_parms)
360{
361 hashmapForEach(str_parms->map, dump_entry, str_parms);
362}