Version 0.1.3 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         cat = ast->root;
55         while(cat) {
56                 v = cat->root;
57                 while(v) {
58                         vn = v;
59                         free(v->name);
60                         free(v->value);
61                         v = v->next;
62                         free(vn);
63                 }
64                 catn = cat;
65                 cat = cat->next;
66                 free(catn);
67         }
68         free(ast);
69 }
70
71 int ast_true(char *s)
72 {
73         if (!s)
74                 return 0;
75         /* Determine if this is a true value */
76         if (!strcasecmp(s, "yes") ||
77             !strcasecmp(s, "true") ||
78                 !strcasecmp(s, "y") ||
79                 !strcasecmp(s, "t") ||
80                 !strcasecmp(s, "1"))
81                         return -1;
82         return 0;
83 }
84
85 struct ast_variable *ast_variable_browse(struct ast_config *config, char *category)
86 {
87         struct ast_category *cat;
88         cat = config->root;
89         while(cat) {
90                 if (!strcasecmp(cat->name, category))
91                         return cat->root;
92                 cat = cat->next;
93         }
94         return NULL;
95 }
96
97 char *ast_variable_retrieve(struct ast_config *config, char *category, char *value)
98 {
99         struct ast_variable *v;
100         if (category) {
101                 v = ast_variable_browse(config, category);
102                 while (v) {
103                         if (!strcasecmp(value, v->name))
104                                 return v->value;
105                         v=v->next;
106                 }
107         } else {
108                 struct ast_category *cat;
109                 cat = config->root;
110                 while(cat) {
111                         v = cat->root;
112                         while (v) {
113                                 if (!strcasecmp(value, v->name))
114                                         return v->value;
115                                 v=v->next;
116                         }
117                         cat = cat->next;
118                 }
119         }
120         return NULL;
121 }
122
123 struct ast_config *ast_load(char *configfile)
124 {
125         char fn[256];
126         char buf[256];
127         struct ast_config *tmp=NULL;
128         struct ast_category *tmpc=NULL;
129         struct ast_variable *v, *last=NULL;
130         FILE *f;
131         char *c, *cur;
132         int lineno=0;
133         if (configfile[0] == '/') {
134                 strncpy(fn, configfile, sizeof(fn));
135         } else {
136                 snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
137         }
138         if ((option_verbose > 1) && !option_debug) {
139                 ast_verbose(  VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
140                 fflush(stdout);
141         }
142         if ((f = fopen(fn, "r"))) {
143                 if (option_debug)
144                         ast_log(LOG_DEBUG, "Parsing %s\n", fn);
145                 else if (option_verbose > 1)
146                         ast_verbose( "Found\n");
147                 tmp = malloc(sizeof(struct ast_config));
148                 if (!tmp) {
149                         ast_log(LOG_WARNING, "Out of memory\n");
150                         fclose(f);
151                         return NULL;
152                 }
153                 tmp->root = NULL;
154                 while(!feof(f)) {
155                         fgets(buf, sizeof(buf), f);
156                         lineno++;
157                         if (!feof(f)) {
158                                 /* Strip off lines using ; as comment */
159                                 c = strchr(buf, ';');
160                                 if (c)
161                                         *c = '\0';
162                                 cur = strip(buf);
163                                 if (strlen(cur)) {
164                                         /* Actually parse the entry */
165                                         if (cur[0] == '[') {
166                                                 /* A category header */
167                                                 /* XXX Don't let them use the same category twice XXX */
168                                                 c = strchr(cur, ']');
169                                                 if (c) {
170                                                         *c = 0;
171                                                         tmpc = malloc(sizeof(struct ast_category));
172                                                         if (!tmpc) {
173                                                                 ast_destroy(tmp);
174                                                                 ast_log(LOG_WARNING,
175                                                                         "Out of memory, line %d\n", lineno);
176                                                                 fclose(f);
177                                                                 return NULL;
178                                                         }
179                                                         strncpy(tmpc->name, cur+1, sizeof(tmpc->name));
180                                                         tmpc->root =  NULL;
181                                                         tmpc->next = tmp->root;
182                                                         tmp->root = tmpc;
183                                                         last =  NULL;
184                                                 } else {
185                                                         ast_log(LOG_WARNING, 
186                                                                 "parse error: no closing ']', line %d\n", lineno);
187                                                         ast_destroy(tmp);
188                                                         fclose(f);
189                                                         return NULL;
190                                                 }
191                                         } else {
192                                                 /* Just a line (variable = value) */
193                                                 if (!tmpc) {
194                                                         ast_log(LOG_WARNING,
195                                                                 "parse error: No category context for line %d\n", lineno);
196                                                         ast_destroy(tmp);
197                                                         fclose(f);
198                                                         return NULL;
199                                                 }
200                                                 c = strchr(cur, '=');
201                                                 if (c) {
202                                                         *c = 0;
203                                                         c++;
204                                                         v = malloc(sizeof(struct ast_variable));
205                                                         if (v) {
206                                                                 v->next = NULL;
207                                                                 v->name = strdup(strip(cur));
208                                                                 v->value = strdup(strip(c));
209                                                                 if (last)  
210                                                                         last->next = v;
211                                                                 else
212                                                                         tmpc->root = v;
213                                                                 last = v;
214                                                         } else {
215                                                                 ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno);
216                                                                 fclose(f);
217                                                                 ast_destroy(tmp);
218                                                         }
219                                                 } else {
220                                                         ast_log(LOG_WARNING, "No = in line %d\n", lineno);
221                                                         fclose(f);
222                                                         ast_destroy(tmp);
223                                                 }
224                                                                                                                 
225                                         }
226                                 }
227                         }
228                 }
229                 fclose(f);              
230         } else {
231                 if (option_debug)
232                         ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
233                 else if (option_verbose > 1)
234                         ast_verbose( "Not found (%s)", strerror(errno));
235         }
236         return tmp;
237 }
238
239 char *ast_category_browse(struct ast_config *config, char *prev)
240 {       
241         struct ast_category *cat;
242         if (!prev) {
243                 if (config->root)
244                         return config->root->name;
245                 else
246                         return NULL;
247         }
248         cat = config->root;
249         while(cat) {
250                 if (!strcasecmp(cat->name, prev)) {
251                         if (cat->next)
252                                 return cat->next->name;
253                         else
254                                 return NULL;
255                 }
256                 cat = cat->next;
257         }
258         return NULL;
259 }