• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
config_new(const char * filename)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 
config_free(config_t * config)61 void config_free(config_t *config) {
62   if (!config)
63     return;
64 
65   list_free(config->sections);
66   free(config);
67 }
68 
config_has_section(const config_t * config,const char * section)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 
config_has_key(const config_t * config,const char * section,const char * key)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 
config_get_int(const config_t * config,const char * section,const char * key,int def_value)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 
config_get_bool(const config_t * config,const char * section,const char * key,bool def_value)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 
config_get_string(const config_t * config,const char * section,const char * key,const char * def_value)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 
config_set_int(config_t * config,const char * section,const char * key,int value)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 
config_set_bool(config_t * config,const char * section,const char * key,bool value)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 
config_set_string(config_t * config,const char * section,const char * key,const char * value)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 
trim(char * str)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 
config_parse(FILE * fp,config_t * config)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 
section_new(const char * name)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 
section_free(void * ptr)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 
section_find(const config_t * config,const char * section)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 
entry_new(const char * key,const char * value)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 
entry_free(void * ptr)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 
entry_find(const config_t * config,const char * section,const char * key)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