add .gitignore
[tedtools.git] / prs_inf.c
1 /*
2  * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *        notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *        notice, this list of conditions and the following disclaimer in the
12  *        documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *        may be used to endorse or promote products derived from this software
15  *        without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "tlog.h"
37 #include "tmalloc.h"
38 #include "prs_inf.h"
39
40 #define INF_WAIT        1
41 #define INF_COMMENT     2
42 #define INF_SECTION     3
43 #define INF_KEY         4
44 #define INF_WAITVAL     5
45 #define INF_INQVAL      6
46 #define INF_INVAL       7
47 #define INF_QESCAPE     8
48 #define INF_ESCAPE      9
49 #define INF_WAITDELIM   10
50
51
52 #define CHECKBUF        do {            \
53         if (bufptr-buf+1>=buflen) {     \
54         int diff = bufptr-buf;          \
55         buflen*=2;                      \
56         buf=trealloc(buf,buflen);       \
57         bufptr=buf+diff;                \
58         }                               \
59 } while(0)
60
61 #define CHECKMAP        do {            \
62         if (mapptr-map+1>=maplen) {     \
63         int diff = mapptr-map;          \
64         maplen*=2;                      \
65         map=trealloc(map,maplen);       \
66         mapptr=map+diff;                \
67         }                               \
68 } while(0)
69
70 #define ISKEYNAME(c)    ( (c)=='_' || isalnum(c) )
71
72 static void
73 clrbackspace(char *ptr, char *buf) {
74         while(ptr>=buf && (*ptr==' '||*ptr=='\t') ) {
75                 *ptr='\0';
76                 ptr--;
77         }
78 }
79
80 InfMap*
81 INFParse(char *file) {
82         FILE *in;
83         int maplen=32, buflen=32;
84         InfMap *mapptr,*map;
85         int state=INF_WAIT, c;
86         char *buf,*bufptr;
87         int lineno=1;
88
89         if ( (in=fopen(file,"r"))==NULL )
90                 tlog(TL_ALARM|TL_EXIT,"Can't open inf file '%s': %s", file, strerror(errno));
91
92         map=mapptr=(InfMap*)tmalloc(sizeof(InfMap)*maplen);
93         buf = bufptr = (char*)tmalloc(buflen);
94         mapptr->section=NULL; 
95
96         while( (c=fgetc(in))!=EOF ) {
97                 CHECKBUF;
98                 CHECKMAP;
99                 if (c=='\r')
100                         continue;
101
102                 if ( state==INF_WAIT ) {
103                         if ( c=='\n' )
104                                 lineno++;
105                         else if ( c=='[' ) {
106                                 bufptr=buf;
107                                 state=INF_SECTION;
108                         } else if ( c=='#' )
109                                 state=INF_COMMENT;
110                         else if ( ISKEYNAME(c) ) {
111                                 if ( mapptr->section==NULL )
112                                         tlog(TL_ALARM|TL_EXIT, "Undefined section name at line %d, file %s", lineno, file);
113                                 bufptr=buf;
114                                 *bufptr=c;
115                                 bufptr++;
116                                 state=INF_KEY;
117                         }
118                 } else if ( state==INF_SECTION ) {
119                         if ( c==']' ) {
120                                 if ( bufptr==buf ) {
121                                         tlog(TL_ALARM|TL_EXIT,
122                                                 "Void section name at line %d, file %s", lineno, file);
123                                 } else {
124                                         if ( mapptr->section ) tfree(mapptr->section);
125                                         *bufptr='\0';
126                                         mapptr->section = tstrdup(buf);
127                                         bufptr=buf;     
128                                 }
129                                 state=INF_WAIT;
130                         } else if ( ISKEYNAME(c) ) {
131                                 *bufptr=c;
132                                 bufptr++;
133                         } else 
134                                 tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
135                 } else if ( state==INF_COMMENT ) {
136                         if (c=='\n') {
137                                 lineno++;
138                                 state=INF_WAIT;
139                         }
140                 } else if ( state==INF_KEY ) {
141                         if (ISKEYNAME(c)) {
142                                 *bufptr=c;
143                                 bufptr++;
144                         } else if (c=='=') {
145                                 *bufptr='\0';
146                                 mapptr->key = tstrdup(buf);
147                                 bufptr=buf;
148                                 state=INF_WAITVAL;
149                         } else if (c==' ' || c=='\t') {
150                                 *bufptr='\0';
151                                 mapptr->key = tstrdup(buf);
152                                 bufptr=buf;
153                                 state=INF_WAITDELIM;
154                         } else
155                                 tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
156                 } else if ( state==INF_WAITDELIM ) {
157                         if (c=='=')
158                                 state=INF_WAITVAL;
159                         else if (!(c==' ' || c=='\t'))
160                                 tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file);
161                 } else if ( state==INF_WAITVAL ) {
162                         if ( c=='\n' ) {
163                                 bufptr=buf;
164                                 *bufptr='\0';
165                                 mapptr->value=tstrdup(buf);
166                                 mapptr++;
167                                 mapptr->section = tstrdup((mapptr-1)->section);
168                                 state=INF_WAIT;
169                                 lineno++;
170                         } else if ( c=='\\' ) {
171                                 bufptr=buf;
172                                 state=INF_ESCAPE;
173                         } else if ( c=='"' ) {
174                                 bufptr=buf;
175                                 state=INF_INQVAL;
176                         } else if ( !(c==' ' || c=='\t') ) {
177                                 bufptr=buf;
178                                 *bufptr=c;
179                                 bufptr++;
180                                 state=INF_INVAL;
181                         }
182                 } else if ( state==INF_ESCAPE ) {
183                         *bufptr=c;
184                         bufptr++;
185                         state=INF_INVAL;
186                         if (c=='\n') lineno++;
187                 } else if ( state==INF_QESCAPE ) {
188                         *bufptr=c;
189                         bufptr++;
190                         state=INF_INQVAL;
191                         if (c=='\n') lineno++;
192                 } else if ( state==INF_INVAL ) {
193                         if ( c=='#' ) {
194                                 *bufptr=' ';
195                                 clrbackspace(bufptr,buf);
196                                 mapptr->value=tstrdup(buf);
197                                 mapptr++;
198                                 mapptr->section = tstrdup((mapptr-1)->section);
199                                 bufptr=buf;
200                                 state=INF_COMMENT;
201                         } else if (c=='\n') {
202                                 *bufptr=' ';
203                                 clrbackspace(bufptr,buf);
204                                 mapptr->value=tstrdup(buf);
205                                 mapptr++;
206                                 mapptr->section = tstrdup((mapptr-1)->section);
207                                 bufptr=buf;
208                                 state=INF_WAIT;
209                                 lineno++;
210                         } else if (c=='\\') {
211                                 state=INF_ESCAPE;
212                         } else {
213                                 *bufptr=c;
214                                 bufptr++;
215                         }
216                 } else if ( state==INF_INQVAL ) {
217                         if (c=='\\') {
218                                 state=INF_QESCAPE;
219                         } else if ( c=='"' ) {
220                                 *bufptr='\0';
221                                 mapptr->value=tstrdup(buf);
222                                 mapptr++;
223                                 mapptr->section = tstrdup((mapptr-1)->section);
224                                 bufptr=buf;
225                                 state=INF_WAIT;
226                         } else {
227                                 *bufptr=c;
228                                 bufptr++;
229                                 if (c=='\n') lineno++;
230                         }
231                 } else 
232                         tlog( TL_CRIT|TL_EXIT,"INFParse: internal error, unknown state %d", state );
233         }
234
235         if ( state==INF_INVAL ) {
236                 *bufptr=' ';
237                 clrbackspace(bufptr,buf);
238                 mapptr->value=tstrdup(buf);
239                 mapptr++;
240                 mapptr->section=NULL;
241                 bufptr=buf;
242         } else if ( state!=INF_WAIT ) {
243                 tlog( TL_ALARM|TL_EXIT,"Unexpected end of file %s", file);
244         } else if (mapptr->section) {
245                 tfree(mapptr->section);
246                 mapptr->section=NULL;
247         }
248         tfree(buf);
249         fclose(in);
250
251         return map;     
252 }
253
254 void  
255 INFFree(InfMap *inf) {
256         InfMap *ptr=inf;
257         while(ptr && ptr->section) {
258                 tfree(ptr->section);
259                 if (ptr->key) tfree(ptr->key);
260                 if (ptr->value) tfree(ptr->value);
261                 ptr++;
262         }
263         tfree(inf);
264 }
265
266 InfMap*
267 INFFindInfMap(InfMap *inf, char *sect, char *key) {
268         while(inf && inf->section) {
269                 if (
270                         (sect==NULL || strcmp(inf->section,sect)==0) &&
271                         (key==NULL || strcmp(inf->key,key)==0)
272                    )
273                    return inf;
274
275                 inf++;
276         }
277         return NULL;
278 }
279
280 int
281 INFGetInt(InfMap *inf, char *sect, char *key, int *val) {
282         inf = INFFindInfMap(inf, sect, key);
283         if (inf) {
284                 *val=atoi(inf->value);
285                 return 0;
286         }
287         return 1;
288 }
289
290 int
291 INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val) {
292         inf = INFFindInfMap(inf, sect, key);
293         if (inf) {
294                 *val=strtoul(inf->value, NULL,0);
295                 return 0;
296         }
297         return 1;
298 }
299
300 int
301 INFGetFloat(InfMap *inf, char *sect, char *key, float *val) {
302         inf = INFFindInfMap(inf, sect, key);
303         if (inf) {
304                 *val=strtof(inf->value, NULL);
305                 return 0;
306         }
307         return 1;
308 }
309
310 int
311 INFGetDouble(InfMap *inf, char *sect, char *key, double *val) {
312         inf = INFFindInfMap(inf, sect, key);
313         if (inf) {
314                 *val=strtod(inf->value, NULL);
315                 return 0;
316         }
317         return 1;
318 }
319
320 int
321 INFGetString(InfMap *inf, char *sect, char *key, char **val) {
322         inf = INFFindInfMap(inf, sect, key);
323         if (inf) {
324                 *val=tstrdup(inf->value);
325                 return 0;
326         }
327         return 1;
328 }
329
330 static int
331 parseBool(char *str)
332 {
333         struct {
334                 char *key;
335                 int      val;
336         }
337                 bdata[] = 
338                 {
339                         {"1",   1},
340                         {"0",   0},
341                         {"on",  1},
342                         {"off", 0},
343                         {"enable",      1},
344                         {"disable",     0},
345                         {"true",        1},
346                         {"false",       0},
347                         {"yes", 1},
348                         {"no",  0}
349                 };
350         int i;
351
352         while(*str && isspace(*str))
353                 str++;
354
355         for(i=0;i<lengthof(bdata);i++)
356                 if ( strcasecmp(bdata[i].key, str) == 0 )
357                         return bdata[i].val;
358
359         tlog(TL_ALARM|TL_EXIT, "Unknown value '%s' for boolean variable", str);
360
361         return 0;
362 }
363
364 int
365 INFGetBoolean(InfMap *inf, char *sect, char *key, int *val) {
366         inf = INFFindInfMap(inf, sect, key);
367         if (inf) {
368                 *val=parseBool(inf->value);
369                 return 0;
370         }
371         return 1;
372 }
373
374