diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/moslib.h | 1 | ||||
| -rw-r--r-- | include/moslib/string.h | 386 |
2 files changed, 387 insertions, 0 deletions
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 |
