├── LICENSE ├── README.md └── src ├── s_str.h └── s_str.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Michael J Welsh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmartString 2 | A Lightweight, Fast, and Safe C Library Meant to Mimic String Functionality Present in C++ 3 | 4 | 5 | ## Ideology 6 | The goal of this library is to provide string-like functionality similar to C++'s STL string class. Every "smart" string worries about memory management and data organization for you, letting you better focus on your task ahead. The "smart" string type is "s_str". Every s_str function has the prefix "s_str\_" and takes in the memory address of the s_str that it will operate on as the first argument (with the exception of the *create* functions). Every s_str that is created **must** be later destroyed with a call to *destroy*. This library only supports **ASCII** characters as of now. 7 | 8 | 9 | ## API 10 | The following is a list of available functions. Refer to the greatly commented header for details. 11 | - create, create_from_char, create_from_multi_char, create_from_c_str, create_from_s_str 12 | - destroy 13 | - c_str 14 | - c_substr 15 | - assign_char, assign_multi_char, assign_c_str, assign_s_str 16 | - at 17 | - remove_at 18 | - find_char, find_c_str, find_s_str 19 | - rfind_char, rfind_c_str, rfind_s_str 20 | - capacity 21 | - reserve 22 | - size 23 | - length 24 | - empty 25 | - clear 26 | - trim 27 | - shrink_to_fit 28 | - push_back 29 | - pop_back 30 | - append_c_str, append_s_str 31 | - first_word 32 | - remove_first_word 33 | - last_word 34 | - remove_last_word 35 | - erase 36 | - insert_char, insert_c_str, insert_s_str 37 | - sepwith_char, sepwith_c_str, sepwith_s_str 38 | - replace 39 | - replace_all 40 | - swap 41 | - foreach 42 | - foreach_all 43 | - compare_c_str, compare_s_str 44 | - sort 45 | 46 | 47 | ## Example 48 | ```C 49 | s_str foo = s_str_create_from_c_str(" wow "); 50 | 51 | s_str_trim(&foo); 52 | s_str_pop_back(&foo); 53 | 54 | // Output: First print:wo. 55 | printf("First print:%s.\n", s_str_c_str(&foo)); 56 | 57 | s_str_append_c_str(&foo, "bar"); 58 | s_str_insert_char(&foo, 2, ' '); 59 | 60 | // Output: Second print:wo bar. 61 | printf("Second print:%s.\n", s_str_c_str(&foo)); 62 | 63 | s_str_remove_first_word(&foo); 64 | s_str_remove_at(&foo, 1); 65 | 66 | // Output: Third print:br. 67 | printf("Third print:%s.\n", s_str_c_str(&foo)); 68 | 69 | s_str_destroy(&foo); 70 | 71 | ``` 72 | -------------------------------------------------------------------------------- /src/s_str.h: -------------------------------------------------------------------------------- 1 | /* Purpose: This lightweight library for "smart" strings is meant to mimick how strings function in C++. 2 | * Authors Note: The user should interface with the type "s_str", which is guaranteed to always be memory safe and contain a terminating null character. 3 | * A "s_str" should ONLY be instantiated/assigned with a call to one of the varying s_str_create functions and MUST be later 4 | * deconstructed/deallocated via a call to s_str_destroy. 5 | */ 6 | 7 | 8 | #ifndef S_STRING_H 9 | #define S_STRING_H 10 | 11 | 12 | #include 13 | 14 | 15 | /* The first parameter of every function is a pointer-to-s_str since all functions use/manipulate the 16 | * s_str's value (and because of the fact that there is no "this" keyword in C). 17 | * 18 | * Note that calling functions which cause the s_str to dynamically reallocate due to the addition/subtraction of 19 | * member(s) may not do anything at all if the needed space in memory cannot be allocated, leaving the s_str in a 20 | * guaranteed unchanged/safe state. Memory safety is #1 priority. 21 | * 22 | * Many functions pertaining to the s_str type allow you to add/remove '\0'. These are treated like every-other 23 | * character and a s_str is not limited to a single '\0'. A call to the s_str_c_str or s_str_c_substr function can 24 | * return a const pointer-to-char that points to the held string containing multiple terminating null characters. The point is, 25 | * it is often a sign of bad programming practice if you are manually inserting/deleting terminating null characters and doing so 26 | * can easily lead to unexpected results in user-defined code (although it is completely legal). This should go without saying, 27 | * but to be clear, the terminating null character is removed and appended to the end of the s_str whenever you add a 28 | * char/C-string/s_str to a s_str. No matter what, it is guaranteed that the s_str will have a terminating null character. 29 | */ 30 | 31 | 32 | /* Typedef that should be used exclusively! 33 | * 34 | * Example: 35 | * s_str foo = s_str_create_from_c_str("pogchamp"); 36 | * int str_length = s_str_length(&foo); 37 | * s_str_clear(&foo); 38 | * s_str_append_c_str(&foo,"bar1235654241dsfa"); 39 | * printf("%s\n", s_str_c_str(&foo)); 40 | * s_str_destroy(&foo); 41 | */ 42 | typedef void *s_str; 43 | 44 | 45 | /* Dynamically allocates memory to create a new s_str that contains only a default terminating null character. The s_str MUST call s_str_destroy 46 | * to free memory at some point. 47 | * 48 | * Returns a unique and newly made s_str, or NULL if memory cannot be allocated to hold the s_str. 49 | */ 50 | s_str s_str_create(void); 51 | 52 | 53 | /* Dynamically allocates memory to create a new s_str that contains the char and a default terminating null character. The s_str MUST call 54 | * s_str_destroy to free memory at some point. 55 | * 56 | * Returns a unique and newly made s_str, or NULL if memory cannot be allocated to hold the s_str. 57 | */ 58 | s_str s_str_create_from_char(const char c); 59 | 60 | 61 | /* Dynamically allocates memory to create a new s_str that contains the char for the given length and a default terminating null character. The s_str MUST 62 | * call s_str_destroy to free memory at some point. 63 | * 64 | * Returns a unique and newly made s_str, or NULL if memory cannot be allocated to hold the s_str. 65 | */ 66 | s_str s_str_create_from_multi_char(const size_t length, const char c); 67 | 68 | 69 | /* Dynamically allocates memory to create a new s_str. The s_str MUST call s_str_destroy to free memory at some point. 70 | * 71 | * Takes in either a C-string literal (or any memory address to char that has a terminating null character at somepoint in memory) or NULL. 72 | * If c_str_ptr == NULL, then the s_str is default initialized (i.e. the "string" it represents will only be made up of a terminating null character); 73 | * otherwise, the s_str is set equal to a copy of the C-string. 74 | * 75 | * Returns a unique and newly made s_str, or NULL if memory cannot be allocated to hold the s_str. 76 | */ 77 | s_str s_str_create_from_c_str(const char *const c_str_ptr); 78 | 79 | 80 | /* Dynamically allocates memory to create a new s_str. The s_str MUST call s_str_destroy to free memory at some point. 81 | * 82 | * Takes in either the memory address of a s_str or NULL. If s_str_ptr_for_create == NULL, then the s_str is default initialized (i.e. the "string" it 83 | * represents will only be made up of a terminating null character); otherwise, the s_str is set equal to a copy of the (dereferenced) s_str_ptr_for_create. 84 | * 85 | * Returns a unique and newly made s_str, or NULL if memory cannot be allocated to hold the s_str. 86 | */ 87 | s_str s_str_create_from_s_str(const s_str *const s_str_ptr_for_create); 88 | 89 | 90 | /* Attempts to free allocated memory relating to the s_str. The s_str is then set equal to NULL. 91 | * 92 | * If the s_str is invalid or already freed, this function simply does nothing. 93 | */ 94 | void s_str_destroy(s_str *const this_); 95 | 96 | 97 | /* Retrieves and returns a C-style string guaranteed to have a terminating null character. 98 | * 99 | * This function is incredibly important in library/user defined string manipulation because it doesn't rely on the 100 | * implementation of a s_str. 101 | * 102 | * Note that the contents of the returned C-string cannot be altered for the sake of memory safety (hence the constness)! 103 | * 104 | * Its worth mentioning that implementation does allow the user to freely add/remove '\0' via manipulation functions 105 | * just like any other char (except there will ALWAYS be a default terminating null character located at the end of the s_str). This behavior is 106 | * defined; however, the user should be wary and avoid doing this because upon calling s_str_c_str, the returned C-string will contain the 107 | * original terminating null character at the end, plus any additional terminating null character's throughout. Unexpected outcomes to user defined 108 | * functionality may occur! 109 | */ 110 | const char* s_str_c_str(const s_str *const this_); 111 | 112 | 113 | /* Retrieves and returns a C-style string starting at "index" that is guaranteed to have a terminating null character. 114 | * 115 | * If "index" is out of range, a pointer-to-const-char is returned that points to the default terminating null 116 | * character. 117 | * 118 | * This function behaves similarly to s_str_c_str. 119 | */ 120 | const char* s_str_c_substr(const s_str *const this_, const size_t index); 121 | 122 | 123 | /* Sets the s_str equal to the char, clearing all previously stored elements. 124 | */ 125 | void s_str_assign_char(s_str *const this_, const char c); 126 | 127 | 128 | /* Sets the s_str equal to the char for the given length, clearing all previously stored elements. 129 | */ 130 | void s_str_assign_multi_char(s_str *const this_, const size_t length, const char c); 131 | 132 | 133 | /* Sets the s_str equal to a copy of the C-string, clearing all previously stored elements. 134 | */ 135 | void s_str_assign_c_str(s_str *const this_, const char *const c_str_ptr); 136 | 137 | 138 | /* Sets the s_str equal to a copy of the (dereferenced) s_str_ptr_for_assign, clearing all previously stored elements. 139 | */ 140 | void s_str_assign_s_str(s_str *const this_, const s_str *const s_str_ptr_for_assign); 141 | 142 | 143 | /* Retrieves and returns the char at "index" in the s_str. Returns '\0' if "index" is out of range. 144 | */ 145 | char s_str_at(const s_str *const this_, const size_t index); 146 | 147 | 148 | /* Removes the char located at "index". If "index" is out of range or is the index of the default terminating null 149 | * character, this function does nothing. 150 | */ 151 | void s_str_remove_at(const s_str *const this_, const size_t index); 152 | 153 | 154 | /* Attempts to find the first appearance of the char, starting from the front and ending at the back of the s_str. 155 | * Returns the index of the first matching char if found; otherwise, returns the index of the default terminating null character. 156 | */ 157 | size_t s_str_find_char(const s_str *const this_, const char c); 158 | 159 | 160 | /* Attempts to find the first appearance of the c_str, starting from the front and ending at the back of the s_str. 161 | * Returns the index at the beginning of the first matching c_str if found. If not found or if the C-string is larger in size than the s_str, 162 | * returns the index of the default terminating null character. 163 | */ 164 | size_t s_str_find_c_str(const s_str *const this_, const char *const c_str_ptr); 165 | 166 | 167 | /* Attempts to find the first appearance of the (dereferenced) s_str_ptr_for_find, starting from the front and ending at the back of the s_str. 168 | * Returns the index at the beginning of the first matching string if found. If not found or if the (dereferenced) s_str_ptr_for_find is larger 169 | * in size than the s_str, returns the index of the default terminating null character. 170 | */ 171 | size_t s_str_find_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_find); 172 | 173 | 174 | /* Attempts to find the first appearance of the char, starting from the back and ending at the front of the s_str. 175 | * Returns the index of the first matching char if found; otherwise, returns the index of the default terminating null character. 176 | */ 177 | size_t s_str_rfind_char(const s_str *const this_, const char c); 178 | 179 | 180 | /* Attempts to find the first appearance of the c_str, starting from the back and ending at the front of the s_str. 181 | * Returns the index at the beginning of the first matching c_str if found. If not found or if the C-string is larger in size than the s_str, 182 | * returns the index of the default terminating null character. 183 | */ 184 | size_t s_str_rfind_c_str(const s_str *const this_, const char *const c_str_ptr); 185 | 186 | 187 | /* Attempts to find the first appearance of the (dereferenced) s_str_ptr_for_rfind, starting from the back and ending at the front of the s_str. 188 | * Returns the index at the beginning of the first matching string if found. If not found or if the (dereferenced) s_str_ptr_for_rfind is larger 189 | * in size than the s_str, returns the index of the default terminating null character. 190 | */ 191 | size_t s_str_rfind_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_rfind); 192 | 193 | 194 | /* Returns the maximum number of elements the s_str can store (including the terminating null character) before 195 | * needing to dynamically reallocate. 196 | * 197 | * Note: Dynamic reallocation is all automatic and the user should not worry about it unless reallocation time is 198 | * expensive (which is unlikely in even huge strings since char is only 1 byte). 199 | * 200 | * Note: The capacity of a s_str is always greater than or equal to the s_str's size. The capacity represents the 201 | * max number of elements the s_str can store before needing to reallocate. 202 | */ 203 | size_t s_str_capacity(const s_str *const this_); 204 | 205 | 206 | /* Requests the s_str to reserve enough space in memory so that the s_str can store the given "num_elem's" before needing to 207 | * reallocate. If "num_elem's" is less than or equal to the current s_str capacity, the request is denied. 208 | */ 209 | void s_str_reserve(s_str *const this_, size_t num_elem); 210 | 211 | 212 | /* Returns the size of the s_str (the total number of held elements). 213 | * 214 | * The returned total will count every single character present, including terminating null characters. 215 | */ 216 | size_t s_str_size(const s_str *const this_); 217 | 218 | 219 | /* Returns the "strlen" of the s_str. 220 | * 221 | * It is important to realize that if the s_str contains multiple terminating null characters, the returned length will only 222 | * be the size of the s_str up to but not including the first terminating null character. 223 | */ 224 | size_t s_str_length(const s_str *const this_); 225 | 226 | 227 | /* Returns true if the s_str is empty (excluding the default terminating null character). 228 | * Returns false if the s_str contains an element other than the default terminating null character. 229 | */ 230 | _Bool s_str_empty(const s_str *const this_); 231 | 232 | 233 | /* Clears all elements in the s_str. 234 | */ 235 | void s_str_clear(const s_str *const this_); 236 | 237 | 238 | /* Removes any preceding or trailing spaces in the s_str. 239 | * Example: 240 | * s_str foo = s_str_create_from_c_str(" test "); 241 | * s_str_trim(&foo); 242 | * printf("\"%s\"\n", s_str_c_str(&foo)); 243 | * // Output: "test" 244 | * s_str_destroy(&foo); 245 | */ 246 | void s_str_trim(const s_str *const this_); 247 | 248 | 249 | /* Requests the s_str to reduce its capacity to fit its size. 250 | */ 251 | void s_str_shrink_to_fit(s_str *const this_); 252 | 253 | 254 | /* Adds the char to the end of the s_str. 255 | */ 256 | void s_str_push_back(s_str *const this_, const char c); 257 | 258 | 259 | /* Removes the char (excluding the default terminating null character) located at the end of the s_str. 260 | * 261 | * Returns the removed char. 262 | */ 263 | char s_str_pop_back(const s_str *const this_); 264 | 265 | 266 | /* Appends the c_str to the end of the s_str. 267 | */ 268 | void s_str_append_c_str(s_str *const this_, const char *const c_str_ptr); 269 | 270 | 271 | /* Appends the (dereferenced) s_str_ptr_for_append to the end of the s_str. 272 | */ 273 | void s_str_append_s_str(s_str *const this_, const s_str *const s_str_ptr_for_append); 274 | 275 | 276 | /* Retrieves and returns the memory address of the s_str's first word. This function does the same thing as s_str_c_str 277 | * but is more explicit in its intention when paired with the functions s_str_remove_first_word, s_str_last_word, and 278 | * s_str_remove_last_word. 279 | */ 280 | const char* s_str_first_word(const s_str *const this_); 281 | 282 | 283 | /* Removes s_str's first word plus any trailing spaces. The first word is either the string of characters preceding the first space, the first 284 | * space itself, or the entire s_str if there are no spaces. 285 | */ 286 | void s_str_remove_first_word(const s_str *const this_); 287 | 288 | 289 | /* Retrieves and returns the memory address of the s_str's last word. The beginning of the last word is the string of 290 | * characters following the last space, the last space itself, or if there are no spaces, the entire s_str. 291 | */ 292 | const char* s_str_last_word(const s_str *const this_); 293 | 294 | 295 | /* Removes the s_str's last word plus any preceding spaces. The last word is either the string of characters following 296 | * the last space, the last space itself, or if there are no spaces, the entire s_str. 297 | */ 298 | void s_str_remove_last_word(const s_str *const this_); 299 | 300 | 301 | /* Erases the portion of the s_str that begins at the character position "index" and spans "length" characters (or until the end of the s_str). 302 | * 303 | * Range: [index, length) 304 | */ 305 | void s_str_erase(const s_str *const this_, const size_t index, size_t length); 306 | 307 | 308 | /* Inserts the char into the s_str right before the character at "index". 309 | */ 310 | void s_str_insert_char(s_str *const this_, const size_t index, const char c); 311 | 312 | 313 | /* Inserts the C-string into the s_str right before the character at "index". 314 | */ 315 | void s_str_insert_c_str(s_str *const this_, const size_t index, const char *const c_str_ptr); 316 | 317 | 318 | /* Inserts the (dereferenced) s_str_ptr_for_insert into the s_str right before the s_str's character at "index". 319 | */ 320 | void s_str_insert_s_str(s_str *const this_, const size_t index, const s_str *const s_str_ptr_for_insert); 321 | 322 | 323 | /* Seperates every element in the s_str with char. If the size of the s_str is 1, then this function does nothing. 324 | */ 325 | void s_str_sepwith_char(s_str *const this_, const char c); 326 | 327 | 328 | /* Seperates every element in the s_str with the C-string. If the size of the s_str is 1, then this function does nothing. 329 | */ 330 | void s_str_sepwith_c_str(s_str *const this_, const char *const c_str_ptr); 331 | 332 | 333 | /* Seperates every element in the s_str with the (dereferenced) s_str_ptr_for_sepwith. If the size of the s_str is 1, then 334 | * this function does nothing. 335 | */ 336 | void s_str_sepwith_s_str(s_str *const this_, const s_str *const s_str_ptr_for_sepwith); 337 | 338 | 339 | /* Replaces the portion of the s_str that begins at "index" and spans "length" characters with char (or until the end of 340 | * the s_str). 341 | * 342 | * Range: [index, length) 343 | */ 344 | void s_str_replace(const s_str *const this_, const size_t index, size_t length, const char c); 345 | 346 | 347 | /* Replaces the entire s_str with char. 348 | */ 349 | void s_str_replace_all(const s_str *const this_, const char c); 350 | 351 | 352 | /* Swaps the elements in the s_str's. 353 | * 354 | * Example: 355 | * s_str str1 = s_str_create_from_c_str("1234"); 356 | * s_str str2 = s_str_create_from_c_str("abcdef"); 357 | * s_str_swap(&str1, &str2); 358 | * printf("str1: %s, str2: %s\n", s_str_c_str(&str1), s_str_c_str(&str2)); 359 | * // Output: str1: abcdef, str2: 1234 360 | * s_str_destroy(&str1); 361 | * s_str_destroy(&str2); 362 | */ 363 | void s_str_swap(s_str *const this_, s_str *const s_str_ptr_for_swap); 364 | 365 | 366 | /* Calls the given function (which takes a pointer-to-char and returns nothing (void)) for each element in the s_str that begins at the 367 | * character position "index" and spans "length" characters (or until the end of the s_str). The default terminating null character is 368 | * excluded. 369 | * 370 | * Range: [index, length) 371 | */ 372 | void s_str_foreach(const s_str *const this_, const size_t index, size_t length, void (*const fptr)(char *)); 373 | 374 | 375 | /* Calls the given function (which takes a pointer-to-char and returns nothing (void)) for each element in the s_str. The default 376 | * terminating null character is excluded. 377 | */ 378 | void s_str_foreach_all(const s_str *const this_, void (*const fptr)(char *)); 379 | 380 | 381 | /* Compares the s_str with the C-string (excludes the default terminating null character and the C-string's terminating 382 | * null character). 383 | * 384 | * Returns 0 if they compare equal. 385 | * 386 | * Returns < 0 if either the value of the first character that does not match is lower in the s_str, or all 387 | * compared characters match but the s_str is shorter in size. 388 | * 389 | * Returns > 0 if either the value of the first character that does not match is greater in the s_str, or all 390 | * compared characters match but the s_str is longer in size. 391 | */ 392 | int s_str_compare_c_str(const s_str *const this_, const char *const c_str_ptr); 393 | 394 | 395 | /* Compares the s_str with the (dereferenced) s_str_ptr_for_compare (excludes the default terminating null character in 396 | * both s_str's). 397 | * 398 | * Returns 0 if they compare equal. 399 | * 400 | * Returns < 0 if either the value of the first character that does not match is lower in the s_str, or all 401 | * compared characters match but the s_str is shorter in size. 402 | * 403 | * Returns > 0 if either the value of the first character that does not match is greater in the s_str, or all 404 | * compared characters match but the s_str is longer in size. 405 | */ 406 | int s_str_compare_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_compare); 407 | 408 | 409 | /* Sorts the s_str's elements by using the function pointer "compare" in a fashion identical to qsort (omits the 410 | * default terminating null character from sort). 411 | */ 412 | void s_str_sort(s_str *const this_, int (*const compare)(const void *, const void *)); 413 | 414 | 415 | #endif 416 | -------------------------------------------------------------------------------- /src/s_str.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | #include "s_str.h" 7 | 8 | 9 | #define access_struct(pointer_to_void) (*(struct S_STRING_STRUCT *) pointer_to_void) 10 | 11 | 12 | /* This struct is what the s_str points to. This struct contains information that should not be accessed by the user. This information is vital 13 | * in the s_str's implementation. 14 | */ 15 | struct S_STRING_STRUCT{ 16 | // Total number of elements the string can hold before needing to reallocate 17 | size_t capacity; 18 | 19 | // Total number of elements currently in the string (the default terminating null character is included) 20 | size_t size; 21 | 22 | // Flexible array member that holds all elements 23 | char string[]; 24 | }; 25 | 26 | 27 | /* Creates a temporary s_str whose capacity is equal to the given number of elements plus an additional 50% of unused memory and size is 28 | * equal to the given number of elements. The s_str's elements are left to be handled by the calling function. 29 | * 30 | * Returns NULL if the given number of elements is less than the size of the s_str or if the temporary s_str cannot 31 | * allocate the required amount of memory. Returns the temporary s_str otherwise. 32 | * 33 | * Upon success, the returned s_str MUST be destroyed at some point! 34 | */ 35 | static inline s_str s_str_create_temp(const s_str *const this_, const size_t num_elem){ 36 | if(num_elem >= access_struct(*this_).size){ 37 | s_str temp = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char) * (size_t) (1.5 * num_elem)); 38 | 39 | if(temp != NULL){ 40 | access_struct(temp).capacity = (size_t) (1.5 * num_elem); 41 | access_struct(temp).size = num_elem; 42 | 43 | return temp; 44 | } 45 | } 46 | 47 | return NULL; 48 | } 49 | 50 | 51 | s_str s_str_create(void){ 52 | s_str new_str = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char)); 53 | 54 | if(new_str != NULL){ 55 | access_struct(new_str).capacity = 1; 56 | access_struct(new_str).size = 1; 57 | 58 | access_struct(new_str).string[0] = '\0'; 59 | } 60 | 61 | return new_str; 62 | } 63 | 64 | 65 | s_str s_str_create_from_char(const char c){ 66 | s_str new_str = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char) * 2); 67 | 68 | if(new_str != NULL){ 69 | access_struct(new_str).capacity = 2; 70 | access_struct(new_str).size = 2; 71 | 72 | access_struct(new_str).string[0] = c; 73 | access_struct(new_str).string[1] = '\0'; 74 | } 75 | 76 | return new_str; 77 | } 78 | 79 | 80 | s_str s_str_create_from_multi_char(const size_t length, const char c){ 81 | s_str new_str = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char) * (length + 1)); 82 | 83 | if(new_str != NULL){ 84 | access_struct(new_str).capacity = length + 1; 85 | access_struct(new_str).size = length + 1; 86 | 87 | for(size_t counter = 0; counter < length; ++counter){ 88 | access_struct(new_str).string[counter] = c; 89 | } 90 | access_struct(new_str).string[length] = '\0'; 91 | } 92 | 93 | return new_str; 94 | } 95 | 96 | 97 | s_str s_str_create_from_c_str(const char *const c_str_ptr){ 98 | s_str new_str; 99 | 100 | if(c_str_ptr == NULL){ 101 | new_str = s_str_create(); 102 | }else{ 103 | new_str = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char) * (strlen(c_str_ptr) + 1)); 104 | 105 | if(new_str != NULL){ 106 | access_struct(new_str).capacity = strlen(c_str_ptr) + 1; 107 | access_struct(new_str).size = strlen(c_str_ptr) + 1; 108 | 109 | memcpy(access_struct(new_str).string, c_str_ptr, sizeof(char) * (strlen(c_str_ptr) + 1)); 110 | } 111 | } 112 | 113 | return new_str; 114 | } 115 | 116 | 117 | s_str s_str_create_from_s_str(const s_str *const s_str_ptr_for_create){ 118 | s_str new_str; 119 | 120 | if(s_str_ptr_for_create == NULL){ 121 | new_str = s_str_create(); 122 | }else{ 123 | new_str = malloc(sizeof(struct S_STRING_STRUCT) + sizeof(char) * access_struct(*s_str_ptr_for_create).size); 124 | 125 | if(new_str != NULL){ 126 | access_struct(new_str).capacity = access_struct(*s_str_ptr_for_create).size; 127 | access_struct(new_str).size = access_struct(*s_str_ptr_for_create).size; 128 | 129 | memcpy(access_struct(new_str).string, access_struct(*s_str_ptr_for_create).string, sizeof(char) * access_struct(*s_str_ptr_for_create).size); 130 | } 131 | } 132 | 133 | return new_str; 134 | } 135 | 136 | 137 | void s_str_destroy(s_str *const this_){ 138 | if(this_ != NULL && *this_ != NULL){ 139 | free(*this_); 140 | *this_ = NULL; 141 | } 142 | } 143 | 144 | 145 | const char* s_str_c_str(const s_str *const this_){ 146 | assert(this_ != NULL && *this_ != NULL); 147 | 148 | return access_struct(*this_).string; 149 | } 150 | 151 | 152 | const char* s_str_c_substr(const s_str *const this_, const size_t index){ 153 | assert(this_ != NULL && *this_ != NULL); 154 | 155 | if(index >= access_struct(*this_).size){ 156 | return access_struct(*this_).string + access_struct(*this_).size - 1; 157 | }else{ 158 | return access_struct(*this_).string + index; 159 | } 160 | } 161 | 162 | 163 | void s_str_assign_char(s_str *const this_, const char c){ 164 | assert(this_ != NULL && *this_ != NULL); 165 | 166 | if(access_struct(*this_).capacity < 2){ 167 | s_str temp = s_str_create_temp(this_, 2); 168 | 169 | if(temp != NULL){ 170 | access_struct(temp).string[0] = c; 171 | access_struct(temp).string[1] = '\0'; 172 | 173 | free(*this_); 174 | *this_ = temp; 175 | } 176 | }else{ 177 | access_struct(*this_).string[0] = c; 178 | access_struct(*this_).string[1] = '\0'; 179 | 180 | access_struct(*this_).size = 2; 181 | } 182 | } 183 | 184 | 185 | void s_str_assign_multi_char(s_str *const this_, const size_t length, const char c){ 186 | assert(this_ != NULL && *this_ != NULL); 187 | 188 | if(access_struct(*this_).capacity < length + 1){ 189 | s_str temp = s_str_create_temp(this_, length + 1); 190 | 191 | if(temp != NULL){ 192 | for(size_t counter = 0; counter < length; ++counter){ 193 | access_struct(temp).string[counter] = c; 194 | } 195 | access_struct(temp).string[length] = '\0'; 196 | 197 | free(*this_); 198 | *this_ = temp; 199 | } 200 | }else{ 201 | for(size_t counter = 0; counter < length; ++counter){ 202 | access_struct(*this_).string[counter] = c; 203 | } 204 | access_struct(*this_).string[length] = '\0'; 205 | 206 | access_struct(*this_).size = length + 1; 207 | } 208 | } 209 | 210 | 211 | void s_str_assign_c_str(s_str *const this_, const char *const c_str_ptr){ 212 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 213 | 214 | if(access_struct(*this_).capacity < strlen(c_str_ptr) + 1){ 215 | s_str temp = s_str_create_temp(this_, strlen(c_str_ptr) + 1); 216 | 217 | if(temp != NULL){ 218 | memcpy(access_struct(temp).string, c_str_ptr, sizeof(char) * (strlen(c_str_ptr) + 1)); 219 | 220 | free(*this_); 221 | *this_ = temp; 222 | } 223 | }else{ 224 | memcpy(access_struct(*this_).string, c_str_ptr, sizeof(char) * (strlen(c_str_ptr) + 1)); 225 | 226 | access_struct(*this_).size = strlen(c_str_ptr) + 1; 227 | } 228 | } 229 | 230 | 231 | void s_str_assign_s_str(s_str *const this_, const s_str *const s_str_ptr_for_assign){ 232 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_assign != NULL && *s_str_ptr_for_assign != NULL); 233 | 234 | if(access_struct(*this_).capacity < access_struct(*s_str_ptr_for_assign).size){ 235 | s_str temp = s_str_create_temp(this_, access_struct(*s_str_ptr_for_assign).size); 236 | 237 | if(temp != NULL){ 238 | memcpy(access_struct(temp).string, access_struct(*s_str_ptr_for_assign).string, sizeof(char) * access_struct(*s_str_ptr_for_assign).size); 239 | 240 | free(*this_); 241 | *this_ = temp; 242 | } 243 | }else{ 244 | memcpy(access_struct(*this_).string, access_struct(*s_str_ptr_for_assign).string, sizeof(char) * access_struct(*s_str_ptr_for_assign).size); 245 | 246 | access_struct(*this_).size = access_struct(*s_str_ptr_for_assign).size; 247 | } 248 | } 249 | 250 | 251 | char s_str_at(const s_str *const this_, const size_t index){ 252 | assert(this_ != NULL && *this_ != NULL); 253 | 254 | if(index >= access_struct(*this_).size){ 255 | return '\0'; 256 | }else{ 257 | return access_struct(*this_).string[index]; 258 | } 259 | } 260 | 261 | 262 | void s_str_remove_at(const s_str *const this_, const size_t index){ 263 | assert(this_ != NULL && *this_ != NULL); 264 | 265 | if(index < access_struct(*this_).size - 1){ 266 | memmove(access_struct(*this_).string + index, access_struct(*this_).string + index + 1, sizeof(char) * (access_struct(*this_).size - (index + 1))); 267 | 268 | --access_struct(*this_).size; 269 | } 270 | } 271 | 272 | 273 | size_t s_str_find_char(const s_str *const this_, const char c){ 274 | assert(this_ != NULL && *this_ != NULL); 275 | 276 | for(size_t counter = 0; counter < access_struct(*this_).size; ++counter){ 277 | if(access_struct(*this_).string[counter] == c){ 278 | return counter; 279 | } 280 | } 281 | 282 | return access_struct(*this_).size - 1; 283 | } 284 | 285 | 286 | size_t s_str_find_c_str(const s_str *const this_, const char *const c_str_ptr){ 287 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 288 | 289 | if(strlen(c_str_ptr) == 0){ 290 | return s_str_find_char(this_, '\0'); 291 | }else if(strlen(c_str_ptr) < access_struct(*this_).size){ 292 | for(size_t counter = 0; counter < access_struct(*this_).size - strlen(c_str_ptr); ++counter){ 293 | if(memcmp(access_struct(*this_).string + counter, c_str_ptr, sizeof(char) * strlen(c_str_ptr)) == 0){ 294 | return counter; 295 | } 296 | } 297 | } 298 | 299 | return access_struct(*this_).size - 1; 300 | } 301 | 302 | 303 | size_t s_str_find_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_find){ 304 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_find != NULL && *s_str_ptr_for_find != NULL); 305 | 306 | if(access_struct(*s_str_ptr_for_find).size == 1){ 307 | return s_str_find_char(this_, '\0'); 308 | }else if(access_struct(*s_str_ptr_for_find).size - 1 < access_struct(*this_).size){ 309 | for(size_t counter = 0; counter < access_struct(*this_).size - (access_struct(*s_str_ptr_for_find).size - 1); ++counter){ 310 | if(memcmp(access_struct(*this_).string + counter, access_struct(*s_str_ptr_for_find).string, 311 | sizeof(char) * (access_struct(*s_str_ptr_for_find).size - 1)) == 0){ 312 | 313 | return counter; 314 | } 315 | } 316 | } 317 | 318 | return access_struct(*this_).size - 1; 319 | } 320 | 321 | 322 | size_t s_str_rfind_char(const s_str *const this_, const char c){ 323 | assert(this_ != NULL && *this_ != NULL); 324 | 325 | for(size_t counter = access_struct(*this_).size - 1; ; --counter){ 326 | if(access_struct(*this_).string[counter] == c){ 327 | return counter; 328 | }else if(counter == 0){ 329 | return access_struct(*this_).size - 1; 330 | } 331 | } 332 | } 333 | 334 | 335 | size_t s_str_rfind_c_str(const s_str *const this_, const char *const c_str_ptr){ 336 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 337 | 338 | if(strlen(c_str_ptr) == 0){ 339 | return s_str_rfind_char(this_, '\0'); 340 | }else if(strlen(c_str_ptr) < access_struct(*this_).size){ 341 | for(size_t counter = access_struct(*this_).size - 1 - strlen(c_str_ptr); ; --counter){ 342 | if(memcmp(access_struct(*this_).string + counter, c_str_ptr, sizeof(char) * strlen(c_str_ptr)) == 0){ 343 | return counter; 344 | }else if(counter == 0){ 345 | return access_struct(*this_).size - 1; 346 | } 347 | } 348 | } 349 | 350 | return access_struct(*this_).size - 1; 351 | } 352 | 353 | 354 | size_t s_str_rfind_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_rfind){ 355 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_rfind != NULL && *s_str_ptr_for_rfind != NULL); 356 | 357 | if(access_struct(*s_str_ptr_for_rfind).size == 1){ 358 | return s_str_rfind_char(this_, '\0'); 359 | }else if(access_struct(*s_str_ptr_for_rfind).size - 1 < access_struct(*this_).size){ 360 | for(size_t counter = access_struct(*this_).size - access_struct(*s_str_ptr_for_rfind).size; ; --counter){ 361 | if(memcmp(access_struct(*this_).string + counter, access_struct(*s_str_ptr_for_rfind).string, 362 | sizeof(char) * (access_struct(*s_str_ptr_for_rfind).size - 1)) == 0){ 363 | 364 | return counter; 365 | }else if(counter == 0){ 366 | return access_struct(*this_).size - 1; 367 | } 368 | } 369 | } 370 | 371 | return access_struct(*this_).size - 1; 372 | } 373 | 374 | 375 | size_t s_str_capacity(const s_str *const this_){ 376 | assert(this_ != NULL && *this_ != NULL); 377 | 378 | return access_struct(*this_).capacity; 379 | } 380 | 381 | 382 | void s_str_reserve(s_str *const this_, const size_t num_elem){ 383 | assert(this_ != NULL && *this_ != NULL); 384 | 385 | if(num_elem > access_struct(*this_).size){ 386 | s_str temp = realloc(*this_, sizeof(struct S_STRING_STRUCT) + sizeof(char) * num_elem); 387 | 388 | if(temp != NULL){ 389 | access_struct(temp).capacity = num_elem; 390 | 391 | *this_ = temp; 392 | } 393 | } 394 | } 395 | 396 | 397 | size_t s_str_size(const s_str *const this_){ 398 | assert(this_ != NULL && *this_ != NULL); 399 | 400 | return access_struct(*this_).size; 401 | } 402 | 403 | 404 | size_t s_str_length(const s_str *const this_){ 405 | assert(this_ != NULL && *this_ != NULL); 406 | 407 | return strlen(access_struct(*this_).string); 408 | } 409 | 410 | 411 | _Bool s_str_empty(const s_str *const this_){ 412 | assert(this_ != NULL && *this_ != NULL); 413 | 414 | if(access_struct(*this_).size == 1){ 415 | return 1; 416 | }else{ 417 | return 0; 418 | } 419 | } 420 | 421 | 422 | void s_str_clear(const s_str *const this_){ 423 | assert(this_ != NULL && *this_ != NULL); 424 | 425 | access_struct(*this_).string[0] = '\0'; 426 | access_struct(*this_).size = 1; 427 | } 428 | 429 | 430 | void s_str_trim(const s_str *const this_){ 431 | assert(this_ != NULL && *this_ != NULL); 432 | 433 | // A s_str will ALWAYS have at least a terminating null character; therefore, it will ALWAYS have at least a size of 1 434 | while(access_struct(*this_).string[0] == ' '){ 435 | s_str_remove_at(this_, 0); 436 | } 437 | 438 | while(access_struct(*this_).size > 1 && access_struct(*this_).string[access_struct(*this_).size - 2] == ' '){ 439 | s_str_remove_at(this_, access_struct(*this_).size - 2); 440 | } 441 | } 442 | 443 | 444 | void s_str_shrink_to_fit(s_str *const this_){ 445 | assert(this_ != NULL && *this_ != NULL); 446 | 447 | if(access_struct(*this_).capacity != access_struct(*this_).size){ 448 | s_str temp = realloc(*this_, sizeof(struct S_STRING_STRUCT) + sizeof(char) * access_struct(*this_).size); 449 | 450 | if(temp != NULL){ 451 | access_struct(temp).capacity = access_struct(temp).size; 452 | 453 | *this_ = temp; 454 | } 455 | } 456 | } 457 | 458 | 459 | void s_str_push_back(s_str *const this_, const char c){ 460 | assert(this_ != NULL && *this_ != NULL); 461 | 462 | if(access_struct(*this_).size + 1 > access_struct(*this_).capacity){ 463 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + 1); 464 | 465 | if(temp != NULL){ 466 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * (access_struct(*this_).size - 1)); 467 | access_struct(temp).string[access_struct(*this_).size - 1] = c; 468 | access_struct(temp).string[access_struct(*this_).size] = '\0'; 469 | 470 | free(*this_); 471 | *this_ = temp; 472 | } 473 | }else{ 474 | access_struct(*this_).string[access_struct(*this_).size - 1] = c; 475 | access_struct(*this_).string[access_struct(*this_).size] = '\0'; 476 | 477 | ++access_struct(*this_).size; 478 | } 479 | } 480 | 481 | 482 | char s_str_pop_back(const s_str *const this_){ 483 | assert(this_ != NULL && *this_ != NULL); 484 | 485 | if(access_struct(*this_).size > 1){ 486 | char popped_char = access_struct(*this_).string[access_struct(*this_).size - 2]; 487 | 488 | access_struct(*this_).string[access_struct(*this_).size - 2] = '\0'; 489 | 490 | --access_struct(*this_).size; 491 | 492 | return popped_char; 493 | } 494 | 495 | return '\0'; 496 | } 497 | 498 | 499 | void s_str_append_c_str(s_str *const this_, const char *const c_str_ptr){ 500 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 501 | 502 | if(access_struct(*this_).size + strlen(c_str_ptr) > access_struct(*this_).capacity){ 503 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + strlen(c_str_ptr)); 504 | 505 | if(temp != NULL){ 506 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * (access_struct(*this_).size - 1)); 507 | memcpy(access_struct(temp).string + access_struct(*this_).size - 1, c_str_ptr, sizeof(char) * (strlen(c_str_ptr) + 1)); 508 | 509 | free(*this_); 510 | *this_ = temp; 511 | } 512 | }else{ 513 | memcpy(access_struct(*this_).string + access_struct(*this_).size - 1, c_str_ptr, sizeof(char) * (strlen(c_str_ptr) + 1)); 514 | 515 | access_struct(*this_).size += strlen(c_str_ptr); 516 | } 517 | } 518 | 519 | 520 | void s_str_append_s_str(s_str *const this_, const s_str *const s_str_ptr_for_append){ 521 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_append != NULL && *s_str_ptr_for_append != NULL); 522 | 523 | if(access_struct(*this_).size + access_struct(*s_str_ptr_for_append).size > access_struct(*this_).capacity){ 524 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + access_struct(*s_str_ptr_for_append).size - 1); 525 | 526 | if(temp != NULL){ 527 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * (access_struct(*this_).size - 1)); 528 | memcpy(access_struct(temp).string + access_struct(*this_).size - 1, access_struct(*s_str_ptr_for_append).string, 529 | sizeof(char) * access_struct(*s_str_ptr_for_append).size); 530 | 531 | free(*this_); 532 | *this_ = temp; 533 | } 534 | }else{ 535 | memcpy(access_struct(*this_).string + access_struct(*this_).size - 1, access_struct(*s_str_ptr_for_append).string, 536 | sizeof(char) * access_struct(*s_str_ptr_for_append).size); 537 | 538 | access_struct(*this_).size += access_struct(*s_str_ptr_for_append).size - 1; 539 | } 540 | } 541 | 542 | 543 | const char* s_str_first_word(const s_str *const this_){ 544 | assert(this_ != NULL && *this_ != NULL); 545 | 546 | return access_struct(*this_).string; 547 | } 548 | 549 | 550 | void s_str_remove_first_word(const s_str *const this_){ 551 | assert(this_ != NULL && *this_ != NULL); 552 | 553 | if(access_struct(*this_).size > 1){ 554 | const size_t index = s_str_find_char(this_, ' '); 555 | 556 | if(index == access_struct(*this_).size - 1){ 557 | s_str_clear(this_); 558 | }else{ 559 | memmove(access_struct(*this_).string, access_struct(*this_).string + index + 1, sizeof(char) * (access_struct(*this_).size - (index + 1))); 560 | 561 | access_struct(*this_).size -= index + 1; 562 | } 563 | } 564 | } 565 | 566 | 567 | const char* s_str_last_word(const s_str *const this_){ 568 | assert(this_ != NULL && *this_ != NULL); 569 | 570 | const size_t index = s_str_rfind_char(this_, ' '); 571 | 572 | if(index == access_struct(*this_).size - 1 || access_struct(*this_).size == 2){ 573 | return access_struct(*this_).string; 574 | }else{ 575 | return access_struct(*this_).string + index + 1; 576 | } 577 | } 578 | 579 | 580 | void s_str_remove_last_word(const s_str *const this_){ 581 | assert(this_ != NULL && *this_ != NULL); 582 | 583 | const size_t index = s_str_rfind_char(this_, ' '); 584 | 585 | if(index == access_struct(*this_).size - 1){ 586 | s_str_clear(this_); 587 | }else{ 588 | access_struct(*this_).string[index] = '\0'; 589 | 590 | access_struct(*this_).size -= access_struct(*this_).size - (index + 1); 591 | } 592 | } 593 | 594 | 595 | void s_str_erase(const s_str *const this_, const size_t index, size_t length){ 596 | assert(this_ != NULL && *this_ != NULL); 597 | 598 | if(index < access_struct(*this_).size - 1){ 599 | if(index + length >= access_struct(*this_).size - 1){ 600 | length = access_struct(*this_).size - (index + 1); 601 | } 602 | 603 | memmove(access_struct(*this_).string + index, access_struct(*this_).string + index + length, 604 | sizeof(char) * (access_struct(*this_).size - (index + length))); 605 | 606 | access_struct(*this_).size -= length; 607 | } 608 | } 609 | 610 | 611 | void s_str_insert_char(s_str *const this_, const size_t index, const char c){ 612 | assert(this_ != NULL && *this_ != NULL); 613 | 614 | if(index < access_struct(*this_).size){ 615 | if(access_struct(*this_).size + 1 > access_struct(*this_).capacity){ 616 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + 1); 617 | 618 | if(temp != NULL){ 619 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * index); 620 | memcpy(access_struct(temp).string + index + 1, access_struct(*this_).string + index, 621 | sizeof(char) * (access_struct(*this_).size - index)); 622 | access_struct(temp).string[index] = c; 623 | 624 | free(*this_); 625 | *this_ = temp; 626 | } 627 | }else{ 628 | memmove(access_struct(*this_).string + index + 1, access_struct(*this_).string + index, 629 | sizeof(char) * (access_struct(*this_).size - index)); 630 | access_struct(*this_).string[index] = c; 631 | 632 | ++access_struct(*this_).size; 633 | } 634 | } 635 | } 636 | 637 | 638 | void s_str_insert_c_str(s_str *const this_, const size_t index, const char *const c_str_ptr){ 639 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 640 | 641 | if(index < access_struct(*this_).size && strlen(c_str_ptr) > 0){ 642 | if(access_struct(*this_).size + strlen(c_str_ptr) > access_struct(*this_).capacity){ 643 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + strlen(c_str_ptr)); 644 | 645 | if(temp != NULL){ 646 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * index); 647 | memcpy(access_struct(temp).string + index + strlen(c_str_ptr), access_struct(*this_).string + index, 648 | sizeof(char) * (access_struct(*this_).size - index)); 649 | memcpy(access_struct(temp).string + index, c_str_ptr, sizeof(char) * strlen(c_str_ptr)); 650 | 651 | free(*this_); 652 | *this_ = temp; 653 | } 654 | }else{ 655 | memmove(access_struct(*this_).string + index + strlen(c_str_ptr), access_struct(*this_).string + index, 656 | sizeof(char) * (access_struct(*this_).size - index)); 657 | memcpy(access_struct(*this_).string + index, c_str_ptr, sizeof(char) * strlen(c_str_ptr)); 658 | 659 | access_struct(*this_).size += strlen(c_str_ptr); 660 | } 661 | } 662 | } 663 | 664 | 665 | void s_str_insert_s_str(s_str *const this_, const size_t index, const s_str *const s_str_ptr_for_insert){ 666 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_insert != NULL && *s_str_ptr_for_insert != NULL); 667 | 668 | if(index < access_struct(*this_).size && access_struct(*s_str_ptr_for_insert).size - 1 > 0){ 669 | if(access_struct(*this_).size + access_struct(*s_str_ptr_for_insert).size > access_struct(*this_).capacity){ 670 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + access_struct(*s_str_ptr_for_insert).size - 1); 671 | 672 | if(temp != NULL){ 673 | memcpy(access_struct(temp).string, access_struct(*this_).string, sizeof(char) * index); 674 | memcpy(access_struct(temp).string + index + access_struct(*s_str_ptr_for_insert).size - 1, access_struct(*this_).string + index, 675 | sizeof(char) * (access_struct(*this_).size - index)); 676 | memcpy(access_struct(temp).string + index, access_struct(*s_str_ptr_for_insert).string, 677 | sizeof(char) * (access_struct(*s_str_ptr_for_insert).size - 1)); 678 | 679 | free(*this_); 680 | *this_ = temp; 681 | } 682 | }else{ 683 | memmove(access_struct(*this_).string + index + access_struct(*s_str_ptr_for_insert).size - 1, access_struct(*this_).string + index, 684 | sizeof(char) * (access_struct(*this_).size - index)); 685 | memcpy(access_struct(*this_).string + index, access_struct(*s_str_ptr_for_insert).string, 686 | sizeof(char) * (access_struct(*s_str_ptr_for_insert).size - 1)); 687 | 688 | access_struct(*this_).size += access_struct(*s_str_ptr_for_insert).size - 1; 689 | } 690 | } 691 | } 692 | 693 | 694 | void s_str_sepwith_char(s_str *const this_, const char c){ 695 | assert(this_ != NULL && *this_ != NULL); 696 | 697 | if(access_struct(*this_).size > 1){ 698 | char *const slate = malloc(sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * 1)); 699 | 700 | if(slate != NULL){ 701 | for(size_t num_iterations = 0, counter = 0; num_iterations < access_struct(*this_).size - 2; ++num_iterations, counter += 2){ 702 | slate[counter] = access_struct(*this_).string[num_iterations]; 703 | 704 | slate[counter + 1] = c; 705 | } 706 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * 1 - 2] = access_struct(*this_).string[access_struct(*this_).size - 2]; 707 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * 1 - 1] = '\0'; 708 | 709 | if(access_struct(*this_).size + (access_struct(*this_).size - 2) * 1 > access_struct(*this_).capacity){ 710 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + (access_struct(*this_).size - 2) * 1); 711 | 712 | if(temp != NULL){ 713 | memcpy(access_struct(temp).string, slate, sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * 1)); 714 | 715 | free(*this_); 716 | *this_ = temp; 717 | } 718 | }else{ 719 | memcpy(access_struct(*this_).string, slate, sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * 1)); 720 | 721 | access_struct(*this_).size += (access_struct(*this_).size - 2) * 1; 722 | } 723 | 724 | free(slate); 725 | } 726 | } 727 | } 728 | 729 | 730 | void s_str_sepwith_c_str(s_str *const this_, const char *const c_str_ptr){ 731 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 732 | 733 | if(access_struct(*this_).size > 1 && strlen(c_str_ptr) > 0){ 734 | char *const slate = malloc(sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr))); 735 | 736 | if(slate != NULL){ 737 | for(size_t num_iterations = 0, counter = 0; num_iterations < access_struct(*this_).size - 2; ++num_iterations, counter += 1 + strlen(c_str_ptr)){ 738 | slate[counter] = access_struct(*this_).string[num_iterations]; 739 | memcpy(slate + counter + 1, c_str_ptr, sizeof(char) * strlen(c_str_ptr)); 740 | } 741 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr) - 2] = access_struct(*this_).string[access_struct(*this_).size - 2]; 742 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr) - 1] = '\0'; 743 | 744 | if(access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr) > access_struct(*this_).capacity){ 745 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr)); 746 | 747 | if(temp != NULL){ 748 | memcpy(access_struct(temp).string, slate, 749 | sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr))); 750 | 751 | free(*this_); 752 | *this_ = temp; 753 | } 754 | }else{ 755 | memcpy(access_struct(*this_).string, slate, 756 | sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * strlen(c_str_ptr))); 757 | 758 | access_struct(*this_).size += (access_struct(*this_).size - 2) * strlen(c_str_ptr); 759 | } 760 | 761 | free(slate); 762 | } 763 | } 764 | } 765 | 766 | 767 | void s_str_sepwith_s_str(s_str *const this_, const s_str *const s_str_ptr_for_sepwith){ 768 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_sepwith != NULL && *s_str_ptr_for_sepwith != NULL); 769 | 770 | if(access_struct(*this_).size > 1 && access_struct(*s_str_ptr_for_sepwith).size > 1){ 771 | char *const slate = malloc(sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * 772 | (access_struct(*s_str_ptr_for_sepwith).size - 1))); 773 | 774 | if(slate != NULL){ 775 | for(size_t num_iterations = 0, counter = 0; num_iterations < access_struct(*this_).size - 2; 776 | ++num_iterations, counter += access_struct(*s_str_ptr_for_sepwith).size){ 777 | 778 | slate[counter] = access_struct(*this_).string[num_iterations]; 779 | memcpy(slate + counter + 1, access_struct(*s_str_ptr_for_sepwith).string, sizeof(char) * (access_struct(*s_str_ptr_for_sepwith).size - 1)); 780 | } 781 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1) - 2] = 782 | access_struct(*this_).string[access_struct(*this_).size - 2]; 783 | slate[access_struct(*this_).size + (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1) - 1] = '\0'; 784 | 785 | if(access_struct(*this_).size + (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1) > access_struct(*this_).capacity){ 786 | s_str temp = s_str_create_temp(this_, access_struct(*this_).size + (access_struct(*this_).size - 2) * 787 | (access_struct(*s_str_ptr_for_sepwith).size - 1)); 788 | 789 | if(temp != NULL){ 790 | memcpy(access_struct(temp).string, slate, 791 | sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1))); 792 | 793 | free(*this_); 794 | *this_ = temp; 795 | } 796 | }else{ 797 | memcpy(access_struct(*this_).string, slate, 798 | sizeof(char) * (access_struct(*this_).size + (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1))); 799 | 800 | access_struct(*this_).size += (access_struct(*this_).size - 2) * (access_struct(*s_str_ptr_for_sepwith).size - 1); 801 | } 802 | 803 | free(slate); 804 | } 805 | } 806 | } 807 | 808 | 809 | void s_str_replace(const s_str *const this_, const size_t index, size_t length, const char c){ 810 | assert(this_ != NULL && *this_ != NULL); 811 | 812 | if(index < access_struct(*this_).size - 1){ 813 | if(index + length >= access_struct(*this_).size - 1){ 814 | length = access_struct(*this_).size - (index + 1); 815 | } 816 | 817 | memset(access_struct(*this_).string + index, c, sizeof(char) * length); 818 | } 819 | } 820 | 821 | 822 | void s_str_replace_all(const s_str *const this_, const char c){ 823 | assert(this_ != NULL && *this_ != NULL); 824 | 825 | if(access_struct(*this_).size > 1){ 826 | memset(access_struct(*this_).string, c, sizeof(char) * (access_struct(*this_).size - 1)); 827 | } 828 | } 829 | 830 | 831 | void s_str_swap(s_str *const this_, s_str *const s_str_ptr_for_swap){ 832 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_swap != NULL && *s_str_ptr_for_swap != NULL); 833 | 834 | s_str temp = *this_; 835 | *this_ = *s_str_ptr_for_swap; 836 | *s_str_ptr_for_swap = temp; 837 | } 838 | 839 | 840 | void s_str_foreach(const s_str *this_, const size_t index, size_t length, void (*const fptr)(char *)){ 841 | assert(this_ != NULL && *this_ != NULL && fptr != NULL); 842 | 843 | if(index < access_struct(*this_).size - 1){ 844 | if(index + length >= access_struct(*this_).size - 1){ 845 | length = access_struct(*this_).size - (index + 1); 846 | } 847 | 848 | for(size_t counter = index; counter < index + length; ++counter){ 849 | fptr(access_struct(*this_).string + counter); 850 | } 851 | } 852 | } 853 | 854 | 855 | void s_str_foreach_all(const s_str *this_, void (*const fptr)(char *)){ 856 | assert(this_ != NULL && *this_ != NULL && fptr != NULL); 857 | 858 | for(size_t counter = 0; counter < access_struct(*this_).size - 1; ++counter){ 859 | fptr(access_struct(*this_).string + counter); 860 | } 861 | } 862 | 863 | 864 | int s_str_compare_c_str(const s_str *const this_, const char *const c_str_ptr){ 865 | assert(this_ != NULL && *this_ != NULL && c_str_ptr != NULL); 866 | 867 | if(access_struct(*this_).size - 1 > strlen(c_str_ptr)){ 868 | const int compared_val = memcmp(access_struct(*this_).string, c_str_ptr, sizeof(char) * strlen(c_str_ptr)); 869 | 870 | if(compared_val == 0){ 871 | return 1; 872 | }else{ 873 | return compared_val; 874 | } 875 | }else if(access_struct(*this_).size - 1 < strlen(c_str_ptr)){ 876 | const int compared_val = memcmp(access_struct(*this_).string, c_str_ptr, sizeof(char) * (access_struct(*this_).size - 1)); 877 | 878 | if(compared_val == 0){ 879 | return -1; 880 | }else{ 881 | return compared_val; 882 | } 883 | }else{ 884 | const int compared_val = memcmp(access_struct(*this_).string, c_str_ptr, sizeof(char) * (access_struct(*this_).size - 1)); 885 | 886 | return compared_val; 887 | } 888 | } 889 | 890 | 891 | int s_str_compare_s_str(const s_str *const this_, const s_str *const s_str_ptr_for_compare){ 892 | assert(this_ != NULL && *this_ != NULL && s_str_ptr_for_compare != NULL && *s_str_ptr_for_compare != NULL); 893 | 894 | if(access_struct(*this_).size - 1 > access_struct(*s_str_ptr_for_compare).size - 1){ 895 | const int compared_val = memcmp(access_struct(*this_).string, access_struct(*s_str_ptr_for_compare).string, 896 | sizeof(char) * (access_struct(*s_str_ptr_for_compare).size - 1)); 897 | 898 | if(compared_val == 0){ 899 | return 1; 900 | }else{ 901 | return compared_val; 902 | } 903 | }else if(access_struct(*this_).size - 1 < access_struct(*s_str_ptr_for_compare).size - 1){ 904 | const int compared_val = memcmp(access_struct(*this_).string, access_struct(*s_str_ptr_for_compare).string, 905 | sizeof(char) * (access_struct(*this_).size - 1)); 906 | 907 | if(compared_val == 0){ 908 | return -1; 909 | }else{ 910 | return compared_val; 911 | } 912 | }else{ 913 | const int compared_val = memcmp(access_struct(*this_).string, access_struct(*s_str_ptr_for_compare).string, 914 | sizeof(char) * (access_struct(*this_).size - 1)); 915 | 916 | return compared_val; 917 | } 918 | } 919 | 920 | 921 | void s_str_sort(s_str *const this_, int (*const compare)(const void *, const void *)){ 922 | assert(this_ != NULL && *this_ != NULL && compare != NULL); 923 | 924 | if(access_struct(*this_).size > 2){ 925 | qsort(access_struct(*this_).string, access_struct(*this_).size - 1, sizeof(char), compare); 926 | } 927 | } 928 | --------------------------------------------------------------------------------