Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,1042 +0,0 @@
1
-/*
2
- * Standalone Configuration File Parser
3
- *
4
- * Copyright (C) 2008 iptelorg GmbH
5
- * Written by Jan Janak <jan@iptel.org>
6
- *
7
- * This file is part of Kamailio, a free SIP server.
8
- *
9
- * Kamailio is free software; you can redistribute it and/or modify it under the
10
- * terms of the GNU General Public License as published by the Free Software
11
- * Foundation; either version 2 of the License, or (at your option) any later
12
- * version.
13
- *
14
- * Kamailio is distributed in the hope that it will be useful, but WITHOUT ANY
15
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17
- * details.
18
- *
19
- * You should have received a copy of the GNU General Public License along
20
- * with this program; if not, write to the Free Software Foundation, Inc., 
21
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
- */
23
-/*!
24
- * \file
25
- * \brief Kamailio core :: Standalone Configuration File Parser
26
- * \author Jan Janak <jan@iptel.org>
27
- * \ingroup core
28
- *
29
- * Module: \ref core
30
- *
31
- * See \ref ConfigEngine
32
- *
33
- * \page ConfigEngine
34
- * In file \ref cfg_parser.c 
35
- * Configuration examples
36
- * - \ref ConfigExample1
37
- * - \ref ConfigExample2
38
- * - \ref ConfigExample3
39
- * - \ref ConfigExample4
40
- * - \ref ConfigExample5
41
- * - \ref ConfigExample6
42
- * - \ref ConfigExample7
43
- * - \ref ConfigExample8
44
- *
45
- * <b>Run-time Allocated Destination Variables</b>
46
- * - the destination variable pointers in arrays are assigned at compile time
47
- * - The address of variables allocated on the heap (typically in dynamically allocated
48
- *   structures) is not know and thus we need to assign NULL initially and change the pointer
49
- *   at runtime.
50
- *   (provide an example).
51
- *
52
- * <b>Built-in parsing functions</b>
53
- *
54
- * *_val functions parse the whole option body (including =)
55
- */
56
-
57
-
58
-/*! \page ConfigExample1  Configuration engine Example 1: Options without values
59
- *
60
-\verbatim
61
- *	str file = STR_STATIC_INIT("test.cfg");
62
- *	cfg_parser_t* parser;
63
- *	int feature_a = 0, feature_b = 0;
64
- *
65
- *	cfg_option_t options[] = {
66
- *		{"enable_feature_a",  .param = &feature_a, .val = 1},
67
- *		{"disable_feature_a", .param = &feature_a, .val = 0},
68
- *		{"feature_b",         .param = &feature_b, .val = 1},
69
- *      {0}
70
- *	};
71
- *
72
- *	if ((parser = cfg_parser_init(&file)) == NULL) {
73
- *		ERR("Error while creating parser\n");
74
- *		return -1;
75
- *	}
76
- *
77
- *	cfg_set_options(parser, options);
78
- *
79
- *	if (sr_cfg_parse(parser) < 0) {
80
- *		ERR("Error while parsing configuration file\n");
81
- *      cfg_parser_close(parser);
82
- *		return -1;
83
- *	}
84
- *
85
- *	cfg_parser_close(parser);
86
-\endverbatim
87
- */
88
-
89
-/*! \page ConfigExample2  Configuration engine Example 2: Options with integer values
90
-\verbatim
91
- * 	cfg_option_t options[] = {
92
- *		{"max_number",   .param = &max_number,   .f = cfg_parse_int_val },
93
- *		{"extra_checks", .param = &extra_checks, .f = cfg_parse_bool_val},
94
- *		{0}
95
- *	};
96
-\endverbatim
97
- */
98
-
99
-/*! \page ConfigExample3 Configuration engine Example 3: Enum options
100
-\verbatim
101
- * int scope;
102
- *
103
- *	cfg_option_t scopes[] = {
104
- *	    {"base",     .param = &scope, .val = 1},
105
- *	    {"onelevel", .param = &scope, .val = 2},
106
- *	    {"one",      .param = &scope, .val = 3},
107
- *	    {"subtree",  .param = &scope, .val = 4},
108
- *	    {"sub",      .param = &scope, .val = 5},
109
- *	    {"children", .param = &scope, .val = 6},
110
- *	    {0}
111
- *  };
112
- *
113
- *	cfg_option_t options[] = {
114
- *		{"scope", .param = scopes, .f = cfg_parse_enum_val},
115
- *		{0}
116
- *	};
117
-\endverbatim
118
- */
119
-
120
-/*! \page ConfigExample4 Configuration engine Example 4: Options with string values
121
-\verbatim
122
-* 	str filename = STR_NULL;
123
- *
124
- *	cfg_option_t options[] = {
125
- *		{"filename", .param = &filename, .f = cfg_parse_str_val},
126
- *		{0}
127
- *	};
128
- *
129
- * - By default the function returns a pointer to an internal buffer which will be destroyed
130
- *   by a subsequent call
131
- * - There are flags to tell the function to copy the resuting string in a pkg, shm, glibc,
132
- *   or static buffers
133
-\endverbatim
134
- */
135
-
136
-/*! \page ConfigExample5 Configuration engine Example 5: Custom value parsing
137
- * TBD
138
- */
139
-
140
-/*! \page ConfigExample6 Configuration engine Example 6: Parsing Sections
141
- * TBD
142
- */
143
-
144
-/*! \page ConfigExample7 Configuration engine Example 7: Default Options
145
- * TBD
146
- */
147
-
148
-/*! \page ConfigExample8 Configuration engine Example 8: Memory management of strings
149
- *
150
- * Data types with fixed size are easy, they can be copied into a pre-allocated memory
151
- * buffer, strings cannot because their length is unknown.
152
- */
153
-
154
-#include "cfg_parser.h"
155
-
156
-#include "mem/mem.h"
157
-#include "mem/shm_mem.h"
158
-#include "dprint.h"
159
-#include "trim.h"
160
-#include "ut.h"
161
-
162
-#include <string.h>
163
-#include <stdlib.h>
164
-#include <stdio.h>
165
-#include <libgen.h>
166
-
167
-
168
-/*! \brief The states of the lexical scanner */
169
-enum st {
170
-	ST_S,  /*!< Begin */
171
-	ST_A,  /*!< Alphanumeric */
172
-	ST_AE, /*!< Alphanumeric escaped */
173
-	ST_Q,  /*!< Quoted */
174
-	ST_QE, /*!< Quoted escaped */
175
-	ST_C,  /*!< Comment */
176
-	ST_CE, /*!< Comment escaped */
177
-	ST_E,  /*!< Escaped */
178
-};
179
-
180
-
181
-/*! \brief Test for alphanumeric characters */
182
-#define IS_ALPHA(c) \
183
-    (((c) >= 'a' && (c) <= 'z') || \
184
-     ((c) >= 'A' && (c) <= 'Z') || \
185
-     ((c) >= '0' && (c) <= '9') || \
186
-     (c) == '_')
187
-
188
-
189
-/*! \brief Test for delimiter characters */
190
-#define IS_DELIM(c) \
191
-    ((c) == '=' || \
192
-     (c) == ':' || \
193
-     (c) == ';' || \
194
-     (c) == '.' || \
195
-     (c) == ',' || \
196
-     (c) == '?' || \
197
-     (c) == '[' || \
198
-     (c) == ']' || \
199
-     (c) == '/' || \
200
-     (c) == '@' || \
201
-     (c) == '!' || \
202
-     (c) == '$' || \
203
-     (c) == '%' || \
204
-     (c) == '&' || \
205
-     (c) == '*' || \
206
-     (c) == '(' || \
207
-     (c) == ')' || \
208
-     (c) == '-' || \
209
-     (c) == '+' || \
210
-     (c) == '|' || \
211
-     (c) == '\'')
212
-
213
-
214
-/*! \brief Whitespace characters */
215
-#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r') 
216
-#define IS_QUOTE(c)      ((c) == '\"')  /* Quote characters */
217
-#define IS_COMMENT(c)    ((c) == '#')   /* Characters that start comments */
218
-#define IS_ESCAPE(c)     ((c) == '\\')  /* Escape characters */
219
-#define IS_EOL(c)        ((c) == '\n')  /* End of line */
220
-
221
-
222
-/*! \brief
223
- * Append character to the value of current token
224
- */
225
-#define PUSH(c)                            \
226
-    if (token->val.len >= MAX_TOKEN_LEN) { \
227
-        ERR("%s:%d:%d: Token too long\n",  \
228
-        st->file, st->line, st->col);      \
229
-        return -1;                         \
230
-    }                                      \
231
-    if (token->val.len == 0) {             \
232
-         token->start.line = st->line;     \
233
-         token->start.col = st->col;       \
234
-    }                                      \
235
-    token->val.s[token->val.len++] = (c);
236
-
237
-
238
-/*! \brief
239
- * Return current token from the lexical analyzer
240
- */
241
-#define RETURN(c)               \
242
-    token->end.line = st->line; \
243
-    token->end.col = st->col;   \
244
-    token->type = (c);          \
245
-    print_token(token);         \
246
-    return 0;
247
-
248
-
249
-/*! \brief
250
- * Get next character and update counters
251
- */
252
-#define READ_CHAR      \
253
-     c = fgetc(st->f); \
254
-     if (IS_EOL(c)) {  \
255
-         st->line++;   \
256
-         st->col = 0;  \
257
-     } else {          \
258
-         st->col++;    \
259
-     }
260
-
261
-
262
-cfg_option_t cfg_bool_values[] = {
263
-	{"yes",      .val = 1},
264
-	{"true",     .val = 1},
265
-	{"enable",   .val = 1},
266
-	{"enabled",  .val = 1},
267
-	{"1",        .val = 1},
268
-	{"on",       .val = 1},
269
-	{"no",       .val = 0},
270
-	{"false",    .val = 0},
271
-	{"disable",  .val = 0},
272
-	{"disabled", .val = 0},
273
-	{"0",        .val = 0},
274
-	{"off",      .val = 0},
275
-	{0}
276
-};
277
-
278
-
279
-static void print_token(cfg_token_t* token)
280
-{
281
-#ifdef EXTRA_DEBUG
282
-	int i, j;
283
-	char* buf;
284
-
285
-	if ((buf = pkg_malloc(token->val.len * 2)) == NULL) {
286
-		LM_DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n", 
287
-			token->type, STR_FMT(&token->val),
288
-			token->start.line, token->start.col, 
289
-			token->end.line, token->end.col);
290
-	} else {
291
-		for(i = 0, j = 0; i < token->val.len; i++) {
292
-			switch(token->val.s[i]) {
293
-			case '\n': buf[j++] = '\\'; buf[j++] = 'n'; break;
294
-			case '\r': buf[j++] = '\\'; buf[j++] = 'r'; break;
295
-			case '\t': buf[j++] = '\\'; buf[j++] = 't'; break;
296
-			case '\0': buf[j++] = '\\'; buf[j++] = '0'; break;
297
-			case '\\': buf[j++] = '\\'; buf[j++] = '\\'; break;
298
-			default: buf[j++] = token->val.s[i];
299
-			}
300
-		}
301
-		LM_DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n", 
302
-			token->type, j, buf,
303
-			token->start.line, token->start.col, 
304
-			token->end.line, token->end.col);
305
-		pkg_free(buf);
306
-	}
307
-#endif /* EXTRA_DEBUG */
308
-}
309
-
310
-
311
-int cfg_get_token(cfg_token_t* token, cfg_parser_t* st, unsigned int flags)
312
-{
313
-	static int look_ahead = EOF;
314
-	int c;
315
-	enum st state;
316
-
317
-	state = ST_S;
318
-	
319
-	token->val.s = token->buf;
320
-	token->val.len = 0;
321
-
322
-	if (look_ahead != EOF) {
323
-		c = look_ahead;
324
-		look_ahead = EOF;
325
-	} else {
326
-		READ_CHAR;
327
-	}
328
-
329
-	while(c != EOF) {
330
-		switch(state) {
331
-		case ST_S:
332
-			if (flags & CFG_EXTENDED_ALPHA) {
333
-				if (IS_WHITESPACE(c)) {
334
-					     /* Do nothing */
335
-				} else if (IS_ALPHA(c) ||
336
-					   IS_ESCAPE(c) ||
337
-					   IS_DELIM(c)) {
338
-					PUSH(c);
339
-					state = ST_A;
340
-				} else if (IS_QUOTE(c)) {
341
-					state = ST_Q;
342
-				} else if (IS_COMMENT(c)) {
343
-					state = ST_C;
344
-				} else if (IS_EOL(c)) {
345
-					PUSH(c);
346
-					RETURN(c);
347
-				} else {
348
-					ERR("%s:%d:%d: Invalid character 0x%x\n", 
349
-					    st->file, st->line, st->col, c);
350
-					return -1;
351
-				}
352
-			} else {
353
-				if (IS_WHITESPACE(c)) {
354
-					     /* Do nothing */
355
-				} else if (IS_ALPHA(c)) {
356
-					PUSH(c);
357
-					state = ST_A;
358
-				} else if (IS_QUOTE(c)) {
359
-					state = ST_Q;
360
-				} else if (IS_COMMENT(c)) {
361
-					state = ST_C;
362
-				} else if (IS_ESCAPE(c)) {
363
-					state = ST_E;
364
-				} else if (IS_DELIM(c) || IS_EOL(c)) {
365
-					PUSH(c);
366
-					RETURN(c);
367
-				} else {
368
-					ERR("%s:%d:%d: Invalid character 0x%x\n", 
369
-					    st->file, st->line, st->col, c);
370
-					return -1;
371
-				}
372
-			}
373
-			break;
374
-
375
-		case ST_A:
376
-			if (flags & CFG_EXTENDED_ALPHA) {
377
-				if (IS_ALPHA(c) ||
378
-				    IS_DELIM(c) ||
379
-				    IS_QUOTE(c)) {
380
-					PUSH(c);
381
-				} else if (IS_ESCAPE(c)) {
382
-					state = ST_AE;
383
-				} else if (IS_COMMENT(c) || IS_EOL(c) || IS_WHITESPACE(c)) {
384
-					look_ahead = c;
385
-					RETURN(CFG_TOKEN_ALPHA);
386
-				} else {
387
-					ERR("%s:%d:%d: Invalid character 0x%x\n", 
388
-					    st->file, st->line, st->col, c);
389
-					return -1;
390
-				}
391
-			} else {
392
-				if (IS_ALPHA(c)) {
393
-					PUSH(c);
394
-				} else if (IS_ESCAPE(c)) {
395
-					state = ST_AE;
396
-				} else if (IS_WHITESPACE(c) ||
397
-					   IS_DELIM(c) ||
398
-					   IS_QUOTE(c) ||
399
-					   IS_COMMENT(c) ||
400
-					   IS_EOL(c)) {
401
-					look_ahead = c;
402
-					RETURN(CFG_TOKEN_ALPHA);
403
-				} else {
404
-					ERR("%s:%d:%d: Invalid character 0x%x\n", 
405
-					    st->file, st->line, st->col, c);
406
-					return -1;
407
-				}
408
-			}
409
-			break;
410
-
411
-		case ST_AE:
412
-			if (IS_COMMENT(c) ||
413
-			    IS_QUOTE(c) ||
414
-			    IS_ESCAPE(c)) {
415
-				PUSH(c);
416
-			} else if (c == 'r') {
417
-				PUSH('\r');
418
-			} else if (c == 'n') {
419
-				PUSH('\n');
420
-			} else if (c == 't') {
421
-				PUSH('\t');
422
-			} else if (c == ' ') {
423
-				PUSH(' ');
424
-			} else if (IS_EOL(c)) {
425
-				     /* Do nothing */
426
-			} else {
427
-				ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
428
-				    st->file, st->line, st->col, c);
429
-				return -1;
430
-			}
431
-			state = ST_A;
432
-			break;
433
-
434
-		case ST_Q:
435
-			if (IS_QUOTE(c)) {
436
-				RETURN(CFG_TOKEN_STRING);
437
-			} else if (IS_ESCAPE(c)) {
438
-				state = ST_QE;
439
-				break;
440
-			} else {
441
-				PUSH(c);
442
-			}
443
-			break;
444
-
445
-		case ST_QE:
446
-			if (IS_ESCAPE(c) ||
447
-			    IS_QUOTE(c)) {
448
-				PUSH(c);
449
-			} else if (c == 'n') {
450
-				PUSH('\n');
451
-			} else if (c == 'r') {
452
-				PUSH('\r');
453
-			} else if (c == 't') {
454
-				PUSH('\t');
455
-			} else if (IS_EOL(c)) {
456
-				     /* Do nothing */
457
-			} else {
458
-				ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
459
-				    st->file, st->line, st->col, c);
460
-				return -1;
461
-			}
462
-			state = ST_Q;
463
-			break;
464
-
465
-		case ST_C:
466
-			if (IS_ESCAPE(c)) {
467
-				state = ST_CE;
468
-			} else if (IS_EOL(c)) {
469
-				state = ST_S;
470
-				continue; /* Do not read a new char, return EOL */
471
-			} else {
472
-				     /* Do nothing */
473
-			}
474
-			break;
475
-
476
-		case ST_CE:
477
-			state = ST_C;
478
-			break;
479
-
480
-		case ST_E:
481
-			if (IS_COMMENT(c) ||
482
-			    IS_QUOTE(c) ||
483
-			    IS_ESCAPE(c)) {
484
-				PUSH(c);
485
-				RETURN(c);
486
-			} else if (c == 'r') {
487
-				PUSH('\r');
488
-				RETURN('\r');
489
-			} else if (c == 'n') {
490
-				PUSH('\n');
491
-				RETURN('\n');
492
-			} else if (c == 't') {
493
-				PUSH('\t');
494
-				RETURN('\t');
495
-			} else if (c == ' ') {
496
-				PUSH(' ');
497
-				RETURN(' ');
498
-			} else if (IS_EOL(c)) {
499
-				     /* Escped eol means no eol */
500
-				state = ST_S;
501
-			} else {
502
-				ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
503
-				    st->file, st->line, st->col, c);
504
-				return -1;
505
-			}
506
-			break;
507
-		}
508
-
509
-		READ_CHAR;
510
-	};
511
-
512
-	switch(state) {
513
-	case ST_S: 
514
-	case ST_C:
515
-	case ST_CE:
516
-		return 1;
517
-
518
-	case ST_A:
519
-		RETURN(CFG_TOKEN_ALPHA);
520
-
521
-	case ST_Q:
522
-		ERR("%s:%d:%d: Premature end of file, missing closing quote in"
523
-			" string constant\n", st->file, st->line, st->col);
524
-		return -1;
525
-
526
-	case ST_QE:
527
-	case ST_E:
528
-	case ST_AE:
529
-		ERR("%s:%d:%d: Premature end of file, missing escaped character\n", 
530
-		    st->file, st->line, st->col);
531
-		return -1;
532
-	}
533
-	BUG("%s:%d:%d: Invalid state %d\n",
534
-		st->file, st->line, st->col, state);
535
-	return -1;
536
-}
537
-
538
-
539
-int cfg_parse_section(void* param, cfg_parser_t* st, unsigned int flags)
540
-{
541
-	cfg_token_t t;
542
-	int ret;
543
-
544
-	ret = cfg_parse_str(param, st, flags);
545
-	if (ret < 0) return ret;
546
-	if (ret > 0) {
547
-		ERR("%s:%d:%d: Section name missing.\n",
548
-			st->file, st->line, st->col);
549
-		return ret;
550
-	}
551
-
552
-	ret = cfg_get_token(&t, st, flags);
553
-	if (ret < 0) goto error;
554
-	if (ret > 0) {
555
-		ERR("%s:%d:%d: Closing ']' missing\n", st->file, st->line, st->col);
556
-		goto error;
557
-	}
558
-	if (t.type != ']') {
559
-		ERR("%s:%d:%d: Syntax error, ']' expected\n", 
560
-		    st->file, t.start.line, t.start.col);
561
-		goto error;
562
-	}
563
-
564
-	if (cfg_eat_eol(st, flags)) goto error;
565
-	return 0;
566
-
567
- error:
568
-	if (param && ((str*)param)->s) {
569
-		if (flags & CFG_STR_PKGMEM) {
570
-			pkg_free(((str*)param)->s);
571
-			((str*)param)->s = NULL;
572
-		} else if (flags & CFG_STR_SHMMEM) {
573
-			shm_free(((str*)param)->s);
574
-			((str*)param)->s = NULL;
575
-		} else if (flags & CFG_STR_MALLOC) {
576
-			free(((str*)param)->s);
577
-			((str*)param)->s = NULL;
578
-		}		
579
-	}
580
-	return -1;
581
-}
582
-
583
-
584
-static char* get_base_name(str* filename)
585
-{
586
-	char* tmp1, *tmp2, *res;
587
-	int len;
588
-
589
-	res = NULL;
590
-	if ((tmp1 = as_asciiz(filename)) == NULL) {
591
-		ERR("cfg_parser: No memory left\n");
592
-		goto error;
593
-	}
594
-	
595
-	if ((tmp2 = basename(tmp1)) == NULL) {
596
-		ERR("cfg_parser: Error in basename\n");
597
-		goto error;
598
-	}
599
-	len = strlen(tmp2);
600
-
601
-	if ((res = pkg_malloc(len + 1)) == NULL) {
602
-		ERR("cfg_parser: No memory left");
603
-		goto error;
604
-	}
605
-	memcpy(res, tmp2, len + 1);
606
-	pkg_free(tmp1);
607
-	return res;
608
-
609
- error:
610
-	if (tmp1) pkg_free(tmp1);
611
-	return NULL;
612
-}
613
-
614
-
615
-
616
-/** initialize the config parser.
617
- * @param basedir - path to the config file name. If 0 the path
618
- *               (base directory) of the main ser.cfg file will be used, else
619
- *               basedir will be concatenated to the filename. It will be
620
- *               used only if filename is not an absolute path.
621
- * @param filename - config filename (can include path elements).
622
- * @return 0 on error, !=0 on success.
623
- */
624
-cfg_parser_t* cfg_parser_init(str* basedir, str* filename)
625
-{
626
-	cfg_parser_t* st;
627
-	char* pathname, *base, *abs_pathname;
628
-
629
-	abs_pathname = NULL;
630
-	pathname = filename->s;
631
-	st = NULL;
632
-	base = NULL;
633
-	
634
-	/* if basedir == 0 or != "" get_abs_pathname */
635
-	if (basedir == 0  || basedir->len != 0) {
636
-		if ((abs_pathname = get_abs_pathname(basedir, filename)) == NULL) {
637
-			ERR("cfg_parser: Error while converting %.*s to absolute"
638
-					" pathname\n", STR_FMT(filename));
639
-			goto error;
640
-		}
641
-		pathname = abs_pathname;
642
-	}
643
-
644
-	if ((base = get_base_name(filename)) == NULL) goto error;
645
-
646
-	if ((st = (cfg_parser_t*)pkg_malloc(sizeof(*st))) == NULL) {
647
-		ERR("cfg_parser: No memory left\n");
648
-		goto error;
649
-	}
650
-	memset(st, '\0', sizeof(*st));
651
-
652
-	if ((st->f = fopen(pathname, "r")) == NULL) {
653
-		ERR("cfg_parser: Unable to open file '%s'\n", pathname);
654
-		goto error;
655
-	}
656
-
657
-	if (abs_pathname) pkg_free(abs_pathname);
658
-
659
-	st->file = base;
660
-	st->line = 1;
661
-	st->col = 0;
662
-	return st;
663
-
664
- error:
665
-	if (st) {
666
-		if (st->f) fclose(st->f);
667
-		pkg_free(st);
668
-	}
669
-	if (base) pkg_free(base);
670
-	if (abs_pathname) pkg_free(abs_pathname);
671
-	return NULL;
672
-}
673
-
674
-
675
-void cfg_parser_close(cfg_parser_t* st)
676
-{
677
-	if (!st) return;
678
-	if (st->f) fclose(st->f);
679
-	if (st->file) pkg_free(st->file);
680
-	pkg_free(st);
681
-}
682
-
683
-
684
-void cfg_section_parser(cfg_parser_t* st, cfg_func_f parser, void* param)
685
-{
686
-	if (st == NULL) return;
687
-	st->section.parser = parser;
688
-	st->section.param = param;
689
-}
690
-
691
-
692
-void cfg_set_options(cfg_parser_t* st, cfg_option_t* options)
693
-{
694
-	if (st) st->options = options;
695
-}
696
-
697
-
698
-static int process_option(cfg_parser_t* st, cfg_option_t* opt)
699
-{
700
-	if (opt->f) {
701
-		/* We have a function so store it and pass opt->dst to it */
702
-		if (opt->f(opt->param, st, opt->flags) < 0) return -1;
703
-	} else {
704
-		/* We have no function, so if we have a pointer to some
705
-		 * variable in opt->param then store the value of opt->i
706
-		 * there, the variable is assumed to be of type i
707
-		 */
708
-		if (opt->param) *(int*)opt->param = opt->val;
709
-	}
710
-	return 0;
711
-}
712
-
713
-
714
-int sr_cfg_parse(cfg_parser_t* st)
715
-{
716
-	int ret;
717
-	cfg_token_t t;
718
-	cfg_option_t* opt;
719
-
720
-	while(1) {
721
-		ret = cfg_get_token(&t, st, 0);
722
-		if (ret < 0) return ret;
723
-		if (ret > 0) break;
724
-
725
-		switch(t.type) {
726
-		case CFG_TOKEN_ALPHA:
727
-			/* Lookup the option name */
728
-			if ((opt = cfg_lookup_token(st->options, &t.val)) == NULL) {
729
-				ERR("%s:%d:%d: Unsupported option '%.*s'\n", 
730
-				    st->file, t.start.line, t.start.col, STR_FMT(&t.val));
731
-				return -1;
732
-			}
733
-
734
-			st->cur_opt = &t;
735
-			if (process_option(st, opt) < 0) { st->cur_opt = 0; return -1; }
736
-			st->cur_opt = 0;
737
-			break;
738
-
739
-		case '[': 
740
-			if (st->section.parser == NULL) {
741
-				ERR("%s:%d:%d: Syntax error\n", st->file,
742
-					t.start.line, t.start.col);
743
-				return -1;
744
-			}
745
-			if (st->section.parser(st->section.param, st, 0) < 0) return -1;
746
-			break;
747
-
748
-			     /* Empty line */
749
-		case '\n': continue;
750
-
751
-		default:
752
-			ERR("%s:%d:%d: Syntax error\n", 
753
-			    st->file, t.start.line, t.start.col);
754
-			return -1;
755
-		}
756
-	}
757
-	return 0;
758
-}
759
-
760
-
761
-cfg_option_t* cfg_lookup_token(cfg_option_t* table, str* token)
762
-{
763
-	int len, i;
764
-	int (*cmp)(const char* s1, const char* s2, size_t n) = NULL;
765
-
766
-
767
-	if (table == NULL) return NULL;
768
-
769
-	for(i = 0; table[i].name; i++) {
770
-		len = strlen(table[i].name);
771
-
772
-		if (table[i].flags & CFG_PREFIX) {
773
-			if (token->len < len) continue;
774
-		} else {
775
-			if (token->len != len) continue;
776
-		}
777
-
778
-		if (table[i].flags & CFG_CASE_SENSITIVE) cmp = strncmp;
779
-		else cmp = strncasecmp;
780
-
781
-		if (cmp(token->s, table[i].name, len)) continue;
782
-		return table + i;
783
-	}
784
-	if (table[i].flags & CFG_DEFAULT) {
785
-		return table + i;
786
-	}
787
-	return NULL;
788
-}
789
-
790
-
791
-int cfg_eat_equal(cfg_parser_t* st, unsigned int flags)
792
-{
793
-	cfg_token_t t;
794
-	int ret;
795
-
796
-	ret = cfg_get_token(&t, st, flags);
797
-	if (ret < 0) return ret;
798
-	if (ret > 0) {
799
-		ERR("%s:%d:%d: Delimiter '=' missing\n", 
800
-		    st->file, st->line, st->col);
801
-		return ret;
802
-	}
803
-
804
-	if (t.type != '=') {
805
-		ERR("%s:%d:%d: Syntax error, '=' expected\n", 
806
-		    st->file, t.start.line, t.start.col);
807
-		return -1;
808
-	}
809
-	return 0;
810
-}
811
-
812
-
813
-int cfg_eat_eol(cfg_parser_t* st, unsigned int flags)
814
-{
815
-	cfg_token_t t;
816
-	int ret;
817
-
818
-	/* Skip EOL */
819
-	ret = cfg_get_token(&t, st, 0);
820
-	if (ret < 0) return ret;
821
-	if (ret > 0) return 0;
822
-	if (t.type != '\n') {
823
-		ERR("%s:%d:%d: End of line expected\n", 
824
-			st->file, t.start.line, t.start.col);
825
-		return -1;
826
-	}
827
-	return 0;
828
-}
829
-
830
-
831
-int cfg_parse_enum(void* param, cfg_parser_t* st, unsigned int flags)
832
-{
833
-	int ret;
834
-    cfg_token_t t;
835
-	cfg_option_t* values, *val;
836
-	
837
-	values = (cfg_option_t*)param;
838
-
839
-	ret = cfg_get_token(&t, st, flags);
840
-	if (ret != 0) return ret;
841
-
842
-	if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
843
-		ERR("%s:%d:%d: Invalid enum value '%.*s'\n",
844
-		    st->file, t.start.line, t.start.col, STR_FMT(&t.val));
845
-		return -1;
846
-	}
847
-
848
-	if (values) {
849
-		if ((val = cfg_lookup_token(values, &t.val)) == NULL) {
850
-			ERR("%s:%d:%d Unsupported enum value '%.*s'\n", 
851
-				st->file, t.start.line, t.start.col, STR_FMT(&t.val));
852
-			return -1;
853
-		}
854
-		return process_option(st, val);
855
-	} else {
856
-		return 0;
857
-	}
858
-}
859
-
860
-
861
-int cfg_parse_enum_opt(void* param, cfg_parser_t* st, unsigned int flags)
862
-{
863
-	int ret;
864
-
865
-	if (cfg_eat_equal(st, flags)) return -1;
866
-
867
-	ret = cfg_parse_enum(param, st, CFG_EXTENDED_ALPHA | flags);
868
-	if (ret > 0) {
869
-		ERR("%s:%d:%d: Option value missing\n",
870
-		    st->file, st->line, st->col);
871
-		return ret;
872
-	} else if (ret < 0) return ret;
873
-
874
-	if (cfg_eat_eol(st, flags)) return -1;
875
-	return 0;
876
-}
877
-
878
-
879
-int cfg_parse_str(void* param, cfg_parser_t* st, unsigned int flags)
880
-{
881
-	str* val;
882
-	int ret;
883
-	char* buf;
884
-    cfg_token_t t;
885
-	
886
-	ret = cfg_get_token(&t, st, flags);
887
-	if (ret != 0) return ret;
888
-	
889
-	if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
890
-		ERR("%s:%d:%d: Invalid string value '%.*s', a string expected.\n",
891
-		    st->file, t.start.line, t.start.col, STR_FMT(&t.val));
892
-		return -1;
893
-	}
894
-
895
-	if (!param) return 0;
896
-	val = (str*)param;
897
-
898
-	if (flags & CFG_STR_STATIC) {
899
-		if (!val->s || val->len <= t.val.len) {
900
-			ERR("%s:%d:%d: Destination string buffer too small\n",
901
-				st->file, t.start.line, t.start.col);
902
-			return -1;
903
-		}
904
-		buf = val->s;
905
-	} else if (flags & CFG_STR_SHMMEM) {
906
-		if ((buf = shm_malloc(t.val.len + 1)) == NULL) {
907