00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00154 #include "cfg_parser.h"
00155
00156 #include "mem/mem.h"
00157 #include "mem/shm_mem.h"
00158 #include "dprint.h"
00159 #include "trim.h"
00160 #include "ut.h"
00161
00162 #include <string.h>
00163 #include <stdlib.h>
00164 #include <stdio.h>
00165 #include <libgen.h>
00166
00167
00169 enum st {
00170 ST_S,
00171 ST_A,
00172 ST_AE,
00173 ST_Q,
00174 ST_QE,
00175 ST_C,
00176 ST_CE,
00177 ST_E,
00178 };
00179
00180
00182 #define IS_ALPHA(c) \
00183 (((c) >= 'a' && (c) <= 'z') || \
00184 ((c) >= 'A' && (c) <= 'Z') || \
00185 ((c) >= '0' && (c) <= '9') || \
00186 (c) == '_')
00187
00188
00190 #define IS_DELIM(c) \
00191 ((c) == '=' || \
00192 (c) == ':' || \
00193 (c) == ';' || \
00194 (c) == '.' || \
00195 (c) == ',' || \
00196 (c) == '?' || \
00197 (c) == '[' || \
00198 (c) == ']' || \
00199 (c) == '/' || \
00200 (c) == '@' || \
00201 (c) == '!' || \
00202 (c) == '$' || \
00203 (c) == '%' || \
00204 (c) == '&' || \
00205 (c) == '*' || \
00206 (c) == '(' || \
00207 (c) == ')' || \
00208 (c) == '-' || \
00209 (c) == '+' || \
00210 (c) == '|' || \
00211 (c) == '\'')
00212
00213
00215 #define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r')
00216 #define IS_QUOTE(c) ((c) == '\"')
00217 #define IS_COMMENT(c) ((c) == '#')
00218 #define IS_ESCAPE(c) ((c) == '\\')
00219 #define IS_EOL(c) ((c) == '\n')
00220
00221
00225 #define PUSH(c) \
00226 if (token->val.len >= MAX_TOKEN_LEN) { \
00227 ERR("%s:%d:%d: Token too long\n", \
00228 st->file, st->line, st->col); \
00229 return -1; \
00230 } \
00231 if (token->val.len == 0) { \
00232 token->start.line = st->line; \
00233 token->start.col = st->col; \
00234 } \
00235 token->val.s[token->val.len++] = (c);
00236
00237
00241 #define RETURN(c) \
00242 token->end.line = st->line; \
00243 token->end.col = st->col; \
00244 token->type = (c); \
00245 print_token(token); \
00246 return 0;
00247
00248
00252 #define READ_CHAR \
00253 c = fgetc(st->f); \
00254 if (IS_EOL(c)) { \
00255 st->line++; \
00256 st->col = 0; \
00257 } else { \
00258 st->col++; \
00259 }
00260
00261
00262 cfg_option_t cfg_bool_values[] = {
00263 {"yes", .val = 1},
00264 {"true", .val = 1},
00265 {"enable", .val = 1},
00266 {"enabled", .val = 1},
00267 {"1", .val = 1},
00268 {"on", .val = 1},
00269 {"no", .val = 0},
00270 {"false", .val = 0},
00271 {"disable", .val = 0},
00272 {"disabled", .val = 0},
00273 {"0", .val = 0},
00274 {"off", .val = 0},
00275 {0}
00276 };
00277
00278
00279 static void print_token(cfg_token_t* token)
00280 {
00281 #ifdef EXTRA_DEBUG
00282 int i, j;
00283 char* buf;
00284
00285 if ((buf = pkg_malloc(token->val.len * 2)) == NULL) {
00286 DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n",
00287 token->type, STR_FMT(&token->val),
00288 token->start.line, token->start.col,
00289 token->end.line, token->end.col);
00290 } else {
00291 for(i = 0, j = 0; i < token->val.len; i++) {
00292 switch(token->val.s[i]) {
00293 case '\n': buf[j++] = '\\'; buf[j++] = 'n'; break;
00294 case '\r': buf[j++] = '\\'; buf[j++] = 'r'; break;
00295 case '\t': buf[j++] = '\\'; buf[j++] = 't'; break;
00296 case '\0': buf[j++] = '\\'; buf[j++] = '0'; break;
00297 case '\\': buf[j++] = '\\'; buf[j++] = '\\'; break;
00298 default: buf[j++] = token->val.s[i];
00299 }
00300 }
00301 DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n",
00302 token->type, j, buf,
00303 token->start.line, token->start.col,
00304 token->end.line, token->end.col);
00305 pkg_free(buf);
00306 }
00307 #endif
00308 }
00309
00310
00311 int cfg_get_token(cfg_token_t* token, cfg_parser_t* st, unsigned int flags)
00312 {
00313 static int look_ahead = EOF;
00314 int c;
00315 enum st state;
00316
00317 state = ST_S;
00318
00319 token->val.s = token->buf;
00320 token->val.len = 0;
00321
00322 if (look_ahead != EOF) {
00323 c = look_ahead;
00324 look_ahead = EOF;
00325 } else {
00326 READ_CHAR;
00327 }
00328
00329 while(c != EOF) {
00330 switch(state) {
00331 case ST_S:
00332 if (flags & CFG_EXTENDED_ALPHA) {
00333 if (IS_WHITESPACE(c)) {
00334
00335 } else if (IS_ALPHA(c) ||
00336 IS_ESCAPE(c) ||
00337 IS_DELIM(c)) {
00338 PUSH(c);
00339 state = ST_A;
00340 } else if (IS_QUOTE(c)) {
00341 state = ST_Q;
00342 } else if (IS_COMMENT(c)) {
00343 state = ST_C;
00344 } else if (IS_EOL(c)) {
00345 PUSH(c);
00346 RETURN(c);
00347 } else {
00348 ERR("%s:%d:%d: Invalid character 0x%x\n",
00349 st->file, st->line, st->col, c);
00350 return -1;
00351 }
00352 } else {
00353 if (IS_WHITESPACE(c)) {
00354
00355 } else if (IS_ALPHA(c)) {
00356 PUSH(c);
00357 state = ST_A;
00358 } else if (IS_QUOTE(c)) {
00359 state = ST_Q;
00360 } else if (IS_COMMENT(c)) {
00361 state = ST_C;
00362 } else if (IS_ESCAPE(c)) {
00363 state = ST_E;
00364 } else if (IS_DELIM(c) || IS_EOL(c)) {
00365 PUSH(c);
00366 RETURN(c);
00367 } else {
00368 ERR("%s:%d:%d: Invalid character 0x%x\n",
00369 st->file, st->line, st->col, c);
00370 return -1;
00371 }
00372 }
00373 break;
00374
00375 case ST_A:
00376 if (flags & CFG_EXTENDED_ALPHA) {
00377 if (IS_ALPHA(c) ||
00378 IS_DELIM(c) ||
00379 IS_QUOTE(c)) {
00380 PUSH(c);
00381 } else if (IS_ESCAPE(c)) {
00382 state = ST_AE;
00383 } else if (IS_COMMENT(c) || IS_EOL(c) || IS_WHITESPACE(c)) {
00384 look_ahead = c;
00385 RETURN(CFG_TOKEN_ALPHA);
00386 } else {
00387 ERR("%s:%d:%d: Invalid character 0x%x\n",
00388 st->file, st->line, st->col, c);
00389 return -1;
00390 }
00391 } else {
00392 if (IS_ALPHA(c)) {
00393 PUSH(c);
00394 } else if (IS_ESCAPE(c)) {
00395 state = ST_AE;
00396 } else if (IS_WHITESPACE(c) ||
00397 IS_DELIM(c) ||
00398 IS_QUOTE(c) ||
00399 IS_COMMENT(c) ||
00400 IS_EOL(c)) {
00401 look_ahead = c;
00402 RETURN(CFG_TOKEN_ALPHA);
00403 } else {
00404 ERR("%s:%d:%d: Invalid character 0x%x\n",
00405 st->file, st->line, st->col, c);
00406 return -1;
00407 }
00408 }
00409 break;
00410
00411 case ST_AE:
00412 if (IS_COMMENT(c) ||
00413 IS_QUOTE(c) ||
00414 IS_ESCAPE(c)) {
00415 PUSH(c);
00416 } else if (c == 'r') {
00417 PUSH('\r');
00418 } else if (c == 'n') {
00419 PUSH('\n');
00420 } else if (c == 't') {
00421 PUSH('\t');
00422 } else if (c == ' ') {
00423 PUSH(' ');
00424 } else if (IS_EOL(c)) {
00425
00426 } else {
00427 ERR("%s:%d:%d: Unsupported escape character 0x%x\n",
00428 st->file, st->line, st->col, c);
00429 return -1;
00430 }
00431 state = ST_A;
00432 break;
00433
00434 case ST_Q:
00435 if (IS_QUOTE(c)) {
00436 RETURN(CFG_TOKEN_STRING);
00437 } else if (IS_ESCAPE(c)) {
00438 state = ST_QE;
00439 break;
00440 } else {
00441 PUSH(c);
00442 }
00443 break;
00444
00445 case ST_QE:
00446 if (IS_ESCAPE(c) ||
00447 IS_QUOTE(c)) {
00448 PUSH(c);
00449 } else if (c == 'n') {
00450 PUSH('\n');
00451 } else if (c == 'r') {
00452 PUSH('\r');
00453 } else if (c == 't') {
00454 PUSH('\t');
00455 } else if (IS_EOL(c)) {
00456
00457 } else {
00458 ERR("%s:%d:%d: Unsupported escape character 0x%x\n",
00459 st->file, st->line, st->col, c);
00460 return -1;
00461 }
00462 state = ST_Q;
00463 break;
00464
00465 case ST_C:
00466 if (IS_ESCAPE(c)) {
00467 state = ST_CE;
00468 } else if (IS_EOL(c)) {
00469 state = ST_S;
00470 continue;
00471 } else {
00472
00473 }
00474 break;
00475
00476 case ST_CE:
00477 state = ST_C;
00478 break;
00479
00480 case ST_E:
00481 if (IS_COMMENT(c) ||
00482 IS_QUOTE(c) ||
00483 IS_ESCAPE(c)) {
00484 PUSH(c);
00485 RETURN(c);
00486 } else if (c == 'r') {
00487 PUSH('\r');
00488 RETURN('\r');
00489 } else if (c == 'n') {
00490 PUSH('\n');
00491 RETURN('\n');
00492 } else if (c == 't') {
00493 PUSH('\t');
00494 RETURN('\t');
00495 } else if (c == ' ') {
00496 PUSH(' ');
00497 RETURN(' ');
00498 } else if (IS_EOL(c)) {
00499
00500 state = ST_S;
00501 } else {
00502 ERR("%s:%d:%d: Unsupported escape character 0x%x\n",
00503 st->file, st->line, st->col, c);
00504 return -1;
00505 }
00506 break;
00507 }
00508
00509 READ_CHAR;
00510 };
00511
00512 switch(state) {
00513 case ST_S:
00514 case ST_C:
00515 case ST_CE:
00516 return 1;
00517
00518 case ST_A:
00519 RETURN(CFG_TOKEN_ALPHA);
00520
00521 case ST_Q:
00522 ERR("%s:%d:%d: Premature end of file, missing closing quote in"
00523 " string constant\n", st->file, st->line, st->col);
00524 return -1;
00525
00526 case ST_QE:
00527 case ST_E:
00528 case ST_AE:
00529 ERR("%s:%d:%d: Premature end of file, missing escaped character\n",
00530 st->file, st->line, st->col);
00531 return -1;
00532 }
00533 BUG("%s:%d:%d: Invalid state %d\n",
00534 st->file, st->line, st->col, state);
00535 return -1;
00536 }
00537
00538
00539 int cfg_parse_section(void* param, cfg_parser_t* st, unsigned int flags)
00540 {
00541 cfg_token_t t;
00542 int ret;
00543
00544 ret = cfg_parse_str(param, st, flags);
00545 if (ret < 0) return ret;
00546 if (ret > 0) {
00547 ERR("%s:%d:%d: Section name missing.\n",
00548 st->file, st->line, st->col);
00549 return ret;
00550 }
00551
00552 ret = cfg_get_token(&t, st, flags);
00553 if (ret < 0) goto error;
00554 if (ret > 0) {
00555 ERR("%s:%d:%d: Closing ']' missing\n", st->file, st->line, st->col);
00556 goto error;
00557 }
00558 if (t.type != ']') {
00559 ERR("%s:%d:%d: Syntax error, ']' expected\n",
00560 st->file, t.start.line, t.start.col);
00561 goto error;
00562 }
00563
00564 if (cfg_eat_eol(st, flags)) goto error;
00565 return 0;
00566
00567 error:
00568 if (param && ((str*)param)->s) {
00569 if (flags & CFG_STR_PKGMEM) {
00570 pkg_free(((str*)param)->s);
00571 ((str*)param)->s = NULL;
00572 } else if (flags & CFG_STR_SHMMEM) {
00573 shm_free(((str*)param)->s);
00574 ((str*)param)->s = NULL;
00575 } else if (flags & CFG_STR_MALLOC) {
00576 free(((str*)param)->s);
00577 ((str*)param)->s = NULL;
00578 }
00579 }
00580 return -1;
00581 }
00582
00583
00584 static char* get_base_name(str* filename)
00585 {
00586 char* tmp1, *tmp2, *res;
00587 int len;
00588
00589 res = NULL;
00590 if ((tmp1 = as_asciiz(filename)) == NULL) {
00591 ERR("cfg_parser: No memory left\n");
00592 goto error;
00593 }
00594
00595 if ((tmp2 = basename(tmp1)) == NULL) {
00596 ERR("cfg_parser: Error in basename\n");
00597 goto error;
00598 }
00599 len = strlen(tmp2);
00600
00601 if ((res = pkg_malloc(len + 1)) == NULL) {
00602 ERR("cfg_parser: No memory left");
00603 goto error;
00604 }
00605 memcpy(res, tmp2, len + 1);
00606 pkg_free(tmp1);
00607 return res;
00608
00609 error:
00610 if (tmp1) pkg_free(tmp1);
00611 return NULL;
00612 }
00613
00614
00615
00624 cfg_parser_t* cfg_parser_init(str* basedir, str* filename)
00625 {
00626 cfg_parser_t* st;
00627 char* pathname, *base, *abs_pathname;
00628
00629 abs_pathname = NULL;
00630 pathname = filename->s;
00631 st = NULL;
00632 base = NULL;
00633
00634
00635 if (basedir == 0 || basedir->len != 0) {
00636 if ((abs_pathname = get_abs_pathname(basedir, filename)) == NULL) {
00637 ERR("cfg_parser: Error while converting %.*s to absolute"
00638 " pathname\n", STR_FMT(filename));
00639 goto error;
00640 }
00641 pathname = abs_pathname;
00642 }
00643
00644 if ((base = get_base_name(filename)) == NULL) goto error;
00645
00646 if ((st = (cfg_parser_t*)pkg_malloc(sizeof(*st))) == NULL) {
00647 ERR("cfg_parser: No memory left\n");
00648 goto error;
00649 }
00650 memset(st, '\0', sizeof(*st));
00651
00652 if ((st->f = fopen(pathname, "r")) == NULL) {
00653 ERR("cfg_parser: Unable to open file '%s'\n", pathname);
00654 goto error;
00655 }
00656
00657 if (abs_pathname) pkg_free(abs_pathname);
00658
00659 st->file = base;
00660 st->line = 1;
00661 st->col = 0;
00662 return st;
00663
00664 error:
00665 if (st) {
00666 if (st->f) fclose(st->f);
00667 pkg_free(st);
00668 }
00669 if (base) pkg_free(base);
00670 if (abs_pathname) pkg_free(abs_pathname);
00671 return NULL;
00672 }
00673
00674
00675 void cfg_parser_close(cfg_parser_t* st)
00676 {
00677 if (!st) return;
00678 if (st->f) fclose(st->f);
00679 if (st->file) pkg_free(st->file);
00680 pkg_free(st);
00681 }
00682
00683
00684 void cfg_section_parser(cfg_parser_t* st, cfg_func_f parser, void* param)
00685 {
00686 if (st == NULL) return;
00687 st->section.parser = parser;
00688 st->section.param = param;
00689 }
00690
00691
00692 void cfg_set_options(cfg_parser_t* st, cfg_option_t* options)
00693 {
00694 if (st) st->options = options;
00695 }
00696
00697
00698 static int process_option(cfg_parser_t* st, cfg_option_t* opt)
00699 {
00700 if (opt->f) {
00701
00702 if (opt->f(opt->param, st, opt->flags) < 0) return -1;
00703 } else {
00704
00705
00706
00707
00708 if (opt->param) *(int*)opt->param = opt->val;
00709 }
00710 return 0;
00711 }
00712
00713
00714 int sr_cfg_parse(cfg_parser_t* st)
00715 {
00716 int ret;
00717 cfg_token_t t;
00718 cfg_option_t* opt;
00719
00720 while(1) {
00721 ret = cfg_get_token(&t, st, 0);
00722 if (ret < 0) return ret;
00723 if (ret > 0) break;
00724
00725 switch(t.type) {
00726 case CFG_TOKEN_ALPHA:
00727
00728 if ((opt = cfg_lookup_token(st->options, &t.val)) == NULL) {
00729 ERR("%s:%d:%d: Unsupported option '%.*s'\n",
00730 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00731 return -1;
00732 }
00733
00734 st->cur_opt = &t;
00735 if (process_option(st, opt) < 0) return -1;
00736 break;
00737
00738 case '[':
00739 if (st->section.parser == NULL) {
00740 ERR("%s:%d:%d: Syntax error\n", st->file,
00741 t.start.line, t.start.col);
00742 return -1;
00743 }
00744 if (st->section.parser(st->section.param, st, 0) < 0) return -1;
00745 break;
00746
00747
00748 case '\n': continue;
00749
00750 default:
00751 ERR("%s:%d:%d: Syntax error\n",
00752 st->file, t.start.line, t.start.col);
00753 return -1;
00754 }
00755 }
00756 return 0;
00757 }
00758
00759
00760 cfg_option_t* cfg_lookup_token(cfg_option_t* table, str* token)
00761 {
00762 int len, i;
00763 int (*cmp)(const char* s1, const char* s2, size_t n) = NULL;
00764
00765
00766 if (table == NULL) return NULL;
00767
00768 for(i = 0; table[i].name; i++) {
00769 len = strlen(table[i].name);
00770
00771 if (table[i].flags & CFG_PREFIX) {
00772 if (token->len < len) continue;
00773 } else {
00774 if (token->len != len) continue;
00775 }
00776
00777 if (table[i].flags & CFG_CASE_SENSITIVE) cmp = strncmp;
00778 else cmp = strncasecmp;
00779
00780 if (cmp(token->s, table[i].name, len)) continue;
00781 return table + i;
00782 }
00783 if (table[i].flags & CFG_DEFAULT) {
00784 return table + i;
00785 }
00786 return NULL;
00787 }
00788
00789
00790 int cfg_eat_equal(cfg_parser_t* st, unsigned int flags)
00791 {
00792 cfg_token_t t;
00793 int ret;
00794
00795 ret = cfg_get_token(&t, st, flags);
00796 if (ret < 0) return ret;
00797 if (ret > 0) {
00798 ERR("%s:%d:%d: Delimiter '=' missing\n",
00799 st->file, st->line, st->col);
00800 return ret;
00801 }
00802
00803 if (t.type != '=') {
00804 ERR("%s:%d:%d: Syntax error, '=' expected\n",
00805 st->file, t.start.line, t.start.col);
00806 return -1;
00807 }
00808 return 0;
00809 }
00810
00811
00812 int cfg_eat_eol(cfg_parser_t* st, unsigned int flags)
00813 {
00814 cfg_token_t t;
00815 int ret;
00816
00817
00818 ret = cfg_get_token(&t, st, 0);
00819 if (ret < 0) return ret;
00820 if (ret > 0) return 0;
00821 if (t.type != '\n') {
00822 ERR("%s:%d:%d: End of line expected\n",
00823 st->file, t.start.line, t.start.col);
00824 return -1;
00825 }
00826 return 0;
00827 }
00828
00829
00830 int cfg_parse_enum(void* param, cfg_parser_t* st, unsigned int flags)
00831 {
00832 int ret;
00833 cfg_token_t t;
00834 cfg_option_t* values, *val;
00835
00836 values = (cfg_option_t*)param;
00837
00838 ret = cfg_get_token(&t, st, flags);
00839 if (ret != 0) return ret;
00840
00841 if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00842 ERR("%s:%d:%d: Invalid enum value '%.*s'\n",
00843 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00844 return -1;
00845 }
00846
00847 if (values) {
00848 if ((val = cfg_lookup_token(values, &t.val)) == NULL) {
00849 ERR("%s:%d:%d Unsupported enum value '%.*s'\n",
00850 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00851 return -1;
00852 }
00853 return process_option(st, val);
00854 } else {
00855 return 0;
00856 }
00857 }
00858
00859
00860 int cfg_parse_enum_opt(void* param, cfg_parser_t* st, unsigned int flags)
00861 {
00862 int ret;
00863
00864 if (cfg_eat_equal(st, flags)) return -1;
00865
00866 ret = cfg_parse_enum(param, st, CFG_EXTENDED_ALPHA | flags);
00867 if (ret > 0) {
00868 ERR("%s:%d:%d: Option value missing\n",
00869 st->file, st->line, st->col);
00870 return ret;
00871 } else if (ret < 0) return ret;
00872
00873 if (cfg_eat_eol(st, flags)) return -1;
00874 return 0;
00875 }
00876
00877
00878 int cfg_parse_str(void* param, cfg_parser_t* st, unsigned int flags)
00879 {
00880 str* val;
00881 int ret;
00882 char* buf;
00883 cfg_token_t t;
00884
00885 ret = cfg_get_token(&t, st, flags);
00886 if (ret != 0) return ret;
00887
00888 if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00889 ERR("%s:%d:%d: Invalid string value '%.*s', a string expected.\n",
00890 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00891 return -1;
00892 }
00893
00894 if (!param) return 0;
00895 val = (str*)param;
00896
00897 if (flags & CFG_STR_STATIC) {
00898 if (!val->s || val->len <= t.val.len) {
00899 ERR("%s:%d:%d: Destination string buffer too small\n",
00900 st->file, t.start.line, t.start.col);
00901 return -1;
00902 }
00903 buf = val->s;
00904 } else if (flags & CFG_STR_SHMMEM) {
00905 if ((buf = shm_malloc(t.val.len + 1)) == NULL) {
00906 ERR("%s:%d:%d: Out of shared memory\n", st->file,
00907 t.start.line, t.start.col);
00908 return -1;
00909 }
00910 if (val->s) shm_free(val->s);
00911 } else if (flags & CFG_STR_MALLOC) {
00912 if ((buf = malloc(t.val.len + 1)) == NULL) {
00913 ERR("%s:%d:%d: Out of malloc memory\n", st->file,
00914 t.start.line, t.start.col);
00915 return -1;
00916 }
00917 if (val->s) free(val->s);
00918 } else if (flags & CFG_STR_PKGMEM) {
00919 if ((buf = pkg_malloc(t.val.len + 1)) == NULL) {
00920 ERR("%s:%d:%d: Out of private memory\n", st->file,
00921 t.start.line, t.start.col);
00922 return -1;
00923 }
00924 if (val->s) pkg_free(val->s);
00925 } else {
00926 *val = t.val;
00927 return 0;
00928 }
00929
00930 memcpy(buf, t.val.s, t.val.len);
00931 buf[t.val.len] = '\0';
00932 val->s = buf;
00933 val->len = t.val.len;
00934 return 0;
00935 }
00936
00937
00938 int cfg_parse_str_opt(void* param, cfg_parser_t* st, unsigned int flags)
00939 {
00940 int ret;
00941
00942 if (cfg_eat_equal(st, flags)) return -1;
00943
00944 ret = cfg_parse_str(param, st, flags | CFG_EXTENDED_ALPHA);
00945 if (ret > 0) {
00946 ERR("%s:%d:%d: Option value missing\n",
00947 st->file, st->line, st->col);
00948 } else if (ret < 0) return ret;
00949
00950 if (cfg_eat_eol(st, flags)) return -1;
00951 return 0;
00952 }
00953
00954
00955 int cfg_parse_int(void* param, cfg_parser_t* st, unsigned int flags)
00956 {
00957 int* val;
00958 int ret, tmp;
00959 cfg_token_t t;
00960
00961 val = (int*)param;
00962
00963 ret = cfg_get_token(&t, st, flags);
00964 if (ret != 0) return ret;
00965
00966 if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00967 ERR("%s:%d:%d: Invalid integer value '%.*s'\n",
00968 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00969 return -1;
00970 }
00971
00972 if (str2sint(&t.val, &tmp) < 0) {
00973 ERR("%s:%d:%d: Invalid integer value '%.*s'\n",
00974 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00975 return -1;
00976 }
00977
00978 if (val) *val = tmp;
00979 return 0;
00980 }
00981
00982
00983 int cfg_parse_int_opt(void* param, cfg_parser_t* st, unsigned int flags)
00984 {
00985 int ret;
00986
00987 if (cfg_eat_equal(st, flags)) return -1;
00988
00989 ret = cfg_parse_int(param, st, flags);
00990 if (ret > 0) {
00991 ERR("%s:%d:%d: Option value missing\n",
00992 st->file, st->line, st->col);
00993 } else if (ret < 0) return ret;
00994
00995 if (cfg_eat_eol(st, flags)) return -1;
00996 return 0;
00997 }
00998
00999
01000 int cfg_parse_bool(void* param, cfg_parser_t* st, unsigned int flags)
01001 {
01002 int ret, *val;
01003 cfg_token_t t;
01004 cfg_option_t* map;
01005
01006 val = (int*)param;
01007
01008 ret = cfg_get_token(&t, st, flags);
01009 if (ret != 0) return ret;
01010
01011 if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
01012 ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n",
01013 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
01014 return -1;
01015 }
01016
01017 if ((map = cfg_lookup_token(cfg_bool_values, &t.val)) == NULL) {
01018 ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n",
01019 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
01020 return -1;
01021 }
01022
01023 if (val) *val = map->val;
01024 return 0;
01025 }
01026
01027
01028 int cfg_parse_bool_opt(void* param, cfg_parser_t* st, unsigned int flags)
01029 {
01030 int ret;
01031 if (cfg_eat_equal(st, flags)) return -1;
01032
01033 ret = cfg_parse_bool(param, st, CFG_EXTENDED_ALPHA | flags);
01034 if (ret > 0) {
01035 ERR("%s:%d:%d: Option value missing\n",
01036 st->file, st->line, st->col);
01037 } else if (ret < 0) return ret;
01038
01039 if (cfg_eat_eol(st, flags)) return -1;
01040 return 0;
01041 }