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 48extern FILE *cfg_yyin; 49extern int cfg_yylex(cfg_t *cfg); 50extern int cfg_lexer_include(cfg_t *cfg, const char *fname); 51extern void cfg_scan_string_begin(const char *buf); 52extern void cfg_scan_string_end(void); 53extern void cfg_scan_fp_begin(FILE *fp); 54extern void cfg_scan_fp_end(void); 55extern char *cfg_qstring; 56 57char *cfg_yylval = 0; 58 59const char confuse_version[] = PACKAGE_VERSION; 60const char confuse_copyright[] = PACKAGE_STRING" by Martin Hedenfalk <martin@bzero.se>"; 61const char confuse_author[] = "Martin Hedenfalk <martin@bzero.se>"; 62 63static 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 74static 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 90static 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 106int 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 131DLLIMPORT 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 176DLLIMPORT const char *cfg_title(cfg_t *cfg) 177{ 178 if(cfg) 179 return cfg->title; 180 return 0; 181} 182 183DLLIMPORT const char *cfg_name(cfg_t *cfg) 184{ 185 if(cfg) 186 return cfg->name; 187 return 0; 188} 189 190DLLIMPORT const char *cfg_opt_name(cfg_opt_t *opt) 191{ 192 if(opt) 193 return opt->name; 194 return 0; 195} 196 197DLLIMPORT unsigned int cfg_opt_size(cfg_opt_t *opt) 198{ 199 if(opt) 200 return opt->nvalues; 201 return 0; 202} 203 204DLLIMPORT unsigned int cfg_size(cfg_t *cfg, const char *name) 205{ 206 return cfg_opt_size(cfg_getopt(cfg, name)); 207} 208 209DLLIMPORT 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 220DLLIMPORT 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 226DLLIMPORT signed long cfg_getint(cfg_t *cfg, const char *name) 227{ 228 return cfg_getnint(cfg, name, 0); 229} 230 231DLLIMPORT 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 242DLLIMPORT 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 248DLLIMPORT double cfg_getfloat(cfg_t *cfg, const char *name) 249{ 250 return cfg_getnfloat(cfg, name, 0); 251} 252 253DLLIMPORT 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 264DLLIMPORT 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 270DLLIMPORT cfg_bool_t cfg_getbool(cfg_t *cfg, const char *name) 271{ 272 return cfg_getnbool(cfg, name, 0); 273} 274 275DLLIMPORT 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 286DLLIMPORT 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 291DLLIMPORT char *cfg_getstr(cfg_t *cfg, const char *name) 292{ 293 return cfg_getnstr(cfg, name, 0); 294} 295 296DLLIMPORT 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 307DLLIMPORT 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 312DLLIMPORT void *cfg_getptr(cfg_t *cfg, const char *name) 313{ 314 return cfg_getnptr(cfg, name, 0); 315} 316 317DLLIMPORT 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 325DLLIMPORT 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 330DLLIMPORT 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 356DLLIMPORT 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 361DLLIMPORT cfg_t *cfg_getsec(cfg_t *cfg, const char *name) 362{ 363 return cfg_getnsec(cfg, name, 0); 364} 365 366static 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 376DLLIMPORT 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 385static 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 409DLLIMPORT 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 422static 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 530DLLIMPORT cfg_value_t * 531cfg_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 719DLLIMPORT 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 730DLLIMPORT 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 751static 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 769static 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 1038DLLIMPORT 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 1056DLLIMPORT 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 1073DLLIMPORT 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 1093DLLIMPORT 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 1118DLLIMPORT 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 1163DLLIMPORT 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 1188static 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 1205DLLIMPORT 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 1224DLLIMPORT 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 1236static 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 1260DLLIMPORT 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 1269DLLIMPORT 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 1275DLLIMPORT void cfg_setint(cfg_t *cfg, const char *name, long int value) 1276{ 1277 cfg_setnint(cfg, name, value, 0); 1278} 1279 1280DLLIMPORT 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 1289DLLIMPORT 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 1295DLLIMPORT void cfg_setfloat(cfg_t *cfg, const char *name, double value) 1296{ 1297 cfg_setnfloat(cfg, name, value, 0); 1298} 1299 1300DLLIMPORT 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 1309DLLIMPORT 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 1315DLLIMPORT void cfg_setbool(cfg_t *cfg, const char *name, cfg_bool_t value) 1316{ 1317 cfg_setnbool(cfg, name, value, 0); 1318} 1319 1320DLLIMPORT 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 1330DLLIMPORT 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 1336DLLIMPORT void cfg_setstr(cfg_t *cfg, const char *name, const char *value) 1337{ 1338 cfg_setnstr(cfg, name, value, 0); 1339} 1340 1341static 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 1372DLLIMPORT 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 1386DLLIMPORT 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 1399DLLIMPORT 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 1438static void cfg_indent(FILE *fp, int indent) 1439{ 1440 while(indent--) 1441 fprintf(fp, " "); 1442} 1443 1444DLLIMPORT 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 1526DLLIMPORT void cfg_opt_print(cfg_opt_t *opt, FILE *fp) 1527{ 1528 cfg_opt_print_indent(opt, fp, 0); 1529} 1530 1531DLLIMPORT 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 1539DLLIMPORT void cfg_print(cfg_t *cfg, FILE *fp) 1540{ 1541 cfg_print_indent(cfg, fp, 0); 1542} 1543 1544DLLIMPORT 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 1556DLLIMPORT 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 1562static 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 1627DLLIMPORT 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 1639