summaryrefslogtreecommitdiff
path: root/str.c
diff options
context:
space:
mode:
Diffstat (limited to 'str.c')
-rw-r--r--str.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/str.c b/str.c
new file mode 100644
index 0000000..5f03e35
--- /dev/null
+++ b/str.c
@@ -0,0 +1,124 @@
+#include "str.h"
+#include "crash.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define CRASH_IF_OOB(str, len) {\
+ if (len > str.length)\
+ crash("String access out of bounds: %ld > %ld\n", len, str.length);\
+}
+
+static inline char* alloc_data_ptr(size_t length) {
+ char* data_ptr = malloc(length);
+ if (data_ptr == NULL)
+ crash("Out of memory allocating new string of length %ld\n", length);
+ return data_ptr;
+}
+
+static inline char* alloc_c_str(size_t length) {
+ char* c_str = malloc(length + 1);
+ if (c_str == NULL)
+ crash("Out of memory allocating C string buffer of size %ld", length + 1);
+
+ c_str[length] = 0;
+ return c_str;
+}
+
+char* str_at(const str_t str, size_t idx) {
+ CRASH_IF_OOB(str, idx + 1);
+ return str.__data + idx;
+}
+
+str_t str_slice(const str_t str, size_t start, size_t length) {
+ CRASH_IF_OOB(str, start + length);
+ str_t slice = {.length = length, .__data = str.__data + start};
+ return slice;
+}
+
+int str_cmp(const str_t s1, const str_t s2) {
+ if (s1.length == s2.length)
+ return memcmp(s1.__data, s2.__data, s1.length);
+ else if (s1.length > s2.length) {
+ int cmp = memcmp(s1.__data, s2.__data, s2.length);
+ if (cmp != 0) return cmp;
+ return 1;
+ } else {
+ int cmp = memcmp(s1.__data, s2.__data, s1.length);
+ if (cmp != 0) return cmp;
+ return -1;
+ }
+}
+
+ssize_t str_indexof(const str_t str, char c) {
+ for (ssize_t i = 0; i < str.length; i++) {
+ if (str.__data[i] == c) return i;
+ }
+ return -1;
+}
+
+ssize_t str_rindexof(const str_t str, char c) {
+ for (ssize_t i = (ssize_t)str.length - 1; i >= 0; i--) {
+ if (str.__data[i] == c) return i;
+ }
+ return -1;
+}
+
+str_t str_heap_dup(const str_t str) {
+ char* data_ptr = alloc_data_ptr(str.length);
+ str_t dup_str = {.length = str.length, .__data = data_ptr};
+ return dup_str;
+}
+
+str_t str_heap_cat(const str_t s1, const str_t s2) {
+ size_t new_len = s1.length + s2.length;
+ char* data_ptr = alloc_data_ptr(new_len);
+ str_t cat_str = {.length = new_len, .__data = data_ptr};
+ return cat_str;
+}
+
+void str_to_c_str(char* dst, size_t dst_size, const str_t* src) {
+ if (src->length >= dst_size)
+ crash(
+ "String is too long to hold in C string buffer: %ld >= %ld\n",
+ src->length,
+ dst_size);
+
+ memmove(dst, src->__data, src->length);
+ dst[src->length] = 0;
+}
+
+char* str_to_heap_c_str(const str_t src) {
+ char* dst = alloc_c_str(src.length);
+ memcpy(dst, src.__data, src.length);
+ return dst;
+}
+
+str_t str_init(char* data, size_t length) {
+ str_t str = {.length = length, .__data = data};
+ return str;
+}
+
+str_t str_heap_alloc(size_t length) {
+ char* data_ptr = alloc_data_ptr(length);
+ str_t str = {.length = length, .__data = data_ptr};
+ return str;
+}
+
+str_t str_heap_alloc_iv(const char* c_str) {
+ size_t length = strlen(c_str);
+ char* data_ptr = alloc_data_ptr(length);
+ memcpy(data_ptr, c_str, length);
+ str_t str = {.length = length, .__data = data_ptr};
+ return str;
+}
+
+str_t str_heap_alloc_iv_slice(const char* c_str, size_t start, size_t length) {
+ char* data_ptr = alloc_data_ptr(length);
+ memcpy(data_ptr, c_str + start, length);
+ str_t str = {.length = length, .__data = data_ptr};
+ return str;
+}
+
+void str_heap_destroy(str_t str) {
+ free(str.__data);
+}