• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
33 struct str_parms {
34     Hashmap *map;
35 };
36 
37 
str_eq(void * key_a,void * key_b)38 static 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 */
str_hash_fn(void * str)44 static 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 
str_parms_create(void)54 struct 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 
68 err:
69     free(str_parms);
70     return NULL;
71 }
72 
remove_pair(void * key,void * value,void * context)73 static 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 
str_parms_destroy(struct str_parms * str_parms)83 void 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 
str_parms_create_str(const char * _string)90 struct 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 
106     LOGV("%s: source string == '%s'\n", __func__, _string);
107 
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++;
135 next_pair:
136         kvpair = strtok_r(NULL, ";", &tmpstr);
137     }
138 
139     if (!items)
140         LOGV("%s: no items found in string\n", __func__);
141 
142     free(str);
143 
144     return str_parms;
145 
146 err_strdup:
147     str_parms_destroy(str_parms);
148 err_create_str_parms:
149     return NULL;
150 }
151 
str_parms_del(struct str_parms * str_parms,const char * key)152 void str_parms_del(struct str_parms *str_parms, const char *key)
153 {
154     hashmapRemove(str_parms->map, (void *)key);
155 }
156 
str_parms_add_str(struct str_parms * str_parms,const char * key,const char * value)157 int str_parms_add_str(struct str_parms *str_parms, const char *key,
158                       const char *value)
159 {
160     void *old_val;
161     char *tmp;
162 
163     tmp = strdup(value);
164     old_val = hashmapPut(str_parms->map, (void *)key, tmp);
165 
166     if (old_val) {
167         free(old_val);
168     } else if (errno == ENOMEM) {
169         free(tmp);
170         return -ENOMEM;
171     }
172     return 0;
173 }
174 
str_parms_add_int(struct str_parms * str_parms,const char * key,int value)175 int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
176 {
177     char val_str[12];
178     int ret;
179 
180     ret = snprintf(val_str, sizeof(val_str), "%d", value);
181     if (ret < 0)
182         return -EINVAL;
183 
184     ret = str_parms_add_str(str_parms, key, val_str);
185     return ret;
186 }
187 
str_parms_add_float(struct str_parms * str_parms,const char * key,float value)188 int str_parms_add_float(struct str_parms *str_parms, const char *key,
189                         float value)
190 {
191     char val_str[23];
192     int ret;
193 
194     ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
195     if (ret < 0)
196         return -EINVAL;
197 
198     ret = str_parms_add_str(str_parms, key, val_str);
199     return ret;
200 }
201 
str_parms_get_str(struct str_parms * str_parms,const char * key,char * val,int len)202 int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
203                       int len)
204 {
205     char *value;
206 
207     value = hashmapGet(str_parms->map, (void *)key);
208     if (value)
209         return strlcpy(val, value, len);
210 
211     return -ENOENT;
212 }
213 
str_parms_get_int(struct str_parms * str_parms,const char * key,int * val)214 int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
215 {
216     char *value;
217     char *end;
218 
219     value = hashmapGet(str_parms->map, (void *)key);
220     if (!value)
221         return -ENOENT;
222 
223     *val = (int)strtol(value, &end, 0);
224     if (*value != '\0' && *end == '\0')
225         return 0;
226 
227     return -EINVAL;
228 }
229 
str_parms_get_float(struct str_parms * str_parms,const char * key,float * val)230 int str_parms_get_float(struct str_parms *str_parms, const char *key,
231                         float *val)
232 {
233     float out;
234     char *value;
235     char *end;
236 
237     value = hashmapGet(str_parms->map, (void *)key);
238     if (!value)
239         return -ENOENT;
240 
241     out = strtof(value, &end);
242     if (*value != '\0' && *end == '\0')
243         return 0;
244 
245     return -EINVAL;
246 }
247 
combine_strings(void * key,void * value,void * context)248 static bool combine_strings(void *key, void *value, void *context)
249 {
250     char **old_str = context;
251     char *new_str;
252     int ret;
253 
254     ret = asprintf(&new_str, "%s%s%s=%s",
255                    *old_str ? *old_str : "",
256                    *old_str ? ";" : "",
257                    (char *)key,
258                    (char *)value);
259     if (*old_str)
260         free(*old_str);
261 
262     if (ret >= 0) {
263         *old_str = new_str;
264         return true;
265     }
266 
267     *old_str = NULL;
268     return false;
269 }
270 
str_parms_to_str(struct str_parms * str_parms)271 char *str_parms_to_str(struct str_parms *str_parms)
272 {
273     char *str = NULL;
274 
275     if (hashmapSize(str_parms->map) > 0)
276         hashmapForEach(str_parms->map, combine_strings, &str);
277     else
278         str = strdup("");
279     return str;
280 }
281 
dump_entry(void * key,void * value,void * context)282 static bool dump_entry(void *key, void *value, void *context)
283 {
284     LOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
285     return true;
286 }
287 
str_parms_dump(struct str_parms * str_parms)288 void str_parms_dump(struct str_parms *str_parms)
289 {
290     hashmapForEach(str_parms->map, dump_entry, str_parms);
291 }
292 
293 #ifdef TEST_STR_PARMS
test_str_parms_str(const char * str)294 static void test_str_parms_str(const char *str)
295 {
296     struct str_parms *str_parms;
297     char *out_str;
298     int ret;
299 
300     str_parms = str_parms_create_str(str);
301     str_parms_dump(str_parms);
302     out_str = str_parms_to_str(str_parms);
303     str_parms_destroy(str_parms);
304     LOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
305     free(out_str);
306 }
307 
main(void)308 int main(void)
309 {
310     struct str_parms *str_parms;
311 
312     test_str_parms_str("");
313     test_str_parms_str(";");
314     test_str_parms_str("=");
315     test_str_parms_str("=;");
316     test_str_parms_str("=bar");
317     test_str_parms_str("=bar;");
318     test_str_parms_str("foo=");
319     test_str_parms_str("foo=;");
320     test_str_parms_str("foo=bar");
321     test_str_parms_str("foo=bar;");
322     test_str_parms_str("foo=bar;baz");
323     test_str_parms_str("foo=bar;baz=");
324     test_str_parms_str("foo=bar;baz=bat");
325     test_str_parms_str("foo=bar;baz=bat;");
326 
327     return 0;
328 }
329 #endif
330