diff options
author | sanine <sanine.not@pm.me> | 2023-02-07 19:47:49 -0600 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-02-07 19:47:49 -0600 |
commit | 7743fd1feb81e1659584491ca88d50bd629cccef (patch) | |
tree | b114899c8dc8b32c740cb530e0002a228156b6c8 | |
parent | 79f4b0d33cbb490f957d081bd7c8bc97bd4c689c (diff) |
add KAI_FILL_ARRAY_FROM_TAGS
-rw-r--r-- | src/util/util.h | 49 | ||||
-rw-r--r-- | src/util/util.test.c | 102 |
2 files changed, 151 insertions, 0 deletions
diff --git a/src/util/util.h b/src/util/util.h index 67d3922..71cae4e 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -2,6 +2,7 @@ #define KALMIA_UTIL_H #include <kalmia.h> +#include "xml/xml.h" /** @brief add a new element to an array @@ -39,4 +40,52 @@ size_t kai_text_to_uints(unsigned int *dest, const char *str, size_t count); void *kai_alloc(size_t size, const char *purpose); + +#define KAI_FOR_CHILD_OF_TYPE(parent, child, type) \ +for ( \ + child = kai_tag_get_first_child_with_type(parent, type); \ + child != NULL; \ + child = kai_tag_get_next_sibling_with_type(child, type) \ +) + + +#define KAI_FILL_ARRAY_FROM_TAGS(result, dest, count, type, parent, tag_type, read, release) \ +do { \ + unsigned int count_internal = 0; \ + bool error = false; \ + struct kai_tag_t *tag_internal; \ + KAI_FOR_CHILD_OF_TYPE(parent, tag_internal, tag_type) { \ + count_internal += 1; \ + } \ + \ + if (count_internal == 0) { \ + dest = NULL; \ + } \ + else { \ + dest = malloc(count_internal * sizeof(type)); \ + int i = 0; \ + KAI_FOR_CHILD_OF_TYPE(parent, tag_internal, tag_type) { \ + if (error) break; \ + int result_internal = read(dest + i, tag_internal); \ + if (result_internal != 0) { \ + int j; \ + for (j=0; j<i; j++) { \ + release(dest[i]); \ + } \ + free(dest); \ + dest = NULL; \ + result = -1; \ + count = 0; \ + error = true; \ + } \ + i += 1; \ + } \ + } \ + \ + if (!error) { \ + result = 0; \ + count = count_internal; \ + } \ +} while (0) + #endif diff --git a/src/util/util.test.c b/src/util/util.test.c index 6288039..53bb8b2 100644 --- a/src/util/util.test.c +++ b/src/util/util.test.c @@ -127,6 +127,108 @@ LILY_TEST("convert string to int array with fewer conversions than expected") +int f_read_int(int *dest, struct kai_tag_t *src) +{ + long num = kai_tag_attr_to_long(src, "num", -1); + if (num == -1) { return -1; } + *dest = num; + return 0; +} + +int release_calls; +void f_release_int(int i) { release_calls += 1; } + + +LILY_TEST("KAI_FILL_ARRAY_FROM_TAGS produces NULL when no tags are found") +{ + int result, count; + int *buf; + release_calls = 0; + + struct kai_tag_t *t = kai_parse_string( + "<tag>" + " <xxx />" + " <yyy />" + " <zzz />" + "</tag>" + ); + + KAI_FILL_ARRAY_FROM_TAGS(result, buf, count, int, t, "num", f_read_int, f_release_int); + kai_tag_destroy(t); + + CHECK_EQ(result, 0, "%d"); + CHECK_EQ(release_calls, 0, "%d"); + CHECK_EQ(buf, NULL, "%p"); + CHECK_EQ(count, 0, "%d"); +} +#include LILY_PUSH_TEST() + + +LILY_TEST("KAI_FILL_ARRAY_FROM_TAGS properly fills array") +{ + int result, count; + int *buf; + release_calls = 0; + + struct kai_tag_t *t = kai_parse_string( + "<tag>" + " <xxx />" + " <num num=\"5\" />" + " <yyy />" + " <num num=\"4\" />" + " <num num=\"3\" />" + " <zzz />" + " <num num=\"2\" />" + "</tag>" + ); + + KAI_FILL_ARRAY_FROM_TAGS(result, buf, count, int, t, "num", f_read_int, f_release_int); + kai_tag_destroy(t); + + REQUIRE_EQ(result, 0, "%d"); + CHECK_EQ(release_calls, 0, "%d"); + REQUIRE_EQ(count, 4, "%d"); + CHECK_EQ(buf[0], 5, "%d"); + CHECK_EQ(buf[1], 4, "%d"); + CHECK_EQ(buf[2], 3, "%d"); + CHECK_EQ(buf[3], 2, "%d"); + + free(buf); +} +#include LILY_PUSH_TEST() + + + +LILY_TEST("KAI_FILL_ARRAY_FROM_TAGS properly releases on error") +{ + int result, count; + int *buf; + release_calls = 0; + + struct kai_tag_t *t = kai_parse_string( + "<tag>" + " <xxx />" + " <num num=\"5\" />" + " <yyy />" + " <num num=\"4\" />" + " <num nm=\"3\" />" + " <zzz />" + " <num num=\"2\" />" + "</tag>" + ); + + KAI_FILL_ARRAY_FROM_TAGS(result, buf, count, int, t, "num", f_read_int, f_release_int); + kai_tag_destroy(t); + + CHECK_EQ(result, -1, "%d"); + CHECK_EQ(release_calls, 2, "%d"); + CHECK_EQ(count, 0, "%d"); + CHECK_EQ(buf, NULL, "%p"); +} +#include LILY_PUSH_TEST() + + + #define LILY_FILE_END #include LILY_REGISTER_TESTS() |