Annotation of embedaddon/confuse/src/confuse.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 2002,2003,2007 Martin Hedenfalk <martin@bzero.se>
3: *
4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: */
16:
17: #ifdef HAVE_CONFIG_H
18: # include <config.h>
19: #endif
20:
21: #define _GNU_SOURCE
22: #include <sys/types.h>
23: #include <string.h>
24: #include <stdlib.h>
25: #include <assert.h>
26: #include <errno.h>
27: #ifndef _WIN32
28: # include <pwd.h>
29: #endif
30: #ifdef HAVE_UNISTD_H
31: # include <unistd.h>
32: #endif
33: #include <ctype.h>
34:
35: #include "confuse.h"
36:
37: #define is_set(f, x) (((f) & (x)) == (f))
38:
39: #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT)
40: # include <locale.h>
41: # include <libintl.h>
42: # define _(str) dgettext(PACKAGE, str)
43: #else
44: # define _(str) str
45: #endif
46: #define N_(str) str
47:
48: extern FILE *cfg_yyin;
49: extern int cfg_yylex(cfg_t *cfg);
50: extern int cfg_lexer_include(cfg_t *cfg, const char *fname);
51: extern void cfg_scan_string_begin(const char *buf);
52: extern void cfg_scan_string_end(void);
53: extern void cfg_scan_fp_begin(FILE *fp);
54: extern void cfg_scan_fp_end(void);
55: extern char *cfg_qstring;
56:
57: char *cfg_yylval = 0;
58:
59: const char confuse_version[] = PACKAGE_VERSION;
60: const char confuse_copyright[] = PACKAGE_STRING" by Martin Hedenfalk <martin@bzero.se>";
61: const char confuse_author[] = "Martin Hedenfalk <martin@bzero.se>";
62:
63: static int cfg_parse_internal(cfg_t *cfg, int level,
64: int force_state, cfg_opt_t *force_opt);
65:
66: #define STATE_CONTINUE 0
67: #define STATE_EOF -1
68: #define STATE_ERROR 1
69:
70: #ifndef HAVE_STRDUP
71: # ifdef HAVE__STRDUP
72: # define strdup _strdup
73: # else
74: static char *strdup(const char *s)
75: {
76: char *r;
77:
78: if(s == 0 || *s == 0)
79: return 0;
80:
81: r = malloc(strlen(s) + 1);
82: assert(r);
83: strcpy(r, s);
84: return r;
85: }
86: # endif
87: #endif
88:
89: #ifndef HAVE_STRNDUP
90: static char *strndup(const char *s, size_t n)
91: {
92: char *r;
93:
94: if(s == 0)
95: return 0;
96:
97: r = malloc(n + 1);
98: assert(r);
99: strncpy(r, s, n);
100: r[n] = 0;
101: return r;
102: }
103: #endif
104:
105: #ifndef HAVE_STRCASECMP
106: int strcasecmp(const char *s1, const char *s2)
107: {
108: assert(s1);
109: assert(s2);
110:
111: while(*s1)
112: {
113: int c1 = tolower(*(const unsigned char *)s1);
114: int c2 = tolower(*(const unsigned char *)s2);
115: if(c1 < c2)
116: return -1;
117: if(c1 > c2)
118: return +1;
119:
120: ++s1;
121: ++s2;
122: }
123:
124: if(*s2 != 0)
125: return -1;
126:
127: return 0;
128: }
129: #endif
130:
131: DLLIMPORT cfg_opt_t *cfg_getopt(cfg_t *cfg, const char *name)
132: {
133: unsigned int i;
134: cfg_t *sec = cfg;
135:
136: assert(cfg && cfg->name && name);
137:
138: while(name && *name)
139: {
140: char *secname;
141: size_t len = strcspn(name, "|");
142: if(name[len] == 0 /*len == strlen(name)*/)
143: /* no more subsections */
144: break;
145: if(len)
146: {
147: secname = strndup(name, len);
148: sec = cfg_getsec(sec, secname);
149: if(sec == 0)
150: cfg_error(cfg, _("no such option '%s'"), secname);
151: free(secname);
152: if(sec == 0)
153: return 0;
154: }
155: name += len;
156: name += strspn(name, "|");
157: }
158:
159: for(i = 0; sec->opts[i].name; i++)
160: {
161: if(is_set(CFGF_NOCASE, sec->flags))
162: {
163: if(strcasecmp(sec->opts[i].name, name) == 0)
164: return &sec->opts[i];
165: }
166: else
167: {
168: if(strcmp(sec->opts[i].name, name) == 0)
169: return &sec->opts[i];
170: }
171: }
172: cfg_error(cfg, _("no such option '%s'"), name);
173: return 0;
174: }
175:
176: DLLIMPORT const char *cfg_title(cfg_t *cfg)
177: {
178: if(cfg)
179: return cfg->title;
180: return 0;
181: }
182:
183: DLLIMPORT const char *cfg_name(cfg_t *cfg)
184: {
185: if(cfg)
186: return cfg->name;
187: return 0;
188: }
189:
190: DLLIMPORT const char *cfg_opt_name(cfg_opt_t *opt)
191: {
192: if(opt)
193: return opt->name;
194: return 0;
195: }
196:
197: DLLIMPORT unsigned int cfg_opt_size(cfg_opt_t *opt)
198: {
199: if(opt)
200: return opt->nvalues;
201: return 0;
202: }
203:
204: DLLIMPORT unsigned int cfg_size(cfg_t *cfg, const char *name)
205: {
206: return cfg_opt_size(cfg_getopt(cfg, name));
207: }
208:
209: DLLIMPORT signed long cfg_opt_getnint(cfg_opt_t *opt, unsigned int index)
210: {
211: assert(opt && opt->type == CFGT_INT);
212: if(opt->values && index < opt->nvalues)
213: return opt->values[index]->number;
214: else if(opt->simple_value)
215: return *(signed long *)opt->simple_value;
216: else
217: return 0;
218: }
219:
220: DLLIMPORT signed long cfg_getnint(cfg_t *cfg, const char *name,
221: unsigned int index)
222: {
223: return cfg_opt_getnint(cfg_getopt(cfg, name), index);
224: }
225:
226: DLLIMPORT signed long cfg_getint(cfg_t *cfg, const char *name)
227: {
228: return cfg_getnint(cfg, name, 0);
229: }
230:
231: DLLIMPORT double cfg_opt_getnfloat(cfg_opt_t *opt, unsigned int index)
232: {
233: assert(opt && opt->type == CFGT_FLOAT);
234: if(opt->values && index < opt->nvalues)
235: return opt->values[index]->fpnumber;
236: else if(opt->simple_value)
237: return *(double *)opt->simple_value;
238: else
239: return 0;
240: }
241:
242: DLLIMPORT double cfg_getnfloat(cfg_t *cfg, const char *name,
243: unsigned int index)
244: {
245: return cfg_opt_getnfloat(cfg_getopt(cfg, name), index);
246: }
247:
248: DLLIMPORT double cfg_getfloat(cfg_t *cfg, const char *name)
249: {
250: return cfg_getnfloat(cfg, name, 0);
251: }
252:
253: DLLIMPORT cfg_bool_t cfg_opt_getnbool(cfg_opt_t *opt, unsigned int index)
254: {
255: assert(opt && opt->type == CFGT_BOOL);
256: if(opt->values && index < opt->nvalues)
257: return opt->values[index]->boolean;
258: else if(opt->simple_value)
259: return *(cfg_bool_t *)opt->simple_value;
260: else
261: return cfg_false;
262: }
263:
264: DLLIMPORT cfg_bool_t cfg_getnbool(cfg_t *cfg, const char *name,
265: unsigned int index)
266: {
267: return cfg_opt_getnbool(cfg_getopt(cfg, name), index);
268: }
269:
270: DLLIMPORT cfg_bool_t cfg_getbool(cfg_t *cfg, const char *name)
271: {
272: return cfg_getnbool(cfg, name, 0);
273: }
274:
275: DLLIMPORT char *cfg_opt_getnstr(cfg_opt_t *opt, unsigned int index)
276: {
277: assert(opt && opt->type == CFGT_STR);
278: if(opt->values && index < opt->nvalues)
279: return opt->values[index]->string;
280: else if(opt->simple_value)
281: return *(char **)opt->simple_value;
282: else
283: return 0;
284: }
285:
286: DLLIMPORT char *cfg_getnstr(cfg_t *cfg, const char *name, unsigned int index)
287: {
288: return cfg_opt_getnstr(cfg_getopt(cfg, name), index);
289: }
290:
291: DLLIMPORT char *cfg_getstr(cfg_t *cfg, const char *name)
292: {
293: return cfg_getnstr(cfg, name, 0);
294: }
295:
296: DLLIMPORT void *cfg_opt_getnptr(cfg_opt_t *opt, unsigned int index)
297: {
298: assert(opt && opt->type == CFGT_PTR);
299: if(opt->values && index < opt->nvalues)
300: return opt->values[index]->ptr;
301: else if(opt->simple_value)
302: return *(void **)opt->simple_value;
303: else
304: return 0;
305: }
306:
307: DLLIMPORT void *cfg_getnptr(cfg_t *cfg, const char *name, unsigned int index)
308: {
309: return cfg_opt_getnptr(cfg_getopt(cfg, name), index);
310: }
311:
312: DLLIMPORT void *cfg_getptr(cfg_t *cfg, const char *name)
313: {
314: return cfg_getnptr(cfg, name, 0);
315: }
316:
317: DLLIMPORT cfg_t *cfg_opt_getnsec(cfg_opt_t *opt, unsigned int index)
318: {
319: assert(opt && opt->type == CFGT_SEC);
320: if(opt->values && index < opt->nvalues)
321: return opt->values[index]->section;
322: return 0;
323: }
324:
325: DLLIMPORT cfg_t *cfg_getnsec(cfg_t *cfg, const char *name, unsigned int index)
326: {
327: return cfg_opt_getnsec(cfg_getopt(cfg, name), index);
328: }
329:
330: DLLIMPORT cfg_t *cfg_opt_gettsec(cfg_opt_t *opt, const char *title)
331: {
332: unsigned int i, n;
333:
334: assert(opt && title);
335: if(!is_set(CFGF_TITLE, opt->flags))
336: return 0;
337: n = cfg_opt_size(opt);
338: for(i = 0; i < n; i++)
339: {
340: cfg_t *sec = cfg_opt_getnsec(opt, i);
341: assert(sec && sec->title);
342: if(is_set(CFGF_NOCASE, opt->flags))
343: {
344: if(strcasecmp(title, sec->title) == 0)
345: return sec;
346: }
347: else
348: {
349: if(strcmp(title, sec->title) == 0)
350: return sec;
351: }
352: }
353: return 0;
354: }
355:
356: DLLIMPORT cfg_t *cfg_gettsec(cfg_t *cfg, const char *name, const char *title)
357: {
358: return cfg_opt_gettsec(cfg_getopt(cfg, name), title);
359: }
360:
361: DLLIMPORT cfg_t *cfg_getsec(cfg_t *cfg, const char *name)
362: {
363: return cfg_getnsec(cfg, name, 0);
364: }
365:
366: static cfg_value_t *cfg_addval(cfg_opt_t *opt)
367: {
368: opt->values = realloc(opt->values,
369: (opt->nvalues+1) * sizeof(cfg_value_t *));
370: assert(opt->values);
371: opt->values[opt->nvalues] = malloc(sizeof(cfg_value_t));
372: memset(opt->values[opt->nvalues], 0, sizeof(cfg_value_t));
373: return opt->values[opt->nvalues++];
374: }
375:
376: DLLIMPORT int cfg_numopts(cfg_opt_t *opts)
377: {
378: int n;
379:
380: for(n = 0; opts[n].name; n++)
381: /* do nothing */ ;
382: return n;
383: }
384:
385: static cfg_opt_t *cfg_dupopt_array(cfg_opt_t *opts)
386: {
387: int i;
388: cfg_opt_t *dupopts;
389: int n = cfg_numopts(opts);
390:
391: dupopts = calloc(n+1, sizeof(cfg_opt_t));
392: memcpy(dupopts, opts, n * sizeof(cfg_opt_t));
393:
394: for(i = 0; i < n; i++)
395: {
396: dupopts[i].name = strdup(opts[i].name);
397: if(opts[i].type == CFGT_SEC && opts[i].subopts)
398: dupopts[i].subopts = cfg_dupopt_array(opts[i].subopts);
399:
400: if(is_set(CFGF_LIST, opts[i].flags) || opts[i].type == CFGT_FUNC)
401: dupopts[i].def.parsed = opts[i].def.parsed ? strdup(opts[i].def.parsed) : 0;
402: else if(opts[i].type == CFGT_STR)
403: dupopts[i].def.string = opts[i].def.string ? strdup(opts[i].def.string) : 0;
404: }
405:
406: return dupopts;
407: }
408:
409: DLLIMPORT int cfg_parse_boolean(const char *s)
410: {
411: if(strcasecmp(s, "true") == 0
412: || strcasecmp(s, "on") == 0
413: || strcasecmp(s, "yes") == 0)
414: return 1;
415: else if(strcasecmp(s, "false") == 0
416: || strcasecmp(s, "off") == 0
417: || strcasecmp(s, "no") == 0)
418: return 0;
419: return -1;
420: }
421:
422: static void cfg_init_defaults(cfg_t *cfg)
423: {
424: int i;
425:
426: for(i = 0; cfg->opts[i].name; i++)
427: {
428: /* libConfuse doesn't handle default values for "simple" options */
429: if(cfg->opts[i].simple_value || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
430: continue;
431:
432: if(cfg->opts[i].type != CFGT_SEC)
433: {
434: cfg->opts[i].flags |= CFGF_DEFINIT;
435:
436: if(is_set(CFGF_LIST, cfg->opts[i].flags) ||
437: cfg->opts[i].def.parsed)
438: {
439: int xstate, ret;
440:
441: /* If it's a list, but no default value was given,
442: * keep the option uninitialized.
443: */
444: if(cfg->opts[i].def.parsed == 0 ||
445: cfg->opts[i].def.parsed[0] == 0)
446: continue;
447:
448: /* setup scanning from the string specified for the
449: * "default" value, force the correct state and option
450: */
451:
452: if(is_set(CFGF_LIST, cfg->opts[i].flags))
453: /* lists must be surrounded by {braces} */
454: xstate = 3;
455: else if(cfg->opts[i].type == CFGT_FUNC)
456: xstate = 0;
457: else
458: xstate = 2;
459:
460: cfg_scan_string_begin(cfg->opts[i].def.parsed);
461: do
462: {
463: ret = cfg_parse_internal(cfg, 1, xstate, &cfg->opts[i]);
464: xstate = -1;
465: } while(ret == STATE_CONTINUE);
466: cfg_scan_string_end();
467: if(ret == STATE_ERROR)
468: {
469: /*
470: * If there was an error parsing the default string,
471: * the initialization of the default value could be
472: * inconsistent or empty. What to do? It's a
473: * programming error and not an end user input
474: * error. Lets print a message and abort...
475: */
476: fprintf(stderr, "Parse error in default value '%s'"
477: " for option '%s'\n",
478: cfg->opts[i].def.parsed, cfg->opts[i].name);
479: fprintf(stderr, "Check your initialization macros and the"
480: " libConfuse documentation\n");
481: abort();
482: }
483: }
484: else
485: {
486: switch(cfg->opts[i].type)
487: {
488: case CFGT_INT:
489: cfg_opt_setnint(&cfg->opts[i],
490: cfg->opts[i].def.number, 0);
491: break;
492: case CFGT_FLOAT:
493: cfg_opt_setnfloat(&cfg->opts[i],
494: cfg->opts[i].def.fpnumber, 0);
495: break;
496: case CFGT_BOOL:
497: cfg_opt_setnbool(&cfg->opts[i],
498: cfg->opts[i].def.boolean, 0);
499: break;
500: case CFGT_STR:
501: cfg_opt_setnstr(&cfg->opts[i],
502: cfg->opts[i].def.string, 0);
503: break;
504: case CFGT_FUNC:
505: case CFGT_PTR:
506: break;
507: default:
508: cfg_error(cfg,
509: "internal error in cfg_init_defaults(%s)",
510: cfg->opts[i].name);
511: break;
512: }
513: }
514:
515: /* The default value should only be returned if no value
516: * is given in the configuration file, so we set the RESET
517: * flag here. When/If cfg_setopt() is called, the value(s)
518: * will be freed and the flag unset.
519: */
520: cfg->opts[i].flags |= CFGF_RESET;
521: } /* end if cfg->opts[i].type != CFGT_SEC */
522: else if(!is_set(CFGF_MULTI, cfg->opts[i].flags))
523: {
524: cfg_setopt(cfg, &cfg->opts[i], 0);
525: cfg->opts[i].flags |= CFGF_DEFINIT;
526: }
527: }
528: }
529:
530: DLLIMPORT cfg_value_t *
531: cfg_setopt(cfg_t *cfg, cfg_opt_t *opt, char *value)
532: {
533: cfg_value_t *val = 0;
534: int b;
535: char *s;
536: double f;
537: long int i;
538: void *p;
539: char *endptr;
540:
541: assert(cfg && opt);
542:
543: if(opt->simple_value)
544: {
545: assert(opt->type != CFGT_SEC);
546: val = (cfg_value_t *)opt->simple_value;
547: }
548: else
549: {
550: if(is_set(CFGF_RESET, opt->flags))
551: {
552: cfg_free_value(opt);
553: opt->flags &= ~CFGF_RESET;
554: }
555:
556: if(opt->nvalues == 0 || is_set(CFGF_MULTI, opt->flags) ||
557: is_set(CFGF_LIST, opt->flags))
558: {
559: val = 0;
560: if(opt->type == CFGT_SEC && is_set(CFGF_TITLE, opt->flags))
561: {
562: unsigned int i;
563:
564: /* Check if there already is a section with the same title.
565: */
566:
567: /* Assert that there are either no sections at all, or a
568: * non-NULL section title. */
569: assert(opt->nvalues == 0 || value);
570:
571: for(i = 0; i < opt->nvalues && val == NULL; i++)
572: {
573: cfg_t *sec = opt->values[i]->section;
574: if(is_set(CFGF_NOCASE, cfg->flags))
575: {
576: if(strcasecmp(value, sec->title) == 0)
577: val = opt->values[i];
578: }
579: else
580: {
581: if(strcmp(value, sec->title) == 0)
582: val = opt->values[i];
583: }
584: }
585: if(val && is_set(CFGF_NO_TITLE_DUPES, opt->flags))
586: {
587: cfg_error(cfg, _("found duplicate title '%s'"), value);
588: return 0;
589: }
590: }
591: if(val == NULL)
592: val = cfg_addval(opt);
593: }
594: else
595: val = opt->values[0];
596: }
597:
598: switch(opt->type)
599: {
600: case CFGT_INT:
601: if(opt->parsecb)
602: {
603: if((*opt->parsecb)(cfg, opt, value, &i) != 0)
604: return 0;
605: val->number = i;
606: }
607: else
608: {
609: val->number = strtol(value, &endptr, 0);
610: if(*endptr != '\0')
611: {
612: cfg_error(cfg, _("invalid integer value for option '%s'"),
613: opt->name);
614: return 0;
615: }
616: if(errno == ERANGE)
617: {
618: cfg_error(cfg,
619: _("integer value for option '%s' is out of range"),
620: opt->name);
621: return 0;
622: }
623: }
624: break;
625:
626: case CFGT_FLOAT:
627: if(opt->parsecb)
628: {
629: if((*opt->parsecb)(cfg, opt, value, &f) != 0)
630: return 0;
631: val->fpnumber = f;
632: }
633: else
634: {
635: val->fpnumber = strtod(value, &endptr);
636: if(*endptr != '\0')
637: {
638: cfg_error(cfg,
639: _("invalid floating point value for option '%s'"),
640: opt->name);
641: return 0;
642: }
643: if(errno == ERANGE)
644: {
645: cfg_error(cfg,
646: _("floating point value for option '%s' is out of range"),
647: opt->name);
648: return 0;
649: }
650: }
651: break;
652:
653: case CFGT_STR:
654: free(val->string);
655: if(opt->parsecb)
656: {
657: s = 0;
658: if((*opt->parsecb)(cfg, opt, value, &s) != 0)
659: return 0;
660: val->string = strdup(s);
661: }
662: else
663: val->string = strdup(value);
664: break;
665:
666: case CFGT_SEC:
667: if(is_set(CFGF_MULTI, opt->flags) || val->section == 0)
668: {
669: cfg_free(val->section);
670: val->section = calloc(1, sizeof(cfg_t));
671: assert(val->section);
672: val->section->name = strdup(opt->name);
673: val->section->opts = cfg_dupopt_array(opt->subopts);
674: val->section->flags = cfg->flags;
675: val->section->filename = cfg->filename ? strdup(cfg->filename) : 0;
676: val->section->line = cfg->line;
677: val->section->errfunc = cfg->errfunc;
678: val->section->title = value;
679: }
680: if(!is_set(CFGF_DEFINIT, opt->flags))
681: cfg_init_defaults(val->section);
682: break;
683:
684: case CFGT_BOOL:
685: if(opt->parsecb)
686: {
687: if((*opt->parsecb)(cfg, opt, value, &b) != 0)
688: return 0;
689: }
690: else
691: {
692: b = cfg_parse_boolean(value);
693: if(b == -1)
694: {
695: cfg_error(cfg, _("invalid boolean value for option '%s'"),
696: opt->name);
697: return 0;
698: }
699: }
700: val->boolean = (cfg_bool_t)b;
701: break;
702:
703: case CFGT_PTR:
704: assert(opt->parsecb);
705: if((*opt->parsecb)(cfg, opt, value, &p) != 0)
706: return 0;
707: val->ptr = p;
708: break;
709:
710: default:
711: cfg_error(cfg, "internal error in cfg_setopt(%s, %s)",
712: opt->name, value);
713: assert(0);
714: break;
715: }
716: return val;
717: }
718:
719: DLLIMPORT cfg_errfunc_t cfg_set_error_function(cfg_t *cfg,
720: cfg_errfunc_t errfunc)
721: {
722: cfg_errfunc_t old;
723:
724: assert(cfg);
725: old = cfg->errfunc;
726: cfg->errfunc = errfunc;
727: return old;
728: }
729:
730: DLLIMPORT void cfg_error(cfg_t *cfg, const char *fmt, ...)
731: {
732: va_list ap;
733:
734: va_start(ap, fmt);
735:
736: if(cfg && cfg->errfunc)
737: (*cfg->errfunc)(cfg, fmt, ap);
738: else
739: {
740: if(cfg && cfg->filename && cfg->line)
741: fprintf(stderr, "%s:%d: ", cfg->filename, cfg->line);
742: else if(cfg && cfg->filename)
743: fprintf(stderr, "%s: ", cfg->filename);
744: vfprintf(stderr, fmt, ap);
745: fprintf(stderr, "\n");
746: }
747:
748: va_end(ap);
749: }
750:
751: static int call_function(cfg_t *cfg, cfg_opt_t *opt, cfg_opt_t *funcopt)
752: {
753: int ret;
754: const char **argv;
755: unsigned int i;
756:
757: /* create a regular argv string vector and call
758: * the registered function
759: */
760: argv = calloc(funcopt->nvalues, sizeof(char *));
761: for(i = 0; i < funcopt->nvalues; i++)
762: argv[i] = funcopt->values[i]->string;
763: ret = (*opt->func)(cfg, opt, funcopt->nvalues, argv);
764: cfg_free_value(funcopt);
765: free(argv);
766: return ret;
767: }
768:
769: static int cfg_parse_internal(cfg_t *cfg, int level,
770: int force_state, cfg_opt_t *force_opt)
771: {
772: int state = 0;
773: char *opttitle = 0;
774: cfg_opt_t *opt = 0;
775: cfg_value_t *val = 0;
776: cfg_opt_t funcopt = CFG_STR(0, 0, 0);
777: int num_values = 0; /* number of values found for a list option */
778: int rc;
779:
780: if(force_state != -1)
781: state = force_state;
782: if(force_opt)
783: opt = force_opt;
784:
785: while(1)
786: {
787: int tok = cfg_yylex(cfg);
788:
789: if(tok == 0)
790: {
791: /* lexer.l should have called cfg_error */
792: return STATE_ERROR;
793: }
794:
795: if(tok == EOF)
796: {
797: if(state != 0)
798: {
799: cfg_error(cfg, _("premature end of file"));
800: return STATE_ERROR;
801: }
802: return STATE_EOF;
803: }
804:
805: switch(state)
806: {
807: case 0: /* expecting an option name */
808: if(tok == '}')
809: {
810: if(level == 0)
811: {
812: cfg_error(cfg, _("unexpected closing brace"));
813: return STATE_ERROR;
814: }
815: return STATE_EOF;
816: }
817: if(tok != CFGT_STR)
818: {
819: cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval);
820: return STATE_ERROR;
821: }
822: opt = cfg_getopt(cfg, cfg_yylval);
823: if(opt == 0)
824: return STATE_ERROR;
825: if(opt->type == CFGT_SEC)
826: {
827: if(is_set(CFGF_TITLE, opt->flags))
828: state = 6;
829: else
830: state = 5;
831: }
832: else if(opt->type == CFGT_FUNC)
833: {
834: state = 7;
835: }
836: else
837: state = 1;
838: break;
839:
840: case 1: /* expecting an equal sign or plus-equal sign */
841: if(tok == '+')
842: {
843: if(!is_set(CFGF_LIST, opt->flags))
844: {
845: cfg_error(cfg,
846: _("attempt to append to non-list option '%s'"),
847: opt->name);
848: return STATE_ERROR;
849: }
850: /* Even if the reset flag was set by
851: * cfg_init_defaults, appending to the defaults
852: * should be ok.
853: */
854: opt->flags &= ~CFGF_RESET;
855: }
856: else if(tok == '=')
857: {
858: /* set the (temporary) reset flag to clear the old
859: * values, since we obviously didn't want to append */
860: opt->flags |= CFGF_RESET;
861: }
862: else
863: {
864: cfg_error(cfg, _("missing equal sign after option '%s'"),
865: opt->name);
866: return STATE_ERROR;
867: }
868: if(is_set(CFGF_LIST, opt->flags))
869: {
870: state = 3;
871: num_values = 0;
872: } else
873: state = 2;
874: break;
875:
876: case 2: /* expecting an option value */
877: if(tok == '}' && is_set(CFGF_LIST, opt->flags))
878: {
879: state = 0;
880: if(num_values == 0 && is_set(CFGF_RESET, opt->flags))
881: /* Reset flags was set, and the empty list was
882: * specified. Free all old values. */
883: cfg_free_value(opt);
884: break;
885: }
886:
887: if(tok != CFGT_STR)
888: {
889: cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval);
890: return STATE_ERROR;
891: }
892:
893: if(cfg_setopt(cfg, opt, cfg_yylval) == 0)
894: return STATE_ERROR;
895: if(opt->validcb && (*opt->validcb)(cfg, opt) != 0)
896: return STATE_ERROR;
897: if(is_set(CFGF_LIST, opt->flags))
898: {
899: ++num_values;
900: state = 4;
901: }
902: else
903: state = 0;
904: break;
905:
906: case 3: /* expecting an opening brace for a list option */
907: if(tok != '{')
908: {
909: if(tok != CFGT_STR)
910: {
911: cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval);
912: return STATE_ERROR;
913: }
914:
915: if(cfg_setopt(cfg, opt, cfg_yylval) == 0)
916: return STATE_ERROR;
917: if(opt->validcb && (*opt->validcb)(cfg, opt) != 0)
918: return STATE_ERROR;
919: ++num_values;
920: state = 0;
921: }
922: else
923: state = 2;
924: break;
925:
926: case 4: /* expecting a separator for a list option, or
927: * closing (list) brace */
928: if(tok == ',')
929: state = 2;
930: else if(tok == '}')
931: {
932: state = 0;
933: if(opt->validcb && (*opt->validcb)(cfg, opt) != 0)
934: return STATE_ERROR;
935: }
936: else
937: {
938: cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval);
939: return STATE_ERROR;
940: }
941: break;
942:
943: case 5: /* expecting an opening brace for a section */
944: if(tok != '{')
945: {
946: cfg_error(cfg, _("missing opening brace for section '%s'"),
947: opt->name);
948: return STATE_ERROR;
949: }
950:
951: val = cfg_setopt(cfg, opt, opttitle);
952: opttitle = 0;
953: if(!val)
954: return STATE_ERROR;
955:
956: val->section->line = cfg->line;
957: val->section->errfunc = cfg->errfunc;
958: rc = cfg_parse_internal(val->section, level+1,-1,0);
959: cfg->line = val->section->line;
960: if(rc != STATE_EOF)
961: return STATE_ERROR;
962: if(opt->validcb && (*opt->validcb)(cfg, opt) != 0)
963: return STATE_ERROR;
964: state = 0;
965: break;
966:
967: case 6: /* expecting a title for a section */
968: if(tok != CFGT_STR)
969: {
970: cfg_error(cfg, _("missing title for section '%s'"),
971: opt->name);
972: return STATE_ERROR;
973: }
974: else
975: opttitle = strdup(cfg_yylval);
976: state = 5;
977: break;
978:
979: case 7: /* expecting an opening parenthesis for a function */
980: if(tok != '(')
981: {
982: cfg_error(cfg, _("missing parenthesis for function '%s'"),
983: opt->name);
984: return STATE_ERROR;
985: }
986: state = 8;
987: break;
988:
989: case 8: /* expecting a function parameter or a closing paren */
990: if(tok == ')')
991: {
992: int ret = call_function(cfg, opt, &funcopt);
993: if(ret != 0)
994: return STATE_ERROR;
995: state = 0;
996: }
997: else if(tok == CFGT_STR)
998: {
999: val = cfg_addval(&funcopt);
1000: val->string = strdup(cfg_yylval);
1001: state = 9;
1002: }
1003: else
1004: {
1005: cfg_error(cfg, _("syntax error in call of function '%s'"),
1006: opt->name);
1007: return STATE_ERROR;
1008: }
1009: break;
1010:
1011: case 9: /* expecting a comma in a function or a closing paren */
1012: if(tok == ')')
1013: {
1014: int ret = call_function(cfg, opt, &funcopt);
1015: if(ret != 0)
1016: return STATE_ERROR;
1017: state = 0;
1018: }
1019: else if(tok == ',')
1020: state = 8;
1021: else
1022: {
1023: cfg_error(cfg, _("syntax error in call of function '%s'"),
1024: opt->name);
1025: return STATE_ERROR;
1026: }
1027: break;
1028:
1029: default:
1030: /* missing state, internal error, abort */
1031: assert(0);
1032: }
1033: }
1034:
1035: return STATE_EOF;
1036: }
1037:
1038: DLLIMPORT int cfg_parse_fp(cfg_t *cfg, FILE *fp)
1039: {
1040: int ret;
1041: assert(cfg && fp);
1042:
1043: if(cfg->filename == 0)
1044: cfg->filename = strdup("FILE");
1045: cfg->line = 1;
1046:
1047: cfg_yyin = fp;
1048: cfg_scan_fp_begin(cfg_yyin);
1049: ret = cfg_parse_internal(cfg, 0, -1, 0);
1050: cfg_scan_fp_end();
1051: if(ret == STATE_ERROR)
1052: return CFG_PARSE_ERROR;
1053: return CFG_SUCCESS;
1054: }
1055:
1056: DLLIMPORT int cfg_parse(cfg_t *cfg, const char *filename)
1057: {
1058: int ret;
1059: FILE *fp;
1060:
1061: assert(cfg && filename);
1062:
1063: free(cfg->filename);
1064: cfg->filename = cfg_tilde_expand(filename);
1065: fp = fopen(cfg->filename, "r");
1066: if(fp == 0)
1067: return CFG_FILE_ERROR;
1068: ret = cfg_parse_fp(cfg, fp);
1069: fclose(fp);
1070: return ret;
1071: }
1072:
1073: DLLIMPORT int cfg_parse_buf(cfg_t *cfg, const char *buf)
1074: {
1075: int ret;
1076:
1077: assert(cfg);
1078: if(buf == 0)
1079: return CFG_SUCCESS;
1080:
1081: free(cfg->filename);
1082: cfg->filename = strdup("[buf]");
1083: cfg->line = 1;
1084:
1085: cfg_scan_string_begin(buf);
1086: ret = cfg_parse_internal(cfg, 0, -1, 0);
1087: cfg_scan_string_end();
1088: if(ret == STATE_ERROR)
1089: return CFG_PARSE_ERROR;
1090: return CFG_SUCCESS;
1091: }
1092:
1093: DLLIMPORT cfg_t *cfg_init(cfg_opt_t *opts, cfg_flag_t flags)
1094: {
1095: cfg_t *cfg;
1096:
1097: cfg = calloc(1, sizeof(cfg_t));
1098: assert(cfg);
1099:
1100: cfg->name = strdup("root");
1101: cfg->opts = cfg_dupopt_array(opts);
1102: cfg->flags = flags;
1103: cfg->filename = 0;
1104: cfg->line = 0;
1105: cfg->errfunc = 0;
1106:
1107: cfg_init_defaults(cfg);
1108:
1109: #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT)
1110: setlocale(LC_MESSAGES, "");
1111: setlocale(LC_CTYPE, "");
1112: bindtextdomain(PACKAGE, LOCALEDIR);
1113: #endif
1114:
1115: return cfg;
1116: }
1117:
1118: DLLIMPORT char *cfg_tilde_expand(const char *filename)
1119: {
1120: char *expanded = 0;
1121:
1122: #ifndef _WIN32
1123: /* do tilde expansion
1124: */
1125: if(filename[0] == '~')
1126: {
1127: struct passwd *passwd = 0;
1128: const char *file = 0;
1129:
1130: if(filename[1] == '/' || filename[1] == 0)
1131: {
1132: /* ~ or ~/path */
1133: passwd = getpwuid(geteuid());
1134: file = filename + 1;
1135: }
1136: else
1137: {
1138: /* ~user or ~user/path */
1139: char *user;
1140:
1141: file = strchr(filename, '/');
1142: if(file == 0)
1143: file = filename + strlen(filename);
1144: user = malloc(file - filename);
1145: strncpy(user, filename + 1, file - filename - 1);
1146: passwd = getpwnam(user);
1147: free(user);
1148: }
1149:
1150: if(passwd)
1151: {
1152: expanded = malloc(strlen(passwd->pw_dir) + strlen(file) + 1);
1153: strcpy(expanded, passwd->pw_dir);
1154: strcat(expanded, file);
1155: }
1156: }
1157: #endif
1158: if(!expanded)
1159: expanded = strdup(filename);
1160: return expanded;
1161: }
1162:
1163: DLLIMPORT void cfg_free_value(cfg_opt_t *opt)
1164: {
1165: unsigned int i;
1166:
1167: if(opt == 0)
1168: return;
1169:
1170: if(opt->values)
1171: {
1172: for(i = 0; i < opt->nvalues; i++)
1173: {
1174: if(opt->type == CFGT_STR)
1175: free(opt->values[i]->string);
1176: else if(opt->type == CFGT_SEC)
1177: cfg_free(opt->values[i]->section);
1178: else if(opt->type == CFGT_PTR && opt->freecb && opt->values[i]->ptr)
1179: (opt->freecb)(opt->values[i]->ptr);
1180: free(opt->values[i]);
1181: }
1182: free(opt->values);
1183: }
1184: opt->values = 0;
1185: opt->nvalues = 0;
1186: }
1187:
1188: static void cfg_free_opt_array(cfg_opt_t *opts)
1189: {
1190: int i;
1191:
1192: for(i = 0; opts[i].name; ++i)
1193: {
1194: free(opts[i].name);
1195: if(opts[i].type == CFGT_FUNC || is_set(CFGF_LIST, opts[i].flags))
1196: free(opts[i].def.parsed);
1197: else if(opts[i].type == CFGT_STR)
1198: free(opts[i].def.string);
1199: else if(opts[i].type == CFGT_SEC)
1200: cfg_free_opt_array(opts[i].subopts);
1201: }
1202: free(opts);
1203: }
1204:
1205: DLLIMPORT void cfg_free(cfg_t *cfg)
1206: {
1207: int i;
1208:
1209: if(cfg == 0)
1210: return;
1211:
1212: for(i = 0; cfg->opts[i].name; ++i)
1213: cfg_free_value(&cfg->opts[i]);
1214:
1215: cfg_free_opt_array(cfg->opts);
1216:
1217: free(cfg->name);
1218: free(cfg->title);
1219: free(cfg->filename);
1220:
1221: free(cfg);
1222: }
1223:
1224: DLLIMPORT int cfg_include(cfg_t *cfg, cfg_opt_t *opt, int argc,
1225: const char **argv)
1226: {
1227: opt = NULL;
1228: if(argc != 1)
1229: {
1230: cfg_error(cfg, _("wrong number of arguments to cfg_include()"));
1231: return 1;
1232: }
1233: return cfg_lexer_include(cfg, argv[0]);
1234: }
1235:
1236: static cfg_value_t *cfg_opt_getval(cfg_opt_t *opt, unsigned int index)
1237: {
1238: cfg_value_t *val = 0;
1239:
1240: assert(index == 0 || is_set(CFGF_LIST, opt->flags));
1241:
1242: if(opt->simple_value)
1243: val = (cfg_value_t *)opt->simple_value;
1244: else
1245: {
1246: if(is_set(CFGF_RESET, opt->flags))
1247: {
1248: cfg_free_value(opt);
1249: opt->flags &= ~CFGF_RESET;
1250: }
1251:
1252: if(index >= opt->nvalues)
1253: val = cfg_addval(opt);
1254: else
1255: val = opt->values[index];
1256: }
1257: return val;
1258: }
1259:
1260: DLLIMPORT void cfg_opt_setnint(cfg_opt_t *opt, long int value,
1261: unsigned int index)
1262: {
1263: cfg_value_t *val;
1264: assert(opt && opt->type == CFGT_INT);
1265: val = cfg_opt_getval(opt, index);
1266: val->number = value;
1267: }
1268:
1269: DLLIMPORT void cfg_setnint(cfg_t *cfg, const char *name,
1270: long int value, unsigned int index)
1271: {
1272: cfg_opt_setnint(cfg_getopt(cfg, name), value, index);
1273: }
1274:
1275: DLLIMPORT void cfg_setint(cfg_t *cfg, const char *name, long int value)
1276: {
1277: cfg_setnint(cfg, name, value, 0);
1278: }
1279:
1280: DLLIMPORT void cfg_opt_setnfloat(cfg_opt_t *opt, double value,
1281: unsigned int index)
1282: {
1283: cfg_value_t *val;
1284: assert(opt && opt->type == CFGT_FLOAT);
1285: val = cfg_opt_getval(opt, index);
1286: val->fpnumber = value;
1287: }
1288:
1289: DLLIMPORT void cfg_setnfloat(cfg_t *cfg, const char *name,
1290: double value, unsigned int index)
1291: {
1292: cfg_opt_setnfloat(cfg_getopt(cfg, name), value, index);
1293: }
1294:
1295: DLLIMPORT void cfg_setfloat(cfg_t *cfg, const char *name, double value)
1296: {
1297: cfg_setnfloat(cfg, name, value, 0);
1298: }
1299:
1300: DLLIMPORT void cfg_opt_setnbool(cfg_opt_t *opt, cfg_bool_t value,
1301: unsigned int index)
1302: {
1303: cfg_value_t *val;
1304: assert(opt && opt->type == CFGT_BOOL);
1305: val = cfg_opt_getval(opt, index);
1306: val->boolean = value;
1307: }
1308:
1309: DLLIMPORT void cfg_setnbool(cfg_t *cfg, const char *name,
1310: cfg_bool_t value, unsigned int index)
1311: {
1312: cfg_opt_setnbool(cfg_getopt(cfg, name), value, index);
1313: }
1314:
1315: DLLIMPORT void cfg_setbool(cfg_t *cfg, const char *name, cfg_bool_t value)
1316: {
1317: cfg_setnbool(cfg, name, value, 0);
1318: }
1319:
1320: DLLIMPORT void cfg_opt_setnstr(cfg_opt_t *opt, const char *value,
1321: unsigned int index)
1322: {
1323: cfg_value_t *val;
1324: assert(opt && opt->type == CFGT_STR);
1325: val = cfg_opt_getval(opt, index);
1326: free(val->string);
1327: val->string = value ? strdup(value) : 0;
1328: }
1329:
1330: DLLIMPORT void cfg_setnstr(cfg_t *cfg, const char *name,
1331: const char *value, unsigned int index)
1332: {
1333: cfg_opt_setnstr(cfg_getopt(cfg, name), value, index);
1334: }
1335:
1336: DLLIMPORT void cfg_setstr(cfg_t *cfg, const char *name, const char *value)
1337: {
1338: cfg_setnstr(cfg, name, value, 0);
1339: }
1340:
1341: static void cfg_addlist_internal(cfg_opt_t *opt,
1342: unsigned int nvalues, va_list ap)
1343: {
1344: unsigned int i;
1345:
1346: for(i = 0; i < nvalues; i++)
1347: {
1348: switch(opt->type)
1349: {
1350: case CFGT_INT:
1351: cfg_opt_setnint(opt, va_arg(ap, int), opt->nvalues);
1352: break;
1353: case CFGT_FLOAT:
1354: cfg_opt_setnfloat(opt, va_arg(ap, double),
1355: opt->nvalues);
1356: break;
1357: case CFGT_BOOL:
1358: cfg_opt_setnbool(opt, va_arg(ap, cfg_bool_t),
1359: opt->nvalues);
1360: break;
1361: case CFGT_STR:
1362: cfg_opt_setnstr(opt, va_arg(ap, char*), opt->nvalues);
1363: break;
1364: case CFGT_FUNC:
1365: case CFGT_SEC:
1366: default:
1367: break;
1368: }
1369: }
1370: }
1371:
1372: DLLIMPORT void cfg_setlist(cfg_t *cfg, const char *name,
1373: unsigned int nvalues, ...)
1374: {
1375: va_list ap;
1376: cfg_opt_t *opt = cfg_getopt(cfg, name);
1377:
1378: assert(opt && is_set(CFGF_LIST, opt->flags));
1379:
1380: cfg_free_value(opt);
1381: va_start(ap, nvalues);
1382: cfg_addlist_internal(opt, nvalues, ap);
1383: va_end(ap);
1384: }
1385:
1386: DLLIMPORT void cfg_addlist(cfg_t *cfg, const char *name,
1387: unsigned int nvalues, ...)
1388: {
1389: va_list ap;
1390: cfg_opt_t *opt = cfg_getopt(cfg, name);
1391:
1392: assert(opt && is_set(CFGF_LIST, opt->flags));
1393:
1394: va_start(ap, nvalues);
1395: cfg_addlist_internal(opt, nvalues, ap);
1396: va_end(ap);
1397: }
1398:
1399: DLLIMPORT void cfg_opt_nprint_var(cfg_opt_t *opt, unsigned int index, FILE *fp)
1400: {
1401: const char *str;
1402:
1403: assert(opt && fp);
1404: switch(opt->type)
1405: {
1406: case CFGT_INT:
1407: fprintf(fp, "%ld", cfg_opt_getnint(opt, index));
1408: break;
1409: case CFGT_FLOAT:
1410: fprintf(fp, "%lf", cfg_opt_getnfloat(opt, index));
1411: break;
1412: case CFGT_STR:
1413: str = cfg_opt_getnstr(opt, index);
1414: fprintf(fp, "\"");
1415: while (str && *str)
1416: {
1417: if(*str == '"')
1418: fprintf(fp, "\\\"");
1419: else if(*str == '\\')
1420: fprintf(fp, "\\\\");
1421: else
1422: fprintf(fp, "%c", *str);
1423: str++;
1424: }
1425: fprintf(fp, "\"");
1426: break;
1427: case CFGT_BOOL:
1428: fprintf(fp, "%s", cfg_opt_getnbool(opt, index) ? "true" : "false");
1429: break;
1430: case CFGT_NONE:
1431: case CFGT_SEC:
1432: case CFGT_FUNC:
1433: case CFGT_PTR:
1434: break;
1435: }
1436: }
1437:
1438: static void cfg_indent(FILE *fp, int indent)
1439: {
1440: while(indent--)
1441: fprintf(fp, " ");
1442: }
1443:
1444: DLLIMPORT void cfg_opt_print_indent(cfg_opt_t *opt, FILE *fp, int indent)
1445: {
1446: assert(opt && fp);
1447:
1448: if(opt->type == CFGT_SEC)
1449: {
1450: cfg_t *sec;
1451: unsigned int i;
1452:
1453: for(i = 0; i < cfg_opt_size(opt); i++)
1454: {
1455: sec = cfg_opt_getnsec(opt, i);
1456: cfg_indent(fp, indent);
1457: if(is_set(CFGF_TITLE, opt->flags))
1458: fprintf(fp, "%s \"%s\" {\n", opt->name, cfg_title(sec));
1459: else
1460: fprintf(fp, "%s {\n", opt->name);
1461: cfg_print_indent(sec, fp, indent + 1);
1462: cfg_indent(fp, indent);
1463: fprintf(fp, "}\n");
1464: }
1465: }
1466: else if(opt->type != CFGT_FUNC && opt->type != CFGT_NONE)
1467: {
1468: if(is_set(CFGF_LIST, opt->flags))
1469: {
1470: unsigned int i;
1471:
1472: cfg_indent(fp, indent);
1473: fprintf(fp, "%s = {", opt->name);
1474:
1475: if(opt->nvalues)
1476: {
1477: if(opt->pf)
1478: opt->pf(opt, 0, fp);
1479: else
1480: cfg_opt_nprint_var(opt, 0, fp);
1481: for(i = 1; i < opt->nvalues; i++)
1482: {
1483: fprintf(fp, ", ");
1484: if(opt->pf)
1485: opt->pf(opt, i, fp);
1486: else
1487: cfg_opt_nprint_var(opt, i, fp);
1488: }
1489: }
1490:
1491: fprintf(fp, "}");
1492: }
1493: else
1494: {
1495: cfg_indent(fp, indent);
1496: /* comment out the option if is not set */
1497: if(opt->simple_value)
1498: {
1499: if(opt->type == CFGT_STR && *((char **)opt->simple_value) == 0)
1500: fprintf(fp, "# ");
1501: }
1502: else
1503: {
1504: if(cfg_opt_size(opt) == 0 || (
1505: opt->type == CFGT_STR && (opt->values[0]->string == 0 ||
1506: opt->values[0]->string[0] == 0)))
1507: fprintf(fp, "# ");
1508: }
1509: fprintf(fp, "%s = ", opt->name);
1510: if(opt->pf)
1511: opt->pf(opt, 0, fp);
1512: else
1513: cfg_opt_nprint_var(opt, 0, fp);
1514: }
1515:
1516: fprintf(fp, "\n");
1517: }
1518: else if(opt->pf)
1519: {
1520: cfg_indent(fp, indent);
1521: opt->pf(opt, 0, fp);
1522: fprintf(fp, "\n");
1523: }
1524: }
1525:
1526: DLLIMPORT void cfg_opt_print(cfg_opt_t *opt, FILE *fp)
1527: {
1528: cfg_opt_print_indent(opt, fp, 0);
1529: }
1530:
1531: DLLIMPORT void cfg_print_indent(cfg_t *cfg, FILE *fp, int indent)
1532: {
1533: int i;
1534:
1535: for(i = 0; cfg->opts[i].name; i++)
1536: cfg_opt_print_indent(&cfg->opts[i], fp, indent);
1537: }
1538:
1539: DLLIMPORT void cfg_print(cfg_t *cfg, FILE *fp)
1540: {
1541: cfg_print_indent(cfg, fp, 0);
1542: }
1543:
1544: DLLIMPORT cfg_print_func_t cfg_opt_set_print_func(cfg_opt_t *opt,
1545: cfg_print_func_t pf)
1546: {
1547: cfg_print_func_t oldpf;
1548:
1549: assert(opt);
1550: oldpf = opt->pf;
1551: opt->pf = pf;
1552:
1553: return oldpf;
1554: }
1555:
1556: DLLIMPORT cfg_print_func_t cfg_set_print_func(cfg_t *cfg, const char *name,
1557: cfg_print_func_t pf)
1558: {
1559: return cfg_opt_set_print_func(cfg_getopt(cfg, name), pf);
1560: }
1561:
1562: static cfg_opt_t *cfg_getopt_array(cfg_opt_t *rootopts, int cfg_flags, const char *name)
1563: {
1564: unsigned int i;
1565: cfg_opt_t *opts = rootopts;
1566:
1567: assert(rootopts && name);
1568:
1569: while(name && *name)
1570: {
1571: cfg_t *seccfg;
1572: char *secname;
1573: size_t len = strcspn(name, "|");
1574: if(name[len] == 0 /*len == strlen(name)*/)
1575: /* no more subsections */
1576: break;
1577: if(len)
1578: {
1579: cfg_opt_t *secopt;
1580: secname = strndup(name, len);
1581: secopt = cfg_getopt_array(opts, cfg_flags, secname);
1582: free(secname);
1583: if(secopt == 0)
1584: {
1585: /*fprintf(stderr, "section not found\n");*/
1586: return 0;
1587: }
1588: if(secopt->type != CFGT_SEC)
1589: {
1590: /*fprintf(stderr, "not a section!\n");*/
1591: return 0;
1592: }
1593:
1594: if(!is_set(CFGF_MULTI, secopt->flags) &&
1595: (seccfg = cfg_opt_getnsec(secopt, 0)) != 0)
1596: {
1597: opts = seccfg->opts;
1598: }
1599: else
1600: opts = secopt->subopts;
1601: if(opts == 0)
1602: {
1603: /*fprintf(stderr, "section have no subopts!?\n");*/
1604: return 0;
1605: }
1606: }
1607: name += len;
1608: name += strspn(name, "|");
1609: }
1610:
1611: for(i = 0; opts[i].name; i++)
1612: {
1613: if(is_set(CFGF_NOCASE, cfg_flags))
1614: {
1615: if(strcasecmp(opts[i].name, name) == 0)
1616: return &opts[i];
1617: }
1618: else
1619: {
1620: if(strcmp(opts[i].name, name) == 0)
1621: return &opts[i];
1622: }
1623: }
1624: return 0;
1625: }
1626:
1627: DLLIMPORT cfg_validate_callback_t cfg_set_validate_func(cfg_t *cfg,
1628: const char *name,
1629: cfg_validate_callback_t vf)
1630: {
1631: cfg_opt_t *opt = cfg_getopt_array(cfg->opts, cfg->flags, name);
1632: cfg_validate_callback_t oldvf;
1633: assert(opt);
1634: oldvf = opt->validcb;
1635: opt->validcb = vf;
1636: return oldvf;
1637: }
1638:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>