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 {