Mercurial > hg > th-libs
comparison th_config.c @ 555:36423638841a
Clean up the parser a bit. Also return valid error value when an error
occurs, instead of a bogus value.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 04 Jan 2020 16:49:25 +0200 |
parents | 3a852e9f70a6 |
children | 7dce38c022d7 |
comparison
equal
deleted
inserted
replaced
554:c9b6fea48c8d | 555:36423638841a |
---|---|
253 return PM_ERROR; | 253 return PM_ERROR; |
254 } | 254 } |
255 } | 255 } |
256 | 256 |
257 | 257 |
258 static void th_cfg_set_item(th_cfgparserctx_t *ctx, th_cfgitem_t *item, const char *str) | 258 static int th_cfg_set_item(th_cfgparserctx_t *ctx, th_cfgitem_t *item, const char *str) |
259 { | 259 { |
260 BOOL res = TRUE; | 260 BOOL res = TRUE; |
261 | 261 |
262 switch (item->type) | 262 switch (item->type) |
263 { | 263 { |
276 { | 276 { |
277 th_llist_append(item->v.list, tmp); | 277 th_llist_append(item->v.list, tmp); |
278 th_cfg_set_next_parsemode(ctx, PM_LIST); | 278 th_cfg_set_next_parsemode(ctx, PM_LIST); |
279 | 279 |
280 // Early exit as we set the parsemode here | 280 // Early exit as we set the parsemode here |
281 return; | 281 return THERR_OK; |
282 } | 282 } |
283 else | 283 else |
284 res = FALSE; | 284 res = FALSE; |
285 } | 285 } |
286 break; | 286 break; |
304 default: | 304 default: |
305 res = FALSE; | 305 res = FALSE; |
306 break; | 306 break; |
307 } | 307 } |
308 | 308 |
309 th_cfg_set_parsemode(ctx, res ? PM_IDLE : PM_ERROR); | 309 th_cfg_set_parsemode(ctx, PM_IDLE); |
310 | |
311 return res ? THERR_OK : THERR_INVALID_DATA; | |
310 } | 312 } |
311 | 313 |
312 | 314 |
313 static int th_cfg_read_sect(th_ioctx *fh, th_cfgitem_t *sect, int nesting) | 315 static int th_cfg_read_sect(th_ioctx *fh, th_cfgitem_t *sect, int nesting) |
314 { | 316 { |
315 th_cfgparserctx_t ctx; | 317 th_cfgparserctx_t ctx; |
316 th_cfgitem_t *item = NULL; | 318 th_cfgitem_t *item = NULL; |
317 char *tmpStr = NULL; | 319 char *tmpStr = NULL; |
318 size_t strPos; | 320 size_t strPos; |
319 BOOL isEscaped, isStart, isError, fpSet; | 321 BOOL isEscaped, isStart, fpSet; |
322 int ret = THERR_OK; | |
320 | 323 |
321 // Initialize values | 324 // Initialize values |
322 memset(&ctx, 0, sizeof(ctx)); | 325 memset(&ctx, 0, sizeof(ctx)); |
323 ctx.ch = -1; | 326 ctx.ch = -1; |
324 ctx.nextMode = ctx.prevMode = ctx.parseMode = PM_IDLE; | 327 ctx.nextMode = ctx.prevMode = ctx.parseMode = PM_IDLE; |
325 isEscaped = fpSet = isStart = isError = FALSE; | 328 isEscaped = fpSet = isStart = FALSE; |
326 strPos = 0; | 329 strPos = 0; |
327 | 330 |
328 if ((tmpStr = th_malloc(SET_MAX_BUF + 1)) == NULL) | 331 if ((tmpStr = th_malloc(SET_MAX_BUF + 1)) == NULL) |
329 goto out; | 332 goto out; |
330 | 333 |
337 switch (ctx.ch = thfgetc(fh)) | 340 switch (ctx.ch = thfgetc(fh)) |
338 { | 341 { |
339 case EOF: | 342 case EOF: |
340 if (ctx.parseMode != PM_IDLE) | 343 if (ctx.parseMode != PM_IDLE) |
341 { | 344 { |
342 th_io_error(fh, THERR_OUT_OF_DATA, "Unexpected end of file.\n"); | 345 ret = th_io_error(fh, THERR_OUT_OF_DATA, |
343 ctx.parseMode = PM_ERROR; | 346 "Unexpected end of file.\n"); |
347 goto out; | |
344 } | 348 } |
345 else | 349 |
346 ctx.parseMode = PM_EOF; | 350 ctx.parseMode = PM_EOF; |
347 break; | 351 break; |
348 | 352 |
349 case '\n': | 353 case '\n': |
350 fh->line++; | 354 fh->line++; |
351 } | 355 } |
383 // Check for validation errors | 387 // Check for validation errors |
384 goto out; | 388 goto out; |
385 } | 389 } |
386 else | 390 else |
387 { | 391 { |
388 th_io_error(fh, THERR_INVALID_DATA, | 392 ret = th_io_error(fh, THERR_INVALID_DATA, |
389 "Invalid nesting sequence encountered.\n"); | 393 "Invalid nesting sequence encountered.\n"); |
390 ctx.parseMode = PM_ERROR; | 394 goto out; |
391 } | 395 } |
392 } | 396 } |
393 else | 397 else |
394 if (th_isalpha(ctx.ch)) | 398 if (th_isalpha(ctx.ch)) |
395 { | 399 { |
398 strPos = 0; | 402 strPos = 0; |
399 } | 403 } |
400 else | 404 else |
401 { | 405 { |
402 // Error! Invalid character found | 406 // Error! Invalid character found |
403 th_io_error(fh, THERR_INVALID_DATA, | 407 ret = th_io_error(fh, THERR_INVALID_DATA, |
404 "Unexpected character '%c'.\n", ctx.ch); | 408 "Unexpected character '%c'.\n", ctx.ch); |
405 ctx.parseMode = PM_ERROR; | 409 goto out; |
406 } | 410 } |
407 break; | 411 break; |
408 | 412 |
409 case PM_KEYNAME: | 413 case PM_KEYNAME: |
410 // Configuration KEY name parsing mode | 414 // Configuration KEY name parsing mode |
426 // Add to key name string | 430 // Add to key name string |
427 VADDCH(ctx.ch) | 431 VADDCH(ctx.ch) |
428 else | 432 else |
429 { | 433 { |
430 // Error! Key name string too long! | 434 // Error! Key name string too long! |
431 th_io_error(fh, THERR_INVALID_DATA, "Config key name too long!"); | 435 ret = th_io_error(fh, THERR_INVALID_DATA, |
432 ctx.parseMode = PM_ERROR; | 436 "Config key name too long!"); |
437 goto out; | |
433 } | 438 } |
434 ctx.ch = -1; | 439 ctx.ch = -1; |
435 tmpStr[strPos] = 0; | 440 tmpStr[strPos] = 0; |
436 } | 441 } |
437 else | 442 else |
438 { | 443 { |
439 // Error! Invalid character found | 444 // Error! Invalid character found |
440 tmpStr[strPos] = 0; | 445 tmpStr[strPos] = 0; |
441 th_io_error(fh, THERR_INVALID_DATA, | 446 ret = th_io_error(fh, THERR_INVALID_DATA, |
442 "Unexpected character '%c' in key name '%s'.\n", | 447 "Unexpected character '%c' in key name '%s'.\n", |
443 ctx.ch, tmpStr); | 448 ctx.ch, tmpStr); |
444 ctx.parseMode = PM_ERROR; | 449 goto out; |
445 } | 450 } |
446 break; | 451 break; |
447 | 452 |
448 case PM_KEYSET: | 453 case PM_KEYSET: |
449 if (ctx.ch == '=') | 454 if (ctx.ch == '=') |
472 strPos = 0; | 477 strPos = 0; |
473 } | 478 } |
474 else | 479 else |
475 { | 480 { |
476 // Error! No configuration key by this name found | 481 // Error! No configuration key by this name found |
477 th_io_error(fh, THERR_INVALID_DATA, | 482 ret = th_io_error(fh, THERR_INVALID_DATA, |
478 "No such configuration setting ('%s')\n", | 483 "No such configuration setting ('%s')\n", |
479 tmpStr); | 484 tmpStr); |
480 ctx.parseMode = PM_ERROR; | 485 goto out; |
481 } | 486 } |
482 | 487 |
483 ctx.ch = -1; | 488 ctx.ch = -1; |
484 } | 489 } |
485 else | 490 else |
486 { | 491 { |
487 // Error! '=' expected! | 492 // Error! '=' expected! |
488 th_io_error(fh, THERR_INVALID_DATA, | 493 ret = th_io_error(fh, THERR_INVALID_DATA, |
489 "Unexpected character '%c', assignation '=' was expected.\n", | 494 "Unexpected character '%c', assignation '=' was expected.\n", |
490 ctx.ch); | 495 ctx.ch); |
491 ctx.parseMode = PM_ERROR; | 496 goto out; |
492 } | 497 } |
493 break; | 498 break; |
494 | 499 |
495 case PM_NEXT: | 500 case PM_NEXT: |
496 // Search next item parsing mode | 501 // Search next item parsing mode |
533 case PM_SECTION: | 538 case PM_SECTION: |
534 // Section parsing mode | 539 // Section parsing mode |
535 if (ctx.ch != '{') | 540 if (ctx.ch != '{') |
536 { | 541 { |
537 // Error! Section start '{' expected! | 542 // Error! Section start '{' expected! |
538 th_io_error(fh, THERR_INVALID_DATA, | 543 ret = th_io_error(fh, THERR_INVALID_DATA, |
539 "Unexpected character '%c', section start '{' was expected.\n", | 544 "Unexpected character '%c', section start '{' was expected.\n", |
540 ctx.ch); | 545 ctx.ch); |
541 ctx.parseMode = PM_ERROR; | 546 goto out; |
542 } | 547 } |
543 else | 548 else |
544 { | 549 { |
545 int res = th_cfg_read_sect(fh, item->v.section, nesting + 1); | 550 if ((ret = th_cfg_read_sect(fh, item->v.section, nesting + 1)) != THERR_OK) |
546 if (res == THERR_OK) | 551 goto out; |
547 th_cfg_set_parsemode(&ctx, PM_IDLE); | 552 |
548 else | 553 th_cfg_set_parsemode(&ctx, PM_IDLE); |
549 ctx.parseMode = PM_ERROR; | |
550 | |
551 ctx.ch = -1; | 554 ctx.ch = -1; |
552 } | 555 } |
553 break; | 556 break; |
554 | 557 |
555 case PM_STRING: | 558 case PM_STRING: |
565 else | 568 else |
566 if (!isEscaped && ctx.ch == ctx.strDelim) | 569 if (!isEscaped && ctx.ch == ctx.strDelim) |
567 { | 570 { |
568 // End of string, set the value | 571 // End of string, set the value |
569 tmpStr[strPos] = 0; | 572 tmpStr[strPos] = 0; |
570 th_cfg_set_item(&ctx, item, tmpStr); | 573 if ((ret = th_cfg_set_item(&ctx, item, tmpStr)) != THERR_OK) |
574 goto out; | |
571 } | 575 } |
572 else | 576 else |
573 if (!isEscaped && ctx.ch == '\\') | 577 if (!isEscaped && ctx.ch == '\\') |
574 { | 578 { |
575 // Escape sequence | 579 // Escape sequence |
580 // Add character to string | 584 // Add character to string |
581 VADDCH(ctx.ch) | 585 VADDCH(ctx.ch) |
582 else | 586 else |
583 { | 587 { |
584 // Error! String too long! | 588 // Error! String too long! |
585 th_io_error(fh, THERR_INVALID_DATA, | 589 ret = th_io_error(fh, THERR_INVALID_DATA, |
586 "String too long! Maximum is %d characters.", | 590 "String too long! Maximum is %d characters.", |
587 SET_MAX_BUF); | 591 SET_MAX_BUF); |
588 ctx.parseMode = PM_ERROR; | 592 goto out; |
589 } | 593 } |
590 isEscaped = FALSE; | 594 isEscaped = FALSE; |
591 } | 595 } |
592 | 596 |
593 ctx.ch = -1; | 597 ctx.ch = -1; |
596 case PM_NUMERIC: | 600 case PM_NUMERIC: |
597 // Integer parsing mode | 601 // Integer parsing mode |
598 if (isStart && item->type == ITEM_UINT && ctx.ch == '-') | 602 if (isStart && item->type == ITEM_UINT && ctx.ch == '-') |
599 { | 603 { |
600 // Error! Negative values not allowed for unsigned ints | 604 // Error! Negative values not allowed for unsigned ints |
601 th_io_error(fh, THERR_INVALID_DATA, | 605 ret = th_io_error(fh, THERR_INVALID_DATA, |
602 "Negative value specified for %s, unsigned value expected.", | 606 "Negative value specified for %s, unsigned value expected.", |
603 item->name); | 607 item->name); |
604 ctx.parseMode = PM_ERROR; | 608 goto out; |
605 } | 609 } |
606 else | 610 else |
607 if (isStart && (ctx.ch == '-' || ctx.ch == '+')) | 611 if (isStart && (ctx.ch == '-' || ctx.ch == '+')) |
608 { | 612 { |
609 VADDCH(ctx.ch) | 613 VADDCH(ctx.ch) |
610 else | 614 else |
611 isError = TRUE; | 615 ret = THERR_INVALID_DATA; |
612 } | 616 } |
613 else | 617 else |
614 if (isStart && item->type == ITEM_FLOAT && ctx.ch == '.') | 618 if (isStart && item->type == ITEM_FLOAT && ctx.ch == '.') |
615 { | 619 { |
616 fpSet = TRUE; | 620 fpSet = TRUE; |
617 VADDCH('0') | 621 VADDCH('0') |
618 else | 622 else |
619 isError = TRUE; | 623 ret = THERR_INVALID_DATA; |
620 | 624 |
621 VADDCH(ctx.ch) | 625 VADDCH(ctx.ch) |
622 else | 626 else |
623 isError = TRUE; | 627 ret = THERR_INVALID_DATA; |
624 } | 628 } |
625 else | 629 else |
626 if (item->type == ITEM_FLOAT && ctx.ch == '.' && !fpSet) | 630 if (item->type == ITEM_FLOAT && ctx.ch == '.' && !fpSet) |
627 { | 631 { |
628 fpSet = TRUE; | 632 fpSet = TRUE; |
629 VADDCH(ctx.ch) | 633 VADDCH(ctx.ch) |
630 else | 634 else |
631 isError = TRUE; | 635 ret = THERR_INVALID_DATA; |
632 } | 636 } |
633 else | 637 else |
634 if (th_isdigit(ctx.ch)) | 638 if (th_isdigit(ctx.ch)) |
635 { | 639 { |
636 VADDCH(ctx.ch) | 640 VADDCH(ctx.ch) |
637 else | 641 else |
638 isError = TRUE; | 642 ret = THERR_INVALID_DATA; |
639 } | 643 } |
640 else | 644 else |
641 if (th_cfg_is_end(ctx.ch)) | 645 if (th_cfg_is_end(ctx.ch)) |
642 { | 646 { |
643 // End of integer parsing mode | 647 // End of integer parsing mode |
644 tmpStr[strPos] = 0; | 648 tmpStr[strPos] = 0; |
645 th_cfg_set_item(&ctx, item, tmpStr); | 649 |
650 if ((ret = th_cfg_set_item(&ctx, item, tmpStr)) != THERR_OK) | |
651 goto out; | |
652 | |
646 th_cfg_set_parsemode(&ctx, PM_IDLE); | 653 th_cfg_set_parsemode(&ctx, PM_IDLE); |
647 } | 654 } |
648 else | 655 else |
649 { | 656 { |
650 // Error! Unexpected character. | 657 // Error! Unexpected character. |
651 th_io_error(fh, THERR_INVALID_DATA, | 658 ret = th_io_error(fh, THERR_INVALID_DATA, |
652 "Unexpected character '%c' for numeric setting '%s'.", | 659 "Unexpected character '%c' for numeric setting '%s'.", |
653 ctx.ch, item->name); | 660 ctx.ch, item->name); |
654 ctx.parseMode = PM_ERROR; | 661 goto out; |
655 } | 662 } |
656 | 663 |
657 if (isError) | 664 if (ret != THERR_OK) |
658 { | 665 { |
659 // Error! String too long! | 666 // Error! String too long! |
660 th_io_error(fh, THERR_INVALID_DATA, | 667 ret = th_io_error(fh, ret, |
661 "String too long! Maximum is %d characters.", | 668 "String too long! Maximum is %d characters.", |
662 SET_MAX_BUF); | 669 SET_MAX_BUF); |
663 ctx.parseMode = PM_ERROR; | 670 goto out; |
664 } | 671 } |
665 | 672 |
666 isStart = FALSE; | 673 isStart = FALSE; |
667 ctx.ch = -1; | 674 ctx.ch = -1; |
668 break; | 675 break; |
677 | 684 |
678 if (th_isalnum(ctx.ch)) | 685 if (th_isalnum(ctx.ch)) |
679 { | 686 { |
680 VADDCH(ctx.ch) | 687 VADDCH(ctx.ch) |
681 else | 688 else |
682 isError = TRUE; | 689 ret = THERR_INVALID_DATA; |
683 } | 690 } |
684 else | 691 else |
685 if (th_cfg_is_end(ctx.ch)) | 692 if (th_cfg_is_end(ctx.ch)) |
686 { | 693 { |
687 tmpStr[strPos] = 0; | 694 tmpStr[strPos] = 0; |
688 th_cfg_set_item(&ctx, item, tmpStr); | 695 ret = th_cfg_set_item(&ctx, item, tmpStr); |
689 } | 696 } |
690 | 697 |
691 if (isError || ctx.parseMode == PM_ERROR) | 698 if (ret != THERR_OK) |
692 { | 699 { |
693 th_io_error(fh, THERR_INVALID_DATA, | 700 ret = th_io_error(fh, ret, |
694 "Invalid boolean value for '%s'.\n", | 701 "Invalid boolean value for '%s'.\n", |
695 item->name); | 702 item->name); |
696 ctx.parseMode = PM_ERROR; | 703 goto out; |
697 } | 704 } |
698 ctx.ch = -1; | 705 ctx.ch = -1; |
699 break; | 706 break; |
700 } | 707 } |
701 } | 708 } |
702 | 709 |
703 out: | 710 out: |
704 th_free(tmpStr); | 711 th_free(tmpStr); |
705 | 712 |
706 // Return result | 713 // Return result |
707 if (ctx.parseMode == PM_ERROR) | 714 if (ret == THERR_OK && ctx.parseMode == PM_ERROR) |
708 return fh->status; | 715 ret = THERR_INVALID_DATA; |
709 else | 716 |
710 return THERR_OK; | 717 return ret; |
711 } | 718 } |
712 | 719 |
713 | 720 |
714 int th_cfg_read(th_ioctx *fh, th_cfgitem_t *cfg) | 721 int th_cfg_read(th_ioctx *fh, th_cfgitem_t *cfg) |
715 { | 722 { |