From 8079c736b44470c3b66e2d084cd2367203632d98 Mon Sep 17 00:00:00 2001 From: Tobin Cavanaugh Date: Tue, 28 May 2024 12:15:58 -0700 Subject: [PATCH] Starts with, printing as binary, printing as num --- fstr.c | 749 ++++++++++++++++++++++++++++++++----------------- fstr.h | 143 ++++++---- fstr_convert.c | 55 ++-- fstr_convert.h | 28 ++ main.c | 20 ++ 5 files changed, 663 insertions(+), 332 deletions(-) diff --git a/fstr.c b/fstr.c index 1d02513..dd5a1ee 100644 --- a/fstr.c +++ b/fstr.c @@ -20,40 +20,46 @@ //Internal function prototypes #pragma region PROTOTYPES -void internal_fstr_insert(fstr *str, uintptr_t index, const char *add, uintptr_t addLen); +void internal_fstr_insert(fstr* str, uintptr_t index, const char* add, uintptr_t addLen); -void internal_remove_buf(fstr *str, const char *removeBuf, const usize removeLen); +void internal_remove_buf(fstr* str, const char* removeBuf, const usize removeLen); #pragma endregion PROTOTYPES -void internal_memmove(void *destination, void *source, size_t len) { +void internal_memmove(void* destination, void* source, size_t len) +{ //Pointer to our destination - char *dest = destination; + char* dest = destination; //Pointer to our source - char *src = source; + char* src = source; //If our destination is to the left of our source, i.e. no chance of overlap - if (dest < src) { + if (dest < src) + { memcpy(destination, source, len); - } else { + } + else + { //Get the last source and destination characters - char *lastSrc = src + (len - 1); - char *lastDest = dest + (len - 1); + char* lastSrc = src + (len - 1); + char* lastDest = dest + (len - 1); //Batch with 2 bytes, we could definitely do more, see internal_memcpy - while (len >= sizeof(uint16_t)) { - char *chunkSrc = src + (len - sizeof(uint16_t)); - char *chunkDest = src + (len - sizeof(uint16_t)); + while (len >= sizeof(uint16_t)) + { + char* chunkSrc = src + (len - sizeof(uint16_t)); + char* chunkDest = src + (len - sizeof(uint16_t)); - *((uint16_t *) chunkDest) = *((uint16_t *) chunkSrc); + *((uint16_t*)chunkDest) = *((uint16_t*)chunkSrc); len -= sizeof(uint16_t); } //Go through our whole length - while (len--) { + while (len--) + { //Set the corresponding src character in the dest *lastDest = *lastSrc; *lastDest--; @@ -62,7 +68,8 @@ void internal_memmove(void *destination, void *source, size_t len) { } } -usize fstr_length(const fstr *str) { +usize fstr_length(const fstr* str) +{ usize diff = ((as_ptr(str->end) - as_ptr(str->data)) / sizeof(chr)); return diff; } @@ -70,7 +77,8 @@ usize fstr_length(const fstr *str) { /// Sets the end pointer of the fstr /// \param str /// \param newLength -void internal_fstr_set_end(fstr *str, usize newLength) { +void internal_fstr_set_end(fstr* str, usize newLength) +{ //Set the end to the address last indexed character of the string str->end = as_ptr(&str->data[newLength]); } @@ -78,12 +86,17 @@ void internal_fstr_set_end(fstr *str, usize newLength) { /// Custom String Length function /// \param buf The string to check /// \return The length of the string, NOT including the null terminator -usize internal_C_string_length(const chr *buf) { - if (USING_WCHAR) { +usize internal_C_string_length(const chr* buf) +{ + if (USING_WCHAR) + { return wcslen(buf); - } else { + } + else + { usize i = 0; - while (buf[i] != '\0') { + while (buf[i] != '\0') + { i++; } @@ -91,42 +104,50 @@ usize internal_C_string_length(const chr *buf) { } } -fstr *fstr_copy(const fstr *str) { +fstr* fstr_copy(const fstr* str) +{ usize len = fstr_length(str); - fstr *new = fstr_from_length(len, '!'); + fstr* new = fstr_from_length(len, '!'); memcpy(new->data, str->data, len * sizeof(chr)); return new; } -void fstr_replace_chr(fstr *str, const chr from, const chr to) { +void fstr_replace_chr(fstr* str, const chr from, const chr to) +{ usize len = fstr_length(str); usize i; - for (i = 0; i < len; i++) { - if (str->data[i] == from) { + for (i = 0; i < len; i++) + { + if (str->data[i] == from) + { str->data[i] = to; } } } -void fstr_remove_at(fstr *str, const usize index, usize length) { - +void fstr_remove_at(fstr* str, const usize index, usize length) +{ usize startLen = fstr_length(str); - if (startLen == 0) { + if (startLen == 0) + { return; } - if (index >= startLen) { + if (index >= startLen) + { str->error = STR_ERR_IndexOutOfBounds; return; } - while (index + length > startLen) { + while (index + length > startLen) + { length--; - if (length == 0) { + if (length == 0) + { str->error = STR_ERR_IndexOutOfBounds; return; } @@ -142,7 +163,7 @@ void fstr_remove_at(fstr *str, const usize index, usize length) { } */ -// internal_memmove(str->data + index, str->data + index + length, (startLen - index - length) * sizeof(chr)); + // internal_memmove(str->data + index, str->data + index + length, (startLen - index - length) * sizeof(chr)); memmove(str->data + index, str->data + index + length, (startLen - index - length) * sizeof(chr)); str->data = realloc(str->data, (startLen - length) * sizeof(chr)); @@ -150,30 +171,38 @@ void fstr_remove_at(fstr *str, const usize index, usize length) { internal_fstr_set_end(str, startLen - length); //MEMCPY approach will not work due to overlapping buffers :( -// memcpy(str->data + index, str->data + index + length, length); -// str->data = realloc(str->data, (startLen - length) * sizeof(chr)); -// internal_fstr_set_end(str, startLen - length); + // memcpy(str->data + index, str->data + index + length, length); + // str->data = realloc(str->data, (startLen - length) * sizeof(chr)); + // internal_fstr_set_end(str, startLen - length); -// str->data = realloc(str->data, k * sizeof(chr)); -// internal_fstr_set_end(str, k); + // str->data = realloc(str->data, k * sizeof(chr)); + // internal_fstr_set_end(str, k); } -void internal_compute_index_of_lps(const char *patBuf, int M, int *lps) { +void internal_compute_index_of_lps(const char* patBuf, int M, int* lps) +{ usize len = 0; usize i = 1; lps[0] = 0; - while (i < M) { - if (patBuf[i] == patBuf[len]) { + while (i < M) + { + if (patBuf[i] == patBuf[len]) + { len++; - lps[i] = (int) len; + lps[i] = (int)len; i++; - } else { - if (len != 0) { + } + else + { + if (len != 0) + { len = lps[len - 1]; - } else { - lps[i] = (int) len; + } + else + { + lps[i] = (int)len; i++; } } @@ -185,7 +214,8 @@ void internal_compute_index_of_lps(const char *patBuf, int M, int *lps) { /// \param buf The buffer to check for /// \param bufLen The length of the buffer /// \return The result with the index in u_val -fstr_result internal_index_of_sub(const fstr *str, const char *buf, const usize bufLen) { +fstr_result internal_index_of_sub(const fstr* str, const char* buf, const usize bufLen) +{ //Tried implementing KMP & BM, both saw worse performance than my brute //force optimized version. Brute force with memcmp seems like it might //be as good as it gets but i'm really not sure... Currently we are getting @@ -193,25 +223,29 @@ fstr_result internal_index_of_sub(const fstr *str, const char *buf, const usize usize strlen = fstr_length(str); - if (bufLen > strlen) { + if (bufLen > strlen) + { return FAILURE; } usize gi; - for (gi = 0; gi < strlen; gi++) { + for (gi = 0; gi < strlen; gi++) + { //Check that our data is within the string. i h - if (str->data + gi <= str->end) { + if (str->data + gi <= str->end) + { //Do the comparison -// if (internal_memeq(str->data + gi, buf, bufLen)) { -// fstr_result res = (fstr_result) {1}; -// res.u_val = gi; -// return res; -// } + // if (internal_memeq(str->data + gi, buf, bufLen)) { + // fstr_result res = (fstr_result) {1}; + // res.u_val = gi; + // return res; + // } //Huge win for memcmp int x = memcmp(str->data + gi, buf, bufLen); - if (x != -1 && x < bufLen) { - fstr_result res = (fstr_result) {1}; + if (x != -1 && x < bufLen) + { + fstr_result res = (fstr_result){1}; res.u_val = gi + x; return res; } @@ -222,12 +256,14 @@ fstr_result internal_index_of_sub(const fstr *str, const char *buf, const usize } -fstr_result fstr_index_of_C(const fstr *str, char *sub) { +fstr_result fstr_index_of_C(const fstr* str, char* sub) +{ return internal_index_of_sub(str, sub, internal_C_string_length(sub)); } -fstr_result fstr_index_of(const fstr *str, const fstr *sub) { +fstr_result fstr_index_of(const fstr* str, const fstr* sub) +{ return internal_index_of_sub(str, sub->data, fstr_length(sub)); } @@ -238,10 +274,11 @@ fstr_result fstr_index_of(const fstr *str, const fstr *sub) { /// \param start The starting index /// \param length The length of the slice to take /// \return The slice which contains a pointer to the strs data -fstr internal_slice(fstr *str, uintptr_t start, uintptr_t length) { - fstr res = (fstr) {0}; +fstr internal_slice(fstr* str, uintptr_t start, uintptr_t length) +{ + fstr res = (fstr){0}; res.data = str->data + start; - res.end = (usize) (str->data + start + length); + res.end = (usize)(str->data + start + length); return res; } @@ -251,11 +288,12 @@ fstr internal_slice(fstr *str, uintptr_t start, uintptr_t length) { /// \param oldLen The length of the old buffer /// \param newBuf The new buffer to replace the old /// \param newLen The length of the new buffer -void internal_replace_sub(fstr *str, - const chr *oldBuf, const usize oldLen, - const chr *newBuf, const usize newLen) { - - if (newLen == 0) { +void internal_replace_sub(fstr* str, + const chr* oldBuf, const usize oldLen, + const chr* newBuf, const usize newLen) +{ + if (newLen == 0) + { internal_remove_buf(str, oldBuf, oldLen); return; } @@ -272,30 +310,32 @@ void internal_replace_sub(fstr *str, //Iterate our string u8 contains = 1; - while (contains) { - + while (contains) + { //Get the index of our substring (if it exists) fstr_result res = internal_index_of_sub(&slice, oldBuf, oldLen); contains = res.success; usize index = res.u_val; //If we dont contain our substring, we're doneF - if (!contains) { + if (!contains) + { break; } //Get the distance between our slice start and our string start as the offset offset = (as_ptr(slice.data) - as_ptr(str->data)); - if (newLen == oldLen) { + if (newLen == oldLen) + { //Basic copy all the data we can. This is fast AF, and we are //limited by having to expand and shrink the string. -// memcpy(str->data + index + offset, newBuf, newLen); + // memcpy(str->data + index + offset, newBuf, newLen); memcpy(str->data + index + offset, newBuf, newLen); removed++; - - } else if (newLen < oldLen) { - + } + else if (newLen < oldLen) + { //Copy in the data memcpy(str->data + index + offset, newBuf, newLen); @@ -306,8 +346,10 @@ void internal_replace_sub(fstr *str, internal_fstr_set_end(str, presize - (oldLen - newLen)); removed++; -// memmove(str->data + index + offset + newLen, str->data + index + offset + oldLen, ); - } else { + // memmove(str->data + index + offset + newLen, str->data + index + offset + oldLen, ); + } + else + { //TODO Do custom implementation of insert and remove for better performance fstr_remove_at(str, index + offset, oldLen); internal_fstr_insert(str, index + offset, newBuf, newLen); @@ -315,68 +357,78 @@ void internal_replace_sub(fstr *str, } //Remove the substring and replace it -// fstr_remove_at(str->data + i, index + offset + i, oldLen - i); -// internal_fstr_insert(str->data + i, index + offset + i, newBuf + i, newLen - i); + // fstr_remove_at(str->data + i, index + offset + i, oldLen - i); + // internal_fstr_insert(str->data + i, index + offset + i, newBuf + i, newLen - i); //Update the end of our slice slice.data = str->data + offset + newLen; slice.end = str->end; //Do a check to see if we are out of string bounds - if (slice.data > slice.end) { + if (slice.data > slice.end) + { contains = 0; } } - if (removed > 0) { - usize size = initialSize - (removed * llabs((int64_t) newLen - (int64_t) oldLen)); + if (removed > 0) + { + usize size = initialSize - (removed * llabs((int64_t)newLen - (int64_t)oldLen)); str->data = realloc(str->data, size); internal_fstr_set_end(str, size); } } -void fstr_replace_C(const fstr *str, const chr *oldBuf, const chr *newBuf) { +void fstr_replace_C(const fstr* str, const chr* oldBuf, const chr* newBuf) +{ internal_replace_sub(str, oldBuf, internal_C_string_length(oldBuf), newBuf, internal_C_string_length(newBuf)); } -void fstr_replace(const fstr *str, const fstr *oldBuf, const fstr *newBuf) { +void fstr_replace(const fstr* str, const fstr* oldBuf, const fstr* newBuf) +{ internal_replace_sub(str, oldBuf->data, fstr_length(oldBuf), newBuf->data, fstr_length(newBuf)); } -void internal_remove_buf(fstr *str, const char *removeBuf, const usize removeLen) { +void internal_remove_buf(fstr* str, const char* removeBuf, const usize removeLen) +{ usize len = fstr_length(str); usize secondary = 0; //TODO I wonder if theres a way to remove the alloc... //I'm too silly rn to be able to figure it out, but TBH we should be able to just shift our 'i' condition back the length of the remove length, and decrease our len //We can also do this non iteratively with memcpy and stuff, but I'm not too worried if this is a bit slow - fstr *copy = fstr_copy(str); + fstr* copy = fstr_copy(str); usize i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { u8 found = 1; //Check for the non-existence of the substring removeBuf usize c; - for (c = 0; c < removeLen; c++) { + for (c = 0; c < removeLen; c++) + { //Do an OOB check, Do char comparison - if ((i + c) >= len || copy->data[c + i] != removeBuf[c]) { + if ((i + c) >= len || copy->data[c + i] != removeBuf[c]) + { found = 0; break; } } //Skip over the stuff we don't want to include - if (found) { + if (found) + { i += removeLen - 1; } - //Place our characters into our str - else { + //Place our characters into our str + else + { str->data[secondary] = copy->data[i]; secondary++; } @@ -388,20 +440,24 @@ void internal_remove_buf(fstr *str, const char *removeBuf, const usize removeLen } -void fstr_remove(const fstr *str, const fstr *buf) { +void fstr_remove(const fstr* str, const fstr* buf) +{ internal_remove_buf(str, buf->data, fstr_length(buf)); } -void fstr_remove_C(const fstr *str, const chr *buf) { +void fstr_remove_C(const fstr* str, const chr* buf) +{ internal_remove_buf(str, buf, internal_C_string_length(buf)); } -void fstr_append_chr(fstr *str, const chr c) { +void fstr_append_chr(fstr* str, const chr c) +{ usize len = fstr_length(str); str->data = realloc(str->data, (len + 1) * sizeof(chr)); //Return an error if alloc fails - if (str->data == NULL) { + if (str->data == NULL) + { str->error = STR_ERR_ReallocFailed; return; } @@ -410,26 +466,31 @@ void fstr_append_chr(fstr *str, const chr c) { internal_fstr_set_end(str, len + 1); } -void fstr_remove_chr_varargs(fstr *str, u8 num_chars, ...) { +void fstr_remove_chr_varargs(fstr* str, u8 num_chars, ...) +{ va_list args; va_start(args, num_chars); usize i; - for (i = 0; i < num_chars; i++) { - fstr_remove_chr(str, (chr) va_arg(args, int)); + for (i = 0; i < num_chars; i++) + { + fstr_remove_chr(str, (chr)va_arg(args, int)); } va_end(args); } -void fstr_remove_chr(fstr *str, const chr c) { +void fstr_remove_chr(fstr* str, const chr c) +{ usize len = fstr_length(str); usize secondary = 0; usize primary; //Iterate our string and place our non-c strings into our same string in order - for (primary = 0; primary < len; primary++) { - if (str->data[primary] != c) { + for (primary = 0; primary < len; primary++) + { + if (str->data[primary] != c) + { str->data[secondary] = str->data[primary]; secondary++; } @@ -441,22 +502,26 @@ void fstr_remove_chr(fstr *str, const chr c) { } -usize fstr_count_internal(const fstr *str, const chr *sub, usize subLength) { +usize internal_fstr_count(const fstr* str, const chr* sub, usize subLength) +{ usize count = 0; fstr slice = *str; - while (1) { + while (1) + { fstr_result res = internal_index_of_sub(&slice, sub, subLength); - if (!res.success) { + if (!res.success) + { break; } count++; slice.data += res.u_val + subLength; - if (slice.data > slice.end) { + if (slice.data > slice.end) + { break; } } @@ -465,22 +530,27 @@ usize fstr_count_internal(const fstr *str, const chr *sub, usize subLength) { } -usize fstr_count_C(const fstr *str, const char *sub) { - return fstr_count_internal(str, sub, internal_C_string_length(sub)); +usize fstr_count_C(const fstr* str, const char* sub) +{ + return internal_fstr_count(str, sub, internal_C_string_length(sub)); } -usize fstr_count(const fstr *str, const fstr *sub) { - return fstr_count_internal(str, sub->data, fstr_length(sub)); +usize fstr_count(const fstr* str, const fstr* sub) +{ + return internal_fstr_count(str, sub->data, fstr_length(sub)); } -usize fstr_count_chr(const fstr *str, const chr value) { +usize fstr_count_chr(const fstr* str, const chr value) +{ usize len = fstr_length(str); usize count = 0; usize i; - for (i = 0; i < len; i++) { - if (str->data[i] == value) { + for (i = 0; i < len; i++) + { + if (str->data[i] == value) + { count++; } } @@ -488,29 +558,33 @@ usize fstr_count_chr(const fstr *str, const chr value) { } -fstr_result fstr_index_of_chr(fstr *str, char c) { +fstr_result fstr_index_of_chr(fstr* str, char c) +{ usize i; usize len = fstr_length(str); - for (i = 0; i < len; i++) { - if (str->data[i] == c) { - return (fstr_result) {1, i}; + for (i = 0; i < len; i++) + { + if (str->data[i] == c) + { + return (fstr_result){1, i}; } } return FAILURE; } -fstr *fstr_substr(fstr *str, usize start, usize length) { - +fstr* fstr_substr(fstr* str, usize start, usize length) +{ usize len = fstr_length(str); - if (start >= len) { + if (start >= len) + { str->error = STR_ERR_IndexOutOfBounds; return fstr_from_C(""); } //Create our dummy string - fstr *sub = fstr_from_length(length, '!'); + fstr* sub = fstr_from_length(length, '!'); //Copy the memory over from our start string memcpy(sub->data, str->data + start, length * sizeof(chr)); @@ -520,9 +594,11 @@ fstr *fstr_substr(fstr *str, usize start, usize length) { return sub; } -void fstr_set_chr(fstr *str, usize index, chr c) { +void fstr_set_chr(fstr* str, usize index, chr c) +{ usize len = fstr_length(str); - if (index >= len) { + if (index >= len) + { str->error = STR_ERR_IndexOutOfBounds; return; } @@ -530,13 +606,13 @@ void fstr_set_chr(fstr *str, usize index, chr c) { str->data[index] = c; } -fstr *fstr_from_C(const chr *buf) { - +fstr* fstr_from_C(const chr* buf) +{ //Calculate the size of our buffer usize bufSize = internal_C_string_length(buf) * sizeof(chr); //Malloc our struct - fstr *str = malloc(sizeof(fstr)); + fstr* str = malloc(sizeof(fstr)); //Malloc our data str->data = malloc(bufSize); @@ -554,8 +630,10 @@ fstr *fstr_from_C(const chr *buf) { } -u8 internal_validate_fstr(fstr *str) { - if (as_ptr(str->data) > str->end) { +u8 internal_validate_fstr(fstr* str) +{ + if (as_ptr(str->data) > str->end) + { str->error = STR_ERR_INCORRECT_CHAR_POINTER; return 0; } @@ -563,79 +641,143 @@ u8 internal_validate_fstr(fstr *str) { return 1; } -void fstr_free(fstr *str) { - if (str != NULL) { - if (str->data != NULL) { +void fstr_free(fstr* str) +{ + if (str != NULL) + { + if (str->data != NULL) + { free(str->data); } free(str); } } -void internal_print_chr(const chr *format, const chr printChr) { - if (USING_WCHAR) { +void internal_print_chr(const chr* format, const chr printChr) +{ + if (USING_WCHAR) + { wprintf(format, printChr); - } else if (USING_CHAR) { + } + else if (USING_CHAR) + { printf(format, printChr); } } -void fstr_print_chrs(const fstr *str) { - if (USING_CHAR) { +void fstr_print_chrs(const fstr* str) +{ + if (USING_CHAR) + { usize i; usize len = fstr_length(str); - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { internal_print_chr("%c", str->data[i]); } } } -void fstr_print_chrs_f(const fstr *str, const chr *format) { +void fstr_print_chrs_f(const fstr* str, const chr* format) +{ usize i; usize len = fstr_length(str); - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { internal_print_chr(format, str->data[i]); } } -void fstr_print(const fstr *str) { - if (str == NULL) { +void fstr_print(const fstr* str) +{ + if (str == NULL) + { return; } - if (USING_CHAR) { + if (USING_CHAR) + { usize len = fstr_length(str); fwrite(str->data, sizeof(chr), len, stdout); - } else if (USING_WCHAR) { + } + else if (USING_WCHAR) + { wprintf(L"%ls", str->data); } } -void fstr_println(const fstr *str) { +void fstr_println(const fstr* str) +{ fstr_print(str); - if (USING_CHAR) { + if (USING_CHAR) + { fwrite("\n", sizeof(chr), 1, stdout); - } else if (USING_WCHAR) { + } + else if (USING_WCHAR) + { wprintf(L"\n"); } } -void fstr_print_hex(const fstr *str) { +void fstr_print_hex(const fstr* str) +{ usize len = fstr_length(str); usize i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { printf("0x%x ", str->data[i]); } } -char *fstr_as_C_heap(const fstr *from) { +void fstr_print_num(const fstr* str) +{ + usize len = fstr_length(str); + usize i = 0; + for (; i < len; i++) + { + printf("%d ", str->data[i]); + } +} + +/// From William Whyte on stackoverflow +/// https://stackoverflow.com/a/3208376/21769995 +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + ((byte) & 0x80 ? '1' : '0'), \ + ((byte) & 0x40 ? '1' : '0'), \ + ((byte) & 0x20 ? '1' : '0'), \ + ((byte) & 0x10 ? '1' : '0'), \ + ((byte) & 0x08 ? '1' : '0'), \ + ((byte) & 0x04 ? '1' : '0'), \ + ((byte) & 0x02 ? '1' : '0'), \ + ((byte) & 0x01 ? '1' : '0') + +void internal_fstr_print_bin(void* data, usize len) +{ + fstr* str = fstr_from_C(""); + + usize i = 0; + + for (; i < len; i++) + { + printf(BYTE_TO_BINARY_PATTERN" ", BYTE_TO_BINARY((chr)(data + i))); + } +} + +void fstr_print_bin(fstr* str) +{ + internal_fstr_print_bin(str->data, fstr_length(str)); +} + +char* fstr_as_C_heap(const fstr* from) +{ //Get the length of our from string usize len = fstr_length(from); //Allocate our new memory, plus one on length for the null terminator - char *toStr = calloc(len + 1, sizeof(char)); + char* toStr = calloc(len + 1, sizeof(char)); //Copy our source data over memcpy(toStr, from->data, len * sizeof(chr)); @@ -646,9 +788,10 @@ char *fstr_as_C_heap(const fstr *from) { return toStr; } -void fstr_append(fstr *str, const fstr *buf) { - - if (buf == NULL) { +void fstr_append(fstr* str, const fstr* buf) +{ + if (buf == NULL) + { str->error = STR_ERR_NullStringArg; return; } @@ -658,7 +801,8 @@ void fstr_append(fstr *str, const fstr *buf) { usize bufLength = fstr_length(buf); usize newLength = startLength + bufLength; - if (newLength == 0) { + if (newLength == 0) + { return; } @@ -666,7 +810,8 @@ void fstr_append(fstr *str, const fstr *buf) { str->data = realloc(str->data, newLength * sizeof(chr)); //Return an error if alloc fails - if (str->data == NULL) { + if (str->data == NULL) + { str->error = STR_ERR_ReallocFailed; return; } @@ -678,9 +823,10 @@ void fstr_append(fstr *str, const fstr *buf) { internal_fstr_set_end(str, newLength); } -void fstr_append_C(fstr *str, const chr *buf) { - - if (buf == NULL) { +void fstr_append_C(fstr* str, const chr* buf) +{ + if (buf == NULL) + { str->error = STR_ERR_NullStringArg; return; } @@ -694,7 +840,8 @@ void fstr_append_C(fstr *str, const chr *buf) { str->data = realloc(str->data, newLen * sizeof(chr)); //Return an error if realloc fails - if (str->data == NULL) { + if (str->data == NULL) + { str->error = STR_ERR_ReallocFailed; return; } @@ -706,15 +853,16 @@ void fstr_append_C(fstr *str, const chr *buf) { internal_fstr_set_end(str, newLen); } -fstr *fstr_from_length(usize length, const chr fill) { - +fstr* fstr_from_length(usize length, const chr fill) +{ //Error check - if (length <= 0) { + if (length <= 0) + { return fstr_from_C(""); } //Create our string - fstr *str = fstr_from_C(""); + fstr* str = fstr_from_C(""); //Malloc new string data with the correct size str->data = malloc(length * sizeof(chr)); @@ -726,22 +874,24 @@ fstr *fstr_from_length(usize length, const chr fill) { memset(str->data, fill, length * sizeof(chr)); //Set the end pointer to the last character of our stringF -// str->end = as_ptr(&str->data[length]); + // str->end = as_ptr(&str->data[length]); internal_fstr_set_end(str, length); return str; } -void fstr_terminate(fstr *str, chr c) { +void fstr_terminate(fstr* str, chr c) +{ fstr_result res = fstr_index_of_chr(str, c); - if (res.success) { + if (res.success) + { str->data = realloc(str->data, res.u_val * sizeof(str)); internal_fstr_set_end(str, res.u_val); } } -fstr *fstr_from_format_C(const char *format, ...) { - +fstr* fstr_from_format_C(const char* format, ...) +{ //Varargs stuff va_list args; va_start(args, format); @@ -751,7 +901,7 @@ fstr *fstr_from_format_C(const char *format, ...) { //Create the new string, we divide by sizeof chr in case chars are bigger //TODO This divide could be wrong - fstr *str = fstr_from_length(size / sizeof(chr), '!'); + fstr* str = fstr_from_length(size / sizeof(chr), '!'); //Write the varargs to the string with the proper format vsprintf(str->data, format, args); @@ -761,9 +911,10 @@ fstr *fstr_from_format_C(const char *format, ...) { return str; } -void fstr_append_format_C(fstr *str, const char *format, ...) { - - if (format == NULL) { +void fstr_append_format_C(fstr* str, const char* format, ...) +{ + if (format == NULL) + { str->error = STR_ERR_NullStringArg; return; } @@ -780,7 +931,8 @@ void fstr_append_format_C(fstr *str, const char *format, ...) { str->data = realloc(str->data, (finalSize + 1) * sizeof(chr)); //Return an error if alloc fails - if (str->data == NULL) { + if (str->data == NULL) + { str->error = STR_ERR_ReallocFailed; return; } @@ -794,15 +946,16 @@ void fstr_append_format_C(fstr *str, const char *format, ...) { va_end(args); } -void internal_fstr_overwrite(fstr *str, usize index, char *buf, usize bufLen) { - +void internal_fstr_overwrite(fstr* str, usize index, char* buf, usize bufLen) +{ usize strlen = fstr_length(str); usize finalSize = MAX(strlen, bufLen + index); - if (finalSize > strlen) { + if (finalSize > strlen) + { str->data = realloc(str->data, finalSize * sizeof(chr)); -// memset(str->data + index, '1', finalSize - index); + // memset(str->data + index, '1', finalSize - index); memset(str->data + strlen, ' ', finalSize - strlen); } @@ -811,15 +964,18 @@ void internal_fstr_overwrite(fstr *str, usize index, char *buf, usize bufLen) { internal_fstr_set_end(str, finalSize); } -void fstr_overwrite_C(fstr *str, usize index, chr *buf) { +void fstr_overwrite_C(fstr* str, usize index, chr* buf) +{ internal_fstr_overwrite(str, index, buf, internal_C_string_length(buf)); } -void fstr_overwrite(fstr *str, usize index, fstr *buf) { +void fstr_overwrite(fstr* str, usize index, fstr* buf) +{ internal_fstr_overwrite(str, index, buf->data, fstr_length(buf)); } -void fstr_overwrite_format_C(fstr *str, usize index, chr *format, ...) { +void fstr_overwrite_format_C(fstr* str, usize index, chr* format, ...) +{ //Varargs stuff va_list args; va_start(args, format); @@ -827,14 +983,17 @@ void fstr_overwrite_format_C(fstr *str, usize index, chr *format, ...) { //Calculate the size of the buffer usize size = _vscprintf(format, args); - if (size + index < fstr_length(str)) { + if (size + index < fstr_length(str)) + { vsprintf(str->data + index, format, args); - } else { + } + else + { //Create the new string, we divide by sizeof chr in case chars are bigger //TODO This divide could be wrong //TODO Consider making this use stack allocation depending on the size of the string. MAKE SURE TO APPLY TO OTHER FORMAT FUNCTIONS //TODO We can also do this in a better way just straight up - fstr *tmp = fstr_from_length(size / sizeof(chr), '!'); + fstr* tmp = fstr_from_length(size / sizeof(chr), '!'); //Write the varargs to the string with the proper format vsprintf(tmp->data, format, args); @@ -847,16 +1006,24 @@ void fstr_overwrite_format_C(fstr *str, usize index, chr *format, ...) { va_end(args); } -chr chr_to_invert(chr a) { - if (USING_CHAR) { - if ((a >= 65 && a <= 90) || (a >= 97 && a <= 122)) { +chr chr_to_invert(chr a) +{ + if (USING_CHAR) + { + if ((a >= 65 && a <= 90) || (a >= 97 && a <= 122)) + { //This works great for well formed non ASCII extended characters - return (chr) (a ^ 0b00100000); + return (chr)(a ^ 0b00100000); } - } else if (USING_WCHAR) { - if (chr_is_lower(a)) { + } + else if (USING_WCHAR) + { + if (chr_is_lower(a)) + { return towupper(a); - } else if (chr_is_upper(a)) { + } + else if (chr_is_upper(a)) + { return towlower(a); } } @@ -864,56 +1031,70 @@ chr chr_to_invert(chr a) { return a; } -chr chr_to_lower(chr a) { - if (chr_is_upper(a)) { +chr chr_to_lower(chr a) +{ + if (chr_is_upper(a)) + { return chr_to_invert(a); } return a; } -chr chr_to_upper(chr a) { - if (chr_is_lower(a)) { +chr chr_to_upper(chr a) +{ + if (chr_is_lower(a)) + { return chr_to_invert(a); } return a; } -chr internal_chr_is_trim(chr c) { +chr internal_chr_is_trim(chr c) +{ return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'); } -void fstr_trim(fstr *str, int8_t side) { - +void fstr_trim(fstr* str, int8_t side) +{ //TODO There must be a better way to do two for loops going in counter directions with same/similar functionality //If we are trimming the left side - if (side <= 0) { - + if (side <= 0) + { usize startTrim = 0; usize i; //Go through the string, keep count of any trim characters, if theres a non trim character then we exit and cut that off - for (i = 0; i < fstr_length(str); i++) { + for (i = 0; i < fstr_length(str); i++) + { chr c = str->data[i]; - if (internal_chr_is_trim(c)) { + if (internal_chr_is_trim(c)) + { startTrim++; - } else { + } + else + { break; } } fstr_remove_at(str, 0, startTrim); } - if (side >= 0) { + if (side >= 0) + { usize endTrim = 0; usize i; //See (side <= 0) - for (i = fstr_length(str) - 1; i >= 0; i--) { + for (i = fstr_length(str) - 1; i >= 0; i--) + { chr c = str->data[i]; - if (internal_chr_is_trim(c)) { + if (internal_chr_is_trim(c)) + { endTrim++; - } else { + } + else + { break; } } @@ -923,34 +1104,41 @@ void fstr_trim(fstr *str, int8_t side) { } -void fstr_to_lower(fstr *a) { +void fstr_to_lower(fstr* a) +{ usize len = fstr_length(a); usize i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { a->data[i] = chr_to_lower(a->data[i]); } } -void fstr_to_upper(fstr *a) { +void fstr_to_upper(fstr* a) +{ usize len = fstr_length(a); usize i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { a->data[i] = chr_to_upper(a->data[i]); } } -void fstr_invertcase(fstr *a) { +void fstr_invertcase(fstr* a) +{ usize len = fstr_length(a); usize i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { chr c = a->data[i]; a->data[i] = chr_to_invert(c); } } -u8 fstr_equals(fstr *a, fstr *b) { - - if (b == NULL) { +u8 fstr_equals(fstr* a, fstr* b) +{ + if (b == NULL) + { a->error = STR_ERR_NullStringArg; return 0; } @@ -958,13 +1146,16 @@ u8 fstr_equals(fstr *a, fstr *b) { usize aLen = fstr_length(a); usize bLen = fstr_length(b); - if (aLen != bLen) { + if (aLen != bLen) + { return 0; } usize i; - for (i = 0; i < aLen; i++) { - if (a->data[i] != b->data[i]) { + for (i = 0; i < aLen; i++) + { + if (a->data[i] != b->data[i]) + { return 0; } } @@ -972,17 +1163,21 @@ u8 fstr_equals(fstr *a, fstr *b) { return 1; } -u8 fstr_equals_C(fstr *a, chr *b) { +u8 fstr_equals_C(fstr* a, chr* b) +{ usize alen = fstr_length(a); usize blen = internal_C_string_length(b); - if (alen != blen) { + if (alen != blen) + { return 0; } usize i = 0; - for (; i < alen; i++) { - if (a->data[i] != b[i]) { + for (; i < alen; i++) + { + if (a->data[i] != b[i]) + { return 0; } } @@ -991,15 +1186,18 @@ u8 fstr_equals_C(fstr *a, chr *b) { } -void fstr_reverse(fstr *str) { +void fstr_reverse(fstr* str) +{ usize len = fstr_length(str); - if (len == 0 || len == 1) { + if (len == 0 || len == 1) + { return; } //TODO Refactor fstr_reverse. It's fine but not quite clean - if (len == 2) { + if (len == 2) + { chr tmp = str->data[0]; str->data[0] = str->data[1]; str->data[1] = tmp; @@ -1009,7 +1207,8 @@ void fstr_reverse(fstr *str) { usize i = 0; usize j = len; - for (i; i < len; i++) { + for (i; i < len; i++) + { j--; chr tmp = str->data[i]; @@ -1017,13 +1216,15 @@ void fstr_reverse(fstr *str) { str->data[j] = tmp; //TODO Refactor fstr_reverse. It's fine but not quite clean - if (j == i) { + if (j == i) + { break; } } } -void fstr_clear(fstr *str) { +void fstr_clear(fstr* str) +{ free(str->data); str->data = calloc(1, sizeof(chr)); internal_fstr_set_end(str, 0); @@ -1034,16 +1235,18 @@ void fstr_clear(fstr *str) { /// \param add /// \param index /// \param addLen -void internal_fstr_insert(fstr *str, uintptr_t index, const char *add, uintptr_t addLen) { - +void internal_fstr_insert(fstr* str, uintptr_t index, const char* add, uintptr_t addLen) +{ usize startLen = fstr_length(str); usize finalLen = startLen + addLen; - if (addLen == 0) { + if (addLen == 0) + { return; } - if (index >= finalLen) { + if (index >= finalLen) + { str->error = STR_ERR_IndexOutOfBounds; return; } @@ -1051,7 +1254,8 @@ void internal_fstr_insert(fstr *str, uintptr_t index, const char *add, uintptr_t str->data = realloc(str->data, finalLen * sizeof(chr)); //Return an error if realloc fails - if (str->data == NULL) { + if (str->data == NULL) + { str->error = STR_ERR_ReallocFailed; return; } @@ -1062,29 +1266,30 @@ void internal_fstr_insert(fstr *str, uintptr_t index, const char *add, uintptr_t usize rightBufSize = (startLen - index) * sizeof(chr); //Weve gotta write into a temporary buffer cuz otherwise we end up reading then rewriting already written data - chr *tmp = malloc(rightBufSize); + chr* tmp = malloc(rightBufSize); //Write the right most data into a temporary buffer -// memcpy(tmp, str->data + index, rightBufSize); + // memcpy(tmp, str->data + index, rightBufSize); memcpy(tmp, str->data + index, rightBufSize); //Copy the right most data and place it at its ideal location, leaving //some remaining data after u_val with size of add -// memcpy(str->data + (index + addLen), tmp, rightBufSize); + // memcpy(str->data + (index + addLen), tmp, rightBufSize); memcpy(str->data + (index + addLen), tmp, rightBufSize); free(tmp); //Replace the data after u_val with the size of add with the actual add data -// memcpy(str->data + index, add, addLen * sizeof(chr)); + // memcpy(str->data + index, add, addLen * sizeof(chr)); memcpy(str->data + index, add, addLen * sizeof(chr)); internal_fstr_set_end(str, finalLen); } -void fstr_insert(fstr *str, usize index, const fstr *add) { - - if (add == NULL) { +void fstr_insert(fstr* str, usize index, const fstr* add) +{ + if (add == NULL) + { str->error = STR_ERR_NullStringArg; return; } @@ -1092,8 +1297,10 @@ void fstr_insert(fstr *str, usize index, const fstr *add) { internal_fstr_insert(str, index, add->data, fstr_length(add)); } -void fstr_insert_C(fstr *str, usize index, const chr *add) { - if (add == NULL) { +void fstr_insert_C(fstr* str, usize index, const chr* add) +{ + if (add == NULL) + { str->error = STR_ERR_NullStringArg; return; } @@ -1101,15 +1308,16 @@ void fstr_insert_C(fstr *str, usize index, const chr *add) { internal_fstr_insert(str, index, add, internal_C_string_length(add)); } -fstr **fstr_split(fstr *str) { - +fstr** fstr_split(fstr* str) +{ } -void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side) { - +void fstr_pad(fstr* str, usize targetLength, chr pad, int8_t side) +{ usize currentLen = fstr_length(str); - if (targetLength <= currentLen) { + if (targetLength <= currentLen) + { str->error = STR_ERR_IndexOutOfBounds; return; } @@ -1117,17 +1325,19 @@ void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side) { usize diff = targetLength - currentLen; ///Pad the left side - if (side < 0) { + if (side < 0) + { //Pad the left side - fstr *prePad = fstr_from_length(diff, pad); + fstr* prePad = fstr_from_length(diff, pad); fstr_insert(str, 0, prePad); free(prePad); return; } ///Pad both sides - if (side == 0) { + if (side == 0) + { //Insert the pad on the left - fstr *left = fstr_from_length(diff / 2, pad); + fstr* left = fstr_from_length(diff / 2, pad); fstr_insert(str, 0, left); //Pad the remaining right side. This is technically recursive but only ever a depth of 1 @@ -1138,9 +1348,10 @@ void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side) { return; } ///Pad the right side - if (side > 0) { + if (side > 0) + { //Pad the right side - fstr *prePad = fstr_from_length(diff, pad); + fstr* prePad = fstr_from_length(diff, pad); usize len = fstr_length(str); fstr_insert(str, len, prePad); @@ -1150,6 +1361,36 @@ void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side) { } } -u8 fstr_succeeded(fstr *str) { +u8 fstr_succeeded(fstr* str) +{ return str->error == 0; -} \ No newline at end of file +} + +u8 internal_fstr_starts_with(char* base, usize baseLen, char* sub, usize subLen) +{ + if (subLen > baseLen) + { + return 0; + } + + return (memcmp(base, sub, subLen * sizeof(chr)) == 0); +} + +u8 fstr_starts_with(fstr* base, fstr* sub) +{ + return internal_fstr_starts_with(base->data, fstr_length(base), sub->data, fstr_length(sub)); +} + +u8 fstr_starts_with_C(fstr* base, chr* sub) +{ + return internal_fstr_starts_with(base->data, fstr_length(base), sub, internal_C_string_length(sub)); +} + +u8 fstr_starts_with_chr(fstr* base, chr sub) +{ + if (fstr_length(base) > 0) + { + return (base->data[0] == sub); + } + return 0; +} diff --git a/fstr.h b/fstr.h index 081c7d1..e560e20 100644 --- a/fstr.h +++ b/fstr.h @@ -29,7 +29,8 @@ //#define chr wchar_t ///String errors, these will be updated on the fstr struct that you are using, in the error field -typedef enum : uint8_t { +typedef enum : uint8_t +{ STR_ERR_None = 0, STR_ERR_IndexOutOfBounds = 1, STR_ERR_AllocFailed = 2, @@ -40,12 +41,14 @@ typedef enum : uint8_t { //This struct is used to handle the results of functions that might return different things. //In particular, it has the possibility of returning a boolean telling you if the function succeeded or not. -typedef struct { +typedef struct +{ uint8_t success; //This union defines either an integer value or a float value. //Most functions will return an u_val (index value) unless specified. - union { + union + { usize u_val; int64_t i_val; double f_val; @@ -53,7 +56,8 @@ typedef struct { } fstr_result; ///The main fstr struct, this is a new string type that uses a pointer to the end of the char array to control for length. -typedef struct { +typedef struct +{ //The address of the last character in our string, inclusive. usize end; @@ -61,13 +65,12 @@ typedef struct { STR_ERR error; //The starting pointer of our string data - chr *data; + chr* data; } fstr; #pragma endregion Definitions - ///////////////////////////// /// FUNCTION DECLARATIONS /// ///////////////////////////// @@ -94,19 +97,19 @@ chr chr_to_upper(chr a); /// Creates an fstr from a pre-existing C string /// \param buf /// \return -fstr *fstr_from_C(const chr *buf); +fstr* fstr_from_C(const chr* buf); /// Creates a fstr from a C format string /// \param format Like printf /// \param ... Args /// \return -fstr *fstr_from_format_C(const char *format, ...); +fstr* fstr_from_format_C(const char* format, ...); /// Creates a string filled with the chr fill with a length of length /// \param length Total length of the string /// \param fill The fill character /// \return -fstr *fstr_from_length(usize length, const chr fill); +fstr* fstr_from_length(usize length, const chr fill); #pragma endregion String_Creation @@ -115,42 +118,42 @@ fstr *fstr_from_length(usize length, const chr fill); /// Append a C style string to our str /// \param str The string being appended to /// \param buf The string to be added -void fstr_append_C(fstr *str, const chr *buf); +void fstr_append_C(fstr* str, const chr* buf); /// Appends the fstr buf to the fstr /// \param str The string being appended to /// \param buf The string to be added -void fstr_append(fstr *str, const fstr *buf); +void fstr_append(fstr* str, const fstr* buf); /// Appends a single character to the string /// \param str The string being appended to /// \param c The character to be appended -void fstr_append_chr(fstr *str, const chr c); +void fstr_append_chr(fstr* str, const chr c); /// Insert a string at a particular point /// \param str The string to be modified /// \param add The string to be added /// \param index 0 inserts the string before any other data -void fstr_insert(fstr *str, usize index, const fstr *add); +void fstr_insert(fstr* str, usize index, const fstr* add); /// Inserts a C string at a particular point, see fstr_insert /// \param str The string to be modified /// \param add The C string to be added /// \param index 0 inserts the string before any other data -void fstr_insert_C(fstr *str, usize index, const chr *add); +void fstr_insert_C(fstr* str, usize index, const chr* add); /// Appends a formatted C string to the fstr /// \param str The string to be appended to /// \param format The C string format of the data to be added /// \param ... Takes varargs -void fstr_append_format_C(fstr *str, const char *format, ...); +void fstr_append_format_C(fstr* str, const char* format, ...); /// Pads the string to fit a target length /// \param str /// \param targetLength width of max pad /// \param pad The character to pad /// \param side -1 for pad left, 0 for pad both, 1 for pad right -void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side); +void fstr_pad(fstr* str, usize targetLength, chr pad, int8_t side); #pragma endregion String_Append @@ -158,25 +161,33 @@ void fstr_pad(fstr *str, usize targetLength, chr pad, int8_t side); /// Prints the characters as hex codes separated by spaces /// \param str The string to be printed -void fstr_print_hex(const fstr *str); +void fstr_print_hex(const fstr* str); + +/// Prints the characters as binary seperated by spaces +/// @param str The string to be printed +void fstr_print_bin(fstr* str); + +/// Prints the characters as their numberical values separated by spaces +/// @param str The string to be printed +void fstr_print_num(const fstr* str); /// Prints the string then a newline /// \param str The string to be printed -void fstr_println(const fstr *str); +void fstr_println(const fstr* str); /// Prints the chrs with a format applied to each character. This MUST include %c and cannot include any other % formatting. /// A good use for this is fstr_print_chrs_f(str, "%c,"); To comma separate the characters. /// \param str /// \param format -void fstr_print_chrs_f(const fstr *str, const chr *format); +void fstr_print_chrs_f(const fstr* str, const chr* format); /// Prints the string one character at a time /// \param str The string to be printed -void fstr_print_chrs(const fstr *str); +void fstr_print_chrs(const fstr* str); /// Prints the string at once by writing to the STDOUT /// \param str The string to be printed -void fstr_print(const fstr *str); +void fstr_print(const fstr* str); #pragma endregion Printing @@ -186,71 +197,71 @@ void fstr_print(const fstr *str); /// \param str The string to look through /// \param sub The substring to check for /// \return The fstr_result, index is stored in i_val. -fstr_result fstr_index_of_C(const fstr *str, chr *sub); +fstr_result fstr_index_of_C(const fstr* str, chr* sub); /// Returns the index of the first instances of the substring in the string. Index is stored in fstr_result.i_val /// \param str The string to look through /// \param sub The substring to check for /// \return The fstr_result, index is stored in i_val. -fstr_result fstr_index_of(const fstr *str, const fstr *sub); +fstr_result fstr_index_of(const fstr* str, const fstr* sub); /// Clear all the string characters /// \param str The string to clear -void fstr_clear(fstr *str); +void fstr_clear(fstr* str); /// Removes the character at the particular index /// \param str The string to be modified /// \param index The index of the char to be removed, 0 based. Will not crash on OOB -void fstr_remove_at(fstr *str, const usize index, const usize length); +void fstr_remove_at(fstr* str, const usize index, const usize length); /// Reverses the string /// \param str The string to be reversed -void fstr_reverse(fstr *str); +void fstr_reverse(fstr* str); /// Removes any instances of the fstr buf in the str /// \param str The source string /// \param buf The buf to remove from the str -void fstr_remove(const fstr *str, const fstr *buf); +void fstr_remove(const fstr* str, const fstr* buf); /// Removes any instances of the chr array buf in the str /// \param str The source string /// \param buf The buf to remove from the str -void fstr_remove_C(const fstr *str, const chr *buf); +void fstr_remove_C(const fstr* str, const chr* buf); /// Replaces any instances of the from character with the to character /// \param str The source string /// \param from The chr as its found in the source /// \param to The new chr to replace the from chr -void fstr_replace_chr(fstr *str, const chr from, const chr to); +void fstr_replace_chr(fstr* str, const chr from, const chr to); /// Removes any instances of a character, rippling the string. fstr_remove_chr(str, "AABBCC", 'A') -> "BBCC" /// \param str The string to be removed c /// \param c The chr to be removed -void fstr_remove_chr(fstr *str, const chr c); +void fstr_remove_chr(fstr* str, const chr c); /// Replaces the character at a particular index, you can also do direct indexing. Does do OOB checking. /// \param str The string to replace /// \param index The index of the character, 0 being the start of the string /// \param c The character to be assigned -void fstr_set_chr(fstr *str, usize index, chr c); +void fstr_set_chr(fstr* str, usize index, chr c); /// Removes all instances of the char parameters /// \param str The string to be modified /// \param num_chars The count of char params to be passed /// \param ... Chars to be removed -void fstr_remove_chr_varargs(fstr *str, uint8_t num_chars, ...); +void fstr_remove_chr_varargs(fstr* str, uint8_t num_chars, ...); /// Makes the string lowercase /// \param a The string to modify -void fstr_to_lower(fstr *a); +void fstr_to_lower(fstr* a); /// Makes the string uppercase /// \param a The string to modify -void fstr_to_upper(fstr *a); +void fstr_to_upper(fstr* a); /// Makes any uppercase into lowercase, and any lowercase into uppercase /// \param a The string to modify -void fstr_invertcase(fstr *a); +void fstr_invertcase(fstr* a); #pragma endregion String_Modification @@ -261,111 +272,133 @@ void fstr_invertcase(fstr *a); /// \param start The start index of the substring /// \param length The length of the substring /// \return The substring -fstr *fstr_substr(fstr *str, usize start, usize length); +fstr* fstr_substr(fstr* str, usize start, usize length); /// Counts the instances of a C substring in str /// \param str The string to search /// \param sub The substring to look for /// \return The count of substrings -usize fstr_count_C(const fstr *str, const chr *sub); +usize fstr_count_C(const fstr* str, const chr* sub); /// Counts the instances of an fstr substring in the string /// \param str The string to search /// \param sub The substring to look for /// \return The count of substringsF -usize fstr_count(const fstr *str, const fstr *sub); +usize fstr_count(const fstr* str, const fstr* sub); /// returns an fstr result if the character was found. The value is in the u_val /// \param str The string to search /// \param c The character to compare /// \return The fstr_result with the value being the u_val -fstr_result fstr_index_of_chr(fstr *str, char c); +fstr_result fstr_index_of_chr(fstr* str, char c); /// Gets the count of the chr value in the fstr /// \param str The string to be checked /// \param value The chr to check the string for /// \return The count of characters -usize fstr_count_chr(const fstr *str, const chr value); +usize fstr_count_chr(const fstr* str, const chr value); /// Copies the fstr and returns the new copy /// \param str The string to be copied /// \return A copy of the fstr -fstr *fstr_copy(const fstr *str); +fstr* fstr_copy(const fstr* str); /// Returns the fstr as a C string. This string MUST later be freed. /// \param from The string to be used /// \return The char * buffer -char *fstr_as_C_heap(const fstr *from); +char* fstr_as_C_heap(const fstr* from); /// Frees the fstr and its data /// \param str The string to free -void fstr_free(fstr *str); +void fstr_free(fstr* str); /// Returns the length of the string /// \param str The corresponding string /// \return The length of the string. Ex: ":)" returns 2 -usize fstr_length(const fstr *str); +usize fstr_length(const fstr* str); /// Whether or not the string is in a state of error /// \param str /// \return -uint8_t fstr_succeeded(fstr *str); +uint8_t fstr_succeeded(fstr* str); /// If the a strings contents equals the b strings contents /// \param a The first string /// \param b The second string /// \return 1 if it equals, 0 if its not equal -uint8_t fstr_equals(fstr *a, fstr *b); +uint8_t fstr_equals(fstr* a, fstr* b); /// If the a strings contents equals the b C string contents /// \param a The first string /// \param b The second string /// \return 1 if it equals, 0 if its not equal -uint8_t fstr_equals_C(fstr *a, chr *b); +uint8_t fstr_equals_C(fstr* a, chr* b); /// Trims a particular side of the fstr from all spaces, tabs, newlines, carriage returns, and the like. /// \param str The string to be modified /// \param side The side to trim, 0 for both sides, -1 for left, +1 for right -void fstr_trim(fstr *str, int8_t side); +void fstr_trim(fstr* str, int8_t side); /// Replaces any instances of oldBuf with newBuf /// \param str The string to be modified /// \param oldBuf The old buffer /// \param newBuf The new buffer -void fstr_replace_C(const fstr *str, const chr *oldBuf, const chr *newBuf); +void fstr_replace_C(const fstr* str, const chr* oldBuf, const chr* newBuf); /// Replaces any instances of oldBuf with newBuf /// \param str The string to be modified /// \param oldBuf The old buffer /// \param newBuf The new buffer -void fstr_replace(const fstr *str, const fstr *oldBuf, const fstr *newBuf); +void fstr_replace(const fstr* str, const fstr* oldBuf, const fstr* newBuf); /// Terminates the string at the particular character, /// resizing the allocated memory as well /// \param str The string to terminate /// \param c The character to terminate at -void fstr_terminate(fstr *str, chr c); +void fstr_terminate(fstr* str, chr c); /// Overwrites the contents of the string at index with the buf. Expands the string with spaces if necessary /// \param str The string to modify /// \param index The index to overwrite the string at, 0 would replace the first characters /// \param buf The character buffer to use -void fstr_overwrite_C(fstr *str, usize index, chr *buf); +void fstr_overwrite_C(fstr* str, usize index, chr* buf); /// Overwrites the contents of the string at index with the buf. Expands the string with spaces if necessary /// \param str The string to modify /// \param index The index to overwrite the string at, 0 would replace the first characters /// \param buf The character buffer to use -void fstr_overwrite(fstr *str, usize index, fstr *buf); +void fstr_overwrite(fstr* str, usize index, fstr* buf); /// Overwrites the contents of the string at index with the buf. Expands the string with spaces if necessary. Uses a string format a la printf /// \param str The string to modify /// \param index The index to overwrite the string at, 0 would replace the first characters /// \param buf The character buffer to use -void fstr_overwrite_format_C(fstr *str, usize index, chr *format, ...); +void fstr_overwrite_format_C(fstr* str, usize index, chr* format, ...); #pragma endregion String_Utilities -#endif //FSTR_FSTR_H \ No newline at end of file +#pragma region String_Analysis + +/// Returns 1 if base starts with sub +/// @param base The base string +/// @param sub The sub to check +/// @return 1 if base starts with sub +uint8_t fstr_starts_with(fstr* base, fstr* sub); + +/// Returns 1 if base starts with sub +/// @param base The base string +/// @param sub The sub to check +/// @return 1 if base starts with sub +uint8_t fstr_starts_with_C(fstr* base, chr* sub); + +/// Returns 1 if base starts with sub +/// @param base The base string +/// @param sub The sub to check +/// @return 1 if base starts with sub +uint8_t fstr_starts_with_chr(fstr* base, chr sub); + +#pragma endregion String_Analysis + +#endif //FSTR_FSTR_H diff --git a/fstr_convert.c b/fstr_convert.c index ece8da8..cf5952b 100644 --- a/fstr_convert.c +++ b/fstr_convert.c @@ -99,12 +99,6 @@ u64 to_u64(i64 val) // return res; // } -/// Calculate an i_val from a string -/// @param str The string -/// @return An fstr_result with the result in i_val. -/// Sides will be trimmed of spaces, non numerical or negative -/// sign characters cause success to be false, though the i_val -/// will be the correct value up until that character. fstr_result fstr_to_i64(const fstr* str) { //Make a copy of the string @@ -167,38 +161,40 @@ fstr_result fstr_to_i64(const fstr* str) return result; } -/// Calculates a u_val from a binary string, like so "10100001" -/// @param str The string of the binary -/// @return An fstr_result with the value in u_val. -/// Success will be set to false if a non-binary character is found. -fstr_result fstr_u64_from_bin(fstr* str) +fstr_result fstr_u64_from_bin_ex(fstr* instr, chr True, chr False) { - int count = 0; - int i = fstr_length(str) - 1; + fstr str = *instr; - fstr_result result = {0}; + //Skip the first two chars + if (fstr_starts_with_C(&str, "0b") || fstr_starts_with_C(&str, "0B")) + { + str.data += 2; + } + fstr_result result = {0}; + int count = 0; + int i = fstr_length(&str) - 1; usize sum = 0; //Read right to left while (i >= 0) { - chr b = str->data[i]; + chr b = str.data[i]; + - if (b == '1') + //If using C chars + if (b == True) { sum += pow(2, count); } //Skip any non 0 and 1 numbers and don't increment the counter. - //This counts as being unsuccessful, but may still generate a - //correct result - else if (b != '0') + else if (b != False) { i--; - result.success = 0; continue; } + count++; i--; } @@ -209,9 +205,21 @@ fstr_result fstr_u64_from_bin(fstr* str) return result; } -/// Converts a string to a double -/// @param str The string to be converted -/// @return +fstr_result fstr_u64_from_bin(fstr* str) +{ + //Handle digits based on char version + chr True = '1'; + chr False = '0'; + + if (sizeof(chr) == sizeof(wchar_t)) + { + True = L'1'; + False = L'0'; + } + + return fstr_u64_from_bin_ex(str, True, False); +} + fstr_result fstr_to_double(fstr* str) { fstr_result result = {0}; @@ -251,3 +259,4 @@ fstr_result fstr_to_double(fstr* str) return result; } + diff --git a/fstr_convert.h b/fstr_convert.h index 2813a44..e293491 100644 --- a/fstr_convert.h +++ b/fstr_convert.h @@ -11,8 +11,36 @@ #ifndef FSTR_FSTR_PARSE_H #define FSTR_FSTR_PARSE_H +/// Calculate an i_val from a string +/// @param str The string +/// @return An fstr_result with the result in i_val. +/// Sides will be trimmed of spaces, non numerical or negative +/// sign characters cause success to be false, though the i_val +/// will be the correct value up until that character. fstr_result fstr_to_i64(const fstr* str); + +/// Calculate an f_val from a string +/// @param str The string +/// @return An fstr_result with the result in f_val. +/// Sides will be trimmed of spaces, non numerical, negative, +/// or decimal characters will cause success to be false, +/// though the value will be correct up until that character. fstr_result fstr_to_double(fstr* str); + +/// Calculates a u_val from a binary string, like so "10100001" or "0b0101" +/// @param str The string of the binary +/// @return An fstr_result with the value in u_val. +/// Any non-binary !('0'|'1') will be skipped and the value will +/// continue to be calculated fstr_result fstr_u64_from_bin(fstr* str); +/// Calculates a u_val from a binary string, like so "10100001" or "0b0101" +/// @param str The string of the binary +/// @return An fstr_result with the value in u_val. +/// Any non-binary !('0'|'1') will be skipped and the value will +/// continue to be calculated. This extension method allows customs chrs for +/// 1 and 0, being true and false respectively. Use the fstr_u64_from_bin for +/// these to be set to the defaults, '1' and '0' +fstr_result fstr_u64_from_bin_ex(fstr* instr, chr True, chr False); + #endif //FSTR_FSTR_PARSE_H diff --git a/main.c b/main.c index 918ac00..eb27206 100644 --- a/main.c +++ b/main.c @@ -192,6 +192,26 @@ int main() printf("%llu\n\n", fstr_u64_from_bin(str).u_val); + fstr_free(str); + } + + { + fstr* str = fstr_from_C("0x0101010001"); + + printf("%llu\n\n", fstr_u64_from_bin(str).u_val); + + fstr_free(str); + } + + { + fstr* str = fstr_from_C("ABCDEF"); + fstr_print_bin(str); + fstr_println(NULL); + fstr_print_hex(str); + fstr_println(NULL); + fstr_print_num(str); + + fstr_free(str); } }