summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--strarr.h141
-rw-r--r--test.c48
2 files changed, 175 insertions, 14 deletions
diff --git a/strarr.h b/strarr.h
index 69ae4a4..878cf95 100644
--- a/strarr.h
+++ b/strarr.h
@@ -3,32 +3,62 @@
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
typedef struct strarr {
char *data; /* the underlying data */
size_t len; /* the amount of string entries */
- size_t used; /* the total bytes used of the capacity for the strings, incl NULL */
- size_t cap; /* the total bytes allocated to the buffer, incl NULL */
+ /* For instance, if the strings are { "Hello", "World" },
+ and 100 bytes are allocated, `used` is 13 bytes (w/ two str NULLs and one arr NULL),
+ and `cap` is 100 bytes. The index of the arr NULL is [used - 1] */
+ size_t used; /* the total bytes used of the capacity for the strings, incl NULLs */
+ size_t cap; /* the total bytes allocated to the buffer, incl NULLs */
} strarr;
+/* The capacity should _include_ the trailing NULL of the array. */
void
strarr_init_empty(strarr *sa, size_t cap)
{
sa->len = 0;
- sa->used = 0;
+ sa->used = 1; /* as includes the NULL */
sa->cap = cap;
sa->data = (char*) malloc(cap);
+ sa->data[sa->cap] = '\0';
}
+/* Get a pointer to the NULL that terminates the array. Useful for bounds checking,
+ * or over-writing it in the case of, e.g. strarr_app.
+ */
+char *
+strarr_internal_ptr_to_arr_null(strarr *sa)
+{
+ size_t i = sa->used == 0 ? 0 : sa->used - 1;
+ return &sa->data[i];
+}
+
+int
+strarr_internal_is_corrupted(strarr *sa)
+{
+ if (
+ sa->used > sa->cap
+ || *strarr_internal_ptr_to_arr_null(sa) != '\0'
+ ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
void
strarr_init_from_str_split(strarr *sa, const char *str, char del)
{
size_t len = strlen(str);
- char* data = (char*) malloc(len + 1); /* include the NULL terminator */
+ char* data = (char*) malloc(len + 2); /* include the NULL terminator for str and arr*/
sa->data = data;
- sa->cap = len + 1;
- memcpy(sa->data, str, len);
+ sa->cap = len + 2; /* includes the NULL terminators */
+ memcpy(sa->data, str, len + 1); /* include the NULL of the str but no extra bytes. */
/* There are at minimum one entries. */
sa->len = 1;
@@ -40,25 +70,108 @@ strarr_init_from_str_split(strarr *sa, const char *str, char del)
sa->len++;
}
}
-
-
+ sa->used = len + 2; // + str NULL + arr NULL
+
+ /* Add the NULL terminator for the array. */
+ sa->data[sa->used] = '\0';
}
+void strarr_debug(strarr *sa)
+{
+ printf("sa->len :: %d\n", sa->len);
+ printf("sa->cap :: %d\n", sa->cap);
+ printf("sa->used :: %d\n", sa->used);
+ printf("used ck :: %s\n", sa->used > sa->cap ? "exceeds cap" : "within cap");
+ printf("corrupted :: %s\n", strarr_internal_is_corrupted(sa) ? "yes" : "no" );
+
+ printf("sa->data :: ");
+ for (int i = 0; i < sa->cap; ++i) {
+ sa->data[i] == '\0' ? printf("<0>") : printf("%c", sa->data[i]);
+ }
+ printf("\n");
+
+}
-/* Copy string into strarr, appending it in the process. */
void
+strarr_free(strarr *sa)
+{
+ free(sa->data);
+}
+
+
+/* Copy string into strarr, appending it in the process.
+ TODO: add check for when appending in excess of `cap` and returning an error. */
+void
strarr_app(strarr *sa, char *str)
{
size_t len = strlen(str);
- strcpy(&sa->data[sa->used], str);
+ // Overwrite arr NULL: TODO: add bounds check with `cap`.
+ strcpy(strarr_internal_ptr_to_arr_null(sa), str);
+ sa->used += (len + 1); /* new str + new str NULL */
+ *strarr_internal_ptr_to_arr_null(sa) = '\0'; /* as was overwritten */
+ sa->len++; /* Add one more entry */
+}
+
+char *
+strarr_index(strarr *sa, size_t idx)
+{
+ size_t cnt = 0;
+
+ if (idx == 0) {
+ return sa->data;
+ }
- sa->len++;
- sa->used += len;
- sa->cap += len;
-
+ for (char *i = sa->data; i < strarr_internal_ptr_to_arr_null(sa) - 1; ++i) {
+ if (*i == '\0') {
+ if (++cnt == idx) {
+ // If we've encountered the NULL, the index of the next str
+ // is one byte after it.
+ return i + 1;
+ }
+ }
+ }
+
+ return NULL;
}
+/* Initialize `sa` from `from`, whilst pointing to the same
+ underlying data. The caller does not need to call `free`;
+ since the array is shared, any actions taken may corrupt
+ the original structure.
+ */
+void
+strarr_init_clone_shallow(strarr *sa, const strarr *from)
+{
+ sa->cap = from->cap;
+ sa->data = from->data;
+ sa->len = from->len;
+ sa->used = from->used;
+}
+
+/* Initialize `sa` from `from`, allocating a new array and
+ copying the contents of from into it. The caller must
+ call strarr_free.
+ */
+void
+strarr_init_clone_deep(strarr *sa, const strarr *from)
+{
+ sa->cap = from->cap;
+ sa->len = from->len;
+ sa->used = from->used;
+ sa->data = (char*) malloc(from->cap);
+ strcpy(sa->data, from->data);
+}
+char *
+strarr_next(strarr *sa, char *ptr)
+{
+ if (!ptr) {
+ return NULL;
+ }
+
+ while (*ptr++) ;
+ return *ptr ? ptr : NULL;
+}
#endif
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..0739642
--- /dev/null
+++ b/test.c
@@ -0,0 +1,48 @@
+#include "strarr.h"
+#include <stdio.h>
+
+int main()
+{
+ strarr sa;
+ strarr_init_from_str_split(&sa, "Hello\nWorld", '\n');
+ int i;
+ char* p;
+ strarr_debug(&sa);
+ for (p = strarr_index(&sa, 0), i = 0; p != NULL; p = strarr_next(&sa, p), i++) {
+ printf("sa[%d] = %s\n", i, p);
+ }
+
+ for (int i = 0; i <= 3; ++i) {
+ const char *c = strarr_index(&sa, i);
+ printf("*strarr_index(%d) = %s\n", i, c == NULL ? "nullptr" : c);
+ }
+
+ strarr_free(&sa);
+
+ /* Test initting empty and append */
+ printf("\n\n---------- Second test w init_empty ---------------\n\n");
+ strarr sa2;
+ strarr_init_empty(&sa2, 35);
+ printf("Before appending, after strarr_init_empty: \n");
+ strarr_debug(&sa2);
+ printf("\n");
+
+ strarr_app(&sa2, "Hello");
+ strarr_app(&sa2, "World");
+ strarr_app(&sa2, "woogie boogie");
+ printf("After strarr_app:\n");
+ strarr_debug(&sa2);
+
+ /* And the usual loop. */
+ for (p = strarr_index(&sa2, 0), i = 0; p != NULL; p = strarr_next(&sa2, p), i++) {
+ printf("sa2[%d] = %s\n", i, p);
+ }
+
+ for (int i = 0; i <= 3; ++i) {
+ const char *c = strarr_index(&sa2, i);
+ printf("*strarr_index(%d) = %s\n", i, c == NULL ? "nullptr" : c);
+ }
+
+ strarr_free(&sa2);
+}
+