str_parms.c revision 70b93034f3ce06404e9b042c80759da25dac99d8
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 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 106 ALOGV("%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++; 135next_pair: 136 kvpair = strtok_r(NULL, ";", &tmpstr); 137 } 138 139 if (!items) 140 ALOGV("%s: no items found in string\n", __func__); 141 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; 161 void *tmp_key; 162 void *tmp_val; 163 164 tmp_key = strdup(key); 165 tmp_val = strdup(value); 166 old_val = hashmapPut(str_parms->map, tmp_key, tmp_val); 167 168 if (old_val) { 169 free(old_val); 170 } else if (errno == ENOMEM) { 171 free(tmp_key); 172 free(tmp_val); 173 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{ 287 ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value); 288 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); 307 ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str); 308 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 333