aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMosder <xmosder12@gmail.com>2026-08-18 16:48:53 +0200
committerMosder <xmosder12@gmail.com>2026-08-18 16:48:53 +0200
commit1cb408c0e4f42c4b11e8e2f80374c26bb905ef22 (patch)
treebbb555fccea06ffc586a17b41d26ddf3281e74bc
parent94ae190fab09d6ec421b35474e620f664b88647f (diff)
feat: added basic definitions and documentation + templates for implementation and tests for string slices
-rw-r--r--Makefile2
-rw-r--r--include/moslib.h1
-rw-r--r--include/moslib/string.h386
-rw-r--r--src/string.c73
-rw-r--r--tests/string_tests.c46
-rw-r--r--tests/string_tests.h3
-rw-r--r--tests/tests.c2
7 files changed, 513 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 0ea8a5a..3aa26d9 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,7 @@ headers:
compile: memory structures
$(CC) $(CFLAGS) -c src/tester.c
+ $(CC) $(CFLAGS) -c src/string.c
memory:
$(CC) $(CFLAGS) -c src/mem/alloc.c
@@ -28,6 +29,7 @@ structures:
test:
$(CC) $(CFLAGS_TEST) -c tests/mem/alloc_tests.c
$(CC) $(CFLAGS_TEST) -c tests/ds/array_tests.c
+ $(CC) $(CFLAGS_TEST) -c tests/string_tests.c
$(CC) $(CFLAGS_TEST) -lmoslib *.o tests/tests.c -o run_tests
./run_tests
rm run_tests *.o
diff --git a/include/moslib.h b/include/moslib.h
index b863678..777d951 100644
--- a/include/moslib.h
+++ b/include/moslib.h
@@ -11,4 +11,5 @@
#include "moslib/ds/array.h"
#include "moslib/mem/alloc.h"
+#include "moslib/string.h"
#include "moslib/tester.h"
diff --git a/include/moslib/string.h b/include/moslib/string.h
new file mode 100644
index 0000000..82685b4
--- /dev/null
+++ b/include/moslib/string.h
@@ -0,0 +1,386 @@
+// moslib/string.h
+// Length aware string slices
+
+// ======================================== QUICK USAGE GUIDE =========================================
+// ----------------------------------------------------------------------------------------------------
+//
+// StringSlice is defined as a struct which contains a pointer to the beginning of a string and its
+// length:
+//
+// typedef struct {
+// const char *data;
+// size_t len;
+// } StringSlice;
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// To get a string slice from a C string you can use:
+//
+// char *str = "Hello, World!";
+// StringSlice ss = ss_from_str(str);
+//
+// If you want to use a string literal to create a slice at compile time, use:
+//
+// StringSlice ss = SS_LIT("literal");
+//
+// You can also use this lib's implementation of dynamic array as a sort of string builder and then
+// get a string slice from it:
+//
+// char hello[] = "Hello, ";
+// char world[] = "World!";
+// char *sb = NULL;
+// arr_append_n(sb, hello, strlen(hello));
+// arr_append_n(sb, world, strlen(world));
+// StringSlice ss = ss_from_arr(sb);
+//
+// Be ware that freeing the array will create a dangling pointer in the slice.
+//
+// You can also just use a wrapper for getting it from 2 variables:
+//
+// StringSlice ss = ss_from_vars("[in][out]", 4);
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// To print a slice you can either use:
+//
+// ss_print(ss);
+//
+// Which will just print a slice to stdout (without trailing new line).
+//
+// Or, instead, you can use SS_FMT and SS_ARGS(ss) macros:
+//
+// printf("Slice: " SS_FMT "\n", SS_ARGS(ss));
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// To check if two slices are equal, use:
+//
+// int are_eq = ss_eq(ss1, ss2);
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// You can split a slice in two using "split" functions:
+//
+// StringSlice ss1 = ss_from_str("Hello, World!");
+// StringSlice ss2 = ss_split(&ss1, ','); // ss2 = "Hello", ss3 = " World!"
+// StringSlice ss3 = ss_split_str(&ss2, "ll"); // ss3 = "He", ss2 = "o"
+// StringSlice ss4 = ss_split_ss(&ss1, ss_from_lit("rld")); // ss4 = " Wo", ss1 = "!"
+//
+// They will return a slice containing everything before the delimiter and modify in place the given
+// slice to contain everything after the delimiter.
+// If the delimiter wasn't found - returned slice will be the same as the given one and the given one
+// will be emptied. The same will happen for an empty delimiter in _str / _ss variants.
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// You can trim a slice from whitespace using:
+//
+// StringSlice trimmed = ss_trim(ss); // same as trim_left + trim_right
+// StringSlice trimmed_l = ss_trim_left(ss);
+// StringSlice trimmed_r = ss_trim_right(ss);
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// To check whether a slice starts or ends with a slice / string, you can use:
+//
+// int flag1 = ss_starts_with(ss, ss_prefix);
+// int flag2 = ss_ends_with(ss, ss_suffix);
+// int flag3 = ss_starts_with_str(ss, str_prefix);
+// int flag4 = ss_ends_with_str(ss, str_suffix);
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// To find within a slice a part which begins with given target, use:
+//
+// StringSlice target1 = ss_find(ss, ss_target);
+// StringSlice target2 = ss_find_str(ss, str_target);
+//
+// The return value is a slice that begins at the beginning of the specified target and ends at the end
+// of the original slice.
+// If the target was an emptry slice / string - returns the entire slice.
+// If the target was not found - returns empty slice.
+//
+// ----------------------------------------------------------------------------------------------------
+//
+// If you want to get length of a slice then you can simply use the len field of the struct.
+// However, if you want to know the length which respects utf-8 encoding, use:
+//
+// size_t utf8_len = ss_utf8_len(ss);
+//
+// ----------------------------------------------------------------------------------------------------
+// ===================================== END OF QUICK USAGE GUIDE =====================================
+
+#include <stddef.h>
+
+#ifndef MOSLIB_STRING_H
+#define MOSLIB_STRING_H
+
+#ifndef MOS_FORCE_PREFIXES
+
+#define StringSlice MosStringSlice
+#define ss_from_str mos_ss_from_str
+#define SS_LIT MOS_SS_LIT
+#define ss_from_arr mos_ss_from_arr
+#define ss_from_vars mos_ss_from_vars
+#define ss_print mos_ss_print
+#define SS_FMT MOS_SS_FMT
+#define SS_ARGS MOS_SS_ARGS
+#define ss_eq mos_ss_eq
+#define ss_split mos_ss_split
+#define ss_split_str mos_ss_split_str
+#define ss_split_ss mos_ss_split_ss
+#define ss_trim mos_ss_trim
+#define ss_trim_left mos_ss_trim_left
+#define ss_trim_right mos_ss_trim_right
+#define ss_starts_with mos_ss_starts_with
+#define ss_ends_with mos_ss_ends_with
+#define ss_starts_with_str mos_ss_starts_with_str
+#define ss_ends_with_str mos_ss_ends_with_str
+#define ss_find mos_ss_find
+#define ss_find_str mos_ss_find_str
+#define ss_utf8_len mos_ss_utf8_len
+
+#endif // MOS_FORCE_PREFIXES
+
+typedef struct {
+ const char *data;
+ size_t len;
+} MosStringSlice;
+
+// Create a string slice from a C string
+//
+// Arguments:
+// str
+// a C string to create a slice from
+//
+// Returns:
+// a newly created string slice
+extern MosStringSlice mos_ss_from_str(const char *str);
+
+// Create a string slice from a string literal at compile time
+//
+// Arguments:
+// lit
+// a string literal to create a slice from
+//
+// Returns:
+// a newly created string slice
+#define MOS_SS_LIT(lit) (MosStringSlice){.data = (lit), .len = sizeof(lit) - 1}
+
+// Create a string slice from this lib's dynamic array implementation
+//
+// Arguments:
+// arr
+// dynamic array of characters
+//
+// Returns:
+// a newly created string slice
+extern MosStringSlice mos_ss_from_arr(char *arr);
+
+// Create a string slice from two variables representing it
+//
+// Arguments:
+// str
+// pointer to the beginning of a slice
+//
+// len
+// length of the slice
+//
+// Returns:
+// a newly created string slice
+extern MosStringSlice mos_ss_from_vars(const char *str, size_t len);
+
+// Print a slice to stdout without the trailing new line
+//
+// Arguments:
+// ss
+// a slice to print
+extern void mos_ss_print(MosStringSlice ss);
+
+// Format specifier for printing a slice
+#define MOS_SS_FMT "%.*s"
+
+// Argument list to use with the format specifier
+#define MOS_SS_ARGS(ss) (int)(ss).len, (ss).data
+
+// Check if two slices are equal
+//
+// Arguments:
+// ss1
+// first slice to compare
+//
+// ss2
+// second slice to compare
+//
+// Returns:
+// 1 if slices are equal, 0 otherwise
+extern int mos_ss_eq(MosStringSlice ss1, MosStringSlice ss2);
+
+// Split a slice by a character delimiter
+// If the delimiter is not found - treats the end of the slice as the delimiter
+//
+// Arguments:
+// ss
+// pointer to the slice to split
+// will be modified in place to contain everything after the delimiter
+//
+// delim
+// the delimiter to split by
+//
+// Returns:
+// a slice containing everything before the delimiter
+extern MosStringSlice mos_ss_split(MosStringSlice *ss, char delim);
+
+// Split a slice by a C string delimiter
+// If the delimiter is not found or is an empty string - treats the end of the slice as the delimiter
+//
+// Arguments:
+// ss
+// pointer to the slice to split
+// will be modified in place to contain everything after the delimiter
+//
+// delim
+// the delimiter to split by
+//
+// Returns:
+// a slice containing everything before the delimiter
+extern MosStringSlice mos_ss_split_str(MosStringSlice *ss, const char *delim);
+
+// Split a slice by a slice delimiter
+// If the delimiter is not found or is an empty slice - treats the end of the slice as the delimiter
+//
+// Arguments:
+// ss
+// pointer to the slice to split
+// will be modified in place to contain everything after the delimiter
+//
+// delim
+// the delimiter to split by
+//
+// Returns:
+// a slice containing everything before the delimiter
+extern MosStringSlice mos_ss_split_ss(MosStringSlice *ss, MosStringSlice delim);
+
+// Time a slice of white space from both the left and the right side
+//
+// Arguments:
+// ss
+// slice to trim
+//
+// Returns:
+// a trimmed slice
+extern MosStringSlice mos_ss_trim(MosStringSlice ss);
+
+// Time a slice of white space from the left side
+//
+// Arguments:
+// ss
+// slice to trim
+//
+// Returns:
+// a trimmed slice
+extern MosStringSlice mos_ss_trim_left(MosStringSlice ss);
+
+// Time a slice of white space from the right side
+//
+// Arguments:
+// ss
+// slice to trim
+//
+// Returns:
+// a trimmed slice
+extern MosStringSlice mos_ss_trim_right(MosStringSlice ss);
+
+// Check whether a slice starts with a given slice prefix
+//
+// Arguments:
+// ss
+// slice to check if it starts with the prefix
+//
+// prefix
+// expected prefix of the slice
+//
+// Returns:
+// 1 if the slice starts with the prefix, 0 otherwise
+extern int mos_ss_starts_with(MosStringSlice ss, MosStringSlice prefix);
+
+// Check whether a slice ends with a given slice suffix
+//
+// Arguments:
+// ss
+// slice to check if it ends with the suffix
+//
+// suffix
+// expected suffix of the slice
+//
+// Returns:
+// 1 if the slice ends with the suffix, 0 otherwise
+extern int mos_ss_ends_with(MosStringSlice ss, MosStringSlice suffix);
+
+// Check whether a slice starts with a given C string prefix
+//
+// Arguments:
+// ss
+// slice to check if it starts with the prefix
+//
+// prefix
+// expected prefix of the slice
+//
+// Returns:
+// 1 if the slice starts with the prefix, 0 otherwise
+extern int mos_ss_starts_with_str(MosStringSlice ss, const char *prefix);
+
+// Check whether a slice ends with a given C string suffix
+//
+// Arguments:
+// ss
+// slice to check if it ends with the suffix
+//
+// suffix
+// expected suffix of the slice
+//
+// Returns:
+// 1 if the slice ends with the suffix, 0 otherwise
+extern int mos_ss_ends_with_str(MosStringSlice ss, const char *suffix);
+
+// Find the given slice target inside a slice
+//
+// Arguments:
+// ss
+// slice to find the target in
+//
+// target
+// target to find
+//
+// Returns:
+// a slice starting at target and ending in the same place as the original,
+// the entire slice - if the target was an empty slice,
+// an empty slice - if the target was not found
+extern MosStringSlice mos_ss_find(MosStringSlice ss, MosStringSlice target);
+
+// Find the given C string target inside a slice
+//
+// Arguments:
+// ss
+// slice to find the target in
+//
+// target
+// target to find
+//
+// Returns:
+// a slice starting at target and ending in the same place as the original,
+// the entire slice - if the target was an empty string,
+// an empty slice - if the target was not found
+extern MosStringSlice mos_ss_find_str(MosStringSlice ss, const char *target);
+
+// Get the length of the slice with respect to the utf-8 encoding
+//
+// Arguments:
+// ss
+// slice to get the utf-8 length of
+//
+// Returns:
+// utf-8 length
+extern size_t mos_ss_utf8_len(MosStringSlice ss);
+
+#endif // MOSLIB_MEM_ALLOC_H
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..e81b4a3
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,73 @@
+#define MOS_FORCE_PREFIXES
+#include "moslib/string.h"
+
+MosStringSlice mos_ss_from_str(const char *str) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_from_arr(char *arr) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_from_vars(const char *str, size_t len) {
+ return (MosStringSlice){0};
+}
+
+void mos_ss_print(MosStringSlice ss) {
+}
+
+int mos_ss_eq(MosStringSlice ss1, MosStringSlice ss2) {
+ return 0;
+}
+
+MosStringSlice mos_ss_split(MosStringSlice *ss, char delim) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_split_str(MosStringSlice *ss, const char *delim) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_split_ss(MosStringSlice *ss, MosStringSlice delim) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_trim(MosStringSlice ss) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_trim_left(MosStringSlice ss) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_trim_right(MosStringSlice ss) {
+ return (MosStringSlice){0};
+}
+
+int mos_ss_starts_with(MosStringSlice ss, MosStringSlice prefix) {
+ return 0;
+}
+
+int mos_ss_ends_with(MosStringSlice ss, MosStringSlice suffix) {
+ return 0;
+}
+
+int mos_ss_starts_with_str(MosStringSlice ss, const char *prefix) {
+ return 0;
+}
+
+int mos_ss_ends_with_str(MosStringSlice ss, const char *suffix) {
+ return 0;
+}
+
+MosStringSlice mos_ss_find(MosStringSlice ss, MosStringSlice target) {
+ return (MosStringSlice){0};
+}
+
+MosStringSlice mos_ss_find_str(MosStringSlice ss, const char *target) {
+ return (MosStringSlice){0};
+}
+
+size_t mos_ss_utf8_len(MosStringSlice ss) {
+ return 0;
+}
diff --git a/tests/string_tests.c b/tests/string_tests.c
new file mode 100644
index 0000000..c1afd4f
--- /dev/null
+++ b/tests/string_tests.c
@@ -0,0 +1,46 @@
+#include "string_tests.h"
+#include "moslib/string.h"
+
+Test creating() {
+ test_assert(0, "TODO");
+}
+
+Test printing() {
+ test_assert(0, "TODO");
+}
+
+Test comparing() {
+ test_assert(0, "TODO");
+}
+
+Test splitting() {
+ test_assert(0, "TODO");
+}
+
+Test trimming() {
+ test_assert(0, "TODO");
+}
+
+Test prefix_suffix() {
+ test_assert(0, "TODO");
+}
+
+Test finding() {
+ test_assert(0, "TODO");
+}
+
+Test utf8_len_test() {
+ test_assert(0, "TODO");
+}
+
+void string_tests(Tester *tester) {
+ TestGroup *group = add_test_group(tester, "moslib/string.h");
+ add_test(group, creating);
+ add_test(group, printing);
+ add_test(group, comparing);
+ add_test(group, splitting);
+ add_test(group, trimming);
+ add_test(group, prefix_suffix);
+ add_test(group, finding);
+ add_test(group, utf8_len_test);
+}
diff --git a/tests/string_tests.h b/tests/string_tests.h
new file mode 100644
index 0000000..901c134
--- /dev/null
+++ b/tests/string_tests.h
@@ -0,0 +1,3 @@
+#include <moslib/tester.h>
+
+extern void string_tests(Tester *tester);
diff --git a/tests/tests.c b/tests/tests.c
index 7846d91..378daf6 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -2,12 +2,14 @@
#include "ds/array_tests.h"
#include "mem/alloc_tests.h"
+#include "string_tests.h"
int main(void) {
Tester *tester = new_tester();
mem_alloc_tests(tester);
ds_array_tests(tester);
+ string_tests(tester);
run_tests(tester);
free_tester(tester);