shithub: rjson

Download patch

ref: c5dfca354a35575443084622a74de02ef3e6ea8e
author: sirjofri <sirjofri@sirjofri.de>
date: Sat Mar 7 18:27:14 EST 2026

adds files

--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+LIB=rjson.a$O
+OFILES= \
+	rjson.$O\
+
+</sys/src/cmd/mklib
\ No newline at end of file
--- /dev/null
+++ b/rjson.c
@@ -1,0 +1,144 @@
+#include <u.h>
+#include <libc.h>
+#include <json.h>
+#include "rjson.h"
+
+int
+rjsontostruct(JSON *json, Rjson *rjson, void *target)
+{
+	Rjson *rj;
+	JSON *j;
+	char **s;
+	double *n;
+	int *b;
+	char *o;
+	
+	if (!json) {
+		werrstr("invalid json");
+		return 0;
+	}
+	
+	if (!target) {
+		werrstr("invalid target struct");
+		return 0;
+	}
+	
+	if (!rjson) {
+		werrstr("invalid rjson");
+		return 0;
+	}
+	
+	for (rj = rjson; rj->name; rj++) {
+		j = jsonbyname(json, rj->name);
+		if (!j)
+			continue;
+		if (j->t != rj->type) {
+			werrstr("inconsistent type: %s is not %d\n", rj->name, rj->type);
+			return 0;
+		}
+		switch (j->t) {
+		case JSONNull:
+			/* skip null */
+			break;
+		case JSONBool:
+			b = (int*)((char*)target + rj->addr);
+			*b = !!j->n;
+			break;
+		case JSONNumber:
+			n = (double*)((char*)target + rj->addr);
+			*n = j->n;
+			break;
+		case JSONString:
+			s = (char**)((char*)target + rj->addr);
+			*s = strdup(j->s);
+			break;
+		case JSONArray: // TODO
+			break;
+		case JSONObject:
+			if (!rj->sub) {
+				werrstr("object %s without valid rjson", rj->name);
+				return 0;
+			}
+			o = (char*)target + rj->addr;
+			return rjsontostruct(j, rj->sub, o);
+			break;
+		}
+	}
+	return 1;
+}
+
+static void
+jappend(JSON *json, char *name, JSON *jn)
+{
+	JSONEl *jel;
+	
+	if (!json->first) {
+		jel = json->first = mallocz(sizeof(JSONEl), 1);
+	} else {
+		for (jel = json->first; jel->next; jel = jel->next)
+			;
+		jel->next = mallocz(sizeof(JSONEl), 1);
+		jel = jel->next;
+	}
+	assert(jel);
+	jel->name = strdup(name);
+	jel->val = jn;
+}
+
+JSON*
+rstructtojson(void *src, Rjson *rjson)
+{
+	JSON *json, *j;
+	Rjson *rj;
+	int *i;
+	double *n;
+	char **s;
+	char *o;
+	
+	if (!src) {
+		werrstr("invalid src");
+		return nil;
+	}
+	if (!rjson) {
+		werrstr("invalid rjson");
+		return nil;
+	}
+	
+	json = mallocz(sizeof(JSON), 1);
+	assert(json);
+	
+	json->t = JSONObject;
+	for (rj = rjson; rj->name; rj++) {
+		if (rj->type == JSONNull)
+			continue;
+		if (rj->type == JSONObject) {
+			o = (char*)src + rj->addr;
+			j = rstructtojson(o, rj->sub);
+			jappend(json, rj->name, j);
+			continue;
+		}
+		j = mallocz(sizeof(JSON), 1);
+		assert(j);
+		jappend(json, rj->name, j);
+		
+		j->t = rj->type;
+		switch (j->t) {
+		case JSONBool:
+			i = (int*)((char*)src + rj->addr);
+			j->n = *i;
+			break;
+		case JSONNumber:
+			n = (double*)((char*)src + rj->addr);
+			j->n = *n;
+			break;
+		case JSONString:
+			s = (char**)((char*)src + rj->addr);
+			j->s = strdup(*s);
+			break;
+		case JSONArray: // TODO
+			break;
+		}
+	}
+	
+	return json;
+}
--- /dev/null
+++ b/rjson.h
@@ -1,0 +1,17 @@
+#define RJSON_BEGIN(A) Rjson A[] = {
+#define RJSON_END() { 0, 0, nil }};
+#define RJSON_STRING(A, N) { offsetof(A, N), JSONString, "N", nil },
+#define RJSON_NUMBER(A, N) { offsetof(A, N), JSONNumber, "N", nil },
+#define RJSON_BOOL(A, N) { offsetof(A, N), JSONBool, "N", nil },
+#define RJSON_OBJECT(A, N, S) { offsetof(A, N), JSONObject, "N", S },
+
+typedef struct Rjson Rjson;
+struct Rjson {
+	int addr;
+	int type;
+	char *name;
+	Rjson *sub;
+};
+
+int rjsontostruct(JSON *json, Rjson*, void*);
+JSON *rstructtojson(void *src, Rjson*);
--- /dev/null
+++ b/test/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TEST=t
+LIB=../rjson.a$O
+
+</sys/src/cmd/mktest
--- /dev/null
+++ b/test/t.c
@@ -1,0 +1,88 @@
+#include <u.h>
+#include <libc.h>
+#include "json.h"
+#include "../rjson.h"
+
+typedef struct Sub Sub;
+struct Sub {
+	char *xyz;
+};
+
+RJSON_BEGIN(Sub_rjson)
+	RJSON_STRING(Sub,xyz)
+RJSON_END()
+
+typedef struct Test Test;
+struct Test {
+	char *one;
+	char *two;
+	double num;
+	int bool;
+	Sub obj;
+};
+
+RJSON_BEGIN(Test_rjson)
+	RJSON_STRING(Test,one)
+	RJSON_STRING(Test,two)
+	RJSON_NUMBER(Test,num)
+	RJSON_BOOL(Test,bool)
+	RJSON_OBJECT(Test,obj,Sub_rjson)
+RJSON_END()
+
+
+char *testjson = ""
+"{\n"
+"	\"one\": \"eins\",\n"
+"	\"two\": \"zwei\",\n"
+"	\"num\": 5.540000,\n"
+"	\"bool\": true,\n"
+"	\"obj\": {\n"
+"		\"xyz\": \"abc\"\n"
+"	}\n"
+"}\n";
+
+void
+main()
+{
+	Test t;
+	JSON *j;
+	char *s;
+	int verbose;
+	verbose = !!getenv("verbose");
+	
+	JSONfmtinstall();
+	
+	j = jsonparse(testjson);
+	if (!j)
+		sysfatal("%r");
+	
+	if (verbose) fprint(2, "=== Testing rjsontostruct\n");
+	if (rjsontostruct(j, Test_rjson, &t)) {
+		if (verbose) {
+			fprint(2, "parsed: %r\n");
+			fprint(2, "  one: %s\n", t.one);
+			fprint(2, "  two: %s\n", t.two);
+			fprint(2, "  num: %f\n", t.num);
+			fprint(2, " bool: %d\n", t.bool);
+			fprint(2, "     obj.xyz: %s\n", t.obj.xyz);
+		}
+	} else {
+		fprint(2, "parse failed: %r\n");
+	}
+	
+	jsonfree(j);
+	
+	if (verbose) fprint(2, "=== Testing rstructtojson\n");
+	j = rstructtojson(&t, Test_rjson);
+	if (!j)
+		sysfatal("err: %r");
+	if (verbose)
+		fprint(2, "%J\n", j);
+	
+	s = smprint("%J\n", j);
+	
+	if (strcmp(s, testjson) != 0)
+		exits("test failed");
+	
+	exits(nil);
+}
--