Mercurial > hg > th-libs
comparison th_config.c @ 776:680324e43852
Rename a number of config parser variables etc.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 02 Jul 2023 00:43:59 +0300 |
parents | 456235ae762e |
children | 484853471eaf |
comparison
equal
deleted
inserted
replaced
775:456235ae762e | 776:680324e43852 |
---|---|
197 }; | 197 }; |
198 | 198 |
199 | 199 |
200 typedef struct | 200 typedef struct |
201 { | 201 { |
202 int ch, strDelim, | 202 int ch, delim, |
203 prevMode, nextMode, parseMode; | 203 prev, next, mode; |
204 } th_cfgparserctx_t; | 204 } th_cfgparserctx_t; |
205 | 205 |
206 /// @endcond | 206 /// @endcond |
207 | 207 |
208 | 208 |
209 static void th_cfg_set_parsemode(th_cfgparserctx_t *ctx, const int mode) | 209 static void th_cfg_set_parsemode(th_cfgparserctx_t *ctx, const int mode) |
210 { | 210 { |
211 ctx->prevMode = ctx->parseMode; | 211 ctx->prev = ctx->mode; |
212 ctx->parseMode = mode; | 212 ctx->mode = mode; |
213 } | 213 } |
214 | 214 |
215 | 215 |
216 static void th_cfg_set_next_parsemode(th_cfgparserctx_t *ctx, const int mode) | 216 static void th_cfg_set_next_parsemode(th_cfgparserctx_t *ctx, const int mode) |
217 { | 217 { |
218 th_cfg_set_parsemode(ctx, PM_NEXT); | 218 th_cfg_set_parsemode(ctx, PM_NEXT); |
219 ctx->nextMode = mode; | 219 ctx->next = mode; |
220 } | 220 } |
221 | 221 |
222 | 222 |
223 #define VADDCH(ch) if (strPos < SET_CFG_MAX_PARSE_BUF) { tmpStr[strPos++] = ch; } | 223 #define VADDCH(ch) if (pos < SET_CFG_MAX_PARSE_BUF) { str[pos++] = ch; } |
224 | 224 |
225 | 225 |
226 static bool th_cfg_is_end(const int ch) | 226 static bool th_cfg_is_end(const int ch) |
227 { | 227 { |
228 return | 228 return |
321 | 321 |
322 static int th_cfg_read_sect(th_ioctx_t *fh, th_cfgitem_t *sect, int nesting) | 322 static int th_cfg_read_sect(th_ioctx_t *fh, th_cfgitem_t *sect, int nesting) |
323 { | 323 { |
324 th_cfgparserctx_t ctx; | 324 th_cfgparserctx_t ctx; |
325 th_cfgitem_t *item = NULL; | 325 th_cfgitem_t *item = NULL; |
326 char *tmpStr = NULL; | 326 char *str = NULL; |
327 size_t strPos; | 327 size_t pos; |
328 bool isEscaped, isStart, fpSet; | 328 bool escaped, start, fpseparator; |
329 int ret = THERR_OK; | 329 int ret = THERR_OK; |
330 | 330 |
331 // Initialize values | 331 // Initialize values |
332 memset(&ctx, 0, sizeof(ctx)); | 332 memset(&ctx, 0, sizeof(ctx)); |
333 ctx.ch = -1; | 333 ctx.ch = -1; |
334 ctx.nextMode = ctx.prevMode = ctx.parseMode = PM_IDLE; | 334 ctx.next = ctx.prev = ctx.mode = PM_IDLE; |
335 isEscaped = fpSet = isStart = false; | 335 escaped = fpseparator = start = false; |
336 strPos = 0; | 336 pos = 0; |
337 | 337 |
338 if ((tmpStr = th_malloc(SET_CFG_MAX_PARSE_BUF + 1)) == NULL) | 338 if ((str = th_malloc(SET_CFG_MAX_PARSE_BUF + 1)) == NULL) |
339 goto out; | 339 goto out; |
340 | 340 |
341 // Parse the configuration | 341 // Parse the configuration |
342 while (ctx.parseMode != PM_EOF && ctx.parseMode != PM_ERROR) | 342 while (ctx.mode != PM_EOF && ctx.mode != PM_ERROR) |
343 { | 343 { |
344 if (ctx.ch == -1) | 344 if (ctx.ch == -1) |
345 { | 345 { |
346 // Get next character | 346 // Get next character |
347 switch (ctx.ch = thfgetc(fh)) | 347 switch (ctx.ch = thfgetc(fh)) |
348 { | 348 { |
349 case EOF: | 349 case EOF: |
350 if (ctx.parseMode != PM_IDLE) | 350 if (ctx.mode != PM_IDLE) |
351 { | 351 { |
352 ret = th_io_error(fh, THERR_OUT_OF_DATA, | 352 ret = th_io_error(fh, THERR_OUT_OF_DATA, |
353 "Unexpected end of file."); | 353 "Unexpected end of file."); |
354 goto out; | 354 goto out; |
355 } | 355 } |
356 | 356 |
357 ctx.parseMode = PM_EOF; | 357 ctx.mode = PM_EOF; |
358 break; | 358 break; |
359 | 359 |
360 case '\n': | 360 case '\n': |
361 fh->line++; | 361 fh->line++; |
362 } | 362 } |
363 } | 363 } |
364 | 364 |
365 switch (ctx.parseMode) | 365 switch (ctx.mode) |
366 { | 366 { |
367 case PM_COMMENT: | 367 case PM_COMMENT: |
368 // Comment parsing mode | 368 // Comment parsing mode |
369 if (ctx.ch == '\n') | 369 if (ctx.ch == '\n') |
370 { | 370 { |
371 // End of line, end of comment | 371 // End of line, end of comment |
372 th_cfg_set_parsemode(&ctx, ctx.prevMode); | 372 th_cfg_set_parsemode(&ctx, ctx.prev); |
373 } | 373 } |
374 ctx.ch = -1; | 374 ctx.ch = -1; |
375 break; | 375 break; |
376 | 376 |
377 case PM_IDLE: | 377 case PM_IDLE: |
404 else | 404 else |
405 if (th_isalpha(ctx.ch)) | 405 if (th_isalpha(ctx.ch)) |
406 { | 406 { |
407 // Start of key name found | 407 // Start of key name found |
408 th_cfg_set_parsemode(&ctx, PM_KEYNAME); | 408 th_cfg_set_parsemode(&ctx, PM_KEYNAME); |
409 strPos = 0; | 409 pos = 0; |
410 } | 410 } |
411 else | 411 else |
412 { | 412 { |
413 // Error! Invalid character found | 413 // Error! Invalid character found |
414 ret = th_io_error(fh, THERR_INVALID_DATA, | 414 ret = th_io_error(fh, THERR_INVALID_DATA, |
442 ret = th_io_error(fh, THERR_INVALID_DATA, | 442 ret = th_io_error(fh, THERR_INVALID_DATA, |
443 "Config key name too long!"); | 443 "Config key name too long!"); |
444 goto out; | 444 goto out; |
445 } | 445 } |
446 ctx.ch = -1; | 446 ctx.ch = -1; |
447 tmpStr[strPos] = 0; | 447 str[pos] = 0; |
448 } | 448 } |
449 else | 449 else |
450 { | 450 { |
451 // Error! Invalid character found | 451 // Error! Invalid character found |
452 tmpStr[strPos] = 0; | 452 str[pos] = 0; |
453 ret = th_io_error(fh, THERR_INVALID_DATA, | 453 ret = th_io_error(fh, THERR_INVALID_DATA, |
454 "Unexpected character '%c' in key name '%s'.", | 454 "Unexpected character '%c' in key name '%s'.", |
455 ctx.ch, tmpStr); | 455 ctx.ch, str); |
456 goto out; | 456 goto out; |
457 } | 457 } |
458 break; | 458 break; |
459 | 459 |
460 case PM_KEYSET: | 460 case PM_KEYSET: |
461 if (ctx.ch == '=') | 461 if (ctx.ch == '=') |
462 { | 462 { |
463 // Find key from configuration | 463 // Find key from configuration |
464 bool found; | 464 bool found; |
465 tmpStr[strPos] = 0; | 465 str[pos] = 0; |
466 | 466 |
467 for (item = sect, found = false; item != NULL && !found; ) | 467 for (item = sect, found = false; item != NULL && !found; ) |
468 { | 468 { |
469 if (item->type != CFG_ITEM_COMMENT && | 469 if (item->type != CFG_ITEM_COMMENT && |
470 item->name != NULL && | 470 item->name != NULL && |
471 strcmp(item->name, tmpStr) == 0) | 471 strcmp(item->name, str) == 0) |
472 found = true; | 472 found = true; |
473 else | 473 else |
474 item = (th_cfgitem_t *) item->node.next; | 474 item = (th_cfgitem_t *) item->node.next; |
475 } | 475 } |
476 | 476 |
477 // Check if key was found | 477 // Check if key was found |
478 if (found) | 478 if (found) |
479 { | 479 { |
480 // Okay, set next mode | 480 // Okay, set next mode |
481 th_cfg_set_next_parsemode(&ctx, th_cfg_get_parsemode(item->type)); | 481 th_cfg_set_next_parsemode(&ctx, th_cfg_get_parsemode(item->type)); |
482 isStart = true; | 482 start = true; |
483 fpSet = false; | 483 fpseparator = false; |
484 strPos = 0; | 484 pos = 0; |
485 } | 485 } |
486 else | 486 else |
487 { | 487 { |
488 // Error! No configuration key by this name found | 488 // Error! No configuration key by this name found |
489 ret = th_io_error(fh, THERR_INVALID_DATA, | 489 ret = th_io_error(fh, THERR_INVALID_DATA, |
490 "No such configuration setting: '%s'.", | 490 "No such configuration setting: '%s'.", |
491 tmpStr); | 491 str); |
492 goto out; | 492 goto out; |
493 } | 493 } |
494 | 494 |
495 ctx.ch = -1; | 495 ctx.ch = -1; |
496 } | 496 } |
518 ctx.ch = -1; | 518 ctx.ch = -1; |
519 } | 519 } |
520 else | 520 else |
521 { | 521 { |
522 // Next item found | 522 // Next item found |
523 th_cfg_set_parsemode(&ctx, ctx.nextMode); | 523 th_cfg_set_parsemode(&ctx, ctx.next); |
524 } | 524 } |
525 break; | 525 break; |
526 | 526 |
527 case PM_LIST: | 527 case PM_LIST: |
528 if (isStart) | 528 if (start) |
529 { | 529 { |
530 th_cfg_set_parsemode(&ctx, PM_STRING); | 530 th_cfg_set_parsemode(&ctx, PM_STRING); |
531 } | 531 } |
532 else | 532 else |
533 if (ctx.ch == ',') | 533 if (ctx.ch == ',') |
534 { | 534 { |
535 th_cfg_set_next_parsemode(&ctx, PM_STRING); | 535 th_cfg_set_next_parsemode(&ctx, PM_STRING); |
536 ctx.ch = -1; | 536 ctx.ch = -1; |
537 isStart = true; | 537 start = true; |
538 } | 538 } |
539 else | 539 else |
540 { | 540 { |
541 th_cfg_set_parsemode(&ctx, PM_IDLE); | 541 th_cfg_set_parsemode(&ctx, PM_IDLE); |
542 } | 542 } |
562 } | 562 } |
563 break; | 563 break; |
564 | 564 |
565 case PM_STRING: | 565 case PM_STRING: |
566 // String parsing mode | 566 // String parsing mode |
567 if (isStart) | 567 if (start) |
568 { | 568 { |
569 // Start of string, get delimiter | 569 // Start of string, get delimiter |
570 ctx.strDelim = ctx.ch; | 570 ctx.delim = ctx.ch; |
571 isStart = false; | 571 start = false; |
572 strPos = 0; | 572 pos = 0; |
573 isEscaped = false; | 573 escaped = false; |
574 } | 574 } |
575 else | 575 else |
576 if (!isEscaped && ctx.ch == ctx.strDelim) | 576 if (!escaped && ctx.ch == ctx.delim) |
577 { | 577 { |
578 // End of string, set the value | 578 // End of string, set the value |
579 tmpStr[strPos] = 0; | 579 str[pos] = 0; |
580 if ((ret = th_cfg_set_item(&ctx, item, tmpStr)) != THERR_OK) | 580 if ((ret = th_cfg_set_item(&ctx, item, str)) != THERR_OK) |
581 goto out; | 581 goto out; |
582 } | 582 } |
583 else | 583 else |
584 if (!isEscaped && ctx.ch == '\\') | 584 if (!escaped && ctx.ch == '\\') |
585 { | 585 { |
586 // Escape sequence | 586 // Escape sequence |
587 isEscaped = true; | 587 escaped = true; |
588 } | 588 } |
589 else | 589 else |
590 { | 590 { |
591 // Add character to string | 591 // Add character to string |
592 VADDCH(ctx.ch) | 592 VADDCH(ctx.ch) |
596 ret = th_io_error(fh, THERR_INVALID_DATA, | 596 ret = th_io_error(fh, THERR_INVALID_DATA, |
597 "String too long! Maximum is %d characters.", | 597 "String too long! Maximum is %d characters.", |
598 SET_CFG_MAX_PARSE_BUF); | 598 SET_CFG_MAX_PARSE_BUF); |
599 goto out; | 599 goto out; |
600 } | 600 } |
601 isEscaped = false; | 601 escaped = false; |
602 } | 602 } |
603 | 603 |
604 ctx.ch = -1; | 604 ctx.ch = -1; |
605 break; | 605 break; |
606 | 606 |
607 case PM_NUMERIC: | 607 case PM_NUMERIC: |
608 // Integer parsing mode | 608 // Integer parsing mode |
609 if (isStart && item->type == CFG_ITEM_UINT && ctx.ch == '-') | 609 if (start && item->type == CFG_ITEM_UINT && ctx.ch == '-') |
610 { | 610 { |
611 // Error! Negative values not allowed for unsigned ints | 611 // Error! Negative values not allowed for unsigned ints |
612 ret = th_io_error(fh, THERR_INVALID_DATA, | 612 ret = th_io_error(fh, THERR_INVALID_DATA, |
613 "Negative value specified for %s, unsigned value expected.", | 613 "Negative value specified for %s, unsigned value expected.", |
614 item->name); | 614 item->name); |
615 goto out; | 615 goto out; |
616 } | 616 } |
617 else | 617 else |
618 if (isStart && (ctx.ch == '-' || ctx.ch == '+')) | 618 if (start && (ctx.ch == '-' || ctx.ch == '+')) |
619 { | 619 { |
620 VADDCH(ctx.ch) | 620 VADDCH(ctx.ch) |
621 else | 621 else |
622 ret = THERR_INVALID_DATA; | 622 ret = THERR_INVALID_DATA; |
623 } | 623 } |
624 else | 624 else |
625 if (isStart && item->type == CFG_ITEM_FLOAT && ctx.ch == '.') | 625 if (start && item->type == CFG_ITEM_FLOAT && ctx.ch == '.') |
626 { | 626 { |
627 fpSet = true; | 627 fpseparator = true; |
628 VADDCH('0') | 628 VADDCH('0') |
629 else | 629 else |
630 ret = THERR_INVALID_DATA; | 630 ret = THERR_INVALID_DATA; |
631 | 631 |
632 VADDCH(ctx.ch) | 632 VADDCH(ctx.ch) |
633 else | 633 else |
634 ret = THERR_INVALID_DATA; | 634 ret = THERR_INVALID_DATA; |
635 } | 635 } |
636 else | 636 else |
637 if (item->type == CFG_ITEM_FLOAT && ctx.ch == '.' && !fpSet) | 637 if (item->type == CFG_ITEM_FLOAT && ctx.ch == '.' && !fpseparator) |
638 { | 638 { |
639 fpSet = true; | 639 fpseparator = true; |
640 VADDCH(ctx.ch) | 640 VADDCH(ctx.ch) |
641 else | 641 else |
642 ret = THERR_INVALID_DATA; | 642 ret = THERR_INVALID_DATA; |
643 } | 643 } |
644 else | 644 else |
650 } | 650 } |
651 else | 651 else |
652 if (th_cfg_is_end(ctx.ch)) | 652 if (th_cfg_is_end(ctx.ch)) |
653 { | 653 { |
654 // End of integer parsing mode | 654 // End of integer parsing mode |
655 tmpStr[strPos] = 0; | 655 str[pos] = 0; |
656 | 656 |
657 if ((ret = th_cfg_set_item(&ctx, item, tmpStr)) != THERR_OK) | 657 if ((ret = th_cfg_set_item(&ctx, item, str)) != THERR_OK) |
658 goto out; | 658 goto out; |
659 | 659 |
660 th_cfg_set_parsemode(&ctx, PM_IDLE); | 660 th_cfg_set_parsemode(&ctx, PM_IDLE); |
661 } | 661 } |
662 else | 662 else |
675 "String too long! Maximum is %d characters.", | 675 "String too long! Maximum is %d characters.", |
676 SET_CFG_MAX_PARSE_BUF); | 676 SET_CFG_MAX_PARSE_BUF); |
677 goto out; | 677 goto out; |
678 } | 678 } |
679 | 679 |
680 isStart = false; | 680 start = false; |
681 ctx.ch = -1; | 681 ctx.ch = -1; |
682 break; | 682 break; |
683 | 683 |
684 case PM_BOOL: | 684 case PM_BOOL: |
685 // Boolean parsing mode | 685 // Boolean parsing mode |
686 if (isStart) | 686 if (start) |
687 { | 687 { |
688 isStart = false; | 688 start = false; |
689 strPos = 0; | 689 pos = 0; |
690 } | 690 } |
691 | 691 |
692 if (th_isalnum(ctx.ch)) | 692 if (th_isalnum(ctx.ch)) |
693 { | 693 { |
694 VADDCH(ctx.ch) | 694 VADDCH(ctx.ch) |
696 ret = THERR_INVALID_DATA; | 696 ret = THERR_INVALID_DATA; |
697 } | 697 } |
698 else | 698 else |
699 if (th_cfg_is_end(ctx.ch)) | 699 if (th_cfg_is_end(ctx.ch)) |
700 { | 700 { |
701 tmpStr[strPos] = 0; | 701 str[pos] = 0; |
702 ret = th_cfg_set_item(&ctx, item, tmpStr); | 702 ret = th_cfg_set_item(&ctx, item, str); |
703 } | 703 } |
704 | 704 |
705 if (ret != THERR_OK) | 705 if (ret != THERR_OK) |
706 { | 706 { |
707 ret = th_io_error(fh, ret, | 707 ret = th_io_error(fh, ret, |
713 break; | 713 break; |
714 } | 714 } |
715 } | 715 } |
716 | 716 |
717 out: | 717 out: |
718 th_free(tmpStr); | 718 th_free(str); |
719 | 719 |
720 // Return result | 720 // Return result |
721 if (ret == THERR_OK && ctx.parseMode == PM_ERROR) | 721 if (ret == THERR_OK && ctx.mode == PM_ERROR) |
722 ret = THERR_INVALID_DATA; | 722 ret = THERR_INVALID_DATA; |
723 | 723 |
724 return ret; | 724 return ret; |
725 } | 725 } |
726 | 726 |