Home | History | Annotate | Download | only in src
      1 #define LOG_TAG "bt_osi_config"
      2 
      3 #include <assert.h>
      4 #include <ctype.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <utils/Log.h>
      9 
     10 #include "config.h"
     11 #include "list.h"
     12 
     13 typedef struct {
     14   char *key;
     15   char *value;
     16 } entry_t;
     17 
     18 typedef struct {
     19   char *name;
     20   list_t *entries;
     21 } section_t;
     22 
     23 struct config_t {
     24   list_t *sections;
     25 };
     26 
     27 static void config_parse(FILE *fp, config_t *config);
     28 
     29 static section_t *section_new(const char *name);
     30 static void section_free(void *ptr);
     31 static section_t *section_find(const config_t *config, const char *section);
     32 
     33 static entry_t *entry_new(const char *key, const char *value);
     34 static void entry_free(void *ptr);
     35 static entry_t *entry_find(const config_t *config, const char *section, const char *key);
     36 
     37 config_t *config_new(const char *filename) {
     38   assert(filename != NULL);
     39 
     40   FILE *fp = fopen(filename, "rt");
     41   if (!fp) {
     42     ALOGE("%s unable to open file '%s': %s", __func__, filename, strerror(errno));
     43     return NULL;
     44   }
     45 
     46   config_t *config = calloc(1, sizeof(config_t));
     47   if (!config) {
     48     ALOGE("%s unable to allocate memory for config_t.", __func__);
     49     fclose(fp);
     50     return NULL;
     51   }
     52 
     53   config->sections = list_new(section_free);
     54   config_parse(fp, config);
     55 
     56   fclose(fp);
     57 
     58   return config;
     59 }
     60 
     61 void config_free(config_t *config) {
     62   if (!config)
     63     return;
     64 
     65   list_free(config->sections);
     66   free(config);
     67 }
     68 
     69 bool config_has_section(const config_t *config, const char *section) {
     70   assert(config != NULL);
     71   assert(section != NULL);
     72 
     73   return (section_find(config, section) != NULL);
     74 }
     75 
     76 bool config_has_key(const config_t *config, const char *section, const char *key) {
     77   assert(config != NULL);
     78   assert(section != NULL);
     79   assert(key != NULL);
     80 
     81   return (entry_find(config, section, key) != NULL);
     82 }
     83 
     84 int config_get_int(const config_t *config, const char *section, const char *key, int def_value) {
     85   assert(config != NULL);
     86   assert(section != NULL);
     87   assert(key != NULL);
     88 
     89   entry_t *entry = entry_find(config, section, key);
     90   if (!entry)
     91     return def_value;
     92 
     93   char *endptr;
     94   int ret = strtol(entry->value, &endptr, 0);
     95   return (*endptr == '\0') ? ret : def_value;
     96 }
     97 
     98 bool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value) {
     99   assert(config != NULL);
    100   assert(section != NULL);
    101   assert(key != NULL);
    102 
    103   entry_t *entry = entry_find(config, section, key);
    104   if (!entry)
    105     return def_value;
    106 
    107   if (!strcmp(entry->value, "true"))
    108     return true;
    109   if (!strcmp(entry->value, "false"))
    110     return false;
    111 
    112   return def_value;
    113 }
    114 
    115 const char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value) {
    116   assert(config != NULL);
    117   assert(section != NULL);
    118   assert(key != NULL);
    119 
    120   entry_t *entry = entry_find(config, section, key);
    121   if (!entry)
    122     return def_value;
    123 
    124   return entry->value;
    125 }
    126 
    127 void config_set_int(config_t *config, const char *section, const char *key, int value) {
    128   assert(config != NULL);
    129   assert(section != NULL);
    130   assert(key != NULL);
    131 
    132   char value_str[32] = { 0 };
    133   sprintf(value_str, "%d", value);
    134   config_set_string(config, section, key, value_str);
    135 }
    136 
    137 void config_set_bool(config_t *config, const char *section, const char *key, bool value) {
    138   assert(config != NULL);
    139   assert(section != NULL);
    140   assert(key != NULL);
    141 
    142   config_set_string(config, section, key, value ? "true" : "false");
    143 }
    144 
    145 void config_set_string(config_t *config, const char *section, const char *key, const char *value) {
    146   section_t *sec = section_find(config, section);
    147   if (!sec) {
    148     sec = section_new(section);
    149     list_append(config->sections, sec);
    150   }
    151 
    152   for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
    153     entry_t *entry = list_node(node);
    154     if (!strcmp(entry->key, key)) {
    155       free(entry->value);
    156       entry->value = strdup(value);
    157       return;
    158     }
    159   }
    160 
    161   entry_t *entry = entry_new(key, value);
    162   list_append(sec->entries, entry);
    163 }
    164 
    165 static char *trim(char *str) {
    166   while (isspace(*str))
    167     ++str;
    168 
    169   if (!*str)
    170     return str;
    171 
    172   char *end_str = str + strlen(str) - 1;
    173   while (end_str > str && isspace(*end_str))
    174     --end_str;
    175 
    176   end_str[1] = '\0';
    177   return str;
    178 }
    179 
    180 static void config_parse(FILE *fp, config_t *config) {
    181   assert(fp != NULL);
    182   assert(config != NULL);
    183 
    184   int line_num = 0;
    185   char line[1024];
    186   char section[1024];
    187   strcpy(section, CONFIG_DEFAULT_SECTION);
    188 
    189   while (fgets(line, sizeof(line), fp)) {
    190     char *line_ptr = trim(line);
    191     ++line_num;
    192 
    193     // Skip blank and comment lines.
    194     if (*line_ptr == '\0' || *line_ptr == '#')
    195       continue;
    196 
    197     if (*line_ptr == '[') {
    198       size_t len = strlen(line_ptr);
    199       if (line_ptr[len - 1] != ']') {
    200         ALOGD("%s unterminated section name on line %d.", __func__, line_num);
    201         continue;
    202       }
    203       strncpy(section, line_ptr + 1, len - 2);
    204       section[len - 2] = '\0';
    205     } else {
    206       char *split = strchr(line_ptr, '=');
    207       if (!split) {
    208         ALOGD("%s no key/value separator found on line %d.", __func__, line_num);
    209         continue;
    210       }
    211 
    212       *split = '\0';
    213       config_set_string(config, section, trim(line_ptr), trim(split + 1));
    214     }
    215   }
    216 }
    217 
    218 static section_t *section_new(const char *name) {
    219   section_t *section = calloc(1, sizeof(section_t));
    220   if (!section)
    221     return NULL;
    222 
    223   section->name = strdup(name);
    224   section->entries = list_new(entry_free);
    225   return section;
    226 }
    227 
    228 static void section_free(void *ptr) {
    229   if (!ptr)
    230     return;
    231 
    232   section_t *section = ptr;
    233   free(section->name);
    234   list_free(section->entries);
    235 }
    236 
    237 static section_t *section_find(const config_t *config, const char *section) {
    238   for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
    239     section_t *sec = list_node(node);
    240     if (!strcmp(sec->name, section))
    241       return sec;
    242   }
    243 
    244   return NULL;
    245 }
    246 
    247 static entry_t *entry_new(const char *key, const char *value) {
    248   entry_t *entry = calloc(1, sizeof(entry_t));
    249   if (!entry)
    250     return NULL;
    251 
    252   entry->key = strdup(key);
    253   entry->value = strdup(value);
    254   return entry;
    255 }
    256 
    257 static void entry_free(void *ptr) {
    258   if (!ptr)
    259     return;
    260 
    261   entry_t *entry = ptr;
    262   free(entry->key);
    263   free(entry->value);
    264 }
    265 
    266 static entry_t *entry_find(const config_t *config, const char *section, const char *key) {
    267   section_t *sec = section_find(config, section);
    268   if (!sec)
    269     return NULL;
    270 
    271   for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
    272     entry_t *entry = list_node(node);
    273     if (!strcmp(entry->key, key))
    274       return entry;
    275   }
    276 
    277   return NULL;
    278 }
    279