add support for UCX strings in cxPropertiesFill()

Sat, 02 Nov 2024 19:27:45 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 02 Nov 2024 19:27:45 +0100
changeset 972
a9a1d07a6840
parent 971
cc204fc56c9c
child 973
05910a8994f7

add support for UCX strings in cxPropertiesFill()

src/cx/properties.h file | annotate | diff | comparison | revisions
src/properties.c file | annotate | diff | comparison | revisions
tests/test_properties.c file | annotate | diff | comparison | revisions
--- a/src/cx/properties.h	Sat Nov 02 13:48:53 2024 +0100
+++ b/src/cx/properties.h	Sat Nov 02 19:27:45 2024 +0100
@@ -42,6 +42,7 @@
 #include "array_list.h"
 
 #include <stdio.h>
+#include <string.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -371,7 +372,13 @@
     cxPropertiesInit(prop, cx_properties_config_default)
 
 /**
- * Sets an input buffer.
+ * Fills the input buffer with data.
+ *
+ * Currently unprocessed data is copied to a temporary buffer.
+ * This temporary buffer is allocated on the heap, unless you specified
+ * a buffer on the stack with #cxPropertiesUseStack().
+ * In that case, the stack buffer is used, until the capacity is not sufficient
+ * anymore.
  *
  * After calling this function, you can parse the data by calling
  * cxPropertiesNext() until the status is #CX_PROPERTIES_NO_DATA.
@@ -379,18 +386,19 @@
  * @param prop the properties interface
  * @param buf a pointer to data
  * @param len the length of the data
+ * @return non-zero when a memory allocation was necessary but failed
  */
 __attribute__((__nonnull__))
-void cxPropertiesInput(
+int cxPropertiesFilln(
         CxProperties *prop,
         const char *buf,
         size_t len
 );
 
 /**
- * Sets a new input buffer after copying the current unprocessed data
- * to a temporary buffer.
+ * Fills the input buffer with a string.
  *
+ * Currently unprocessed data is copied to a temporary buffer.
  * This temporary buffer is allocated on the heap, unless you specified
  * a buffer on the stack with #cxPropertiesUseStack().
  * In that case, the stack buffer is used, until the capacity is not sufficient
@@ -400,16 +408,60 @@
  * copied, it behaves exactly as #cxPropertiesInput().
  *
  * @param prop the properties interface
- * @param buf a pointer to data
- * @param len the length of the data
+ * @param str the string
+ * @return non-zero when a memory allocation was necessary but failed
+ */
+#define cxPropertiesFill(prop, str) _Generic((str), \
+    cxstring: cx_properties_fill_cxstr,             \
+    cxmutstr: cx_properties_fill_mutstr,            \
+    char*: cx_properties_fill_str,                  \
+    const char*: cx_properties_fill_str)            \
+    (prop, str)
+
+/**
+ * Implementation of cxPropertiesFill() for cxstring.
+ *
+ * @param prop the properties interface
+ * @param str the string
  * @return non-zero when a memory allocation was necessary but failed
  */
 __attribute__((__nonnull__))
-int cxPropertiesFill(
+static inline int cx_properties_fill_cxstr(
+        CxProperties *prop,
+        cxstring str
+) {
+    return cxPropertiesFilln(prop, str.ptr, str.length);
+}
+
+/**
+ * Implementation of cxPropertiesFill() for cxmutstr.
+ *
+ * @param prop the properties interface
+ * @param str the string
+ * @return non-zero when a memory allocation was necessary but failed
+ */
+__attribute__((__nonnull__))
+static inline int cx_properties_fill_mutstr(
         CxProperties *prop,
-        const char *buf,
-        size_t len
-);
+        cxmutstr str
+) {
+    return cxPropertiesFilln(prop, str.ptr, str.length);
+}
+
+/**
+ * Implementation of cxPropertiesFill() for zero terminated C strings.
+ *
+ * @param prop the properties interface
+ * @param str the string
+ * @return non-zero when a memory allocation was necessary but failed
+ */
+__attribute__((__nonnull__))
+static inline int cx_properties_fill_str(
+        CxProperties *prop,
+        const char *str
+) {
+    return cxPropertiesFilln(prop, str, strlen(str));
+}
 
 /**
  * Specifies stack memory that shall be used by #cxPropertiesFill().
--- a/src/properties.c	Sat Nov 02 13:48:53 2024 +0100
+++ b/src/properties.c	Sat Nov 02 19:27:45 2024 +0100
@@ -28,7 +28,6 @@
 
 #include "cx/properties.h"
 
-#include <string.h>
 #include <assert.h>
 
 static const int CX_PROPERTIES_FLAG_USE_STACK = 0x01;
@@ -106,23 +105,15 @@
     return cx_properties_rescuen_input(prop, len);
 }
 
-void cxPropertiesInput(
-        CxProperties *prop,
-        const char *buf,
-        size_t len
-) {
-    prop->text = buf;
-    prop->text_size = len;
-    prop->text_pos = 0;
-}
-
-int cxPropertiesFill(
+int cxPropertiesFilln(
         CxProperties *prop,
         const char *buf,
         size_t len
 ) {
     if (cx_properties_rescue_input(prop)) return 1;
-    cxPropertiesInput(prop, buf, len);
+    prop->text = buf;
+    prop->text_size = len;
+    prop->text_pos = 0;
     return 0;
 }
 
@@ -429,7 +420,9 @@
         }
 
         // set the input buffer and read the k/v-pairs
-        cxPropertiesInput(prop, input.ptr, input.length);
+        prop->text = input.ptr;
+        prop->text_size = input.length;
+        prop->text_pos = 0;
 
         CxPropertiesStatus kv_status;
         do {
--- a/tests/test_properties.c	Sat Nov 02 13:48:53 2024 +0100
+++ b/tests/test_properties.c	Sat Nov 02 19:27:45 2024 +0100
@@ -96,7 +96,7 @@
     cxstring value;
     CX_TEST_DO {
         for (int i = 0; i < 10; i++) {
-            cxPropertiesInput(&prop, tests[i], strlen(tests[i]));
+            cxPropertiesFill(&prop, tests[i]);
             CX_TEST_ASSERT(prop.text == tests[i]);
             CX_TEST_ASSERT(prop.text_size == strlen(tests[i]));
             CX_TEST_ASSERT(prop.text_pos == 0);
@@ -115,29 +115,42 @@
     cxPropertiesDestroy(&prop);
 }
 
-CX_TEST(test_properties_next_multi) {
+CX_TEST_SUBROUTINE(test_properties_next_multi_check, CxProperties *prop) {
     const char *keys[] = {
-        "a",
-        "b",
-        "c",
-        "uap",
-        "name",
-        "key1",
-        "key2",
-        "key3"
+            "a",
+            "b",
+            "c",
+            "uap",
+            "name",
+            "key1",
+            "key2",
+            "key3"
     };
 
     const char *values[] = {
-        "a value",
-        "b value",
-        "core",
-        "core",
-        "ucx",
-        "value1",
-        "value2",
-        "value3"
+            "a value",
+            "b value",
+            "core",
+            "core",
+            "ucx",
+            "value1",
+            "value2",
+            "value3"
     };
+    CxPropertiesStatus result;
+    cxstring key;
+    cxstring value;
+    for (int i = 0; i < 8; i++) {
+        result = cxPropertiesNext(prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(!cx_strcmp(key, cx_str(keys[i])));
+        CX_TEST_ASSERT(!cx_strcmp(value, cx_str(values[i])));
+    }
+    result = cxPropertiesNext(prop, &key, &value);
+    CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+}
 
+CX_TEST(test_properties_next_multi) {
     const char *str = "#\n"
         "# properties\n"
         "# contains key/value pairs\n"
@@ -157,22 +170,25 @@
 
     CxProperties prop;
     cxPropertiesInitDefault(&prop);
-    CxPropertiesStatus result;
-    cxstring key;
-    cxstring value;
 
     CX_TEST_DO {
+        CxPropertiesStatus result;
+        cxstring key;
+        cxstring value;
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NULL_INPUT);
-        cxPropertiesInput(&prop, str, strlen(str));
-        for (int i = 0; i < 8; i++) {
-            result = cxPropertiesNext(&prop, &key, &value);
-            CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
-            CX_TEST_ASSERT(!cx_strcmp(key, cx_str(keys[i])));
-            CX_TEST_ASSERT(!cx_strcmp(value, cx_str(values[i])));
-        }
-        result = cxPropertiesNext(&prop, &key, &value);
-        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+
+        // check for C string
+        cxPropertiesFill(&prop, str);
+        CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
+
+        // check for cxstring
+        cxPropertiesFill(&prop, cx_str(str));
+        CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
+
+        // check for mutstr
+        cxPropertiesFill(&prop, cx_mutstr((char*)str));
+        CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
     }
     cxPropertiesDestroy(&prop);
 }
@@ -187,35 +203,35 @@
 
     CX_TEST_DO {
         str = "";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
 
         str = "  \n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
 
         str = "name";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "    ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         // call fill twice in a row
         str = "= ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         str = "value";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name")));
@@ -223,17 +239,17 @@
 
         // second round
         str = "#comment\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
 
         str = "#comment\nname2 = ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "value2\na = b\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name2")));
@@ -245,17 +261,17 @@
         CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("b")));
 
         str = "# comment\n#\n#\ntests = ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "test1 ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "test2 test3 test4\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("tests")));
@@ -263,17 +279,17 @@
 
         // test if cxPropertiesNext finds a name/value after a comment
         str = "# just a comment";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = " in 3";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = " parts\nx = 1\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key,  &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("x")));
@@ -305,41 +321,41 @@
     memset(long_value+1024, 'y', 1024);
 
     CX_TEST_DO {
-        cxPropertiesFill(&prop, long_key, 10);
+        cxPropertiesFilln(&prop, long_key, 10);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_key + 10, 202);
+        cxPropertiesFilln(&prop, long_key + 10, 202);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_key + 212, 200);
+        cxPropertiesFilln(&prop, long_key + 212, 200);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_key + 412, 100);
+        cxPropertiesFilln(&prop, long_key + 412, 100);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         const char *str = " = ";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_value, 512);
+        cxPropertiesFilln(&prop, long_value, 512);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_value + 512, 1024);
+        cxPropertiesFilln(&prop, long_value + 512, 1024);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
-        cxPropertiesFill(&prop, long_value + 1536, 512);
+        cxPropertiesFilln(&prop, long_value + 1536, 512);
         result = cxPropertiesNext(&prop, &key, &value);
         CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
 
         str = "\n#comment\nkey = value\n";
-        cxPropertiesFill(&prop, str, strlen(str));
+        cxPropertiesFill(&prop, str);
         result = cxPropertiesNext(&prop, &key, &value);
         cxstring k = cx_strn(long_key, key_len);
         cxstring v = cx_strn(long_value, value_len);

mercurial