Flattening #defines and general cleanup in icmpmonitor.c.
[icmpmonitor] / cfg.c
CommitLineData
c5de9e27
AT
1/*
2 * $Id: cfg.c,v 1.1.1.1 1999/11/21 08:16:12 lord Exp $
3 *
4 * Vadim Zaliva <lord@crocodile.org>
5 * http://www.crocodile.org/
6 *
7 * Copyright (C) 1999 Vadim Zaliva
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "cfg.h"
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <ctype.h>
30#include <stdarg.h>
31
32#define MAXTOKENLEN 1024
33
34static int cfg_entry_cmp(const void *a,const void *b)
35{
36 return(strcmp((*((struct Dict **)a))->name, (*((struct Dict **)b))->name));
37}
38
39static int cfg_entry_match(const void *a,const void *b)
40{
41 return(strcmp((const char *)a, (*((struct Dict **)b))->name));
42}
43
44char *cfgfind(const char *name,struct Cfg *cfg, int offset)
45{
46 int j;
47 struct Dict **res;
48
49 res=(struct Dict **)bsearch(name,
50 cfg->dict,
51 cfg->nelements,
52 sizeof(struct Dict *),
53 cfg_entry_match
54 );
55
56 if(!res)
57 return NULL;
58
59 if(offset>=(*res)->nvalues)
60 return NULL;
61
62 return (*res)->value[offset];
63}
64
65int writecfg(const char *name,struct Cfg *cfg)
66{
67 FILE *f;
68 int j;
69 int i;
70
71 if((f=fopen(name,"wb"))==NULL)
72 return -1;
73
74 if(cfg)
75 {
76 for(i=0;i<cfg->nelements;i++)
77 {
78 if(!cfg->dict[i]->name)
79 continue;
80 fprintf(f,"%s\t",cfg->dict[i]->name);
81 for(j=0;j<cfg->dict[i]->nvalues;j++)
82 if(cfg->dict[i]->value[j])
83 fprintf(f," %s",cfg->dict[i]->value[j]); //TODO: quote values with spaces.
84 fprintf(f,"\n");
85 }
86 }
87 fclose(f);
88 return 0;
89}
90
91void freecfg(struct Cfg *cfg)
92{
93 int i,j;
94
95 if(!cfg)
96 return;
97
98 for(i=0;i<cfg->nelements;i++)
99 {
100 if(cfg->dict[i]->value)
101 {
102 for(j=0;j<cfg->dict[i]->nvalues;j++)
103 if(cfg->dict[i]->value[j])
104 free(cfg->dict[i]->value[j]);
105 free(cfg->dict[i]->value);
106 }
107
108 if(cfg->dict[i]->name)
109 free(cfg->dict[i]->name);
110 }
111
112 free(cfg->dict);
113 free(cfg);
114}
115
116struct Cfg *readcfg(const char *name)
117{
118 struct Cfg *cfg;
119 FILE *f;
120 char tmp[MAXTOKENLEN];
121 char *s;
122 int c;
123
124 enum
125 {
126 START,
127 NAME,
128 VALUE,
129 INQUOTE,
130 WHITESPACE,
131 COMMENT
132 } state=START;
133
134 int n,i;
135 char *pname,*pvalue;
136
137 if((f=fopen(name,"rb"))==NULL)
138 return NULL;
139
140 cfg=malloc(sizeof(struct Cfg));
141 cfg->nelements=0;
142 s=tmp;
143
144 while((c=fgetc(f))!=EOF)
145 {
146 /* Order of 'case' statements is important here! */
147 switch(state)
148 {
149 case START:
150 if(c=='#')
151 {
152 state=COMMENT;
153 break;
154 }
155 else
156 if(!isspace(c))
157 {
158 s=tmp;
159 state=NAME;
160 } else
161 {
162 break;
163 }
164
165 case NAME:
166 if(isspace(c))
167 {
168 struct Dict *tmp1=malloc(sizeof(struct Dict));
169 *s='\0';
170 tmp1->nvalues = 0;
171 tmp1->value = NULL;
172 tmp1->name = strdup(tmp);
173
174 cfg_add_entry(cfg, tmp1);
175
176 state=WHITESPACE;
177 }
178 else
179 {
180 *s++=c;
181 if(s==(tmp+sizeof(tmp)))
182 {
183 /* internal buffer overflow */
184 freecfg(cfg);
185 return NULL;
186 }
187 }
188 break;
189
190 case WHITESPACE:
191 if(c=='\n')
192 {
193 state=START;
194 break;
195 }
196 else
197 {
198 if(!isspace(c))
199 {
200 s=tmp;
201 state=VALUE;
202 } else
203 {
204 break;
205 }
206 }
207
208 case VALUE:
209 if(c=='"')
210 state=INQUOTE;
211 else
212 if(isspace(c))
213 {
214 struct Dict *last=cfg->dict[cfg->nelements-1];
215 char **tmp1;
216 int i;
217
218 *s='\0';
219 tmp1=last->value;
220 last->value=malloc((last->nvalues+1)*sizeof(char *));
221 if(tmp1)
222 {
223 for(i=0;i<last->nvalues;i++)
224 last->value[i]=tmp1[i];
225 free(tmp1);
226 }
227 last->value[last->nvalues]=strdup(tmp);
228 last->nvalues++;
229 if(c=='\n')
230 state=START;
231 else
232 state=WHITESPACE;
233 } else
234 {
235 *s++=c;
236 if(s==(tmp+sizeof(tmp)))
237 {
238 /* internal buffer overflow */
239 freecfg(cfg);
240 return NULL;
241 }
242 }
243 break;
244
245 case INQUOTE:
246 if(c=='"')
247 {
248 state=VALUE;
249 }
250 else
251 {
252 *s++=c;
253 if(s==(tmp+sizeof(tmp)))
254 {
255 /* internal buffer overflow */
256 freecfg(cfg);
257 return NULL;
258 }
259 }
260 break;
261
262 case COMMENT:
263 if(c=='\n')
264 state=START;
265 break;
266 }
267 }
268
269 sortcfg(cfg);
270 return cfg;
271}
272
273/**
274 * Sorts cfg.
275 * Should be called after each modification
276 * before attempting to retrieve any data.
277 */
278void sortcfg (struct Cfg *cfg)
279{
280 qsort((void *) cfg->dict,
281 cfg->nelements,
282 sizeof(struct Dict *),
283 cfg_entry_cmp);
284
285}
286
287/**
288 * Adds new cfg entry to the end of the dictionary.
289 * you need to call sortcfg() before it could be
290 * really used.
291 */
292void cfg_add_entry (struct Cfg *cfg, struct Dict *d)
293{
294 if(cfg->nelements)
295 {
296 struct Dict **last=cfg->dict;
297 cfg->dict=malloc(sizeof(struct Dict *)*(cfg->nelements+1));
298 memcpy(cfg->dict,last,sizeof(struct Dict *)*cfg->nelements);
299 cfg->dict[cfg->nelements]=d;
300 cfg->nelements++;
301 free(last);
302 }
303 else
304 {
305 cfg->dict = malloc(sizeof(struct Dict *));
306 cfg->dict[0] = d;
307 cfg->nelements = 1;
308 }
309}
310
311
312/**
313 * Adds entry with given name and list of values.
314 * list should be terminated with NULL and contain
315 * only const char pointers.
316 */
317void cfg_new_entry(struct Cfg *cfg, const char *name, ...)
318{
319 int n;
320 va_list ap;
321 struct Dict *tmp=malloc(sizeof(struct Dict));
322
323 tmp->name = strdup(name);
324
325 va_start(ap,name);
326 n=0;
327 while(va_arg(ap, const char *)) n++;
328 va_end(ap);
329
330 tmp->nvalues = n;
331 if(n)
332 {
333 int i;
334
335 va_start(ap,name);
336 tmp->value = malloc(n*sizeof(char *));
337 for(i=0;i<n;i++)
338 tmp->value[i] = strdup(va_arg(ap, const char *));
339 va_end(ap);
340 } else
341 {
342 tmp->value = NULL;
343 }
344
345 cfg_add_entry(cfg, tmp);
346}
347
348void cfg_new_ulong_entry (struct Cfg *cfg, const char *name, unsigned long v)
349{
350 char tmp[80];
351 sprintf(tmp,"%lu",v);
352 cfg_new_entry(cfg, name, tmp, NULL);
353}
354
355/**
356 * add long extended to 'w' chars, with added trailing zeros.
357 *
358 * @param v - field value
359 * @param w - field width
360 */
361void cfg_new_fmt_ulong_entry (struct Cfg *cfg, const char *name, unsigned long v, int w)
362{
363 char tmp[80];
364 sprintf(tmp,"%0*lu",w, v);
365 cfg_new_entry(cfg, name, tmp, NULL);
366}
367
368struct Cfg *newcfg ()
369{
370 struct Cfg *res=malloc(sizeof(struct Cfg));
371 res->nelements = 0;
372 return res;
373}