1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Joyent, Inc. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <ctype.h> 19 #include <strings.h> 20 #include <errno.h> 21 #include <libnvpair.h> 22 #include <sys/ccompile.h> 23 24 #include "libvarpd_files_json.h" 25 26 typedef enum json_type { 27 JSON_TYPE_NOTHING = 0, 28 JSON_TYPE_STRING = 1, 29 JSON_TYPE_INTEGER, 30 JSON_TYPE_DOUBLE, 31 JSON_TYPE_BOOLEAN, 32 JSON_TYPE_NULL, 33 JSON_TYPE_OBJECT, 34 JSON_TYPE_ARRAY 35 } json_type_t; 36 37 typedef enum parse_state { 38 PARSE_ERROR = -1, 39 PARSE_DONE = 0, 40 PARSE_REST, 41 PARSE_OBJECT, 42 PARSE_KEY_STRING, 43 PARSE_COLON, 44 PARSE_STRING, 45 PARSE_OBJECT_COMMA, 46 PARSE_ARRAY, 47 PARSE_BAREWORD, 48 PARSE_NUMBER, 49 PARSE_ARRAY_VALUE, 50 PARSE_ARRAY_COMMA 51 } parse_state_t; 52 53 #define JSON_MARKER ".__json_" 54 #define JSON_MARKER_ARRAY JSON_MARKER "array" 55 56 typedef struct parse_frame { 57 parse_state_t pf_ps; 58 nvlist_t *pf_nvl; 59 60 char *pf_key; 61 void *pf_value; 62 json_type_t pf_value_type; 63 int pf_array_index; 64 65 struct parse_frame *pf_next; 66 } parse_frame_t; 67 68 typedef struct state { 69 const char *s_in; 70 unsigned long s_pos; 71 unsigned long s_len; 72 73 parse_frame_t *s_top; 74 75 nvlist_parse_json_flags_t s_flags; 76 77 /* 78 * This string buffer is used for temporary storage by the 79 * "collect_*()" family of functions. 80 */ 81 custr_t *s_collect; 82 83 int s_errno; 84 custr_t *s_errstr; 85 } state_t; 86 87 typedef void (*parse_handler_t)(state_t *); 88 89 static void 90 movestate(state_t *s, parse_state_t ps) 91 { 92 if (s->s_flags & NVJSON_DEBUG) { 93 (void) fprintf(stderr, "nvjson: move state %d -> %d\n", 94 s->s_top->pf_ps, ps); 95 } 96 s->s_top->pf_ps = ps; 97 } 98 99 static void 100 posterror(state_t *s, int erno, const char *error) 101 { 102 /* 103 * If the caller wants error messages printed to stderr, do that 104 * first. 105 */ 106 if (s->s_flags & NVJSON_ERRORS_TO_STDERR) { 107 (void) fprintf(stderr, "nvjson error (pos %ld, errno %d): %s\n", 108 s->s_pos, erno, error); 109 } 110 111 /* 112 * Try and store the error message for the caller. This may fail if 113 * the error was related to memory pressure, and that condition still 114 * exists. 115 */ 116 s->s_errno = erno; 117 if (s->s_errstr != NULL) { 118 (void) custr_append(s->s_errstr, error); 119 } 120 121 movestate(s, PARSE_ERROR); 122 } 123 124 static int 125 pushstate(state_t *s, parse_state_t ps, parse_state_t retps) 126 { 127 parse_frame_t *n; 128 129 if (s->s_flags & NVJSON_DEBUG) { 130 (void) fprintf(stderr, "nvjson: push state %d -> %d (ret %d)\n", 131 s->s_top->pf_ps, ps, retps); 132 } 133 134 if ((n = calloc(1, sizeof (*n))) == NULL) { 135 posterror(s, errno, "pushstate calloc failure"); 136 return (-1); 137 } 138 139 /* 140 * Store the state we'll return to when popping this 141 * frame: 142 */ 143 s->s_top->pf_ps = retps; 144 145 /* 146 * Store the initial state for the new frame, and 147 * put it on top of the stack: 148 */ 149 n->pf_ps = ps; 150 n->pf_value_type = JSON_TYPE_NOTHING; 151 152 n->pf_next = s->s_top; 153 s->s_top = n; 154 155 return (0); 156 } 157 158 static char 159 popchar(state_t *s) 160 { 161 if (s->s_pos > s->s_len) { 162 return (0); 163 } 164 return (s->s_in[s->s_pos++]); 165 } 166 167 static char 168 peekchar(state_t *s) 169 { 170 if (s->s_pos > s->s_len) { 171 return (0); 172 } 173 return (s->s_in[s->s_pos]); 174 } 175 176 static void 177 discard_whitespace(state_t *s) 178 { 179 while (isspace(peekchar(s))) { 180 (void) popchar(s); 181 } 182 } 183 184 static char *escape_pairs[] = { 185 "\"\"", "\\\\", "//", "b\b", "f\f", "n\n", "r\r", "t\t", NULL 186 }; 187 188 static char 189 collect_string_escape(state_t *s) 190 { 191 int i; 192 char c = popchar(s); 193 194 if (c == '\0') { 195 posterror(s, EPROTO, "EOF mid-escape sequence"); 196 return (-1); 197 } 198 199 /* 200 * Handle four-digit Unicode escapes up to and including \u007f. 201 * Strings that cannot be represented as 7-bit clean ASCII are not 202 * currently supported. 203 */ 204 if (c == 'u') { 205 int res; 206 int ndigs = 0; 207 char digs[5]; 208 209 /* 210 * Deal with 4-digit unicode escape. 211 */ 212 while (ndigs < 4) { 213 if ((digs[ndigs++] = popchar(s)) == '\0') { 214 posterror(s, EPROTO, "EOF mid-escape " 215 "sequence"); 216 return (-1); 217 } 218 } 219 digs[4] = '\0'; 220 if ((res = atoi(digs)) > 127) { 221 posterror(s, EPROTO, "unicode escape above 0x7f"); 222 return (-1); 223 } 224 225 if (custr_appendc(s->s_collect, res) != 0) { 226 posterror(s, errno, "custr_appendc failure"); 227 return (-1); 228 } 229 return (0); 230 } 231 232 /* 233 * See if this is a C-style escape character we recognise. 234 */ 235 for (i = 0; escape_pairs[i] != NULL; i++) { 236 char *ep = escape_pairs[i]; 237 if (ep[0] == c) { 238 if (custr_appendc(s->s_collect, ep[1]) != 0) { 239 posterror(s, errno, "custr_appendc failure"); 240 return (-1); 241 } 242 return (0); 243 } 244 } 245 246 posterror(s, EPROTO, "unrecognised escape sequence"); 247 return (-1); 248 } 249 250 static int 251 collect_string(state_t *s) 252 { 253 custr_reset(s->s_collect); 254 255 for (;;) { 256 char c; 257 258 switch (c = popchar(s)) { 259 case '"': 260 /* 261 * Legal End of String. 262 */ 263 return (0); 264 265 case '\0': 266 posterror(s, EPROTO, "EOF mid-string"); 267 return (-1); 268 269 case '\\': 270 /* 271 * Escape Characters and Sequences. 272 */ 273 if (collect_string_escape(s) != 0) { 274 return (-1); 275 } 276 break; 277 278 default: 279 if (custr_appendc(s->s_collect, c) != 0) { 280 posterror(s, errno, "custr_appendc failure"); 281 return (-1); 282 } 283 break; 284 } 285 } 286 } 287 288 static int 289 collect_bareword(state_t *s) 290 { 291 custr_reset(s->s_collect); 292 293 for (;;) { 294 if (!islower(peekchar(s))) { 295 return (0); 296 } 297 298 if (custr_appendc(s->s_collect, popchar(s)) != 0) { 299 posterror(s, errno, "custr_appendc failure"); 300 return (-1); 301 } 302 } 303 } 304 305 static void 306 hdlr_bareword(state_t *s) 307 { 308 const char *str; 309 310 if (collect_bareword(s) != 0) { 311 return; 312 } 313 314 str = custr_cstr(s->s_collect); 315 if (strcmp(str, "true") == 0) { 316 s->s_top->pf_value_type = JSON_TYPE_BOOLEAN; 317 s->s_top->pf_value = (void *)B_TRUE; 318 } else if (strcmp(str, "false") == 0) { 319 s->s_top->pf_value_type = JSON_TYPE_BOOLEAN; 320 s->s_top->pf_value = (void *)B_FALSE; 321 } else if (strcmp(str, "null") == 0) { 322 s->s_top->pf_value_type = JSON_TYPE_NULL; 323 } else { 324 posterror(s, EPROTO, "expected 'true', 'false' or 'null'"); 325 return; 326 } 327 328 movestate(s, PARSE_DONE); 329 } 330 331 /* ARGSUSED */ 332 static int 333 collect_number(state_t *s, boolean_t *isint, int32_t *result, 334 double *fresult __unused) 335 { 336 boolean_t neg = B_FALSE; 337 int t; 338 339 custr_reset(s->s_collect); 340 341 if (peekchar(s) == '-') { 342 neg = B_TRUE; 343 (void) popchar(s); 344 } 345 /* 346 * Read the 'int' portion: 347 */ 348 if (!isdigit(peekchar(s))) { 349 posterror(s, EPROTO, "malformed number: expected digit (0-9)"); 350 return (-1); 351 } 352 for (;;) { 353 if (!isdigit(peekchar(s))) { 354 break; 355 } 356 if (custr_appendc(s->s_collect, popchar(s)) != 0) { 357 posterror(s, errno, "custr_append failure"); 358 return (-1); 359 } 360 } 361 if (peekchar(s) == '.' || peekchar(s) == 'e' || peekchar(s) == 'E') { 362 posterror(s, ENOTSUP, "do not yet support FRACs or EXPs"); 363 return (-1); 364 } 365 366 t = atoi(custr_cstr(s->s_collect)); 367 368 *isint = B_TRUE; 369 *result = (neg == B_TRUE) ? (-t) : t; 370 return (0); 371 } 372 373 static void 374 hdlr_number(state_t *s) 375 { 376 boolean_t isint; 377 int32_t result; 378 double fresult; 379 380 if (collect_number(s, &isint, &result, &fresult) != 0) { 381 return; 382 } 383 384 if (isint == B_TRUE) { 385 s->s_top->pf_value = (void *)(uintptr_t)result; 386 s->s_top->pf_value_type = JSON_TYPE_INTEGER; 387 } else { 388 s->s_top->pf_value = malloc(sizeof (fresult)); 389 bcopy(&fresult, s->s_top->pf_value, sizeof (fresult)); 390 s->s_top->pf_value_type = JSON_TYPE_DOUBLE; 391 } 392 393 movestate(s, PARSE_DONE); 394 } 395 396 static void 397 hdlr_rest(state_t *s) 398 { 399 char c; 400 discard_whitespace(s); 401 c = popchar(s); 402 switch (c) { 403 case '{': 404 movestate(s, PARSE_OBJECT); 405 return; 406 407 case '[': 408 movestate(s, PARSE_ARRAY); 409 return; 410 411 default: 412 posterror(s, EPROTO, "EOF before object or array"); 413 return; 414 } 415 } 416 417 static int 418 add_empty_child(state_t *s) 419 { 420 /* 421 * Here, we create an empty nvlist to represent this object 422 * or array: 423 */ 424 nvlist_t *empty; 425 if (nvlist_alloc(&empty, NV_UNIQUE_NAME, 0) != 0) { 426 posterror(s, errno, "nvlist_alloc failure"); 427 return (-1); 428 } 429 if (s->s_top->pf_next != NULL) { 430 /* 431 * If we're a child of the frame above, we store ourselves in 432 * that frame's nvlist: 433 */ 434 nvlist_t *nvl = s->s_top->pf_next->pf_nvl; 435 char *key = s->s_top->pf_next->pf_key; 436 437 if (nvlist_add_nvlist(nvl, key, empty) != 0) { 438 posterror(s, errno, "nvlist_add_nvlist failure"); 439 nvlist_free(empty); 440 return (-1); 441 } 442 nvlist_free(empty); 443 if (nvlist_lookup_nvlist(nvl, key, &empty) != 0) { 444 posterror(s, errno, "nvlist_lookup_nvlist failure"); 445 return (-1); 446 } 447 } 448 s->s_top->pf_nvl = empty; 449 return (0); 450 } 451 452 static int 453 decorate_array(state_t *s) 454 { 455 int idx = s->s_top->pf_array_index; 456 /* 457 * When we are done creating an array, we store a 'length' 458 * property on it, as well as an internal-use marker value. 459 */ 460 if (nvlist_add_boolean(s->s_top->pf_nvl, JSON_MARKER_ARRAY) != 0 || 461 nvlist_add_uint32(s->s_top->pf_nvl, "length", idx) != 0) { 462 posterror(s, errno, "nvlist_add failure"); 463 return (-1); 464 } 465 466 return (0); 467 } 468 469 static void 470 hdlr_array(state_t *s) 471 { 472 s->s_top->pf_value_type = JSON_TYPE_ARRAY; 473 474 if (add_empty_child(s) != 0) { 475 return; 476 } 477 478 discard_whitespace(s); 479 480 switch (peekchar(s)) { 481 case ']': 482 (void) popchar(s); 483 484 if (decorate_array(s) != 0) { 485 return; 486 } 487 488 movestate(s, PARSE_DONE); 489 return; 490 491 default: 492 movestate(s, PARSE_ARRAY_VALUE); 493 return; 494 } 495 } 496 497 static void 498 hdlr_array_comma(state_t *s) 499 { 500 discard_whitespace(s); 501 502 switch (popchar(s)) { 503 case ']': 504 if (decorate_array(s) != 0) { 505 return; 506 } 507 508 movestate(s, PARSE_DONE); 509 return; 510 case ',': 511 movestate(s, PARSE_ARRAY_VALUE); 512 return; 513 default: 514 posterror(s, EPROTO, "expected ',' or ']'"); 515 return; 516 } 517 } 518 519 static void 520 hdlr_array_value(state_t *s) 521 { 522 char c; 523 524 /* 525 * Generate keyname from the next array index: 526 */ 527 if (s->s_top->pf_key != NULL) { 528 (void) fprintf(stderr, "pf_key not null! was %s\n", 529 s->s_top->pf_key); 530 abort(); 531 } 532 533 if (asprintf(&s->s_top->pf_key, "%d", s->s_top->pf_array_index++) < 0) { 534 posterror(s, errno, "asprintf failure"); 535 return; 536 } 537 538 discard_whitespace(s); 539 540 /* 541 * Select which type handler we need for the next value: 542 */ 543 switch (c = peekchar(s)) { 544 case '"': 545 (void) popchar(s); 546 (void) pushstate(s, PARSE_STRING, PARSE_ARRAY_COMMA); 547 return; 548 549 case '{': 550 (void) popchar(s); 551 (void) pushstate(s, PARSE_OBJECT, PARSE_ARRAY_COMMA); 552 return; 553 554 case '[': 555 (void) popchar(s); 556 (void) pushstate(s, PARSE_ARRAY, PARSE_ARRAY_COMMA); 557 return; 558 559 default: 560 if (islower(c)) { 561 (void) pushstate(s, PARSE_BAREWORD, 562 PARSE_ARRAY_COMMA); 563 return; 564 } else if (c == '-' || isdigit(c)) { 565 (void) pushstate(s, PARSE_NUMBER, PARSE_ARRAY_COMMA); 566 return; 567 } else { 568 posterror(s, EPROTO, "unexpected character at start " 569 "of value"); 570 return; 571 } 572 } 573 } 574 575 static void 576 hdlr_object(state_t *s) 577 { 578 s->s_top->pf_value_type = JSON_TYPE_OBJECT; 579 580 if (add_empty_child(s) != 0) { 581 return; 582 } 583 584 discard_whitespace(s); 585 586 switch (popchar(s)) { 587 case '}': 588 movestate(s, PARSE_DONE); 589 return; 590 591 case '"': 592 movestate(s, PARSE_KEY_STRING); 593 return; 594 595 default: 596 posterror(s, EPROTO, "expected key or '}'"); 597 return; 598 } 599 } 600 601 static void 602 hdlr_key_string(state_t *s) 603 { 604 if (collect_string(s) != 0) { 605 return; 606 } 607 608 /* 609 * Record the key name of the next value. 610 */ 611 if ((s->s_top->pf_key = strdup(custr_cstr(s->s_collect))) == NULL) { 612 posterror(s, errno, "strdup failure"); 613 return; 614 } 615 616 movestate(s, PARSE_COLON); 617 } 618 619 static void 620 hdlr_colon(state_t *s) 621 { 622 char c; 623 discard_whitespace(s); 624 625 if ((c = popchar(s)) != ':') { 626 posterror(s, EPROTO, "expected ':'"); 627 return; 628 } 629 630 discard_whitespace(s); 631 632 /* 633 * Select which type handler we need for the value after the colon: 634 */ 635 switch (c = peekchar(s)) { 636 case '"': 637 (void) popchar(s); 638 (void) pushstate(s, PARSE_STRING, PARSE_OBJECT_COMMA); 639 return; 640 641 case '{': 642 (void) popchar(s); 643 (void) pushstate(s, PARSE_OBJECT, PARSE_OBJECT_COMMA); 644 return; 645 646 case '[': 647 (void) popchar(s); 648 (void) pushstate(s, PARSE_ARRAY, PARSE_OBJECT_COMMA); 649 return; 650 651 default: 652 if (islower(c)) { 653 (void) pushstate(s, PARSE_BAREWORD, PARSE_OBJECT_COMMA); 654 return; 655 } else if (c == '-' || isdigit(c)) { 656 (void) pushstate(s, PARSE_NUMBER, PARSE_OBJECT_COMMA); 657 return; 658 } else { 659 (void) posterror(s, EPROTO, "unexpected character at " 660 "start of value"); 661 return; 662 } 663 } 664 } 665 666 static void 667 hdlr_object_comma(state_t *s) 668 { 669 discard_whitespace(s); 670 671 switch (popchar(s)) { 672 case '}': 673 movestate(s, PARSE_DONE); 674 return; 675 676 case ',': 677 discard_whitespace(s); 678 if (popchar(s) != '"') { 679 posterror(s, EPROTO, "expected '\"'"); 680 return; 681 } 682 movestate(s, PARSE_KEY_STRING); 683 return; 684 685 default: 686 posterror(s, EPROTO, "expected ',' or '}'"); 687 return; 688 } 689 } 690 691 static void 692 hdlr_string(state_t *s) 693 { 694 if (collect_string(s) != 0) { 695 return; 696 } 697 698 s->s_top->pf_value_type = JSON_TYPE_STRING; 699 if ((s->s_top->pf_value = strdup(custr_cstr(s->s_collect))) == NULL) { 700 posterror(s, errno, "strdup failure"); 701 return; 702 } 703 704 movestate(s, PARSE_DONE); 705 } 706 707 static int 708 store_value(state_t *s) 709 { 710 nvlist_t *targ = s->s_top->pf_next->pf_nvl; 711 char *key = s->s_top->pf_next->pf_key; 712 json_type_t type = s->s_top->pf_value_type; 713 int ret = 0; 714 715 switch (type) { 716 case JSON_TYPE_STRING: 717 if (nvlist_add_string(targ, key, s->s_top->pf_value) != 0) { 718 posterror(s, errno, "nvlist_add_string failure"); 719 ret = -1; 720 } 721 free(s->s_top->pf_value); 722 break; 723 724 case JSON_TYPE_BOOLEAN: 725 if (nvlist_add_boolean_value(targ, key, 726 (boolean_t)s->s_top->pf_value) != 0) { 727 posterror(s, errno, "nvlist_add_boolean_value " 728 "failure"); 729 ret = -1; 730 } 731 break; 732 733 case JSON_TYPE_NULL: 734 if (nvlist_add_boolean(targ, key) != 0) { 735 posterror(s, errno, "nvlist_add_boolean failure"); 736 ret = -1; 737 } 738 break; 739 740 case JSON_TYPE_INTEGER: 741 if (nvlist_add_int32(targ, key, 742 (int32_t)(uintptr_t)s->s_top->pf_value) != 0) { 743 posterror(s, errno, "nvlist_add_int32 failure"); 744 ret = -1; 745 } 746 break; 747 748 case JSON_TYPE_ARRAY: 749 case JSON_TYPE_OBJECT: 750 /* 751 * Objects and arrays are already 'stored' in their target 752 * nvlist on creation. See: hdlr_object, hdlr_array. 753 */ 754 break; 755 756 default: 757 (void) fprintf(stderr, "ERROR: could not store unknown " 758 "type %d\n", type); 759 abort(); 760 } 761 762 s->s_top->pf_value = NULL; 763 free(s->s_top->pf_next->pf_key); 764 s->s_top->pf_next->pf_key = NULL; 765 return (ret); 766 } 767 768 static parse_frame_t * 769 parse_frame_free(parse_frame_t *pf, boolean_t free_nvl) 770 { 771 parse_frame_t *next = pf->pf_next; 772 if (pf->pf_key != NULL) { 773 free(pf->pf_key); 774 } 775 if (pf->pf_value != NULL) { 776 abort(); 777 } 778 if (free_nvl && pf->pf_nvl != NULL) { 779 nvlist_free(pf->pf_nvl); 780 } 781 free(pf); 782 return (next); 783 } 784 785 static parse_handler_t hdlrs[] = { 786 NULL, /* PARSE_DONE */ 787 hdlr_rest, /* PARSE_REST */ 788 hdlr_object, /* PARSE_OBJECT */ 789 hdlr_key_string, /* PARSE_KEY_STRING */ 790 hdlr_colon, /* PARSE_COLON */ 791 hdlr_string, /* PARSE_STRING */ 792 hdlr_object_comma, /* PARSE_OBJECT_COMMA */ 793 hdlr_array, /* PARSE_ARRAY */ 794 hdlr_bareword, /* PARSE_BAREWORD */ 795 hdlr_number, /* PARSE_NUMBER */ 796 hdlr_array_value, /* PARSE_ARRAY_VALUE */ 797 hdlr_array_comma /* PARSE_ARRAY_COMMA */ 798 }; 799 #define NUM_PARSE_HANDLERS (int)(sizeof (hdlrs) / sizeof (hdlrs[0])) 800 801 int 802 nvlist_parse_json(const char *buf, size_t buflen, nvlist_t **nvlp, 803 nvlist_parse_json_flags_t flag, nvlist_parse_json_error_t *errout) 804 { 805 state_t s; 806 807 /* 808 * Check for valid flags: 809 */ 810 if ((flag & NVJSON_FORCE_INTEGER) && (flag & NVJSON_FORCE_DOUBLE)) { 811 errno = EINVAL; 812 return (-1); 813 } 814 if ((flag & ~NVJSON_ALL) != 0) { 815 errno = EINVAL; 816 return (-1); 817 } 818 819 /* 820 * Initialise parsing state structure: 821 */ 822 bzero(&s, sizeof (s)); 823 s.s_in = buf; 824 s.s_pos = 0; 825 s.s_len = buflen; 826 s.s_flags = flag; 827 828 /* 829 * Allocate the collect buffer string. 830 */ 831 if (custr_alloc(&s.s_collect) != 0) { 832 s.s_errno = errno; 833 if (errout != NULL) { 834 (void) snprintf(errout->nje_message, 835 sizeof (errout->nje_message), 836 "custr alloc failure: %s", 837 strerror(errno)); 838 } 839 goto out; 840 } 841 842 /* 843 * If the caller has requested error information, allocate the error 844 * string now. 845 */ 846 if (errout != NULL) { 847 if (custr_alloc_buf(&s.s_errstr, errout->nje_message, 848 sizeof (errout->nje_message)) != 0) { 849 s.s_errno = errno; 850 (void) snprintf(errout->nje_message, 851 sizeof (errout->nje_message), 852 "custr alloc failure: %s", 853 strerror(errno)); 854 goto out; 855 } 856 custr_reset(s.s_errstr); 857 } 858 859 /* 860 * Allocate top-most stack frame: 861 */ 862 if ((s.s_top = calloc(1, sizeof (*s.s_top))) == NULL) { 863 s.s_errno = errno; 864 goto out; 865 } 866 867 s.s_top->pf_ps = PARSE_REST; 868 for (;;) { 869 if (s.s_top->pf_ps < 0) { 870 /* 871 * The parser reported an error. 872 */ 873 goto out; 874 } 875 876 if (s.s_top->pf_ps == PARSE_DONE) { 877 if (s.s_top->pf_next == NULL) { 878 /* 879 * Last frame, so we're really 880 * done. 881 */ 882 *nvlp = s.s_top->pf_nvl; 883 goto out; 884 } else { 885 /* 886 * Otherwise, pop a frame and continue in 887 * previous state. Copy out the value we 888 * created in the old frame: 889 */ 890 if (store_value(&s) != 0) { 891 goto out; 892 } 893 894 /* 895 * Free old frame: 896 */ 897 s.s_top = parse_frame_free(s.s_top, B_FALSE); 898 } 899 } 900 901 /* 902 * Dispatch to parser handler routine for this state: 903 */ 904 if (s.s_top->pf_ps >= NUM_PARSE_HANDLERS || 905 hdlrs[s.s_top->pf_ps] == NULL) { 906 (void) fprintf(stderr, "no handler for state %d\n", 907 s.s_top->pf_ps); 908 abort(); 909 } 910 hdlrs[s.s_top->pf_ps](&s); 911 } 912 913 out: 914 if (errout != NULL) { 915 /* 916 * Copy out error number and parse position. The custr_t for 917 * the error message was backed by the buffer in the error 918 * object, so no copying is required. 919 */ 920 errout->nje_errno = s.s_errno; 921 errout->nje_pos = s.s_pos; 922 } 923 924 /* 925 * Free resources: 926 */ 927 while (s.s_top != NULL) { 928 s.s_top = parse_frame_free(s.s_top, s.s_errno == 0 ? B_FALSE : 929 B_TRUE); 930 } 931 custr_free(s.s_collect); 932 custr_free(s.s_errstr); 933 934 errno = s.s_errno; 935 return (s.s_errno == 0 ? 0 : -1); 936 } 937