#include #include #include static bool append_printf(char **dest, int64_t *size, int64_t *index, const char *fmt, ...) { va_list ap; int64_t len; va_start(ap, fmt); len = vsnprintf(*dest + *index, *size - *index, fmt, ap); va_end(ap); if (*index + len >= *size) { *size = *size * 2 > *size + len + 1 ? *size * 2 : *size + len + 1; *dest = realloc(*dest, *size); va_start(ap, fmt); len = vsnprintf(*dest + *index, *size - *index, fmt, ap); va_end(ap); } // TODO: Fix this ugly cast if (len < 0 || len >= *size) { free(*dest); *dest = ""; return false; } *index += len; return true; } void print_item(struct json *json, char **str, int64_t *size, int64_t *index) { switch (json->type) { case JSON_OBJECT: append_printf(str, size, index, "{"); for (struct json *j = json->children->items[0]; j; j = j->next) { append_printf(str, size, index, "\"%s\":", j->key ? j->key : "(null)"); print_item(j, str, size, index); if (j->next) append_printf(str, size, index, ","); } append_printf(str, size, index, "}"); break; case JSON_ARRAY: append_printf(str, size, index, "["); for (size_t i = 0; i < json->children->nitems; i++) { struct json *j = json->children->items[i]; print_item(j, str, size, index); if (i != json->children->nitems - 1) append_printf(str, size, index, ","); } append_printf(str, size, index, "]"); break; case JSON_NUMBER: append_printf(str, size, index, "%lf", json->num); break; case JSON_TRUE: append_printf(str, size, index, "true"); break; case JSON_FALSE: append_printf(str, size, index, "false"); break; case JSON_NULL: append_printf(str, size, index, "null"); break; case JSON_STRING: append_printf(str, size, index, "\""); for (char *ptr = json->string; *ptr != '\0'; ptr++) { switch (*ptr) { case '\\': append_printf(str, size, index, "%s", "\\\\"); break; case '\"': append_printf(str, size, index, "%s", "\\\""); break; case '\n': append_printf(str, size, index, "%s", "\\n"); break; case '\f': append_printf(str, size, index, "%s", "\\f"); break; case '\b': append_printf(str, size, index, "%s", "\\b"); break; case '\r': append_printf(str, size, index, "%s", "\\r"); break; case '\t': append_printf(str, size, index, "%s", "\\t"); break; default: append_printf(str, size, index, "%c", *ptr); break; } } append_printf(str, size, index, "\""); break; case JSON_INVALID: break; } } char *json_print(struct json *json) { int64_t size = 1024; int64_t index = 0; char *str = calloc(size, sizeof(char)); print_item(json, &str, &size, &index); return str; }