commit ef4c04671995054ba459d9c894eb94d51fac1cb2
parent c85cd9b72c57aedcaec989c8910a72ac3df46d32
Author: ssnf <ssnf@ssnf.xyz>
Date: Fri, 22 Aug 2025 13:09:34 +0000
json
Diffstat:
3 files changed, 196 insertions(+), 0 deletions(-)
diff --git a/include/json.h b/include/json.h
@@ -0,0 +1,34 @@
+AUTOLIB(json)
+
+typedef enum {
+ JNone,
+ JNum,
+ JStr = 1 << 1,
+ JObj = 1 << 2,
+ JErr = 1 << 3
+} JsonType;
+
+typedef union {
+ String s;
+ double n;
+ char c;
+} JsonVal;
+
+typedef struct {
+ String k;
+ JsonVal v;
+ JsonType t;
+} JsonObj;
+
+typedef struct {
+ ulong st[8]; /*obj stack*/
+ String s; /*data buffer*/
+ JsonObj* o; /*obj vector*/
+ JsonObj* cur; /*cur obj*/
+ ulong n; /*stack number*/
+ ulong pos; /*buffer pos*/
+} Json;
+
+void json_close(Json *j);
+int json_init(Json *j, char *file);
+JsonType json_next(Json *j, JsonType t);
diff --git a/src/libjson/json.c b/src/libjson/json.c
@@ -0,0 +1,154 @@
+#include <u.h>
+#include <libc.h>
+
+#include <bio.h>
+#include <str.h>
+#include <vec.h>
+#include <json.h>
+
+static JsonType
+err(Json *j, char *msg)
+{
+ ulong i, n;
+
+ if (!j->cur->k.s)
+ Strinit(&j->cur->k);
+ if (j->cur->t == JStr)
+ Strclose(&j->cur->v.s);
+ Strdup(&j->cur->k, Str(msg));
+ n = 1;
+ for (i = 0; i < j->pos; ++i)
+ if (j->s.s[i] == '\n')
+ ++n;
+ j->cur->v.n = n;
+ j->cur->t = JErr;
+ return JNone;
+}
+
+static void
+JObjclose(JsonObj *o)
+{
+ if (o->k.s)
+ Strclose(&o->k);
+ if (o->t == JStr)
+ Strclose(&o->v.s);
+}
+
+void
+json_close(Json *j)
+{
+ Strclose(&j->s);
+ Vecclose(&j->o);
+}
+
+int
+json_init(Json *j, char *file)
+{
+ int fd;
+
+ fd = 0;
+ memset(j, 0, sizeof(*j));
+ Strinit(&j->s);
+ if (file) {
+ fd = open(file, OREAD);
+ if (fd == -1)
+ return 0;
+ }
+ Strgetf(&j->s, fd);
+ Vecinitf(&j->o, nil, JObjclose);
+ close(fd);
+ return 1;
+}
+
+JsonType
+json_next(Json *j, JsonType t)
+{
+ ulong i;
+ char c, *p, *q;
+
+ if (j->cur && j->cur->t == JErr)
+ return JNone;
+next:
+ if (j->pos == j->s.n)
+ return JNone;
+ j->cur = Vecadd(&j->o);
+loop:
+ for (;j->pos < j->s.n && isspace(j->s.s[j->pos]); ++j->pos);
+ c = j->s.s[j->pos++];
+ switch (c) {
+ case '{':
+ case '[':
+ if (j->cur->t != JNone)
+ return err(j, "double value");
+ if (j->n + 1 >= nelem(j->st))
+ return err(j, "Stack too big!"
+ " Fix your damn data");
+ j->st[j->n++] = j->cur - j->o;
+ j->cur->v.c = c;
+ j->cur->t = JObj;
+ break;
+ case ']':
+ case '}':
+ if (!j->n)
+ return err(j, "bad stack");
+ --j->n;
+ case ',':
+ if (j->cur->k.s && j->cur->t == JNone)
+ return err(j, "missing value");
+ if (j->cur->t == JNone)
+ goto loop;
+ break;
+ case '"':
+ if (j->cur->t != JNone)
+ return err(j, "double value");
+ for (i = j->pos; i < j->s.n; ++i) {
+ c = j->s.s[i];
+ if (c == '\n')
+ return err(j, "invalid value");
+ if (c == '"')
+ break;
+ if (c != '\\')
+ continue;
+ /* there is no escape in Ba Sing Se */
+ c = j->s.s[i + 1];
+ if (c == '\\' || c == '"')
+ ++i;
+ }
+ Strinit(&j->cur->v.s);
+ Stradds(&j->cur->v.s
+ , Strn(j->s.s + j->pos, i - j->pos));
+ j->pos = i + 1;
+ j->cur->t = JStr;
+ goto loop;
+ case ':':
+ if (j->cur->k.s)
+ return err(j, "double key");
+ j->cur->k = j->cur->v.s;
+ memset(&j->cur->v, 0, sizeof(j->cur->v));
+ j->cur->t = JNone;
+ goto loop;
+ default:
+ if (--j->pos == j->s.n)
+ break;
+ if (j->cur->t != JNone)
+ return err(j, "double value");
+ p = j->s.s + j->pos;
+ j->cur->v.n = strtod(p, &q);
+ if (p != q) {
+ j->pos += q - p;
+ j->cur->t = JNum;
+ goto loop;
+ }
+ i = strcspn(p, "{[:,]} \n\r\t");
+ Strinit(&j->cur->v.s);
+ Stradds(&j->cur->v.s, Strn(p, i));
+ j->pos += i;
+ j->cur->t = JStr;
+ goto loop;
+ }
+ if (t == JNone || (t & j->cur->t))
+ return j->cur->t;
+ if (j->cur->t == JObj)
+ for (i = j->n - 1; json_next(j, 0) && j->n != i;);
+ goto next;
+}
diff --git a/src/libjson/mkfile b/src/libjson/mkfile
@@ -0,0 +1,8 @@
+<$PLAN9/src/mkhdr
+
+LIB=libjson.a
+
+OFILES=json.$O
+HFILES= $PLAN9/include/json.h
+
+<$PLAN9/src/mksyslib