Print instananeous rate rather than ewma-affected rate.
[distributedratelimiting.git] / conffile / conffile.c
1 /* config file parser functions
2  *
3  * (C) 2000 by Harald Welte <laforge@gnumonks.org>
4  *
5  * $Id: conffile.c 4946 2003-09-28 15:19:25Z laforge $
6  * 
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 
9  *  as published by the Free Software Foundation
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "conffile.h"
25
26 #ifdef DEBUG_CONF
27 #define DEBUGC(format, args...) fprintf(stderr, format, ## args)
28 #else
29 #define DEBUGC(format, args...)
30 #endif
31
32 /* points to config entry with error */
33 config_entry_t *config_errce = NULL;
34
35 /* Filename of the config file */
36 static char *fname = NULL;
37
38 /* get_word() - Function to parse a line into words.
39  * Arguments:   line    line to parse
40  *              delim   possible word delimiters
41  *              buf     pointer to buffer where word is returned
42  * Return value:        pointer to first char after word
43  * This function can deal with "" quotes 
44  */
45 static char *get_word(char *line, char *not, char *buf)
46 {
47         char *p, *start = NULL, *stop = NULL;
48         int inquote = 0;
49
50         for (p = line; *p; p++) {
51                 if (*p == '"') {
52                         start  = p + 1;
53                         inquote = 1;
54                         break;
55                 }
56                 if (!strchr(not, *p)) {
57                         start = p;
58                         break;
59                 }
60         }
61         if (!start)
62                 return NULL;
63
64         /* determine pointer to one char after word */
65         for (p = start; *p; p++) {
66                 if (inquote) {
67                         if (*p == '"') {
68                                 stop = p;
69                                 break;
70                         }
71                 } else {
72                         if (strchr(not, *p)) {
73                                 stop = p;
74                                 break;
75                         }
76                 }
77         }
78         if (!stop)
79                 return NULL;
80
81         strncpy(buf, start, (size_t) (stop-start));
82         *(buf + (stop-start)) = '\0';
83
84         /* skip quote character */
85         if (inquote)
86                 /* yes, we can return stop + 1. If " was the last 
87                  * character in string, it now points to NULL-term */
88                 return (stop + 1);
89
90         return stop;
91 }
92
93 #if 0
94 /* do we have a config directive for this name */
95 static int config_iskey(char *name)
96 {
97         config_entry_t *ce;
98
99         for (ce = config; ce; ce = ce->next) {
100                 if (!strcmp(name, ce->key))
101                         return 0;
102         }
103
104         return 1;
105 }
106 #endif
107
108 /***********************************************************************
109  * PUBLIC INTERFACE
110  ***********************************************************************/
111
112 /* register config file with us */
113 int config_register_file(const char *file)
114 {
115         /* FIXME: stat of file */
116         if (fname)
117                 return 1;
118
119         fname = (char *) malloc(strlen(file)+1);
120         if (!fname)
121                 return -ERROOM;
122
123         strcpy(fname, file);
124
125         return 0;
126 }
127
128 /* parse config file */
129 int config_parse_file(const char *section, config_entry_t *keys)
130 {
131         FILE *cfile;
132         char *args;
133         config_entry_t *ce;
134         int err = 0;
135         int found = 0;
136         char linebuf[LINE_LEN+1];
137         char *line = linebuf;
138
139         cfile = fopen(fname, "r");
140         if (!cfile)
141                 return -ERROPEN;
142
143         DEBUGC("prasing section [%s]\n", section);
144
145         /* Search for correct section */
146         while (fgets(line, LINE_LEN, cfile)) {
147                 char wordbuf[LINE_LEN];
148                 char *wordend;
149
150                 if (*line == '#')
151                         continue;
152
153                 if (!(wordend = get_word(line, " \t\n[]", (char *) wordbuf)))
154                         continue;
155                 DEBUGC("word: \"%s\"\n", wordbuf);
156                 if (!strcmp(wordbuf, section)) {
157                         found = 1;
158                         break;
159                 }
160         }
161
162         if (!found) {
163                 fclose(cfile);
164                 return -ERRSECTION;
165         }
166
167         /* Parse this section until next section */
168         while (fgets(line, LINE_LEN, cfile))
169         {
170                 char wordbuf[LINE_LEN];
171                 char *wordend;
172                 
173                 DEBUGC("line read: %s\n", line);
174                 if (*line == '#')
175                         continue;
176
177                 if (!(wordend = get_word(line, " =\t\n", (char *) &wordbuf)))
178                         continue;
179
180                 if (wordbuf[0] == '[' ) {
181                         DEBUGC("Next section '%s' encountered\n", wordbuf);
182                         break;
183                 }
184
185                 DEBUGC("parse_file: entering main loop\n");
186                 for (ce = keys; ce; ce = ce->next) {
187                         DEBUGC("parse main loop, key: %s\n", ce->key);
188                         if (strcmp(ce->key, (char *) &wordbuf)) {
189                                 continue;
190                         }
191
192                         wordend = get_word(wordend, " =\t\n", (char *) &wordbuf);
193                         args = (char *)&wordbuf;
194
195                         if (ce->hit && !(ce->options & CONFIG_OPT_MULTI))
196                         {
197                                 DEBUGC("->ce-hit and option not multi!\n");
198                                 config_errce = ce;
199                                 err = -ERRMULT;
200                                 goto cpf_error;
201                         }
202                         ce->hit++;
203
204                         switch (ce->type) {
205                                 case CONFIG_TYPE_STRING:
206                                         if (strlen(args) < 
207                                             CONFIG_VAL_STRING_LEN ) {
208                                                 strcpy(ce->u.string, args);
209                                                 /* FIXME: what if not ? */
210                                         }
211                                         break;
212                                 case CONFIG_TYPE_INT:
213                                         ce->u.value = atoi(args);
214                                         break;
215                                 case CONFIG_TYPE_CALLBACK:
216                                         (ce->u.parser)(args);
217                                         break;
218                         }
219                         break;
220                 }
221                 DEBUGC("parse_file: exiting main loop\n");
222         }
223
224
225         for (ce = keys; ce; ce = ce->next) {
226                 DEBUGC("ce post loop, ce=%s\n", ce->key);
227                 if ((ce->options & CONFIG_OPT_MANDATORY) && (ce->hit == 0)) {
228                         DEBUGC("Mandatory config directive \"%s\" not found\n",
229                                 ce->key);
230                         config_errce = ce;
231                         err = -ERRMAND;
232                         goto cpf_error;
233                 }
234
235         }
236
237 cpf_error:
238         fclose(cfile);
239         return err;
240 }
241