#include "json.h" #include #include #include #include #include "util.h" static void put(Json *j, const char *s, size_t n) { if (j->len + n + 1 > j->cap) { size_t c = j->cap ? j->cap : 4096; while (c < j->len + n + 1) c *= 2; j->buf = xrealloc(j->buf, c, 1); j->cap = c; } memcpy(j->buf + j->len, s, n); j->len += n; j->buf[j->len] = 0; } static void puts_(Json *j, const char *s) { put(j, s, strlen(s)); } /* virgule avant un élément si ce n'est pas le premier du conteneur courant */ static void sep(Json *j) { if (j->depth > 0 && j->need_comma[j->depth]) put(j, ",", 1); if (j->depth > 0) j->need_comma[j->depth] = 1; } void js_init(Json *j) { memset(j, 0, sizeof *j); } void js_free(Json *j) { free(j->buf); memset(j, 0, sizeof *j); } static void open_(Json *j, const char *c) { sep(j); puts_(j, c); if (j->depth >= 63) die("JSON trop profond"); j->depth++; j->need_comma[j->depth] = 0; } void js_obj(Json *j) { open_(j, "{"); } void js_arr(Json *j) { open_(j, "["); } void js_end_obj(Json *j) { j->depth--; puts_(j, "}"); } void js_end_arr(Json *j) { j->depth--; puts_(j, "]"); } static void quoted(Json *j, const char *s) { put(j, "\"", 1); for (const unsigned char *p = (const unsigned char *)s; *p; p++) { char e[8]; if (*p == '"' || *p == '\\') { e[0] = '\\'; e[1] = (char)*p; put(j, e, 2); } else if (*p < 0x20) { snprintf(e, sizeof e, "\\u%04x", *p); puts_(j, e); } else { put(j, (const char *)p, 1); } } put(j, "\"", 1); } void js_key(Json *j, const char *k) { sep(j); quoted(j, k); put(j, ":", 1); j->need_comma[j->depth] = 0; /* la valeur qui suit ne prend pas de virgule */ } void js_str(Json *j, const char *s) { sep(j); quoted(j, s); } void js_num(Json *j, double v, int decimals) { sep(j); if (!isfinite(v)) { puts_(j, "null"); return; } char b[64]; snprintf(b, sizeof b, "%.*f", decimals, v); /* pas de zéros inutiles : 12.50 → 12.5, 3.0 → 3 */ if (decimals > 0) { char *e = b + strlen(b) - 1; while (*e == '0') *e-- = 0; if (*e == '.') *e = 0; } if (strcmp(b, "-0") == 0) strcpy(b, "0"); puts_(j, b); } void js_int(Json *j, long long v) { sep(j); char b[32]; snprintf(b, sizeof b, "%lld", v); puts_(j, b); } void js_null(Json *j) { sep(j); puts_(j, "null"); } void js_save(Json *j, const char *path) { write_file_atomic(path, j->buf ? j->buf : "", j->len); }