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