ucx/json.c

branch
dav-2
changeset 894
e86049631677
parent 891
4d58cbcc9efa
--- a/ucx/json.c	Tue Dec 30 21:39:38 2025 +0100
+++ b/ucx/json.c	Wed Dec 31 16:41:16 2025 +0100
@@ -98,21 +98,21 @@
 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) {
     cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start);
     bool allocated = false;
-    if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) {
+    if (json->uncompleted_tokentype != CX_JSON_NO_TOKEN) {
         allocated = true;
-        str = cx_strcat_m(json->uncompleted.content, 1, str);
-        if (str.ptr == NULL) { // LCOV_EXCL_START
-            return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}};
-        } // LCOV_EXCL_STOP
+        str = cx_strcat(json->uncompleted_content, 1, str);
+        if (str.ptr == NULL) {
+            return (CxJsonToken){CX_JSON_NO_TOKEN, false, CX_NULLSTR}; // LCOV_EXCL_LINE
+        }
+        json->uncompleted_content = CX_NULLSTR;
+        json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
     }
-    json->uncompleted = (CxJsonToken){0};
     CxJsonTokenType ttype;
     if (isstring) {
         ttype = CX_JSON_TOKEN_STRING;
     } else {
-        cxstring s = cx_strcast(str);
-        if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false")
-            || !cx_strcmp(s, "null")) {
+        if (!cx_strcmp(str, "true") || !cx_strcmp(str, "false")
+            || !cx_strcmp(str, "null")) {
             ttype = CX_JSON_TOKEN_LITERAL;
         } else {
             ttype = token_numbertype(str.ptr, str.length);
@@ -122,7 +122,7 @@
         if (allocated) {
             cx_strfree(&str);
         }
-        return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, {NULL, 0}};
+        return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, CX_NULLSTR};
     }
     return (CxJsonToken){ttype, allocated, str};
 }
@@ -162,16 +162,16 @@
 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) {
     // check if there is data in the buffer
     if (cxBufferEof(&json->buffer)) {
-        return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ?
+        return json->uncompleted_tokentype == CX_JSON_NO_TOKEN ?
             CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA;
     }
 
     // current token type and start index
-    CxJsonTokenType ttype = json->uncompleted.tokentype;
+    CxJsonTokenType ttype = json->uncompleted_tokentype;
     size_t token_part_start = json->buffer.pos;
 
     bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING
-        && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\';
+        && cx_strat(json->uncompleted_content, -1) == '\\';
 
     for (size_t i = json->buffer.pos; i < json->buffer.size; i++) {
         char c = json->buffer.space[i];
@@ -189,7 +189,7 @@
                 } else if (ctype != CX_JSON_NO_TOKEN) {
                     // single-char token
                     json->buffer.pos = i + 1;
-                    *result = (CxJsonToken){ctype, false, {NULL, 0}};
+                    *result = (CxJsonToken){ctype, false, CX_NULLSTR};
                     return CX_JSON_NO_ERROR;
                 } else {
                     ttype = CX_JSON_TOKEN_LITERAL; // number or literal
@@ -232,31 +232,25 @@
         return CX_JSON_NO_DATA;
     } else {
         // uncompleted token
-        size_t uncompleted_len = json->buffer.size - token_part_start;
-        if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) {
-            // current token is uncompleted
-            // save current token content
-            CxJsonToken uncompleted = {
-                ttype, true,
-                cx_strdup(cx_strn(json->buffer.space + token_part_start, uncompleted_len))
-            };
-            if (uncompleted.content.ptr == NULL) {
+        cxstring uncompleted = cx_strn(json->buffer.space + token_part_start, json->buffer.size - token_part_start);
+        if (json->uncompleted_tokentype == CX_JSON_NO_TOKEN) {
+            assert(json->uncompleted_content.ptr == NULL);
+            json->uncompleted_content = cx_strdup(uncompleted);
+            if (json->uncompleted_content.ptr == NULL) {
                 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
             }
-            json->uncompleted = uncompleted;
+            json->uncompleted_tokentype = ttype;
         } else {
-            // previously we also had an uncompleted token
+            // previously we already had an uncompleted token
             // combine the uncompleted token with the current token
-            assert(json->uncompleted.allocated);
-            cxmutstr str = cx_strcat_m(json->uncompleted.content, 1,
-                cx_strn(json->buffer.space + token_part_start, uncompleted_len));
-            if (str.ptr == NULL) {
+            cxmutstr s = cx_strcat(json->uncompleted_content, 1, uncompleted);
+            if (s.ptr == NULL) {
                 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
             }
-            json->uncompleted.content = str;
+            json->uncompleted_content = s;
         }
         // advance the buffer position - we saved the stuff in the uncompleted token
-        json->buffer.pos += uncompleted_len;
+        json->buffer.pos += uncompleted.length;
         return CX_JSON_INCOMPLETE_DATA;
     }
 }
@@ -564,7 +558,8 @@
     }
     cxJsonValueFree(json->parsed);
     json->parsed = NULL;
-    token_destroy(&json->uncompleted);
+    json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
+    cx_strfree(&json->uncompleted_content);
     cx_strfree_a(json->allocator, &json->uncompleted_member_name);
 }
 
@@ -1226,7 +1221,7 @@
 
                 // the name
                 actual += wfunc("\"", 1, 1, target);
-                cxstring key = cx_strn(member->key->data, member->key->len);
+                cxstring key = cx_hash_key_as_string(member->key);
                 cxmutstr name = escape_string(key, settings->escape_slash);
                 actual += wfunc(name.ptr, 1, name.length, target);
                 actual += wfunc("\"", 1, 1, target);
@@ -1432,17 +1427,17 @@
     CxBuffer buffer;
     if (cxBufferInit(&buffer, allocator, NULL, 128,
                      CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) {
-        return (cxmutstr){NULL, 0};
+        return CX_NULLSTR; // LCOV_EXCL_LINE
     }
     if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0)
             || cxBufferTerminate(&buffer)) {
         // LCOV_EXCL_START
         buffer.flags &= ~CX_BUFFER_DO_NOT_FREE;
         cxBufferDestroy(&buffer);
-        return (cxmutstr){NULL, 0};
+        return CX_NULLSTR;
         // LCOV_EXCL_STOP
     } else {
-        cxmutstr str = cx_mutstrn(buffer.space, buffer.size);
+        cxmutstr str = cx_bstr_m(&buffer);
         cxBufferDestroy(&buffer);
         return str;
     }
@@ -1490,8 +1485,7 @@
             return cx_vcmp_double(json->number, cxJsonAsDouble(other));
         case CX_JSON_LITERAL:
             return json->literal == other->literal ? 0 : -1;
-        default:
-            // LCOV_EXCL_START
+        default: // LCOV_EXCL_START
             // unreachable
             assert(false);
             return -1;
@@ -1504,7 +1498,7 @@
 }
 
 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source,
-        const CxAllocator* allocator, cx_attr_unused void *data) {
+        const CxAllocator* allocator, CX_UNUSED void *data) {
     if (source == NULL || source->type == CX_JSON_NOTHING) {
         return &cx_json_value_nothing;
     }
@@ -1516,7 +1510,8 @@
             return ret; \
         } else { \
             *target = *ret; \
-            cxFree(allocator, ret); \
+            ret->type = CX_JSON_UNINITIALIZED; \
+            cxJsonValueFree(ret); \
             return target; \
         } \
     }
@@ -1540,8 +1535,7 @@
             arr->array.size = elem_count;
             for (size_t i = 0 ; i < elem_count ; i++) {
                 CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL);
-                if (e == NULL) {
-                    // LCOV_EXCL_START
+                if (e == NULL) { // LCOV_EXCL_START
                     cxJsonValueFree(arr);
                     return NULL;
                     // LCOV_EXCL_STOP
@@ -1558,8 +1552,7 @@
             return_value(cxJsonCreateNumber(allocator, source->number));
         case CX_JSON_LITERAL:
             return_value(cxJsonCreateLiteral(allocator, source->literal));
-        default:
-            // LCOV_EXCL_START
+        default: // LCOV_EXCL_START
             // unreachable
             assert(false);
             return NULL;

mercurial