JSON Minify — C source
Remove all whitespace from JSON for the most compact serialization. Validates as it minifies, runs entirely in your browser, with a shareable link to your exact input.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* json-minify — compact JSON to its smallest valid form. C99 port (canonical
* TS: src/lib/json-minify.ts; Go twin: cli/json-minify). No stdlib JSON
* codec, so — like the Rust port — this is a hand-rolled RFC 8259 scanner:
* validate, copy tokens verbatim, drop only whitespace; invalid JSON -> 0. */
#include <stdio.h>
#include <string.h>
typedef struct { const char *in; char *out; } sc; /* read cursor / write head */
static void skip_ws(sc *p) { while (*p->in==' '||*p->in=='\t'||*p->in=='\n'||*p->in=='\r') p->in++; }
static void put(sc *p, char c) { *p->out++ = c; }
static int digits(sc *p) { int n = 0; while (*p->in >= '0' && *p->in <= '9') { put(p, *p->in++); n++; } return n; }
/* Strings copy verbatim while escapes are validated (\u takes 4 hex digits);
* control chars are rejected — NUL counts, so EOF cannot leak into the output. */
static int str_(sc *p) {
put(p, *p->in++); /* opening quote */
for (;;) {
char c = *p->in++;
if (c == '"') { put(p, c); return 1; }
if (c == '\\') {
char e = *p->in++;
put(p, e);
if (e == 'u') { for (int k = 0; k < 4; k++) { char h = *p->in++; if (h=='\0'||!strchr("0123456789abcdefABCDEF",h)) return 0; put(p,h); } }
else if (e == '\0' || !strchr("\"\\/bfnrt", e)) return 0;
} else if ((unsigned char)c < 0x20) return 0; /* control char / EOF */
else put(p, c);
}
}
/* Numbers are grammar-checked and copied verbatim — no float round-trip. */
static int number(sc *p) {
if (*p->in == '-') put(p, *p->in++);
if (*p->in == '0') put(p, *p->in++); /* "01" is rejected by the caller */
else if (*p->in >= '1' && *p->in <= '9') { put(p, *p->in++); digits(p); }
else return 0;
if (*p->in == '.') { put(p, *p->in++); if (!digits(p)) return 0; }
if (*p->in=='e'||*p->in=='E') { put(p,*p->in++); if (*p->in=='+'||*p->in=='-') put(p,*p->in++); if (!digits(p)) return 0; }
return 1;
}
static int literal(sc *p, const char *w) {
size_t n = strlen(w);
if (strncmp(p->in, w, n) != 0) return 0;
memcpy(p->out, w, n); p->out += n; p->in += n;
return 1;
}
/* Objects and arrays share one loop: ',' continues, the matching bracket
* closes; object elements are "key": value pairs. */
static int value(sc *p) {
skip_ws(p);
if (*p->in == '{' || *p->in == '[') {
char close = *p->in == '{' ? '}' : ']';
put(p, *p->in++); skip_ws(p);
if (*p->in == close) { put(p, *p->in++); return 1; } /* {} / [] */
for (;;) {
if (close == '}') { skip_ws(p); if (*p->in != '"' || !str_(p)) return 0; skip_ws(p); if (*p->in++ != ':') return 0; put(p, ':'); }
if (!value(p)) return 0;
skip_ws(p);
char c = *p->in++;
if (c == ',') { put(p, c); continue; }
if (c == close) { put(p, c); return 1; }
return 0;
}
}
if (*p->in == '"') return str_(p);
if (*p->in=='t'||*p->in=='f'||*p->in=='n') return literal(p, *p->in=='t'?"true":*p->in=='f'?"false":"null");
return (*p->in=='-'||(*p->in>='0'&&*p->in<='9')) ? number(p) : 0;
}
/* Compact JSON serialization of input, or 0 for invalid JSON; out must hold
* strlen(input)+1 bytes — the compact form is never longer than the input. */
int minify_json(const char *input, char *out) {
sc p = { input, out };
if (!value(&p)) return 0;
skip_ws(&p);
if (*p.in != '\0') return 0; /* one top-level value, then whitespace only */
*p.out = '\0';
return 1;
}
int main(void) {
char buf[128];
if (!minify_json("{\n \"a\": 1,\n \"b\": [\n 1,\n 2\n ]\n}", buf)) return 1;
puts(buf); /* {"a":1,"b":[1,2]} — and minify_json("{invalid}") returns 0 */
return 0;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →