Files
seedbox/firmware/test/json.c
Gee 2196633ed5
Some checks failed
check / check (push) Has been cancelled
Seedbox v0.1 + firmware, generic kit/synth, ROOT/SCALE pages
First commit of the repo. Contents beyond the v0.1 simulator and layout:

- Full Pico 2 W firmware (firmware/app, drivers, engine port, host test).
- BANK page and 404 mode A/B removed; learned pads play exactly what was learned.
- 404/MiniFreak renamed to KIT/SYNTH throughout (jacks, code, sim, docs,
  layout labels; wiring rebuilt).
- ROLL returns to page select after a re-roll; a freshly learned track turns on.
- LCD contrast 66.
- ROOT and SCALE pages: 21 scales, AUTO = the seed picks; global and sticky.

Intended music change: the scale table grew from 8 to 21 and AUTO picks from
all of them, so every seed's scale changed. Vectors regenerated with
npm run vectors, plus new key-override cases. Flash record is now version 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:39:36 +03:00

100 lines
3.0 KiB
C

#include "json.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char *p;
static int bad;
static void ws(void){ while(*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') p++; }
static void *xcalloc(size_t n, size_t s){ void *r = calloc(n, s); if(!r){ fprintf(stderr, "out of memory\n"); exit(2); } return r; }
static char *parse_str(void){
const char *s = ++p;
char *out, *o;
while(*p && *p != '"'){ if(*p == '\\' && p[1]) p++; p++; }
if(*p != '"'){ bad = 1; return NULL; }
out = o = xcalloc((size_t)(p - s) + 1, 1);
for(; s < p; s++){ if(*s == '\\') s++; *o++ = *s; }
p++;
return out;
}
static jval *parse_val(void);
static void add(jval *v, jval *item){
v->items = realloc(v->items, sizeof(jval *) * (size_t)(v->n + 1));
if(!v->items){ fprintf(stderr, "out of memory\n"); exit(2); }
v->items[v->n++] = item;
}
static jval *parse_val(void){
jval *v = xcalloc(1, sizeof *v);
ws();
if(*p == '{'){
v->type = J_OBJ; p++; ws();
if(*p == '}'){ p++; return v; }
for(;;){
char *k; jval *item;
ws(); if(*p != '"'){ bad = 1; return v; }
k = parse_str(); ws();
if(*p != ':'){ bad = 1; free(k); return v; }
p++;
item = parse_val(); item->key = k; add(v, item);
ws(); if(*p == ','){ p++; continue; }
if(*p == '}'){ p++; return v; }
bad = 1; return v;
}
}
if(*p == '['){
v->type = J_ARR; p++; ws();
if(*p == ']'){ p++; return v; }
for(;;){
add(v, parse_val());
ws(); if(*p == ','){ p++; continue; }
if(*p == ']'){ p++; return v; }
bad = 1; return v;
}
}
if(*p == '"'){ v->type = J_STR; v->str = parse_str(); return v; }
if(!strncmp(p, "true", 4)){ v->type = J_BOOL; v->num = 1; p += 4; return v; }
if(!strncmp(p, "false", 5)){ v->type = J_BOOL; v->num = 0; p += 5; return v; }
if(!strncmp(p, "null", 4)){ v->type = J_NULL; p += 4; return v; }
if(*p == '-' || (*p >= '0' && *p <= '9')){
char *end;
v->type = J_NUM; v->num = strtoll(p, &end, 10);
if(*end == '.' || *end == 'e' || *end == 'E') bad = 1; /* the vectors are integer-only */
p = end; return v;
}
bad = 1; return v;
}
jval *json_parse_file(const char *path){
FILE *f = fopen(path, "rb");
long n;
char *buf;
jval *v;
if(!f) return NULL;
fseek(f, 0, SEEK_END); n = ftell(f); fseek(f, 0, SEEK_SET);
buf = xcalloc((size_t)n + 1, 1);
if(fread(buf, 1, (size_t)n, f) != (size_t)n){ fclose(f); free(buf); return NULL; }
fclose(f);
p = buf; bad = 0;
v = parse_val();
ws();
if(*p) bad = 1;
free(buf);
if(bad){ json_free(v); return NULL; }
return v;
}
jval *json_get(const jval *o, const char *key){
int i;
if(!o || o->type != J_OBJ) return NULL;
for(i = 0; i < o->n; i++) if(!strcmp(o->items[i]->key, key)) return o->items[i];
return NULL;
}
jval *json_at(const jval *a, int i){ return (a && (a->type == J_ARR || a->type == J_OBJ) && i >= 0 && i < a->n) ? a->items[i] : NULL; }
void json_free(jval *v){
int i;
if(!v) return;
for(i = 0; i < v->n; i++) json_free(v->items[i]);
free(v->items); free(v->str); free(v->key); free(v);
}