#include #include #include #include #include #include "scufcont/scufcont.h" #include "scufcont/DString.h" ScufContResult SCDString_alloc(SCDString *const dstr, const char *str, const size_t len) { dstr->data = (char *) malloc(sizeof(char) * (len + 1)); dstr->len = len; dstr->capacity = len + 1; if (dstr->data == NULL) { return SCUFCONT_OUT_OF_MEMORY; } dstr->data = memcpy(dstr->data, str, len); dstr->data[len] = '\0'; return SCUFCONT_SUCCESS; } ScufContResult SCDString_alloc_copy(SCDString *const dstr, const SCDString *const o) { return SCDString_alloc(dstr, SCDString_c_str(o), o->len); } ScufContResult SCDString_reserve(SCDString *const dstr, const size_t new_capacity) { if (dstr->capacity < new_capacity) { errno = 0; dstr->data = (char *) realloc(dstr->data, sizeof(char) * new_capacity); if (errno != 0) { return SCUFCONT_OUT_OF_MEMORY; } dstr->capacity = new_capacity; } return SCUFCONT_SUCCESS; } void SCDString_free(SCDString *const dstr) { if (dstr->data != NULL) { free(dstr->data); dstr->data = NULL; } dstr->len = 0; dstr->capacity = 0; } void SCDString_shrink_to_fit(SCDString *const dstr) { if (dstr->capacity > dstr->len + 1) { dstr->capacity = dstr->len + 1; dstr->data = (char *) realloc(dstr->data, dstr->capacity); } } ScufContResult SCDString_copy(const SCDString *const src, SCDString *const dst) { ScufContResult res = SCDString_reserve(dst, src->len + 1); if (res != SCUFCONT_SUCCESS) { return res; } dst->len = src->len; memcpy(dst->data, src->data, dst->len); dst->data[dst->len] = '\0'; return SCUFCONT_SUCCESS; } ScufContResult SCDString_at(const SCDString *const dstr, const size_t i) { if (i > dstr->len - 1) { return SCUFCONT_OUT_OF_BOUNDS; } return dstr->data[i]; } bool SCDString_equal(const SCDString *const s1, const SCDString *const s2) { if (s1->data == NULL || s2->data == NULL) { return false; } if (s1->len != s2->len) { return false; } for (size_t i = 0; i < s1->len; i++) { if (s1->data[i] != s2->data[i]) { return false; } } return true; } bool SCDString_equal_c_str(const SCDString *const s1, const char *s2) { if (s1->data == NULL || s2 == NULL) { return false; } if (s1->len != strlen(s2)) { return false; } for (size_t i = 0; i < s1->len; i++) { if (s1->data[i] != s2[i]) { return false; } } return true; } bool SCDString_equal_next_chars_c_str( const SCDString *const dstr, const char *str, const size_t str_len, size_t s ) { if (dstr->len < s || dstr->len < s + str_len) { return false; } const size_t e = s + str_len; for (size_t i = 0; s < e; s++, i++) { if (dstr->data[s] != str[i]) { return false; } } return true; } ScufContResult SCDString_concat_char(SCDString *const dstr, const char ch) { const size_t new_len = dstr->len + 1; if (new_len > dstr->capacity) { ScufContResult res = SCDString_reserve(dstr, new_len + 1); if (res != SCUFCONT_SUCCESS) { return res; } } dstr->data[new_len - 1] = ch; dstr->data[new_len] = '\0'; dstr->len = new_len; return SCUFCONT_SUCCESS; } ScufContResult SCDString_concat_c_str( SCDString *const dstr, const char *str, const size_t str_len ) { const size_t new_len = dstr->len + str_len; if (new_len > dstr->capacity) { ScufContResult res = SCDString_reserve(dstr, new_len + 1); if (res != SCUFCONT_SUCCESS) { return res; } } strncpy(dstr->data + dstr->len, str, str_len); dstr->data[new_len] = '\0'; dstr->len = new_len; return SCUFCONT_SUCCESS; } ScufContResult SCDString_alloc_concat_c_strs( SCDString *const dstr, const char *s1, const size_t s1_len, const char *s2, const size_t s2_len ) { ScufContResult res = SCDString_alloc(dstr, s1, s1_len); if (res != SCUFCONT_SUCCESS) { return res; } res = SCDString_concat_c_str(dstr, s2, s2_len); if (res != SCUFCONT_SUCCESS) { return res; } return SCUFCONT_SUCCESS; } ScufContResult SCDString_split( const SCDString *const dstr, const char *delim, SCDString **const split_arr, size_t *arr_len ) { ScufContResult ret = SCUFCONT_SUCCESS; *arr_len = 0; SCDString elem; ScufContResult res = SCDString_alloc(&elem, "", 0); if (res != SCUFCONT_SUCCESS) { return res; } const size_t delim_len = strlen(delim); for (size_t i = 0; i < dstr->len; i++) { if (SCDString_equal_next_chars_c_str(dstr, delim, delim_len, i)) { *arr_len += 1; *split_arr = realloc(*split_arr, sizeof(SCDString) * (*arr_len)); if (split_arr == NULL) { ret = SCUFCONT_OUT_OF_MEMORY; break; } (*split_arr)[(*arr_len) - 1] = elem; res = SCDString_alloc(&elem, "", 0); if (res != SCUFCONT_SUCCESS) { ret = res; break; } i += delim_len - 1; } else { SCDString_concat_c_str(&elem, dstr->data + i, 1); } } if (ret == SCUFCONT_SUCCESS) { *split_arr = realloc(*split_arr, sizeof(SCDString) * (*arr_len + 1)); if (split_arr != NULL) { (*split_arr)[*arr_len] = elem; *arr_len += 1; return ret; } ret = SCUFCONT_OUT_OF_MEMORY; } for (size_t i = 0; i < *arr_len; i++) { SCDString_free((*split_arr) + i); } free(*split_arr); *split_arr = NULL; SCDString_free(&elem); return ret; } void SCDString_split_arr_free(SCDString **const arr, const size_t arr_len) { for (size_t i = 0; i < arr_len; i++) { SCDString_free((*arr) + i); } free(*arr); *arr = NULL; } ScufContResult SCDString_char_mod(SCDString *const dstr, const size_t at, const char ch) { if (at > dstr->len - 1) { return SCUFCONT_OUT_OF_BOUNDS; } dstr->data[at] = ch; return SCUFCONT_SUCCESS; } ScufContResult SCDString_char_remove_no_shrink(SCDString *const dstr, const size_t at) { if (at > dstr->len - 1) { return SCUFCONT_OUT_OF_BOUNDS; } memmove(&dstr->data[at], &dstr->data[at] + 1, dstr->len - at); dstr->len--; return SCUFCONT_SUCCESS; } ScufContResult SCDString_char_remove(SCDString *const dstr, const size_t at) { const ScufContResult res = SCDString_char_remove_no_shrink(dstr, at); if (res != SCUFCONT_SUCCESS) { return res; } SCDString_shrink_to_fit(dstr); return SCUFCONT_SUCCESS; } ScufContResult SCDString_char_insert(SCDString *const dstr, const size_t at, const char ch) { if (at > dstr->len) { return SCUFCONT_OUT_OF_BOUNDS; } ScufContResult res = SCDString_reserve(dstr, dstr->len + 2); if (res != SCUFCONT_SUCCESS) { return res; } const size_t move_block_size = at == dstr->len ? 1 : dstr->len - at; memmove(&dstr->data[at] + 1, &dstr->data[at], move_block_size); dstr->data[at] = ch; dstr->len++; return SCUFCONT_SUCCESS; } ScufContResult SCDString_replace_c_str_no_shrink(SCDString *const dstr, const char *str, const size_t str_len) { if (dstr->capacity < str_len + 1) { const ScufContResult res = SCDString_reserve(dstr, str_len + 1); if (res != SCUFCONT_SUCCESS) { return res; } } memcpy(dstr->data, str, str_len); dstr->len = str_len; return SCUFCONT_SUCCESS; } ScufContResult SCDString_replace_c_str(SCDString *const dstr, const char *str, const size_t str_len) { const ScufContResult res = SCDString_replace_c_str_no_shrink(dstr, str, str_len); if (res != SCUFCONT_SUCCESS) { return res; } SCDString_shrink_to_fit(dstr); return SCUFCONT_SUCCESS; } void SCDString_trim_whitespace_leading(SCDString *const dstr) { while (isspace(dstr->data[0])) { SCDString_char_remove_no_shrink(dstr, 0); } SCDString_shrink_to_fit(dstr); } void SCDString_trim_whitespace_trailing(SCDString *const dstr) { while (isspace(dstr->data[dstr->len - 1])) { SCDString_char_remove_no_shrink(dstr, dstr->len - 1); } SCDString_shrink_to_fit(dstr); } void SCDString_trim_whitespace(SCDString *const dstr) { SCDString_trim_whitespace_leading(dstr); SCDString_trim_whitespace_trailing(dstr); }