Version 0.1.10 from FTP
[asterisk/asterisk.git] / config.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Configuration File Parser
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <asterisk/config.h>
20 #include <asterisk/options.h>
21 #include <asterisk/logger.h>
22 #include "asterisk.h"
23
24 struct ast_category {
25         char name[80];
26         struct ast_variable *root;
27         struct ast_category *next;
28 };
29
30 struct ast_config {
31         /* Maybe this structure isn't necessary but we'll keep it
32            for now */
33         struct ast_category *root;
34 };
35
36 static char *strip(char *buf)
37 {
38         char *start;
39         /* Strip off trailing whitespace, returns, etc */
40         while(strlen(buf) && (buf[strlen(buf)-1]<33))
41                 buf[strlen(buf)-1] = '\0';
42         start = buf;
43         /* Strip off leading whitespace, returns, etc */
44         while(*start && (*start < 33))
45                 *start++ = '\0';
46         return start;
47 }
48
49 void ast_destroy(struct ast_config *ast)
50 {
51         struct ast_category *cat, *catn;
52         struct ast_variable *v, *vn;
53
54         if (!ast)
55                 return;
56
57         cat = ast->root;
58         while(cat) {
59                 v = cat->root;
60                 while(v) {
61                         vn = v;
62                         free(v->name);
63                         free(v->value);
64                         v = v->next;
65                         free(vn);
66                 }
67                 catn = cat;
68                 cat = cat->next;
69                 free(catn);
70         }
71         free(ast);
72 }
73
74 int ast_true(char *s)
75 {
76         if (!s)
77                 return 0;
78         /* Determine if this is a true value */
79         if (!strcasecmp(s, "yes") ||
80             !strcasecmp(s, "true") ||
81                 !strcasecmp(s, "y") ||
82                 !strcasecmp(s, "t") ||
83                 !strcasecmp(s, "1"))
84                         return -1;
85         return 0;
86 }
87
88 struct ast_variable *ast_variable_browse(struct ast_config *config, char *category)
89 {
90         struct ast_category *cat;
91         cat = config->root;
92         while(cat) {
93                 if (cat->name == category)
94                         return cat->root;
95                 cat = cat->next;
96         }
97         cat = config->root;
98         while(cat) {
99                 if (!strcasecmp(cat->name, category))
100                         return cat->root;
101                 cat = cat->next;
102         }
103         return NULL;
104 }
105
106 char *ast_variable_retrieve(struct ast_config *config, char *category, char *value)
107 {
108         struct ast_variable *v;
109         if (category) {
110                 v = ast_variable_browse(config, category);
111                 while (v) {
112                         if (value == v->name)
113                                 return v->value;
114                         v=v->next;
115                 }
116                 v = ast_variable_browse(config, category);
117                 while (v) {
118                         if (!strcasecmp(value, v->name))
119                                 return v->value;
120                         v=v->next;
121                 }
122         } else {
123                 struct ast_category *cat;
124                 cat = config->root;
125                 while(cat) {
126                         v = cat->root;
127                         while (v) {
128                                 if (!strcasecmp(value, v->name))
129                                         return v->value;
130                                 v=v->next;
131                         }
132                         cat = cat->next;
133                 }
134         }
135         return NULL;
136 }
137
138 int ast_category_exist(struct ast_config *config, char *category_name)
139 {
140         struct ast_category *category = NULL;
141
142         category = config->root;
143
144         while(category) {
145                 if (!strcasecmp(category->name,category_name)) 
146                         return 1;
147                 category = category->next;
148         } 
149
150         return 0;
151 }
152
153 struct ast_config *ast_load(char *configfile)
154 {
155         char fn[256];
156         char buf[256];
157         struct ast_config *tmp=NULL;
158         struct ast_category *tmpc=NULL;
159         struct ast_variable *v, *last=NULL;
160         FILE *f;
161         char *c, *cur;
162         int lineno=0;
163
164         if (configfile[0] == '/') {
165                 strncpy(fn, configfile, sizeof(fn)-1);
166         } else {
167                 snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
168         }
169         if ((option_verbose > 1) && !option_debug) {
170                 ast_verbose(  VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
171                 fflush(stdout);
172         }
173         if ((f = fopen(fn, "r"))) {
174                 if (option_debug)
175                         ast_log(LOG_DEBUG, "Parsing %s\n", fn);
176                 else if (option_verbose > 1)
177                         ast_verbose( "Found\n");
178                 tmp = malloc(sizeof(struct ast_config));
179                 if (!tmp) {
180                         ast_log(LOG_WARNING, "Out of memory\n");
181                         fclose(f);
182                         return NULL;
183                 }
184                 tmp->root = NULL;
185                 while(!feof(f)) {
186                         fgets(buf, sizeof(buf), f);
187                         lineno++;
188                         if (!feof(f)) {
189                                 /* Strip off lines using ; as comment */
190                                 c = strchr(buf, ';');
191                                 if (c)
192                                         *c = '\0';
193                                 cur = strip(buf);
194                                 if (strlen(cur)) {
195                                         /* Actually parse the entry */
196                                         if (cur[0] == '[') {
197                                                 /* A category header */
198                                                 c = strchr(cur, ']');
199                                                 if (c) {
200                                                         *c = 0;
201 #if 0
202                                                         /* 
203                                                          * Check category duplicity before structure
204                                                          * allocation
205                                                          */
206                                                         if (ast_category_exist(tmp,cur+1)) {
207                                                                 ast_destroy(tmp);
208                                                                 ast_log(LOG_WARNING,
209                                                                         "Found duplicit category [%s] in "
210                                                                         "file %s line %d\n",
211                                                                         cur+1,configfile,lineno);
212                                                                 fclose(f);
213                                                                 return NULL; 
214                                                         }
215 #endif                                          
216                                                         tmpc = malloc(sizeof(struct ast_category));
217                                                         if (!tmpc) {
218                                                                 ast_destroy(tmp);
219                                                                 ast_log(LOG_WARNING,
220                                                                         "Out of memory, line %d\n", lineno);
221                                                                 fclose(f);
222                                                                 return NULL;
223                                                         }
224                                                         strncpy(tmpc->name, cur+1, sizeof(tmpc->name)-1);
225                                                         tmpc->root =  NULL;
226                                                         tmpc->next = tmp->root;
227                                                         tmp->root = tmpc;
228                                                         last =  NULL;
229                                                 } else {
230                                                         ast_log(LOG_WARNING, 
231                                                                 "parse error: no closing ']', line %d\n", lineno);
232                                                 }
233                                         } else {
234                                                 /* Just a line (variable = value) */
235                                                 if (!tmpc) {
236                                                         ast_log(LOG_WARNING,
237                                                                 "parse error: No category context for line %d\n", lineno);
238                                                 }
239                                                 c = strchr(cur, '=');
240                                                 if (c) {
241                                                         *c = 0;
242                                                         c++;
243                                                         /* Ignore > in => */
244                                                         if (*c== '>')
245                                                                 c++;
246                                                         v = malloc(sizeof(struct ast_variable));
247                                                         if (v) {
248                                                                 v->next = NULL;
249                                                                 v->name = strdup(strip(cur));
250                                                                 v->value = strdup(strip(c));
251                                                                 v->lineno = lineno;
252                                                                 if (last)  
253                                                                         last->next = v;
254                                                                 else
255                                                                         tmpc->root = v;
256                                                                 last = v;
257                                                         } else {
258                                                                 ast_destroy(tmp);
259                                                                 ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno);
260                                                                 fclose(f);
261                                                                 return NULL;
262                                                         }
263                                                 } else {
264                                                         ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
265                                                 }
266                                                                                                                 
267                                         }
268                                 }
269                         }
270                 }
271                 fclose(f);              
272         } else {
273                 if (option_debug)
274                         ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
275                 else if (option_verbose > 1)
276                         ast_verbose( "Not found (%s)", strerror(errno));
277         }
278         return tmp;
279 }
280
281 char *ast_category_browse(struct ast_config *config, char *prev)
282 {       
283         struct ast_category *cat;
284         if (!prev) {
285                 if (config->root)
286                         return config->root->name;
287                 else
288                         return NULL;
289         }
290         cat = config->root;
291         while(cat) {
292                 if (cat->name == prev) {
293                         if (cat->next)
294                                 return cat->next->name;
295                         else
296                                 return NULL;
297                 }
298                 cat = cat->next;
299         }
300         cat = config->root;
301         while(cat) {
302                 if (!strcasecmp(cat->name, prev)) {
303                         if (cat->next)
304                                 return cat->next->name;
305                         else
306                                 return NULL;
307                 }
308                 cat = cat->next;
309         }
310         return NULL;
311 }