str_parms.c revision 0fad7d023f0229f763a58dd479f78397322baa6d
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 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++; 135next_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 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 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 175int 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 188int 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 202int 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 214int 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 230int 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 248static 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 271char *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 282static 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 288void 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 294static 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 308int 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