From e68e6d4e433fe42a0c6df18b2f2d7990b91b7cd6 Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Sat, 10 Dec 2022 21:26:05 -0600
Subject: add basic float_array parsing

---
 include/kalmia.h             | 16 ++++++++--
 src/CMakeLists.txt           |  1 +
 src/geometry/CMakeLists.txt  |  7 +++++
 src/geometry/geometry.c      | 71 ++++++++++++++++++++++++++++++++++++++++++++
 src/geometry/geometry.h      | 20 +++++++++++++
 src/geometry/geometry.test.c | 49 ++++++++++++++++++++++++++++++
 src/test/test.h              |  2 ++
 7 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 src/geometry/CMakeLists.txt
 create mode 100644 src/geometry/geometry.c
 create mode 100644 src/geometry/geometry.h
 create mode 100644 src/geometry/geometry.test.c

diff --git a/include/kalmia.h b/include/kalmia.h
index 31aff1e..48a608f 100644
--- a/include/kalmia.h
+++ b/include/kalmia.h
@@ -45,7 +45,7 @@
 #ifndef KALMIA_H
 #define KALMIA_H
 
-#include <stddef.h>
+#include <stdlib.h>
 
 /* kalmia uses semantic versioning (semver.org) */
 #define KALMIA_VERSION_MAJOR 0
@@ -53,6 +53,16 @@
 #define KALMIA_VERSION_PATCH 0
 
 
+/* determine precision */
+#ifdef KALMIA_USE_DOUBLE
+typedef double ka_real_t;
+#define KA_STR_TO_REAL(nptr, end) strtod(nptr, end)
+#else
+typedef float ka_real_t;
+#define KA_STR_TO_REAL(nptr, end) strtof(nptr, end)
+#endif
+
+
 /* internal buffer size for strings/sids */
 #ifndef KA_BUF_SIZE
 #define KA_BUF_SIZE 128
@@ -61,6 +71,8 @@
 
 /* format data structures */
 
-typedef double ka_matrix_t[16];
+typedef ka_real_t ka_matrix_t[16];
+
+
 
 #endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f5055b1..78cf520 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,3 +12,4 @@ if (KALMIA_BUILD_TESTS)
 endif()
 
 add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/transform)
+add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/geometry)
diff --git a/src/geometry/CMakeLists.txt b/src/geometry/CMakeLists.txt
new file mode 100644
index 0000000..e1a0995
--- /dev/null
+++ b/src/geometry/CMakeLists.txt
@@ -0,0 +1,7 @@
+project(kalmia)
+
+target_sources(kalmia PUBLIC geometry.c)
+
+if (KALMIA_BUILD_TESTS)
+	target_sources(kalmia-tests PUBLIC geometry.test.c)
+endif()
diff --git a/src/geometry/geometry.c b/src/geometry/geometry.c
new file mode 100644
index 0000000..be9ce25
--- /dev/null
+++ b/src/geometry/geometry.c
@@ -0,0 +1,71 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include <kalmia.h>
+#include <ezxml.h>
+#include "geometry.h"
+
+
+static int copy_str(char **dest, const char *src)
+{
+	if (src == NULL) {
+		*dest = NULL;
+		return 0;
+	}
+
+	size_t len = strlen(src)+1;
+	*dest = malloc(len * sizeof(char));
+	if (*dest == NULL)
+		return -1;
+	strncpy(*dest, src, len);
+	return 0;
+}
+
+
+ka_float_array_t * kai_parse_float_array(ezxml_t tag)
+{
+	if (strcmp(ezxml_name(tag), "float_array") != 0) {
+		/* wrong tag type */
+		return NULL;
+	}
+
+	/* allocate struct */
+	ka_float_array_t *a = malloc(sizeof(ka_float_array_t));
+	if (a == NULL) return NULL;
+
+	/* inspect attributes */
+	const char *count_str = ezxml_attr(tag, "count");
+	a->count = strtol(count_str, NULL, 10);
+
+	const char *id_str = ezxml_attr(tag, "id");
+	if (copy_str(&(a->id), id_str) < 0) {
+		free(a);
+		return NULL;
+	}
+
+	/* parse data */
+	a->array = malloc(a->count * sizeof(ka_real_t));
+	if (a->array == NULL) {
+		free(a->id);
+		free(a);
+		return NULL;
+	}
+
+	char *data = ezxml_txt(tag);
+	char *end;
+	int i;
+	for (i=0; i<a->count; i++) {
+		a->array[i] = KA_STR_TO_REAL(data, &end);
+		data = end;
+	}
+
+	return a;
+}
+
+
+void kai_free_float_array(ka_float_array_t *a)
+{
+	free(a->array);
+	free(a->id);
+	free(a);
+}
diff --git a/src/geometry/geometry.h b/src/geometry/geometry.h
new file mode 100644
index 0000000..971bd1b
--- /dev/null
+++ b/src/geometry/geometry.h
@@ -0,0 +1,20 @@
+#ifndef KALMIA_GEOMETRY_H
+#define KALMIA_GEOMETRY_H
+
+#include <kalmia.h>
+#include <ezxml.h>
+
+typedef struct {
+	char *id;
+	size_t count;
+	ka_real_t *array;
+} ka_float_array_t;
+
+
+/* allocate a new float array and parse an xml tag into it */
+ka_float_array_t * kai_parse_float_array(ezxml_t tag);
+
+/* free a loaded float array */
+void kai_free_float_array(ka_float_array_t *array);
+
+#endif
diff --git a/src/geometry/geometry.test.c b/src/geometry/geometry.test.c
new file mode 100644
index 0000000..f400540
--- /dev/null
+++ b/src/geometry/geometry.test.c
@@ -0,0 +1,49 @@
+#include <string.h>
+#include <math.h>
+#include <kalmia.h>
+#include "test/test.h"
+#include "geometry.h"
+
+
+void parse_float_array();
+
+
+void suite_geometry()
+{
+	lily_run_test(parse_float_array);
+}
+
+
+void parse_float_array()
+{
+	char str[1024];
+	strncpy(
+		str,
+		"<float_array id=\"box-Pos-array\" count=\"24\">\n"
+		"	-0.5 0.5 0.5\n"
+		"	0.5 0.5 0.5\n"
+		"	-0.5 -0.5 0.5\n"
+		"	0.5 -0.5 0.5\n"
+		"	-0.5 0.5 -0.5\n"
+		"	0.5 0.5 -0.5\n"
+		"	-0.5 -0.5 -0.5\n"
+		"	0.5 -0.5 -0.5\n"
+		"</float_array>\n",
+		1024
+	);
+	ezxml_t tag = ezxml_parse_str(str, strlen(str));
+
+	ka_float_array_t *a = kai_parse_float_array(tag);
+	ezxml_free(tag);
+
+	lily_assert_not_null(a);
+	lily_assert_string_equal(a->id, "box-Pos-array");
+	lily_assert_int_equal(a->count, 24);
+
+	int i;
+	for (i=0; i<24; i++) {
+		lily_assert_float_equal(fabs(a->array[i]), 0.5, 1e-3);
+	}
+
+	kai_free_float_array(a);
+}
diff --git a/src/test/test.h b/src/test/test.h
index 17731b9..b50fda5 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -5,11 +5,13 @@
 
 
 void suite_transform();
+void suite_geometry();
 
 
 #define RUN_TESTS() \
 	do { \
 		lily_run_suite(suite_transform); \
+		lily_run_suite(suite_geometry); \
 	} while (0)
 
 #endif
-- 
cgit v1.2.1