static int json_append(bstr *b, const struct mpv_node *src, int indent) { switch (src->format) { case MPV_FORMAT_NONE: APPEND(b, "null"); return 0; case MPV_FORMAT_FLAG: APPEND(b, src->u.flag ? "true" : "false"); return 0; case MPV_FORMAT_INT64: bstr_xappend_asprintf(NULL, b, "%"PRId64, src->u.int64); return 0; case MPV_FORMAT_DOUBLE: bstr_xappend_asprintf(NULL, b, "%f", src->u.double_); return 0; case MPV_FORMAT_STRING: write_json_str(b, src->u.string); return 0; case MPV_FORMAT_NODE_ARRAY: case MPV_FORMAT_NODE_MAP: { struct mpv_node_list *list = src->u.list; bool is_obj = src->format == MPV_FORMAT_NODE_MAP; APPEND(b, is_obj ? "{" : "["); int next_indent = indent >= 0 ? indent + 1 : -1; for (int n = 0; n < list->num; n++) { if (n) APPEND(b, ","); add_indent(b, next_indent); if (is_obj) { write_json_str(b, list->keys[n]); APPEND(b, ":"); } json_append(b, &list->values[n], next_indent); } add_indent(b, indent); APPEND(b, is_obj ? "}" : "]"); return 0; } } return -1; // unknown format }
struct Token* advance_token(int res, struct Token* current, int indent, struct TokenState* state, char* text, int ID_t, int DD_t, struct cTokenError* error) { int numlines = 0; int cindent; int last = state->at; int ind = 0; struct Token* tmp; int i; for (i=state->at; i < state->at + res; i++) { if (text[i] == '\n') { numlines += 1; last = i; } } state->lineno += numlines; if (numlines) { state->charno = state->at + res - last; } else { state->charno += res; } if (!indent || res != 1 || text[state->at] != '\n') { return current; } ind = t_white(state->at+1, text, state->ln); if (ind < 0) { return current; } cindent = state->indents[state->num_indents-1]; if (ind > cindent) { add_indent(state, ind); tmp = (struct Token*)malloc(sizeof(struct Token)); tmp->value = ""; tmp->which = ID_t; tmp->next = NULL; tmp->lineno = state->lineno; tmp->charno = state->charno; current->next = tmp; current = tmp; } else if (ind < cindent) { while (ind < cindent) { state->num_indents -= 1; tmp = (struct Token*)malloc(sizeof(struct Token)); tmp->value = ""; tmp->which = DD_t; tmp->next = NULL; tmp->lineno = state->lineno; tmp->charno = state->charno; current->next = tmp; current = tmp; cindent = state->indents[state->num_indents - 1]; } if (ind != cindent) { // etxt = "invalid indentation -- %d (expected %d)' % (ind, cindent)"; error->text = "invalid indentation"; error->lineno = state->lineno; error->charno = state->charno; // error->wanted = cindent; return NULL; } } return current; }
int serialize_tree(struct kowhai_node_t** desc, void** data, char* target_buffer, size_t target_size, int level, void* get_name_param, kowhai_get_symbol_name_t get_name, int in_union, int* largest_data_field) { int target_offset = 0; struct kowhai_node_t* node; int i, chars; char* node_end_str; while (1) { node = *desc; if (node->type == KOW_BRANCH_END) return target_offset; // indent to current level using tabs chars = add_indent(&target_buffer, &target_size, &target_offset, level); if (chars < 0) return chars; // // write node // switch (node->type) { case KOW_BRANCH_START: case KOW_BRANCH_U_START: { int node_is_union = node->type == KOW_BRANCH_U_START; int largest_child_data_field = 0; void* initial_data = *data; // write header chars = add_header(&target_buffer, &target_size, &target_offset, node, get_name_param, get_name); if (chars < 0) return chars; if (node->count > 1) { struct kowhai_node_t* initial_node = *desc; // write array identifier chars = add_string(&target_buffer, &target_size, &target_offset, ", \""ARRAY"\": [\n"); if (chars < 0) return chars; for (i = 0; i < node->count; i++) { // set descriptor to initial node at the branch array *desc = initial_node; (*desc) += 1; // indent to current level using tab chars = add_indent(&target_buffer, &target_size, &target_offset, level + 1); if (chars < 0) return chars; // write branch children start chars = add_string(&target_buffer, &target_size, &target_offset, "[\n"); if (chars < 0) return chars; // write branch children chars = serialize_tree(desc, data, target_buffer, target_size, level + 1, get_name_param, get_name, node_is_union, &largest_child_data_field); if (chars < 0) return chars; target_offset += chars; target_buffer += chars; target_size -= chars; // increment data pointer if node is a union if (node_is_union) { *data = (char*)initial_data + largest_child_data_field; initial_data = *data; } // indent to current level using tab chars = add_indent(&target_buffer, &target_size, &target_offset, level + 1); if (chars < 0) return chars; // write branch children end chars = add_string(&target_buffer, &target_size, &target_offset, "]"); if (chars < 0) return chars; if (i < node->count - 1) { chars = add_string(&target_buffer, &target_size, &target_offset, ",\n"); if (chars < 0) return chars; } else { chars = add_string(&target_buffer, &target_size, &target_offset, "\n"); if (chars < 0) return chars; } } } else { // write children identifier chars = add_string(&target_buffer, &target_size, &target_offset, ", \""CHILDREN"\": [\n"); if (chars < 0) return chars; // write branch children (*desc) += 1; chars = serialize_tree(desc, data, target_buffer, target_size, level + 1, get_name_param, get_name, node_is_union, &largest_child_data_field); if (chars < 0) return chars; target_offset += chars; target_buffer += chars; target_size -= chars; // increment data pointer if node is a union if (node_is_union) *data = (char*)initial_data + largest_child_data_field; } // indent to current level using tab chars = add_indent(&target_buffer, &target_size, &target_offset, level); if (chars < 0) return chars; // write node end if (level == 0 || (*desc)[1].type == KOW_BRANCH_END) node_end_str = "]}\n"; else node_end_str = "]},\n"; chars = add_string(&target_buffer, &target_size, &target_offset, node_end_str); if (chars < 0) return chars; break; } default: { int value_size = kowhai_get_node_type_size(node->type); // write header chars = add_header(&target_buffer, &target_size, &target_offset, node, get_name_param, get_name); if (chars < 0) return chars; // write value identifier chars = add_string(&target_buffer, &target_size, &target_offset, ", \""VALUE"\": "); if (chars < 0) return chars; // write value/s if (node->type == KOW_CHAR && node->count > 1 && str_printable((char *)*data, node->count)) { // special string case chars = write_string(target_buffer, target_size, "\"%.*s\"", node->count, (char*)*data); if (chars >= 0) { target_buffer += chars; target_size -= chars; target_offset += chars; } else return chars; // increment data pointer if (!in_union) *data = (char*)*data + value_size * node->count; else if (value_size * node->count > *largest_data_field) *largest_data_field = value_size * node->count; } else if (node->count > 1) { // write start bracket chars = add_string(&target_buffer, &target_size, &target_offset, "["); if (chars < 0) return chars; for (i = 0; i < node->count; i++) { // write leaf node array item value chars = add_value(&target_buffer, &target_size, &target_offset, node->type, (char*)*data + i * value_size); if (chars < 0) return chars; // write comma if there is another array item if (i < node->count - 1) { chars = add_string(&target_buffer, &target_size, &target_offset, ", "); if (chars < 0) return chars; } } // increment data pointer if (!in_union) *data = (char*)*data + value_size * node->count; else if (value_size * node->count > *largest_data_field) *largest_data_field = value_size * node->count; // write end bracket chars = add_string(&target_buffer, &target_size, &target_offset, "]"); if (chars < 0) return chars; } else { // write leaf node value chars = add_value(&target_buffer, &target_size, &target_offset, node->type, *data); if (chars < 0) return chars; // increment data pointer if (!in_union) *data = (char*)*data + value_size; else if (value_size > *largest_data_field) *largest_data_field = value_size; } // write node end if (level == 0 || node[1].type == KOW_BRANCH_END) node_end_str = " }\n"; else node_end_str = " },\n"; chars = add_string(&target_buffer, &target_size, &target_offset, node_end_str); if (chars < 0) return chars; break; } } if (level == 0) return target_offset; (*desc) += 1; } }
/* * common worker for above two functions */ static char * JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent) { bool first = true; JsonbIterator *it; JsonbValue v; JsonbIteratorToken type = WJB_DONE; int level = 0; bool redo_switch = false; /* If we are indenting, don't add a space after a comma */ int ispaces = indent ? 1 : 2; /* * Don't indent the very first item. This gets set to the indent flag at * the bottom of the loop. */ bool use_indent = false; bool raw_scalar = false; bool last_was_key = false; if (out == NULL) out = makeStringInfo(); enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64); it = JsonbIteratorInit(in); while (redo_switch || ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)) { redo_switch = false; switch (type) { case WJB_BEGIN_ARRAY: if (!first) appendBinaryStringInfo(out, ", ", ispaces); if (!v.val.array.rawScalar) { add_indent(out, use_indent && !last_was_key, level); appendStringInfoCharMacro(out, '['); } else raw_scalar = true; first = true; level++; break; case WJB_BEGIN_OBJECT: if (!first) appendBinaryStringInfo(out, ", ", ispaces); add_indent(out, use_indent && !last_was_key, level); appendStringInfoCharMacro(out, '{'); first = true; level++; break; case WJB_KEY: if (!first) appendBinaryStringInfo(out, ", ", ispaces); first = true; add_indent(out, use_indent, level); /* json rules guarantee this is a string */ jsonb_put_escaped_value(out, &v); appendBinaryStringInfo(out, ": ", 2); type = JsonbIteratorNext(&it, &v, false); if (type == WJB_VALUE) { first = false; jsonb_put_escaped_value(out, &v); } else { Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY); /* * We need to rerun the current switch() since we need to * output the object which we just got from the iterator * before calling the iterator again. */ redo_switch = true; } break; case WJB_ELEM: if (!first) appendBinaryStringInfo(out, ", ", ispaces); first = false; if (!raw_scalar) add_indent(out, use_indent, level); jsonb_put_escaped_value(out, &v); break; case WJB_END_ARRAY: level--; if (!raw_scalar) { add_indent(out, use_indent, level); appendStringInfoCharMacro(out, ']'); } first = false; break; case WJB_END_OBJECT: level--; add_indent(out, use_indent, level); appendStringInfoCharMacro(out, '}'); first = false; break; default: elog(ERROR, "unknown jsonb iterator token type"); } use_indent = indent; last_was_key = redo_switch; } Assert(level == 0); return out->data; }
static char *add_desc(char *base, size_t *len, size_t *max, unsigned int indent, unsigned int width, const struct opt_table *opt) { size_t off, prefix, l; const char *p; bool same_line = false; base = add_str(base, len, max, opt->names); off = strlen(opt->names); if (opt->type == OPT_HASARG && !strchr(opt->names, ' ') && !strchr(opt->names, '=')) { base = add_str(base, len, max, " <arg>"); off += strlen(" <arg>"); } /* Do we start description on next line? */ if (off + 2 > indent) { base = add_str(base, len, max, "\n"); off = 0; } else { base = add_indent(base, len, max, indent - off); off = indent; same_line = true; } /* Indent description. */ p = opt->desc; while ((l = consume_words(p, width - indent, &prefix)) != 0) { if (!same_line) base = add_indent(base, len, max, indent); p += prefix; base = add_str_len(base, len, max, p, l); base = add_str(base, len, max, "\n"); off = indent + l; p += l; same_line = false; } /* Empty description? Make it match normal case. */ if (same_line) base = add_str(base, len, max, "\n"); if (opt->show) { char buf[OPT_SHOW_LEN + sizeof("...")]; strcpy(buf + OPT_SHOW_LEN, "..."); opt->show(buf, opt->u.arg); /* If it doesn't fit on this line, indent. */ if (off + strlen(" (default: ") + strlen(buf) + strlen(")") > width) { base = add_indent(base, len, max, indent); } else { /* Remove \n. */ (*len)--; } base = add_str(base, len, max, " (default: "); base = add_str(base, len, max, buf); base = add_str(base, len, max, ")\n"); } return base; }