aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/strlist.h3
-rw-r--r--lib/strlist.c113
-rw-r--r--tests/test_strlist.c178
3 files changed, 235 insertions, 59 deletions
diff --git a/include/strlist.h b/include/strlist.h
index 4cf76c6..919bdc1 100644
--- a/include/strlist.h
+++ b/include/strlist.h
@@ -29,6 +29,7 @@ unsigned short strlist_item_as_ushort(StrList *pStrList, size_t index);
short strlist_item_as_short(StrList *pStrList, size_t index);
unsigned char strlist_item_as_uchar(StrList *pStrList, size_t index);
char strlist_item_as_char(StrList *pStrList, size_t index);
+unsigned char strlist_item_as_uchar(StrList *pStrList, size_t index);
char *strlist_item_as_str(StrList *pStrList, size_t index);
char *strlist_item(StrList *pStrList, size_t index);
void strlist_set(StrList *pStrList, size_t index, char *value);
@@ -37,6 +38,8 @@ void strlist_reverse(StrList *pStrList);
void strlist_sort(StrList *pStrList, unsigned int mode);
void strlist_append_strlist(StrList *pStrList1, StrList *pStrList2);
void strlist_append(StrList *pStrList, char *str);
+StrList *strlist_copy(StrList *pStrList);
+int strlist_cmp(StrList *a, StrList *b);
void strlist_free(StrList *pStrList);
#endif //SPM_STRLIST_H
diff --git a/lib/strlist.c b/lib/strlist.c
index 5c1f0e2..b8d394d 100644
--- a/lib/strlist.c
+++ b/lib/strlist.c
@@ -47,6 +47,23 @@ void strlist_append(StrList *pStrList, char *str) {
}
/**
+ * Produce a new copy of a `StrList`
+ * @param pStrList `StrList`
+ * @return `StrList` copy
+ */
+StrList *strlist_copy(StrList *pStrList) {
+ StrList *result = strlist_init();
+ if (pStrList == NULL || result == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < strlist_count(pStrList); i++) {
+ strlist_append(result, strlist_item(pStrList, i));
+ }
+ return result;
+}
+
+/**
* Append the contents of a `StrList` to another `StrList`
* @param pStrList1 `StrList`
* @param pStrList2 `StrList`
@@ -66,44 +83,35 @@ void strlist_append_strlist(StrList *pStrList1, StrList *pStrList2) {
}
/**
- *
- * @param a
- * @param b
- * @return
+ * Compare two `StrList`s
+ * @param a `StrList` structure
+ * @param b `StrList` structure
+ * @return same=0, different=1, error=-1 (a is NULL), -2 (b is NULL)
*/
-static int _strlist_cmpfn(const void *a, const void *b) {
- const char *aa = *(const char**)a;
- const char *bb = *(const char**)b;
- int result = strcmp(aa, bb);
- return result;
-}
+int strlist_cmp(StrList *a, StrList *b) {
+ if (a == NULL) {
+ return -1;
+ }
-/**
- *
- * @param a
- * @param b
- * @return
- */
-static int _strlist_asc_cmpfn(const void *a, const void *b) {
- const char *aa = *(const char**)a;
- const char *bb = *(const char**)b;
- size_t len_a = strlen(aa);
- size_t len_b = strlen(bb);
- return len_a > len_b - strcmp(aa, bb);
-}
+ if (b == NULL) {
+ return -2;
+ }
-/**
- *
- * @param a
- * @param b
- * @return
- */
-static int _strlist_dsc_cmpfn(const void *a, const void *b) {
- const char *aa = *(const char**)a;
- const char *bb = *(const char**)b;
- size_t len_a = strlen(aa);
- size_t len_b = strlen(bb);
- return len_a < len_b - strcmp(aa, bb);
+ if (a->num_alloc != b->num_alloc) {
+ return 1;
+ }
+
+ if (a->num_inuse != b->num_inuse) {
+ return 1;
+ }
+
+ for (size_t i = 0; i < strlist_count(a); i++) {
+ if (strcmp(strlist_item(a, i), strlist_item(b, i)) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
}
/**
@@ -119,20 +127,7 @@ void strlist_sort(StrList *pStrList, unsigned int mode) {
return;
}
- switch (mode) {
- case STRLIST_ASC:
- fn = _strlist_asc_cmpfn;
- break;
- case STRLIST_DSC:
- fn = _strlist_dsc_cmpfn;
- break;
- case STRLIST_DEFAULT:
- default:
- fn = _strlist_cmpfn;
- break;
- }
-
- qsort(pStrList->data, pStrList->num_inuse, sizeof(char *), fn);
+ strsort(pStrList->data, mode);
}
/**
@@ -225,7 +220,7 @@ char *strlist_item_as_str(StrList *pStrList, size_t index) {
* @return `char`
*/
char strlist_item_as_char(StrList *pStrList, size_t index) {
- return (char) *(strlist_item(pStrList, index));
+ return (char) strtol(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -235,7 +230,7 @@ char strlist_item_as_char(StrList *pStrList, size_t index) {
* @return `unsigned char`
*/
unsigned char strlist_item_as_uchar(StrList *pStrList, size_t index) {
- return (unsigned char) *(strlist_item(pStrList, index));
+ return (unsigned char) strtol(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -245,7 +240,7 @@ unsigned char strlist_item_as_uchar(StrList *pStrList, size_t index) {
* @return `short`
*/
short strlist_item_as_short(StrList *pStrList, size_t index) {
- return (short)atoi(strlist_item(pStrList, index));
+ return (short)strtol(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -255,7 +250,7 @@ short strlist_item_as_short(StrList *pStrList, size_t index) {
* @return `unsigned short`
*/
unsigned short strlist_item_as_ushort(StrList *pStrList, size_t index) {
- return (unsigned short)atoi(strlist_item(pStrList, index));
+ return (unsigned short)strtoul(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -265,7 +260,7 @@ unsigned short strlist_item_as_ushort(StrList *pStrList, size_t index) {
* @return `int`
*/
int strlist_item_as_int(StrList *pStrList, size_t index) {
- return atoi(strlist_item(pStrList, index));
+ return (int)strtol(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -275,7 +270,7 @@ int strlist_item_as_int(StrList *pStrList, size_t index) {
* @return `unsigned int`
*/
unsigned int strlist_item_as_uint(StrList *pStrList, size_t index) {
- return (unsigned int)atoi(strlist_item(pStrList, index));
+ return (unsigned int)strtoul(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -285,7 +280,7 @@ unsigned int strlist_item_as_uint(StrList *pStrList, size_t index) {
* @return `long`
*/
long strlist_item_as_long(StrList *pStrList, size_t index) {
- return atol(strlist_item(pStrList, index));
+ return strtol(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -295,7 +290,7 @@ long strlist_item_as_long(StrList *pStrList, size_t index) {
* @return `unsigned long`
*/
unsigned long strlist_item_as_ulong(StrList *pStrList, size_t index) {
- return (unsigned long)atol(strlist_item(pStrList, index));
+ return strtoul(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -305,7 +300,7 @@ unsigned long strlist_item_as_ulong(StrList *pStrList, size_t index) {
* @return `long long`
*/
long long strlist_item_as_long_long(StrList *pStrList, size_t index) {
- return (long long)atoll(strlist_item(pStrList, index));
+ return strtoll(strlist_item(pStrList, index), NULL, 10);
}
/**
@@ -315,7 +310,7 @@ long long strlist_item_as_long_long(StrList *pStrList, size_t index) {
* @return `unsigned long long`
*/
unsigned long long strlist_item_as_ulong_long(StrList *pStrList, size_t index) {
- return (unsigned long long)atoll(strlist_item(pStrList, index));
+ return strtoull(strlist_item(pStrList, index), NULL, 10);
}
/**
diff --git a/tests/test_strlist.c b/tests/test_strlist.c
new file mode 100644
index 0000000..a4ea647
--- /dev/null
+++ b/tests/test_strlist.c
@@ -0,0 +1,178 @@
+#include "spm.h"
+#include "framework.h"
+
+static const char *story_truth = "The quick brown fox jumps over the lazy dog.";
+static const char *story_truth_rev = "dog. jumps over the lazy fox The quick brown";
+static const char *story_truth_sort_asc = "fox dog. The quick brown jumps over the lazy";
+static const char *story_truth_sort_dsc = "jumps over the lazy The quick brown dog. fox";
+
+static char *DATA[] = {
+ "The quick brown",
+ "fox",
+ "jumps over the lazy",
+ "dog.",
+ NULL,
+};
+
+long int MAX_INTS[] = {
+ INT8_MAX,
+ UINT8_MAX,
+ INT16_MAX,
+ UINT16_MAX,
+ INT32_MAX,
+ UINT32_MAX,
+ INT64_MAX,
+ UINT64_MAX,
+ 0,
+};
+
+enum truthValue {
+ int8_max = 0,
+ uint8_max,
+ int16_max,
+ uint16_max,
+ int32_max,
+ uint32_max,
+ int64_max,
+ uint64_max,
+};
+
+
+int main(int argc, char *argv[]) {
+ const char *storyFmt = "expected story: '%s', but got '%s'\n";
+ char *story = NULL;
+ union TestValue testValue = {0,};
+ StrList *strList = NULL;
+ StrList *strListCopy = NULL;
+ StrList *strListNumbers = NULL;
+ StrList truthInit = {1, 0, NULL};
+ size_t used = 0;
+ size_t allocated = 0;
+ char intStr[255];
+ const int DATA_SIZE = (sizeof(DATA) / sizeof(char *)) - 1;
+
+
+ // Initialize string list and check initial state
+ strList = strlist_init();
+ myassert(strList->num_inuse == 0, "strList has wrong number of records in use: %zu (expected %zu)\n", strList->num_inuse, truthInit.num_inuse);
+ myassert(strList->num_alloc == 1, "strList has wrong number of records allocated: %zu (expected %zu)\n", strList->num_alloc, truthInit.num_alloc);
+ myassert(strList->data != NULL, "strList was NULL");
+
+ ssize_t count = strlist_count(strList);
+ myassert(count == 0, "strlist_count returned wrong number of records in use: %zu (expected %zu)\n", count, strList->num_inuse);
+
+ // Populate list with strings
+ for (size_t i = 0; DATA[i] != NULL; i++) {
+ used = i + 1;
+ allocated = used + 1;
+
+ strlist_append(strList, DATA[i]);
+ myassert(strList->num_inuse == used, "incorrect used record count post-append\n");
+ myassert(strList->num_alloc == allocated, "incorrect allocated record count post-append\n");
+ }
+
+ // Is the data represented in the array as we expect it to be?
+ story = join(strList->data, " ");
+ myassert(strcmp(story, story_truth) == 0, storyFmt, story_truth, story);
+ free(story);
+ story = NULL;
+
+ // Copy the array (because we're about to modify it)
+ strListCopy = strlist_copy(strList);
+ myassert(strListCopy != NULL, "strlist_copy failed\n");
+
+ // Does reversing the array work correctly?
+ strlist_reverse(strListCopy);
+
+ story = join(strListCopy->data, " ");
+ // Copy the array (because we're about to modify it)
+ myassert(strcmp(story, story_truth_rev) == 0, storyFmt, story_truth, story);
+ free(story);
+ story = NULL;
+ strlist_free(strListCopy);
+ strListCopy = NULL;
+
+ // Copy the array (because we're about to modify it)
+ strListCopy = strlist_copy(strList);
+ myassert(strListCopy != NULL, "strlist_copy failed\n");
+
+ // Now compare the arrays to make sure they're identical
+ myassert(strlist_cmp(strList, strListCopy) == 0, "strlist_copy result does not match original StrList contents");
+
+ // Sort the array to see if it works.
+ strlist_sort(strListCopy, SPM_SORT_LEN_ASCENDING);
+
+ // The array just got modified, so check to make sure they are NOT identical
+ myassert(strlist_cmp(strList, strListCopy) == 1, "StrList data matches original StrList contents (after modification)");
+
+ story = join(strListCopy->data, " ");
+ myassert(strcmp(story, story_truth_sort_asc) == 0, storyFmt, story_truth_sort_asc, story);
+ free(story);
+ story = NULL;
+ strlist_free(strListCopy);
+ strListCopy = NULL;
+
+ // Copy the array (because we're about to modify it)
+ strListCopy = strlist_copy(strList);
+ myassert(strListCopy != NULL, "strlist_copy failed\n");
+
+ // Sort the array once more using a different comparator
+ strlist_sort(strListCopy, SPM_SORT_LEN_DESCENDING);
+
+ story = join(strListCopy->data, " ");
+ myassert(strcmp(story, story_truth_sort_dsc) == 0, storyFmt, story_truth_sort_dsc, story);
+ free(story);
+ story = NULL;
+ strlist_free(strListCopy);
+ strListCopy = NULL;
+
+ // Now append numerical values (as string) so we can start reading them back
+ for (size_t i = 0; MAX_INTS[i] != 0; i++) {
+ memset(intStr, '\0', sizeof(intStr));
+ sprintf(intStr, "%zu", MAX_INTS[i]);
+ strlist_append(strList, intStr);
+ }
+
+ memset(intStr, '\0', sizeof(intStr));
+ sprintf(intStr, "%lf", MAXFLOAT);
+ strlist_append(strList, intStr);
+
+ // Now make sure values derived from strlist_item_as_*() functions work properly
+ // NOTE: My focus is on 64-bit, so if you're compiling this on a 32-bit computer
+ // and these tests fail for you... That's a shame.
+ testValue.signed_char = strlist_item_as_char(strList, DATA_SIZE + int8_max);
+ myassert(testValue.signed_char == INT8_MAX, "int8_max incorrect: %d", testValue.signed_char);
+
+ testValue.unsigned_char = strlist_item_as_uchar(strList, DATA_SIZE + uint8_max);
+ myassert(testValue.unsigned_char == UINT8_MAX, "uint8_max incorrect: %d", testValue.unsigned_char);
+
+ testValue.signed_short = strlist_item_as_short(strList, DATA_SIZE + int16_max);
+ myassert(testValue.signed_short == INT16_MAX, "int16_max incorrect: %d", testValue.signed_short);
+
+ testValue.unsigned_short = strlist_item_as_ushort(strList, DATA_SIZE + uint16_max);
+ myassert(testValue.unsigned_short == UINT16_MAX, "uint16_max incorrect: %d", testValue.unsigned_short);
+
+ testValue.signed_int = strlist_item_as_int(strList, DATA_SIZE + int32_max);
+ myassert(testValue.signed_int == INT32_MAX, "int32_max incorrect: %d", testValue.signed_int);
+
+ testValue.unsigned_int = strlist_item_as_uint(strList, DATA_SIZE + uint32_max);
+ myassert(testValue.unsigned_int == UINT32_MAX, "uint32_max incorrect: %d", testValue.unsigned_int);
+
+ testValue.signed_long = strlist_item_as_long(strList, DATA_SIZE + int64_max);
+ myassert(testValue.signed_long == INT64_MAX, "int64_max (long) incorrect: %ld", testValue.signed_long);
+
+ testValue.unsigned_long = strlist_item_as_ulong(strList, DATA_SIZE + uint64_max);
+ myassert(testValue.unsigned_long == UINT64_MAX, "uint64_max (long) incorrect: %lu", testValue.unsigned_long);
+
+ testValue.signed_long_long = strlist_item_as_long_long(strList, DATA_SIZE + int64_max);
+ myassert(testValue.signed_long_long == INT64_MAX, "int64_max (long long) incorrect: %lld", testValue.signed_long_long);
+
+ testValue.unsigned_long_long = strlist_item_as_ulong_long(strList, DATA_SIZE + uint64_max);
+ myassert(testValue.unsigned_long_long == UINT64_MAX, "uint64_max (long long) incorrect: %llu", testValue.unsigned_long_long);
+
+ testValue.floating = strlist_item_as_float(strList, DATA_SIZE + uint64_max + 1);
+ myassert(testValue.floating == MAXFLOAT, "floating point maximum incorrect: %f", testValue.floating);
+
+ strlist_free(strList);
+ return 0;
+} \ No newline at end of file