Files
2026-08-10 01:21:15 +08:00

194 lines
5.8 KiB
C

#include <ctype.h>
#include <c_StrUtil.h>
#include <c_Memory.h>
#include "c_ArrayList.h"
// Reverses a string in-place
void c_StrUtil_Reverse(char* str) {
if (!str) return;
const c_size_t len = strlen(str);
if (len <= 1) return;
c_size_t i = 0;
c_size_t j = len - 1;
while (i < j) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
i++;
j--;
}
}
// Converts a string to lowercase into a destination buffer
c_err_t c_StrUtil_ToLower(char* out_dest, const char* src, c_size_t dest_capacity) {
if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM;
c_size_t i = 0;
while (src[i] != '\0') {
if (i >= dest_capacity - 1) {
out_dest[i] = '\0';
return C_ERR_INDEX;
}
out_dest[i] = (char)tolower((unsigned char)src[i]);
i++;
}
out_dest[i] = '\0';
return C_ERR_SUCCESS;
}
// Converts a string to uppercase into a destination buffer
c_err_t c_StrUtil_ToUpper(char* out_dest, const char* src, c_size_t dest_capacity) {
if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM;
c_size_t i = 0;
while (src[i] != '\0') {
if (i >= dest_capacity - 1) {
out_dest[i] = '\0';
return C_ERR_INDEX;
}
out_dest[i] = (char)toupper((unsigned char)src[i]);
i++;
}
out_dest[i] = '\0';
return C_ERR_SUCCESS;
}
// Removes leading and trailing whitespaces into a destination buffer
c_err_t c_StrUtil_Trim(char* out_dest, const char* src, c_size_t dest_capacity) {
if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM;
// Find first non-whitespace character
while (*src && isspace((unsigned char)*src)) {
src++;
}
// Find the end of the string
c_size_t len = strlen(src);
while (len > 0 && isspace((unsigned char)src[len - 1])) {
len--;
}
if (len >= dest_capacity) {
return C_ERR_INDEX;
}
// Copy trimmed substring
memmove(out_dest, src, len);
out_dest[len] = '\0';
return C_ERR_SUCCESS;
}
c_bool_t c_StrUtil_StartsWith(const char* str, const char* prefix) {
if (!str || !prefix) return C_FALSE;
return strncmp(str, prefix, strlen(prefix)) == 0 ? C_TRUE : C_FALSE;
}
c_bool_t c_StrUtil_EndsWith(const char* str, const char* suffix) {
if (!str || !suffix) return C_FALSE;
c_size_t str_len = strlen(str);
c_size_t suf_len = strlen(suffix);
if (suf_len > str_len) return C_FALSE;
return strcmp(str + str_len - suf_len, suffix) == 0 ? C_TRUE : C_FALSE;
}
// Safely extracts a substring with full bounds verification
c_err_t c_StrUtil_Substring(char* out_dest, const char* src, c_size_t start, c_size_t len, c_size_t dest_capacity) {
if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM;
c_size_t src_len = strlen(src);
if (start > src_len) return C_ERR_INDEX;
// Adjust requested length if it overflows source string boundaries
if (start + len > src_len) {
len = src_len - start;
}
if (len >= dest_capacity) {
return C_ERR_INDEX;
}
memcpy(out_dest, src + start, len);
out_dest[len] = '\0';
return C_ERR_SUCCESS;
}
// Replaces occurrences of a substring inside a buffer safely
c_err_t c_StrUtil_Replace(char* out_dest, const char* src, const char* find, const char* replace_with, c_size_t dest_capacity) {
if (!out_dest || !src || !find || !replace_with || dest_capacity == 0) return C_ERR_PARAM;
c_size_t find_len = strlen(find);
c_size_t replace_len = strlen(replace_with);
c_size_t dest_len = 0;
if (find_len == 0) return C_ERR_PARAM;
while (*src) {
// If match found, inject replacement string
if (strncmp(src, find, find_len) == 0) {
if (dest_len + replace_len >= dest_capacity) {
out_dest[dest_len] = '\0';
return C_ERR_INDEX;
}
strcpy(out_dest + dest_len, replace_with);
dest_len += replace_len;
src += find_len;
} else {
// Otherwise, inject individual source character
if (dest_len + 1 >= dest_capacity) {
out_dest[dest_len] = '\0';
return C_ERR_INDEX;
}
out_dest[dest_len] = *src;
dest_len++;
src++;
}
}
out_dest[dest_len] = '\0';
return C_ERR_SUCCESS;
}
c_err_t c_StrUtil_Split(c_ArrayList_t* out_list, const char* src, const char* delimiter) {
if (!out_list || !src || !delimiter) return C_ERR_PARAM;
if (out_list->obj_size != sizeof(c_StrToken_t)) return C_ERR_PARAM; // Type safety assert
const c_size_t delim_len = strlen(delimiter);
if (delim_len == 0) return C_ERR_PARAM;
const char* current = src;
const char* next_match;
while ((next_match = strstr(current, delimiter)) != NULL) {
size_t token_len = next_match - current;
if (token_len > 0) {
c_StrToken_t new_token;
// Bound checking to ensure long strings don't cause buffer overflows
size_t copy_len = (token_len >= C_STR_TOKEN_MAX_LEN) ? (C_STR_TOKEN_MAX_LEN - 1) : token_len;
memcpy(new_token.text, current, copy_len);
new_token.text[copy_len] = '\0';
// Deep-copy token structure payload straight into the dynamic ArrayList
c_ArrayList_Add(out_list, &new_token);
}
current = next_match + delim_len;
}
// Capture the final token remaining after the last delimiter match
if (*current != '\0') {
c_StrToken_t new_token;
size_t token_len = strlen(current);
size_t copy_len = (token_len >= C_STR_TOKEN_MAX_LEN) ? (C_STR_TOKEN_MAX_LEN - 1) : token_len;
memcpy(new_token.text, current, copy_len);
new_token.text[copy_len] = '\0';
c_ArrayList_Add(out_list, &new_token);
}
return C_ERR_SUCCESS;
}