void write_info_helper(std::basic_ostream<typename Ptree::char_type> &stream, const Ptree &pt, int indent) { // Character type typedef typename Ptree::char_type Ch; // Write data if (indent >= 0) { if (!pt.data().empty()) { std::basic_string<Ch> data = create_escapes(pt.template get_own<std::basic_string<Ch> >()); if (is_simple_data(data)) stream << Ch(' ') << data << Ch('\n'); else stream << Ch(' ') << Ch('\"') << data << Ch('\"') << Ch('\n'); } else if (pt.empty()) stream << Ch(' ') << Ch('\"') << Ch('\"') << Ch('\n'); else stream << Ch('\n'); } // Write keys if (!pt.empty()) { // Open brace if (indent >= 0) stream << std::basic_string<Ch>(4 * indent, Ch(' ')) << Ch('{') << Ch('\n'); // Write keys typename Ptree::const_iterator it = pt.begin(); for (; it != pt.end(); ++it) { // Output key std::basic_string<Ch> key = create_escapes(it->first); stream << std::basic_string<Ch>(4 * (indent + 1), Ch(' ')); if (is_simple_key(key)) stream << key; else stream << Ch('\"') << key << Ch('\"'); // Output data and children write_info_helper(stream, it->second, indent + 1); } // Close brace if (indent >= 0) stream << std::basic_string<Ch>(4 * indent, Ch(' ')) << Ch('}') << Ch('\n'); } }
/* * Encode "val" into "gap". * Return FAIL or OK. */ static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) { char_u numbuf[NUMBUFLEN]; char_u *res; list_T *l; dict_T *d; switch (val->v_type) { case VAR_SPECIAL: switch (val->vval.v_number) { case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; case VVAL_NONE: if ((options & JSON_JS) != 0 && (options & JSON_NO_NONE) == 0) /* empty item */ break; /* FALLTHROUGH */ case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; } break; case VAR_NUMBER: vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld", (long long)val->vval.v_number); ga_concat(gap, numbuf); break; case VAR_STRING: res = val->vval.v_string; write_string(gap, res); break; case VAR_FUNC: case VAR_PARTIAL: case VAR_JOB: case VAR_CHANNEL: /* no JSON equivalent TODO: better error */ EMSG(_(e_invarg)); return FAIL; case VAR_LIST: l = val->vval.v_list; if (l == NULL) ga_concat(gap, (char_u *)"[]"); else { if (l->lv_copyID == copyID) ga_concat(gap, (char_u *)"[]"); else { listitem_T *li; l->lv_copyID = copyID; ga_append(gap, '['); for (li = l->lv_first; li != NULL && !got_int; ) { if (json_encode_item(gap, &li->li_tv, copyID, options & JSON_JS) == FAIL) return FAIL; if ((options & JSON_JS) && li->li_next == NULL && li->li_tv.v_type == VAR_SPECIAL && li->li_tv.vval.v_number == VVAL_NONE) /* add an extra comma if the last item is v:none */ ga_append(gap, ','); li = li->li_next; if (li != NULL) ga_append(gap, ','); } ga_append(gap, ']'); l->lv_copyID = 0; } } break; case VAR_DICT: d = val->vval.v_dict; if (d == NULL) ga_concat(gap, (char_u *)"{}"); else { if (d->dv_copyID == copyID) ga_concat(gap, (char_u *)"{}"); else { int first = TRUE; int todo = (int)d->dv_hashtab.ht_used; hashitem_T *hi; d->dv_copyID = copyID; ga_append(gap, '{'); for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) if (!HASHITEM_EMPTY(hi)) { --todo; if (first) first = FALSE; else ga_append(gap, ','); if ((options & JSON_JS) && is_simple_key(hi->hi_key)) ga_concat(gap, hi->hi_key); else write_string(gap, hi->hi_key); ga_append(gap, ':'); if (json_encode_item(gap, &dict_lookup(hi)->di_tv, copyID, options | JSON_NO_NONE) == FAIL) return FAIL; } ga_append(gap, '}'); d->dv_copyID = 0; } } break; case VAR_FLOAT: #ifdef FEAT_FLOAT # if defined(HAVE_MATH_H) if (isnan(val->vval.v_float)) ga_concat(gap, (char_u *)"NaN"); else if (isinf(val->vval.v_float)) ga_concat(gap, (char_u *)"Infinity"); else # endif { vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float); ga_concat(gap, numbuf); } break; #endif case VAR_UNKNOWN: internal_error("json_encode_item()"); return FAIL; } return OK; }