aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2011-06-18 11:56:48 -0700
committerAndroid Code Review <code-review@android.com>2011-06-18 11:56:48 -0700
commit14c2823a631b444687b9d26b7baf4c864091c07b (patch)
treea35ba404f8427b1de024e930c6f305955d472457
parenta08f7ae3c10f4874194fb48ff549e846e39217b7 (diff)
parent89790b892988accff0d1a5c9f191a221369b29ce (diff)
-rw-r--r--libcutils/Android.mk3
-rw-r--r--libcutils/str_parms.c329
2 files changed, 331 insertions, 1 deletions
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 8b739e98..84cccd98 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -46,7 +46,8 @@ commonSources := \
properties.c \
threads.c \
sched_policy.c \
- iosched_policy.c
+ iosched_policy.c \
+ str_parms.c
commonHostSources := \
ashmem-host.c
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
new file mode 100644
index 00000000..dfa1f737
--- /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