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