We use "visited" to keep track of where we are while appending the JSON, since we are doing this without real recursion. 0: Seeing this first time. If it's an object or array, we will append the opening bracket as needed and then push its children. 1: We are done appending all children. Now we just need to append the closing bracket. 2: Only for objects. It means we still have t
| 554 | 0: success |
| 555 | */ |
| 556 | static int json_norm_to_string(DYNAMIC_STRING *buf, |
| 557 | struct json_norm_value *root) |
| 558 | { |
| 559 | DYNAMIC_ARRAY stack; |
| 560 | struct json_norm_frame frame, child_frame; |
| 561 | struct json_norm_value *val; |
| 562 | size_t i; |
| 563 | |
| 564 | if (json_norm_init_dynamic_array(sizeof(struct json_norm_frame), &stack)) |
| 565 | return 1; |
| 566 | |
| 567 | frame.val= root; |
| 568 | frame.index= 0; |
| 569 | frame.visited= UNPROCESSED; |
| 570 | |
| 571 | push_dynamic(&stack, &frame); |
| 572 | |
| 573 | do |
| 574 | { |
| 575 | frame= *(struct json_norm_frame *)pop_dynamic(&stack); |
| 576 | val= frame.val; |
| 577 | |
| 578 | if (!val) |
| 579 | continue; |
| 580 | |
| 581 | if (frame.visited == CLOSE_NON_SCALAR) |
| 582 | { |
| 583 | if (val->type == JSON_VALUE_OBJECT) |
| 584 | { |
| 585 | if (dynstr_append_mem(buf, STRING_WITH_LEN("}"))) |
| 586 | goto error; |
| 587 | } |
| 588 | else if (val->type == JSON_VALUE_ARRAY) |
| 589 | { |
| 590 | if (dynstr_append_mem(buf, STRING_WITH_LEN("]"))) |
| 591 | goto error; |
| 592 | } |
| 593 | continue; |
| 594 | } |
| 595 | else if (frame.visited == WRITE_KEY) |
| 596 | { |
| 597 | struct json_norm_object *obj= &val->value.object; |
| 598 | struct json_norm_kv *kv= |
| 599 | dynamic_element(&obj->kv_pairs, frame.index, struct json_norm_kv*); |
| 600 | |
| 601 | if (frame.index > 0 && dynstr_append_mem(buf, STRING_WITH_LEN(","))) |
| 602 | goto error; |
| 603 | |
| 604 | if (dynstr_append_mem(buf, STRING_WITH_LEN("\"")) || |
| 605 | dynstr_append(buf, kv->key.str) || |
| 606 | dynstr_append_mem(buf, STRING_WITH_LEN("\":"))) |
| 607 | goto error; |
| 608 | continue; |
| 609 | |
| 610 | } |
| 611 | else if (frame.visited == WRITE_ITEM_SEPARATOR) |
| 612 | { |
| 613 | if (frame.index > 0 && dynstr_append_mem(buf, STRING_WITH_LEN(","))) |
no test coverage detected