diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2011-06-18 11:53:34 -0700 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2011-06-18 11:53:34 -0700 |
commit | 89790b892988accff0d1a5c9f191a221369b29ce (patch) | |
tree | a35ba404f8427b1de024e930c6f305955d472457 /libcutils/str_parms.c | |
parent | b6c15de82a9bf477aab34763c9a4e9d8612c8af1 (diff) | |
download | system_core-89790b892988accff0d1a5c9f191a221369b29ce.zip system_core-89790b892988accff0d1a5c9f191a221369b29ce.tar.gz system_core-89790b892988accff0d1a5c9f191a221369b29ce.tar.bz2 |
add strutils
Change-Id: If5938ecd1dfd7f35e326573d10788bacaf3e2383
Diffstat (limited to 'libcutils/str_parms.c')
-rw-r--r-- | libcutils/str_parms.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c new file mode 100644 index 0000000..dfa1f73 --- /dev/null +++ b/libcutils/str_parms.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "str_params" +//#define LOG_NDEBUG 0 + +#define _GNU_SOURCE 1 +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cutils/hashmap.h> +#include <cutils/log.h> +#include <cutils/memory.h> + +#include <cutils/str_parms.h> + +struct str_parms { + Hashmap *map; +}; + + +static bool str_eq(void *key_a, void *key_b) +{ + return !strcmp((const char *)key_a, (const char *)key_b); +} + +/* use djb hash unless we find it inadequate */ +static int str_hash_fn(void *str) +{ + uint32_t hash = 5381; + char *p; + + for (p = str; p && *p; p++) + hash = ((hash << 5) + hash) + *p; + return (int)hash; +} + +struct str_parms *str_parms_create(void) +{ + struct str_parms *str_parms; + + str_parms = calloc(1, sizeof(struct str_parms)); + if (!str_parms) + return NULL; + + str_parms->map = hashmapCreate(5, str_hash_fn, str_eq); + if (!str_parms->map) + goto err; + + return str_parms; + +err: + free(str_parms); + return NULL; +} + +static bool remove_pair(void *key, void *value, void *context) +{ + struct str_parms *str_parms = context; + + hashmapRemove(str_parms->map, key); + free(key); + free(value); + return true; +} + +void str_parms_destroy(struct str_parms *str_parms) +{ + hashmapForEach(str_parms->map, remove_pair, str_parms); + hashmapFree(str_parms->map); + free(str_parms); +} + +struct str_parms *str_parms_create_str(const char *_string) +{ + struct str_parms *str_parms; + char *str; + char *kvpair; + char *tmpstr; + int items = 0; + + str_parms = str_parms_create(); + if (!str_parms) + goto err_create_str_parms; + + str = strdup(_string); + if (!str) + goto err_strdup; + + LOGV("%s: source string == '%s'\n", __func__, _string); + + kvpair = strtok_r(str, ";", &tmpstr); + while (kvpair && *kvpair) { + char *eq = strchr(kvpair, '='); /* would love strchrnul */ + char *value; + char *key; + void *old_val; + + if (eq == kvpair) + goto next_pair; + + if (eq) { + key = strndup(kvpair, eq - kvpair); + if (*(++eq)) + value = strdup(eq); + else + value = strdup(""); + } else { + key = strdup(kvpair); + value = strdup(""); + } + + /* if we replaced a value, free it */ + old_val = hashmapPut(str_parms->map, key, value); + if (old_val) + free(old_val); + + items++; +next_pair: + kvpair = strtok_r(NULL, ";", &tmpstr); + } + + if (!items) + LOGV("%s: no items found in string\n", __func__); + + free(str); + + return str_parms; + +err_strdup: + str_parms_destroy(str_parms); +err_create_str_parms: + return NULL; +} + +void str_parms_del(struct str_parms *str_parms, const char *key) +{ + hashmapRemove(str_parms->map, (void *)key); +} + +int str_parms_add_str(struct str_parms *str_parms, const char *key, + const char *value) +{ + void *old_val; + char *tmp; + + tmp = strdup(value); + old_val = hashmapPut(str_parms->map, (void *)key, tmp); + + if (old_val) { + free(old_val); + } else if (errno == ENOMEM) { + free(tmp); + return -ENOMEM; + } + return 0; +} + +int str_parms_add_int(struct str_parms *str_parms, const char *key, int value) +{ + char val_str[12]; + int ret; + + ret = snprintf(val_str, sizeof(val_str), "%d", value); + if (ret < 0) + return -EINVAL; + + ret = str_parms_add_str(str_parms, key, val_str); + return ret; +} + +int str_parms_add_float(struct str_parms *str_parms, const char *key, + float value) +{ + char val_str[23]; + int ret; + + ret = snprintf(val_str, sizeof(val_str), "%.10f", value); + if (ret < 0) + return -EINVAL; + + ret = str_parms_add_str(str_parms, key, val_str); + return ret; +} + +int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val, + int len) +{ + char *value; + + value = hashmapGet(str_parms->map, (void *)key); + if (value) + return strlcpy(val, value, len); + + return -ENOENT; +} + +int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val) +{ + char *value; + char *end; + + value = hashmapGet(str_parms->map, (void *)key); + if (!value) + return -ENOENT; + + *val = (int)strtol(value, &end, 0); + if (*value != '\0' && *end == '\0') + return 0; + + return -EINVAL; +} + +int str_parms_get_float(struct str_parms *str_parms, const char *key, + float *val) +{ + float out; + char *value; + char *end; + + value = hashmapGet(str_parms->map, (void *)key); + if (!value) + return -ENOENT; + + out = strtof(value, &end); + if (*value != '\0' && *end == '\0') + return 0; + + return -EINVAL; +} + +static bool combine_strings(void *key, void *value, void *context) +{ + char **old_str = context; + char *new_str; + int ret; + + ret = asprintf(&new_str, "%s%s%s=%s", + *old_str ? *old_str : "", + *old_str ? ";" : "", + (char *)key, + (char *)value); + if (*old_str) + free(*old_str); + + if (ret >= 0) { + *old_str = new_str; + return true; + } + + *old_str = NULL; + return false; +} + +char *str_parms_to_str(struct str_parms *str_parms) +{ + char *str = NULL; + + if (hashmapSize(str_parms->map) > 0) + hashmapForEach(str_parms->map, combine_strings, &str); + else + str = strdup(""); + return str; +} + +static bool dump_entry(void *key, void *value, void *context) +{ + LOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value); + return true; +} + +void str_parms_dump(struct str_parms *str_parms) +{ + hashmapForEach(str_parms->map, dump_entry, str_parms); +} + +#ifdef TEST_STR_PARMS +static void test_str_parms_str(const char *str) +{ + struct str_parms *str_parms; + char *out_str; + int ret; + + str_parms = str_parms_create_str(str); + str_parms_dump(str_parms); + out_str = str_parms_to_str(str_parms); + str_parms_destroy(str_parms); + LOGI("%s: '%s' stringified is '%s'", __func__, str, out_str); + free(out_str); +} + +int main(void) +{ + struct str_parms *str_parms; + + test_str_parms_str(""); + test_str_parms_str(";"); + test_str_parms_str("="); + test_str_parms_str("=;"); + test_str_parms_str("=bar"); + test_str_parms_str("=bar;"); + test_str_parms_str("foo="); + test_str_parms_str("foo=;"); + test_str_parms_str("foo=bar"); + test_str_parms_str("foo=bar;"); + test_str_parms_str("foo=bar;baz"); + test_str_parms_str("foo=bar;baz="); + test_str_parms_str("foo=bar;baz=bat"); + test_str_parms_str("foo=bar;baz=bat;"); + + return 0; +} +#endif |