Home | History | Annotate | Download | only in libcutils
      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 
     33 struct str_parms {
     34     Hashmap *map;
     35 };
     36 
     37 
     38 static 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 */
     44 static 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 
     54 struct 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 
     68 err:
     69     free(str_parms);
     70     return NULL;
     71 }
     72 
     73 static 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 
     83 void 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 
     90 struct 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++;
    135 next_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 
    146 err_strdup:
    147     str_parms_destroy(str_parms);
    148 err_create_str_parms:
    149     return NULL;
    150 }
    151 
    152 void str_parms_del(struct str_parms *str_parms, const char *key)
    153 {
    154     hashmapRemove(str_parms->map, (void *)key);
    155 }
    156 
    157 int 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 
    175 int 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 
    188 int 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 
    202 int 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 
    214 int 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 
    230 int 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 
    248 static 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 
    271 char *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 
    282 static 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 
    288 void 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
    294 static 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 
    308 int 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