add allocator support to cxPropertiesLoad() - resolves #776

Mon, 08 Dec 2025 23:09:11 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 08 Dec 2025 23:09:11 +0100
changeset 1557
03fbf1c99e73
parent 1556
afdaa70034f8
child 1558
fc863c877a75

add allocator support to cxPropertiesLoad() - resolves #776

docs/Writerside/topics/properties.h.md file | annotate | diff | comparison | revisions
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/docs/Writerside/topics/properties.h.md	Sun Dec 07 19:36:51 2025 +0100
+++ b/docs/Writerside/topics/properties.h.md	Mon Dec 08 23:09:11 2025 +0100
@@ -66,9 +66,11 @@
         char *buf, size_t capacity);
 
 CxPropertiesStatus cxPropertiesLoad(CxPropertiesConfig config,
+        const CxAllocator *allocator,
         AnyStr filename, CxMap *target);
 
 CxPropertiesStatus cxPropertiesLoadDefault(
+        const CxAllocator *allocator,
         AnyStr filename, CxMap *target);
 ```
 
@@ -115,6 +117,7 @@
 which opens the file designated by the `filename` and loads all properties from that file into the specified `CxMap`.
 The convenience macro `cxPropertiesLoadDefault()` uses the default parser configuration for this.
 The target map must either store pointers of type `char*` or elements of type `cxmutstr`.
+In either case, the specified `allocator` is used to allocate the memory for the value. 
 
 > The stack buffers used by `cxPropertiesLoad()` can be changed when building UCX from sources
 > by setting the `CX_PROPERTIES_LOAD_FILL_SIZE` and `CX_PROPERTIES_LOAD_BUF_SIZE` macros
--- a/src/cx/properties.h	Sun Dec 07 19:36:51 2025 +0100
+++ b/src/cx/properties.h	Mon Dec 08 23:09:11 2025 +0100
@@ -340,13 +340,14 @@
  * Internal function - use cxPropertiesLoad() instead.
  *
  * @param config the parser config
+ * @param allocator the allocator for the values
  * @param filename the file name
  * @param target the target map
  * @return status code
  */
-cx_attr_nonnull
+cx_attr_nonnull_arg(4)
 CX_EXPORT CxPropertiesStatus cx_properties_load(CxPropertiesConfig config,
-        cxstring filename, CxMap *target);
+        const CxAllocator *allocator, cxstring filename, CxMap *target);
 
 /**
  * Loads properties from a file and inserts them into a map.
@@ -357,6 +358,7 @@
  * Any other configuration is not supported.
  *
  * @param config the parser config
+ * @param allocator the allocator for the values that will be stored in the map
  * @param filename (any string) the absolute or relative path to the file
  * @param target (@c CxMap*) the map where the properties shall be added
  * @retval CX_PROPERTIES_NO_ERROR (zero) at least one key/value pair was found
@@ -369,7 +371,8 @@
  * @retval CX_PROPERTIES_MAP_ERROR storing a key/value pair in the map failed
  * @see cxPropertiesLoadDefault()
  */
-#define cxPropertiesLoad(config, filename, target) cx_properties_load(config, cx_strcast(filename), target)
+#define cxPropertiesLoad(config, allocator, filename, target) \
+    cx_properties_load(config, allocator, cx_strcast(filename), target)
 
 /**
  * Loads properties from a file and inserts them into a map with a default config.
@@ -379,6 +382,7 @@
  * The map must either store pointers of type @c char*, or elements of type cxmutstr.
  * Any other configuration is not supported.
  *
+ * @param allocator the allocator for the values that will be stored in the map
  * @param filename (any string) the absolute or relative path to the file
  * @param target (@c CxMap*) the map where the properties shall be added
  * @retval CX_PROPERTIES_NO_ERROR (zero) at least one key/value pair was found
@@ -391,7 +395,8 @@
  * @retval CX_PROPERTIES_MAP_ERROR storing a key/value pair in the map failed
  * @see cxPropertiesLoad()
  */
-#define cxPropertiesLoadDefault(filename, target) cx_properties_load(cx_properties_config_default, cx_strcast(filename), target)
+#define cxPropertiesLoadDefault(allocator, filename, target) \
+    cx_properties_load(cx_properties_config_default, allocator, cx_strcast(filename), target)
 
 
 #ifdef __cplusplus
--- a/src/properties.c	Sun Dec 07 19:36:51 2025 +0100
+++ b/src/properties.c	Mon Dec 08 23:09:11 2025 +0100
@@ -253,7 +253,7 @@
 const unsigned cx_properties_load_buf_size = CX_PROPERTIES_LOAD_BUF_SIZE;
 
 CxPropertiesStatus cx_properties_load(CxPropertiesConfig config,
-        cxstring filename, CxMap *target) {
+        const CxAllocator *allocator, cxstring filename, CxMap *target) {
     // sanity check for the map
     const bool use_cstring = cxCollectionStoresPointers(target);
     if (!use_cstring && cxCollectionElementSize(target) != sizeof(cxmutstr)) {
@@ -302,7 +302,7 @@
             if (status != CX_PROPERTIES_NO_ERROR) {
                 break;
             } else {
-                cxmutstr v = cx_strdup(value);
+                cxmutstr v = cx_strdup_a(allocator, value);
                 if (v.ptr == NULL) {
                     status = CX_PROPERTIES_MAP_ERROR;
                     break;
--- a/tests/test_properties.c	Sun Dec 07 19:36:51 2025 +0100
+++ b/tests/test_properties.c	Mon Dec 08 23:09:11 2025 +0100
@@ -384,6 +384,8 @@
 }
 
 CX_TEST(test_properties_load) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
     char fname[16] = "ucxtestXXXXXX";
     int tmpfd = mkstemp(fname);
     FILE *f = tmpfd < 0 ? NULL : fdopen(tmpfd, "w");
@@ -412,8 +414,8 @@
 
         // we want to load the properties into a map of char* pointers
         CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
-        cxDefineDestructor(map, cxFreeDefault);
-        CxPropertiesStatus status = cxPropertiesLoadDefault(fname, map);
+        cxDefineAdvancedDestructor(map, cxFree, &talloc);
+        CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
 
         CX_TEST_ASSERT(status == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(cxMapSize(map) == 5);
@@ -440,8 +442,11 @@
 
         free(long_key);
         free(long_value);
+        CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
         cxMapFree(map);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
     }
+    cx_testing_allocator_destroy(&talloc);
     if (f) fclose(f);
     remove(fname);
 }

mercurial