changeset 48:55869b5e4761

core: implement properties, closes #2461
author David Demelier <markand@malikania.fr>
date Thu, 16 Jan 2020 14:57:51 +0100
parents f053a9f38c0e
children a8c7db56ccb0
files .hgignore Makefile src/property.c src/property.h tests/test-property.c
diffstat 5 files changed, 288 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Jan 16 13:32:20 2020 +0100
+++ b/.hgignore	Thu Jan 16 14:57:51 2020 +0100
@@ -16,7 +16,8 @@
 ^tests/test-color(\.exe)?$
 ^tests/test-error(\.exe)?$
 ^tests/test-map(\.exe)?$
-^tools/molko-map$
+^tests/test-property(\.exe)?$
+^tools/molko-map(\.exe)?$
 
 # doxygen stuff.
 ^doxygen/html$
--- a/Makefile	Thu Jan 16 13:32:20 2020 +0100
+++ b/Makefile	Thu Jan 16 14:57:51 2020 +0100
@@ -37,6 +37,7 @@
                 src/sys.c \
                 src/texture.c \
                 src/util.c \
+                src/property.c \
                 src/splashscreen.c \
                 src/walksprite.c \
                 src/window.c
@@ -55,7 +56,8 @@
 
 TESTS=          tests/test-color.c \
                 tests/test-error.c \
-                tests/test-map.c
+                tests/test-map.c \
+                tests/test-property.c
 TESTS_INCS=     -I extern/libgreatest -I src ${SDL_CFLAGS}
 TESTS_LIBS=     ${LIB} ${SDL_LDFLAGS} ${LDFLAGS}
 TESTS_OBJS=     ${TESTS:.c=}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/property.c	Thu Jan 16 14:57:51 2020 +0100
@@ -0,0 +1,81 @@
+/*
+ * property.c -- key-value properties
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "property.h"
+
+struct property *
+property_new(const char *key, const char *value)
+{
+	assert(key && strlen(key) <= PROPERTY_KEY_MAX);
+	assert(value && strlen(value) <= PROPERTY_VALUE_MAX);
+
+	struct property *prop;
+
+	prop = ecalloc(1, sizeof (struct property));
+	strncpy(prop->key, key, PROPERTY_KEY_MAX);
+	strncpy(prop->value, value, PROPERTY_VALUE_MAX);
+
+	return prop;
+}
+
+void
+property_add(struct property_list *head, struct property *prop)
+{
+	assert(head);
+	assert(prop);
+
+	if (head->next == NULL)
+		head->next = prop;
+	else
+		head->next->next = prop;
+}
+
+struct property *
+property_find(struct property_list *head, const char *key)
+{
+	assert(head);
+	assert(key);
+
+	for (struct property *it = head->next; it; it = it->next)
+		if (strcmp(it->key, key) == 0)
+			return it;
+
+	return NULL;
+}
+
+void
+property_clear(struct property_list *head)
+{
+	assert(head);
+
+	struct property *it;
+	struct property *next;
+
+	for (it = head->next; it && it->next; ) {
+		next = it->next;
+		free(it);
+		it = next;
+	}
+
+	head->next = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/property.h	Thu Jan 16 14:57:51 2020 +0100
@@ -0,0 +1,102 @@
+/*
+ * property.h -- key-value properties
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_PROPERTY_H
+#define MOLKO_PROPERTY_H
+
+/**
+ * \file property.h
+ * \brief Key-value properties.
+ */
+
+/**
+ * Maximum property key length.
+ */
+#define PROPERTY_KEY_MAX        32
+
+/**
+ * Maximum property value length.
+ */
+#define PROPERTY_VALUE_MAX      128
+
+/**
+ * \brief Key-value properties.
+ *
+ * This structure is implemented as linked-lists.
+ */
+struct property {
+	char key[PROPERTY_KEY_MAX + 1];         /*!< (RW) Property key */
+	char value[PROPERTY_VALUE_MAX + 1];     /*!< (RW) Property value */
+	struct property *next;                  /*!< (RO) Pointer to next property */
+};
+
+/**
+ * \brief The linked list of properties.
+ */
+struct property_list {
+	struct property *next;                  /*!< (RO) Property head */
+};
+
+/**
+ * Create a new property.
+ *
+ * \pre key != NULL
+ * \pre value != NULL
+ * \param key the property key
+ * \param value the property value
+ * \return a non-NULL property
+ * \note The property must be deallocated with free(3)
+ * \see property_clear
+ */
+struct property *
+property_new(const char *key, const char *value);
+
+/**
+ * Add a property to the linked-list specified by head.
+ *
+ * \pre head != NULL
+ * \pre prop != NULL
+ * \param head the linked-list
+ * \param prop the property
+ */
+void
+property_add(struct property_list *head, struct property *prop);
+
+/**
+ * Try to find a property by key.
+ *
+ * \pre head != NULL
+ * \pre key != NULL
+ * \param head the linked-list
+ * \param key the property key
+ * \return the property or NULL on failure
+ */
+struct property *
+property_find(struct property_list *head, const char *key);
+
+/**
+ * Remove and free all properties.
+ *
+ * \pre head != NULL
+ * \param head the linked-list
+ * \warning All properties must be allocated on the heap.
+ */
+void
+property_clear(struct property_list *head);
+
+#endif /* !MOLKO_PROPERTY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-property.c	Thu Jan 16 14:57:51 2020 +0100
@@ -0,0 +1,100 @@
+/*
+ * test-property.c -- test properties
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <greatest.h>
+
+#include <property.h>
+
+TEST
+add(void)
+{
+	struct property_list list = { 0 };
+
+	/*
+	 * 1 value:
+	 * - 0: "name" = "Jean Dujardin"
+	 */
+	property_add(&list, property_new("name", "Jean Dujardin"));
+	ASSERT_STR_EQ(list.next->key, "name");
+	ASSERT_STR_EQ(list.next->value, "Jean Dujardin");
+	ASSERT(!list.next->next);
+
+	/*
+	 * 1 value:
+	 * - 0: "name" = "Jean Dujardin"
+	 * - 1: "name" = "Daniel Balavoine"
+	 */
+	property_add(&list, property_new("name", "Daniel Balavoine"));
+	ASSERT_STR_EQ(list.next->key, "name");
+	ASSERT_STR_EQ(list.next->value, "Jean Dujardin");
+	ASSERT_STR_EQ(list.next->next->key, "name");
+	ASSERT_STR_EQ(list.next->next->value, "Daniel Balavoine");
+	ASSERT(!list.next->next->next);
+
+	property_clear(&list);
+	PASS();
+}
+
+TEST
+find(void)
+{
+	struct property_list list = { 0 };
+
+	/*
+	 * 2 value:
+	 * - "start-x" = "10"
+	 * - "start-y" = "20"
+	 */
+	property_add(&list, property_new("start-x", "10"));
+	property_add(&list, property_new("start-y", "20"));
+	ASSERT_STR_EQ("start-x", property_find(&list, "start-x")->key);
+	ASSERT_STR_EQ("10", property_find(&list, "start-x")->value);
+	ASSERT_STR_EQ("start-y", property_find(&list, "start-y")->key);
+	ASSERT_STR_EQ("20", property_find(&list, "start-y")->value);
+	property_clear(&list);
+	PASS();
+}
+
+TEST
+clear(void)
+{
+	struct property_list list = { 0 };
+
+	property_add(&list, property_new("start-x", "10"));
+	property_add(&list, property_new("start-y", "20"));
+	property_clear(&list);
+	ASSERT(!list.next);
+	PASS();
+}
+
+SUITE(simple)
+{
+	RUN_TEST(add);
+	RUN_TEST(find);
+	RUN_TEST(clear);
+}
+
+GREATEST_MAIN_DEFS();
+
+int
+main(int argc, char **argv)
+{
+	GREATEST_MAIN_BEGIN();
+	RUN_SUITE(simple);
+	GREATEST_MAIN_END();
+}