DString.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include <errno.h>
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include "scufcont/scufcont.h"
  7. #include "scufcont/DString.h"
  8. ScufContResult SCDString_alloc(SCDString *const dstr, const char *str, const size_t len) {
  9. dstr->data = (char *) malloc(sizeof(char) * (len + 1));
  10. dstr->len = len;
  11. dstr->capacity = len + 1;
  12. if (dstr->data == NULL) {
  13. return SCUFCONT_OUT_OF_MEMORY;
  14. }
  15. dstr->data = memcpy(dstr->data, str, len);
  16. dstr->data[len] = '\0';
  17. return SCUFCONT_SUCCESS;
  18. }
  19. ScufContResult SCDString_alloc_copy(SCDString *const dstr, const SCDString *const o) {
  20. return SCDString_alloc(dstr, SCDString_c_str(o), o->len);
  21. }
  22. ScufContResult SCDString_reserve(SCDString *const dstr, const size_t new_capacity) {
  23. if (dstr->capacity < new_capacity) {
  24. errno = 0;
  25. dstr->data = (char *) realloc(dstr->data, sizeof(char) * new_capacity);
  26. if (errno != 0) {
  27. return SCUFCONT_OUT_OF_MEMORY;
  28. }
  29. dstr->capacity = new_capacity;
  30. }
  31. return SCUFCONT_SUCCESS;
  32. }
  33. void SCDString_free(SCDString *const dstr) {
  34. if (dstr->data != NULL) {
  35. free(dstr->data);
  36. dstr->data = NULL;
  37. }
  38. dstr->len = 0;
  39. dstr->capacity = 0;
  40. }
  41. void SCDString_shrink_to_fit(SCDString *const dstr) {
  42. if (dstr->capacity > dstr->len + 1) {
  43. dstr->capacity = dstr->len + 1;
  44. dstr->data = (char *) realloc(dstr->data, dstr->capacity);
  45. }
  46. }
  47. ScufContResult SCDString_copy(const SCDString *const src, SCDString *const dst) {
  48. ScufContResult res = SCDString_reserve(dst, src->len + 1);
  49. if (res != SCUFCONT_SUCCESS) {
  50. return res;
  51. }
  52. dst->len = src->len;
  53. memcpy(dst->data, src->data, dst->len);
  54. dst->data[dst->len] = '\0';
  55. return SCUFCONT_SUCCESS;
  56. }
  57. ScufContResult SCDString_at(const SCDString *const dstr, const size_t i) {
  58. if (i > dstr->len - 1) {
  59. return SCUFCONT_OUT_OF_BOUNDS;
  60. }
  61. return dstr->data[i];
  62. }
  63. bool SCDString_equal(const SCDString *const s1, const SCDString *const s2) {
  64. if (s1->data == NULL || s2->data == NULL) {
  65. return false;
  66. }
  67. if (s1->len != s2->len) {
  68. return false;
  69. }
  70. for (size_t i = 0; i < s1->len; i++) {
  71. if (s1->data[i] != s2->data[i]) {
  72. return false;
  73. }
  74. }
  75. return true;
  76. }
  77. bool SCDString_equal_c_str(const SCDString *const s1, const char *s2) {
  78. if (s1->data == NULL || s2 == NULL) {
  79. return false;
  80. }
  81. if (s1->len != strlen(s2)) {
  82. return false;
  83. }
  84. for (size_t i = 0; i < s1->len; i++) {
  85. if (s1->data[i] != s2[i]) {
  86. return false;
  87. }
  88. }
  89. return true;
  90. }
  91. bool SCDString_equal_next_chars_c_str(
  92. const SCDString *const dstr,
  93. const char *str,
  94. const size_t str_len,
  95. size_t s
  96. ) {
  97. if (dstr->len < s || dstr->len < s + str_len) {
  98. return false;
  99. }
  100. const size_t e = s + str_len;
  101. for (size_t i = 0; s < e; s++, i++) {
  102. if (dstr->data[s] != str[i]) {
  103. return false;
  104. }
  105. }
  106. return true;
  107. }
  108. ScufContResult SCDString_concat_char(SCDString *const dstr, const char ch) {
  109. const size_t new_len = dstr->len + 1;
  110. if (new_len > dstr->capacity) {
  111. ScufContResult res = SCDString_reserve(dstr, new_len + 1);
  112. if (res != SCUFCONT_SUCCESS) {
  113. return res;
  114. }
  115. }
  116. dstr->data[new_len - 1] = ch;
  117. dstr->data[new_len] = '\0';
  118. dstr->len = new_len;
  119. return SCUFCONT_SUCCESS;
  120. }
  121. ScufContResult SCDString_concat_c_str(
  122. SCDString *const dstr,
  123. const char *str,
  124. const size_t str_len
  125. ) {
  126. const size_t new_len = dstr->len + str_len;
  127. if (new_len > dstr->capacity) {
  128. ScufContResult res = SCDString_reserve(dstr, new_len + 1);
  129. if (res != SCUFCONT_SUCCESS) {
  130. return res;
  131. }
  132. }
  133. strncpy(dstr->data + dstr->len, str, str_len);
  134. dstr->data[new_len] = '\0';
  135. dstr->len = new_len;
  136. return SCUFCONT_SUCCESS;
  137. }
  138. ScufContResult SCDString_alloc_concat_c_strs(
  139. SCDString *const dstr,
  140. const char *s1,
  141. const size_t s1_len,
  142. const char *s2,
  143. const size_t s2_len
  144. ) {
  145. ScufContResult res = SCDString_alloc(dstr, s1, s1_len);
  146. if (res != SCUFCONT_SUCCESS) {
  147. return res;
  148. }
  149. res = SCDString_concat_c_str(dstr, s2, s2_len);
  150. if (res != SCUFCONT_SUCCESS) {
  151. return res;
  152. }
  153. return SCUFCONT_SUCCESS;
  154. }
  155. ScufContResult SCDString_split(
  156. const SCDString *const dstr,
  157. const char *delim,
  158. SCDString **const split_arr,
  159. size_t *arr_len
  160. ) {
  161. ScufContResult ret = SCUFCONT_SUCCESS;
  162. *arr_len = 0;
  163. SCDString elem;
  164. ScufContResult res = SCDString_alloc(&elem, "", 0);
  165. if (res != SCUFCONT_SUCCESS) {
  166. return res;
  167. }
  168. const size_t delim_len = strlen(delim);
  169. for (size_t i = 0; i < dstr->len; i++) {
  170. if (SCDString_equal_next_chars_c_str(dstr, delim, delim_len, i)) {
  171. *arr_len += 1;
  172. *split_arr = realloc(*split_arr, sizeof(SCDString) * (*arr_len));
  173. if (split_arr == NULL) {
  174. ret = SCUFCONT_OUT_OF_MEMORY;
  175. break;
  176. }
  177. (*split_arr)[(*arr_len) - 1] = elem;
  178. res = SCDString_alloc(&elem, "", 0);
  179. if (res != SCUFCONT_SUCCESS) {
  180. ret = res;
  181. break;
  182. }
  183. i += delim_len - 1;
  184. } else {
  185. SCDString_concat_c_str(&elem, dstr->data + i, 1);
  186. }
  187. }
  188. if (ret == SCUFCONT_SUCCESS) {
  189. *split_arr = realloc(*split_arr, sizeof(SCDString) * (*arr_len + 1));
  190. if (split_arr != NULL) {
  191. (*split_arr)[*arr_len] = elem;
  192. *arr_len += 1;
  193. return ret;
  194. }
  195. ret = SCUFCONT_OUT_OF_MEMORY;
  196. }
  197. for (size_t i = 0; i < *arr_len; i++) {
  198. SCDString_free((*split_arr) + i);
  199. }
  200. free(*split_arr);
  201. *split_arr = NULL;
  202. SCDString_free(&elem);
  203. return ret;
  204. }
  205. void SCDString_split_arr_free(SCDString **const arr, const size_t arr_len) {
  206. for (size_t i = 0; i < arr_len; i++) {
  207. SCDString_free((*arr) + i);
  208. }
  209. free(*arr);
  210. *arr = NULL;
  211. }
  212. ScufContResult SCDString_char_mod(SCDString *const dstr, const size_t at, const char ch) {
  213. if (at > dstr->len - 1) {
  214. return SCUFCONT_OUT_OF_BOUNDS;
  215. }
  216. dstr->data[at] = ch;
  217. return SCUFCONT_SUCCESS;
  218. }
  219. ScufContResult SCDString_char_remove_no_shrink(SCDString *const dstr, const size_t at) {
  220. if (at > dstr->len - 1) {
  221. return SCUFCONT_OUT_OF_BOUNDS;
  222. }
  223. memmove(&dstr->data[at], &dstr->data[at] + 1, dstr->len - at);
  224. dstr->len--;
  225. return SCUFCONT_SUCCESS;
  226. }
  227. ScufContResult SCDString_char_remove(SCDString *const dstr, const size_t at) {
  228. const ScufContResult res = SCDString_char_remove_no_shrink(dstr, at);
  229. if (res != SCUFCONT_SUCCESS) {
  230. return res;
  231. }
  232. SCDString_shrink_to_fit(dstr);
  233. return SCUFCONT_SUCCESS;
  234. }
  235. ScufContResult SCDString_char_insert(SCDString *const dstr, const size_t at, const char ch) {
  236. if (at > dstr->len) {
  237. return SCUFCONT_OUT_OF_BOUNDS;
  238. }
  239. ScufContResult res = SCDString_reserve(dstr, dstr->len + 2);
  240. if (res != SCUFCONT_SUCCESS) {
  241. return res;
  242. }
  243. const size_t move_block_size = at == dstr->len ? 1 : dstr->len - at;
  244. memmove(&dstr->data[at] + 1, &dstr->data[at], move_block_size);
  245. dstr->data[at] = ch;
  246. dstr->len++;
  247. return SCUFCONT_SUCCESS;
  248. }
  249. ScufContResult SCDString_replace_c_str_no_shrink(SCDString *const dstr, const char *str, const size_t str_len) {
  250. if (dstr->capacity < str_len + 1) {
  251. const ScufContResult res = SCDString_reserve(dstr, str_len + 1);
  252. if (res != SCUFCONT_SUCCESS) {
  253. return res;
  254. }
  255. }
  256. memcpy(dstr->data, str, str_len);
  257. dstr->len = str_len;
  258. return SCUFCONT_SUCCESS;
  259. }
  260. ScufContResult SCDString_replace_c_str(SCDString *const dstr, const char *str, const size_t str_len) {
  261. const ScufContResult res = SCDString_replace_c_str_no_shrink(dstr, str, str_len);
  262. if (res != SCUFCONT_SUCCESS) {
  263. return res;
  264. }
  265. SCDString_shrink_to_fit(dstr);
  266. return SCUFCONT_SUCCESS;
  267. }
  268. void SCDString_trim_whitespace_leading(SCDString *const dstr) {
  269. while (isspace(dstr->data[0])) {
  270. SCDString_char_remove_no_shrink(dstr, 0);
  271. }
  272. SCDString_shrink_to_fit(dstr);
  273. }
  274. void SCDString_trim_whitespace_trailing(SCDString *const dstr) {
  275. while (isspace(dstr->data[dstr->len - 1])) {
  276. SCDString_char_remove_no_shrink(dstr, dstr->len - 1);
  277. }
  278. SCDString_shrink_to_fit(dstr);
  279. }
  280. void SCDString_trim_whitespace(SCDString *const dstr) {
  281. SCDString_trim_whitespace_leading(dstr);
  282. SCDString_trim_whitespace_trailing(dstr);
  283. }