From 38bcad4cb16d93a8c52a86ad9f57d0c05f956b11 Mon Sep 17 00:00:00 2001 From: Logan Grosz Date: Sun, 26 May 2024 11:37:47 -0600 Subject: [PATCH] Adds formation structure as copy of climb structure --- CMakeLists.txt | 1 + formation.c | 199 +++++++++++++++++++++++++++++++++++++++++++ formation.h | 24 ++++++ tests/CMakeLists.txt | 1 + tests/formation.c | 151 ++++++++++++++++++++++++++++++++ 5 files changed, 376 insertions(+) create mode 100644 formation.c create mode 100644 formation.h create mode 100644 tests/formation.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 17bedd2..34ad382 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(grades grades_hueco.c grades_font.c climb.c + formation.c node.c graph.c str_util.c diff --git a/formation.c b/formation.c new file mode 100644 index 0000000..4d324cc --- /dev/null +++ b/formation.c @@ -0,0 +1,199 @@ +#include "formation.h" +#include "str_util.h" +#include +#include +#include + +struct Formation_ +{ + const char *name; + const char *description; + const char *brief; + const char **aliases; + size_t aliaseslen; +}; + +static int contains(const char **strs, size_t len, const char *str) +{ + for (int i = 0; i < len; i++) { + if (strcmp(strs[i], str) == 0) { + return 1; + } + } + + return 0; +} + +Formation Formation_new() +{ + Formation ret; + + if (NULL == (ret = malloc(sizeof(struct Formation_)))) { + errno = ENOMEM; + return NULL; + } else { + ret->name = NULL; + ret->description = NULL; + ret->brief = NULL; + ret->aliases = NULL; + } + + Formation_set_name(ret, ""); + Formation_set_description(ret, ""); + Formation_set_brief(ret, ""); + + ret->aliaseslen = 0; + + errno = 0; + return ret; +} + +void Formation_free(Formation formation) +{ + if (formation == NULL) { + errno = EINVAL; + return; + } + + errno = 0; + if (formation->name) free((void*)formation->name); + if (formation->description) free((void*)formation->description); + if (formation->brief) free((void*)formation->brief); + + if (formation->aliases) { + for (int i = 0; i < formation->aliaseslen; i++) { + free((void*)formation->aliases[i]); + } + + free(formation->aliases); + } + + free(formation); +} + +void Formation_set_name(Formation formation, const char *name) +{ + free_allocate_and_assign_str(&formation->name, name); +} + +const char *Formation_name(Formation formation) +{ + return formation->name; +} + +void Formation_set_description(Formation formation, const char *description) +{ + free_allocate_and_assign_str(&formation->description, description); +} + +const char *Formation_description(Formation formation) +{ + return formation->description; +} + +void Formation_set_brief(Formation formation, const char *description) +{ + free_allocate_and_assign_str(&formation->brief, description); +} + +const char *Formation_brief(Formation formation) +{ + return formation->brief; +} + +void Formation_add_alias(Formation formation, const char *alias) +{ + if (formation == NULL) { + errno = EINVAL; + return; + } + + if (contains(formation->aliases, formation->aliaseslen, alias)) { + return; + } + + const char **aliases; + if (NULL == (aliases = malloc((formation->aliaseslen + 1) * sizeof(const char *)))) { + errno = ENOMEM; + return; + } + + for (size_t i = 0; i < formation->aliaseslen; ++i) { + aliases[i] = formation->aliases[i]; + } + + char *new_str; + if (NULL == (new_str = malloc(strlen(alias) + 1))) { + // TODO Cleanup + errno = ENOMEM; + return; + } + + strcpy(new_str, alias); + + aliases[formation->aliaseslen] = new_str; + + if (formation->aliases) { + free(formation->aliases); + } + + errno = 0; + formation->aliaseslen = formation->aliaseslen + 1; + formation->aliases = aliases; +} + +void Formation_remove_alias(Formation formation, const char *alias) +{ + if (formation == NULL) { + errno = EINVAL; + return; + } + + size_t index = 0; + int found = 0; + + for (index = 0; index < formation->aliaseslen; ++index) { + if (strcmp(formation->aliases[index], alias) == 0) { + found = 1; + break; + } + } + + if (!found) { + errno = 0; + return; + } + + const char **aliases; + if (NULL == (aliases = malloc((formation->aliaseslen - 1) * sizeof(const char *)))) { + errno = ENOMEM; + return; + } + + // Copy elements, skipping the element to remove + for (size_t i = 0, j = 0; i < formation->aliaseslen; ++i) { + if (i != index) { + aliases[j++] = formation->aliases[i]; + } + } + + if (formation->aliases) { + free((void *)formation->aliases[index]); + free(formation->aliases); + } + + errno = 0; + formation->aliaseslen = formation->aliaseslen - 1; + formation->aliases = aliases; +} + +const char **Formation_aliases(const Formation formation, size_t *len) +{ + if (len == NULL) { + errno = EINVAL; + return NULL; + } + + *len = formation->aliaseslen; + return formation->aliases; +} diff --git a/formation.h b/formation.h new file mode 100644 index 0000000..bd2ade5 --- /dev/null +++ b/formation.h @@ -0,0 +1,24 @@ +#ifndef _CLIMBLIB_FORMATION_H_ +#define _CLIMBLIB_FORMATION_H_ + +#include + +typedef struct Formation_* Formation; + +Formation Formation_new(); +void Formation_free(Formation); + +void Formation_set_name(Formation, const char *); +const char *Formation_name(const Formation); + +void Formation_set_description(Formation, const char *); +const char *Formation_description(const Formation); + +void Formation_set_brief(Formation, const char *); +const char *Formation_brief(const Formation); + +void Formation_add_alias(Formation, const char *); +void Formation_remove_alias(Formation, const char *); +const char **Formation_aliases(const Formation, size_t *); + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e1300ad..975d685 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,7 @@ set(TestSources font.c hueco.c climb.c + formation.c graph.c ) diff --git a/tests/formation.c b/tests/formation.c new file mode 100644 index 0000000..ba39a5a --- /dev/null +++ b/tests/formation.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include + +#include "verify.h" + +#include + +static void test_free_null() +{ + Formation_free(NULL); + VERIFY(errno == EINVAL); +} + +static void test_new() +{ + Formation c = Formation_new(); + VERIFY(errno == 0); + VERIFY(c != NULL); + + Formation_free(c); + VERIFY(errno == 0); +} + +static void test_name() +{ + Formation c = Formation_new(); + VERIFY(errno == 0); + VERIFY(c != NULL); + + VERIFY(strcmp(Formation_name(c), "") == 0); + + char name[] = "A Formation Name"; + Formation_set_name(c, name); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_name(c), name) == 0); + + Formation_set_name(c, ""); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_name(c), "") == 0); + + Formation_free(c); + VERIFY(errno == 0); +} + +static void test_description() +{ + Formation c = Formation_new(); + VERIFY(errno == 0); + VERIFY(c != NULL); + + VERIFY(strcmp(Formation_description(c), "") == 0); + + char description[] = "A formation description...\nAnother line..."; + Formation_set_description(c, description); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_description(c), description) == 0); + + Formation_set_description(c, ""); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_description(c), "") == 0); + + Formation_free(c); + VERIFY(errno == 0); +} + +static void test_brief() +{ + Formation c = Formation_new(); + VERIFY(errno == 0); + VERIFY(c != NULL); + + VERIFY(strcmp(Formation_brief(c), "") == 0); + + char brief[] = "A formation brief..."; + Formation_set_brief(c, brief); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_brief(c), brief) == 0); + + Formation_set_brief(c, ""); + VERIFY(errno == 0); + VERIFY(strcmp(Formation_brief(c), "") == 0); + + Formation_free(c); + VERIFY(errno == 0); +} + +static int string_array_contains(const char **arr, unsigned int len, const char *str) +{ + for (int i = 0; i < len; i++) { + if (strcmp(arr[i], str) == 0) { + return 1; + } + } + + return 0; +} + +static void test_aliases() +{ + Formation c = Formation_new(); + VERIFY(errno == 0); + VERIFY(c != NULL); + + char alias1[] = "An alias"; + char alias2[] = "Another alias"; + + Formation_add_alias(c, alias1); + VERIFY(errno == 0); + + Formation_add_alias(c, alias2); + VERIFY(errno == 0); + + size_t aliaseslen; + const char **aliases = Formation_aliases(c, &aliaseslen); + VERIFY(errno == 0); + VERIFY(aliaseslen == 2); + VERIFY(string_array_contains(aliases, aliaseslen, alias1)); + VERIFY(string_array_contains(aliases, aliaseslen, alias2)); + + Formation_remove_alias(c, alias1); + VERIFY(errno == 0); + + aliases = Formation_aliases(c, &aliaseslen); + VERIFY(errno == 0); + VERIFY(aliaseslen == 1); + VERIFY(!string_array_contains(aliases, aliaseslen, alias1)); + VERIFY(string_array_contains(aliases, aliaseslen, alias2)); + + Formation_add_alias(c, alias2); + VERIFY(errno == 0); + Formation_aliases(c, &aliaseslen); + VERIFY(errno == 0); + VERIFY(aliaseslen == 1); + + Formation_free(c); + VERIFY(errno == 0); +} + +int formation() +{ + test_free_null(); + test_new(); + test_name(); + test_description(); + test_brief(); + test_aliases(); + + exit(EXIT_SUCCESS); +}