ucx/json.c

branch
dav-2
changeset 889
42cdbf9bbd49
parent 886
da79af4baec8
--- a/ucx/json.c	Tue Oct 14 21:02:26 2025 +0200
+++ b/ucx/json.c	Sat Nov 08 23:06:11 2025 +0100
@@ -32,6 +32,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <inttypes.h>
+#include <ctype.h>
 
 /*
  * RFC 8259
@@ -127,16 +128,6 @@
     }
 }
 
-static bool json_isdigit(char c) {
-    // TODO: remove once UCX has public API for this
-    return c >= '0' && c <= '9';
-}
-
-static bool json_isspace(char c) {
-    // TODO: remove once UCX has public API for this
-    return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
-}
-
 static int num_isexp(const char *content, size_t length, size_t pos) {
     if (pos >= length) {
         return 0;
@@ -145,7 +136,7 @@
     int ok = 0;
     for (size_t i = pos; i < length; i++) {
         char c = content[i];
-        if (json_isdigit(c)) {
+        if (isdigit((unsigned char)c)) {
             ok = 1;
         } else if (i == pos) {
             if (!(c == '+' || c == '-')) {
@@ -162,7 +153,7 @@
 static CxJsonTokenType token_numbertype(const char *content, size_t length) {
     if (length == 0) return CX_JSON_TOKEN_ERROR;
 
-    if (content[0] != '-' && !json_isdigit(content[0])) {
+    if (content[0] != '-' && !isdigit((unsigned char)content[0])) {
         return CX_JSON_TOKEN_ERROR;
     }
 
@@ -175,7 +166,7 @@
             type = CX_JSON_TOKEN_NUMBER;
         } else if (content[i] == 'e' || content[i] == 'E') {
             return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR;
-        } else if (!json_isdigit(content[i])) {
+        } else if (!isdigit((unsigned char)content[i])) {
             return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep
         }
     }
@@ -239,7 +230,7 @@
             return CX_JSON_TOKEN_STRING;
         }
         default: {
-            if (json_isspace(c)) {
+            if (isspace((unsigned char)c)) {
                 return CX_JSON_TOKEN_SPACE;
             }
         }
@@ -639,6 +630,12 @@
     }
 }
 
+void cxJsonReset(CxJson *json) {
+    const CxAllocator *allocator = json->allocator;
+    cxJsonDestroy(json);
+    cxJsonInit(json, allocator);
+}
+
 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
     if (cxBufferEof(&json->buffer)) {
         // reinitialize the buffer
@@ -1135,10 +1132,39 @@
     return ret;
 }
 
+char *cxJsonAsString(const CxJsonValue *value) {
+    return value->value.string.ptr;
+}
+
+cxstring cxJsonAsCxString(const CxJsonValue *value) {
+    return cx_strcast(value->value.string);
+}
+
+cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
+    return value->value.string;
+}
+
+double cxJsonAsDouble(const CxJsonValue *value) {
+    if (value->type == CX_JSON_INTEGER) {
+        return (double) value->value.integer;
+    } else {
+        return value->value.number;
+    }
+}
+
+int64_t cxJsonAsInteger(const CxJsonValue *value) {
+    if (value->type == CX_JSON_INTEGER) {
+        return value->value.integer;
+    } else {
+        return (int64_t) value->value.number;
+    }
+}
+
 CxIterator cxJsonArrIter(const CxJsonValue *value) {
     return cxIteratorPtr(
         value->value.array.array,
-        value->value.array.array_size
+        value->value.array.array_size,
+        true // arrays need to keep order
     );
 }
 
@@ -1146,11 +1172,12 @@
     return cxIterator(
         value->value.object.values,
         sizeof(CxJsonObjValue),
-        value->value.object.values_size
+        value->value.object.values_size,
+        true // TODO: objects do not always need to keep order
     );
 }
 
-CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) {
+CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
     size_t index = json_find_objvalue(value, name);
     if (index >= value->value.object.values_size) {
         return &cx_json_value_nothing;
@@ -1159,14 +1186,14 @@
     }
 }
 
-CxJsonValue *cx_json_obj_remove_cxstr(CxJsonValue *value, cxstring name) {
+CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
     size_t index = json_find_objvalue(value, name);
     if (index >= value->value.object.values_size) {
         return NULL;
     } else {
         CxJsonObjValue kv = value->value.object.values[index];
         cx_strfree_a(value->allocator, &kv.name);
-        // TODO: replace with cx_array_remove()
+        // TODO: replace with cx_array_remove() / cx_array_remove_fast()
         value->value.object.values_size--;
         memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
         return kv.value;

mercurial