diff --git a/cKit/Base/c_Types.h b/cKit/Base/c_Types.h index bd4a10e..3c00c34 100644 --- a/cKit/Base/c_Types.h +++ b/cKit/Base/c_Types.h @@ -110,10 +110,14 @@ typedef time_t c_time_t; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ +typedef c_size_t c_index_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + typedef int c_err_t; #define C_ERR_OK (0) -#define C_ERR_SUCCESS C_ERR_OK #define C_ERR_FAIL (-1) #define C_ERR_NOMEM (-2) #define C_ERR_PARAM (-3) @@ -121,10 +125,15 @@ typedef int c_err_t; #define C_ERR_EMPTY (-5) #define C_ERR_INDEX (-6) #define C_ERR_STATUS (-7) -#define C_ERR_NOT_FOUND (-8) -#define C_ERR_ALREADY_EXISTS (-9) -#define C_ERR_INVALID C_ERR_FAIL +#define C_ERR_ALREADY_EXISTS (-8) +#define C_ERR_INVALID C_ERR_FAIL +#define C_ERR_SUCCESS C_ERR_OK +#define C_SUCCESS C_ERR_OK +#define C_ERR_OUT_OF_MEMORY C_ERR_NOMEM +#define C_ERR_INVALID_PARAM C_ERR_PARAM +#define C_ERR_OUT_OF_BOUNDS C_ERR_INDEX +#define C_ERR_NOT_FOUND ((c_index_t)C_ERR_FAIL) #endif /*INCLUDED_C_TYPES_H*/ diff --git a/cKit/Foundation/c_StringBuffer.c b/cKit/Foundation/c_StringBuffer.c index b4f9c8c..02194ed 100644 --- a/cKit/Foundation/c_StringBuffer.c +++ b/cKit/Foundation/c_StringBuffer.c @@ -1,7 +1,16 @@ #include #include +#include +#include -#define DEFAULT_INIT_CAPACITY 16 +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define DEFAULT_INIT_CAPACITY 16 +#define GROWTH_FACTOR 2 + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ C_STATIC_FORCE_INLINE c_err_t c_StringBuffer_EnsureCapacity(c_StringBuffer_t* self, c_size_t required_len) { @@ -12,7 +21,7 @@ c_err_t c_StringBuffer_EnsureCapacity(c_StringBuffer_t* self, c_size_t required_ c_size_t new_capacity = self->capacity == 0 ? DEFAULT_INIT_CAPACITY : self->capacity; while (new_capacity < needed_capacity) { - new_capacity *= 2; // Exponential doubling strategy + new_capacity *= GROWTH_FACTOR; // Exponential doubling strategy } char* new_buffer = (char*)C_ALLOC(new_capacity); @@ -78,7 +87,8 @@ c_err_t c_StringBuffer_Prepend(c_StringBuffer_t* self, const char* string, c_siz } c_err_t c_StringBuffer_InsertAt(c_StringBuffer_t* self, c_size_t index, const char* string, c_size_t length) { - if (!self || !self->buffer || !string || length == 0 || index > self->size) return C_ERR_PARAM; + if (!self || !self->buffer || !string || length == 0) return C_ERR_PARAM; + if (index > self->size) return C_ERR_OUT_OF_BOUNDS; c_err_t err = c_StringBuffer_EnsureCapacity(self, length); if (err != C_ERR_OK) return err; @@ -94,7 +104,9 @@ c_err_t c_StringBuffer_InsertAt(c_StringBuffer_t* self, c_size_t index, const ch } c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t length) { - if (!self || !self->buffer || length == 0 || index >= self->size) return C_ERR_PARAM; + if (!self || !self->buffer) return C_ERR_PARAM; + if (index >= self->size) return C_ERR_OUT_OF_BOUNDS; + if (length ==0) return C_SUCCESS; // Clamp length if it attempts to read past the end of the current buffer if (index + length > self->size) { @@ -134,9 +146,12 @@ c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t length, char* buffer, c_size_t buffer_length) { // 1. Guard against invalid pointers, empty destinations, or index out-of-bounds - if (!self || !self->buffer || !buffer || buffer_length == 0 || index > self->size) { + if (!self || !self->buffer || !buffer || buffer_length == 0) { return C_ERR_PARAM; } + if (index > self->size) { + return C_ERR_OUT_OF_BOUNDS; + } // 2. Clamp requested copy length if it exceeds the remaining data payload bounds if (index + length > self->size) { @@ -146,7 +161,7 @@ c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t l // 3. Enforce destination buffer capacity threshold checks // The requested segment requires at least (length + 1) bytes for safe null-termination if (length >= buffer_length) { - return C_ERR_PARAM; // Destination buffer is too small to store the segment safely + return C_ERR_OUT_OF_BOUNDS; // Destination buffer is too small to store the segment safely } // 4. Perform the raw memory copy if there are valid characters to process @@ -159,3 +174,739 @@ c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t l return C_ERR_OK; } + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +c_err_t c_StringBuffer_VPrintf(c_StringBuffer_t* self, const char* format, va_list args) { + if (!self || !format) return C_ERR_INVALID_PARAM; + + // Make a copy of args to measure the required layout length safely + va_list args_copy; + va_copy(args_copy, args); + int formatted_len = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + + if (formatted_len < 0) return C_ERR_INVALID_PARAM; + if (formatted_len == 0) return C_SUCCESS; + + c_size_t length = (c_size_t)formatted_len; + + c_err_t err = c_StringBuffer_EnsureCapacity(self, length); + if (err != C_SUCCESS) return err; + + // Use the original args list for writing directly into the structure block + vsnprintf(self->buffer + self->size, length + 1, format, args); + + self->size += length; + self->buffer[self->size] = '\0'; + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_VPrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, va_list args) { + if (!self || !format) return C_ERR_INVALID_PARAM; + if (index > self->size) return C_ERR_OUT_OF_BOUNDS; + + // Measure the length of the new formatted slice + va_list args_copy; + va_copy(args_copy, args); + int formatted_len = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + + if (formatted_len < 0) return C_ERR_INVALID_PARAM; + if (formatted_len == 0) return C_SUCCESS; + + c_size_t length = (c_size_t)formatted_len; + + c_err_t err = c_StringBuffer_EnsureCapacity(self, length); + if (err != C_SUCCESS) return err; + + // Safely backup the target downstream character that will be stomped by vsnprintf's '\0' + char backup_char = '\0'; + if (index < self->size) { + backup_char = self->buffer[index]; + } + + // Shift the existing string buffer memory forward + memmove(self->buffer + index + length, self->buffer + index, self->size - index); + + // Render formatted string fragments safely into the newly allocated block gap + vsnprintf(self->buffer + index, length + 1, format, args); + + // Overwrite the accidental inner null-terminator using our clean structural backup + if (index < self->size) { + self->buffer[index + length] = backup_char; + } + + self->size += length; + self->buffer[self->size] = '\0'; + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_Printf(c_StringBuffer_t* self, const char* format, ...) { + va_list args; + va_start(args, format); + c_err_t err = c_StringBuffer_VPrintf(self, format, args); + va_end(args); + return err; +} + +c_err_t c_StringBuffer_PrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, ...) { + va_list args; + va_start(args, format); + c_err_t err = c_StringBuffer_VPrintfAt(self, index, format, args); + va_end(args); + return err; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#include +#include + +c_err_t c_StringBuffer_AppendTimestamp(c_StringBuffer_t* self, const char* format, const struct tm* time_info) { + if (!self || !format || !time_info) return C_ERR_INVALID_PARAM; + + // Start with a reasonable initial guess for max timestamp length. + // Most standard timestamps (%Y-%m-%d %H:%M:%S) fit in under 32 or 64 bytes. + c_size_t guess_space = 64; + c_err_t err; + + while (1) { + err = c_StringBuffer_EnsureCapacity(self, guess_space); + if (err != C_SUCCESS) return err; + + // strftime writes into the remaining available capacity space. + // self->capacity - self->size calculation leaves room for the null-terminator. + c_size_t max_write = self->capacity - self->size; + size_t written = strftime(self->buffer + self->size, max_write, format, time_info); + + // strftime returns 0 if the string didn't fit into the provided buffer size + if (written == 0) { + // Check if the pattern genuinely produces a 0-length output (like an empty format string "") + if (format[0] == '\0') { + return C_SUCCESS; + } + // Double the guess size space and try again + guess_space *= 2; + + // Put an upper bound sanity check to prevent infinite loops on broken formatting parameters + if (guess_space > 4096) { + return C_ERR_INVALID_PARAM; + } + continue; + } + + // Success! Advance size tracking variable + self->size += (c_size_t)written; + // strftime automatically guarantees a null terminator at self->buffer[self->size] + break; + } + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_AppendCurrentTimestamp(c_StringBuffer_t* self, const char* format, int use_utc) { + if (!self || !format) return C_ERR_INVALID_PARAM; + + time_t raw_time = time(NULL); + if (raw_time == (time_t)-1) { + return C_ERR_INVALID_PARAM; // Failed to retrieve system clock time + } + + struct tm time_struct; + struct tm* time_ptr; + + // Thread-safe structure assembly variants (fallback to standard if platform requires it) + if (use_utc) { +#if defined(_WIN32) || defined(_WIN64) + if (gmtime_s(&time_struct, &raw_time) != 0) return C_ERR_INVALID_PARAM; + time_ptr = &time_struct; +#else + time_ptr = gmtime_r(&raw_time, &time_struct); +#endif + } else { +#if defined(_WIN32) || defined(_WIN64) + if (localtime_s(&time_struct, &raw_time) != 0) return C_ERR_INVALID_PARAM; + time_ptr = &time_struct; +#else + time_ptr = localtime_r(&raw_time, &time_struct); +#endif + } + + if (!time_ptr) return C_ERR_INVALID_PARAM; + + return c_StringBuffer_AppendTimestamp(self, format, time_ptr); +} + + +c_err_t c_StringBuffer_InsertTimestampAt(c_StringBuffer_t* self, c_size_t index, const char* format, const struct tm* time_info) { + if (!self || !format || !time_info) return C_ERR_INVALID_PARAM; + if (index > self->size) return C_ERR_OUT_OF_BOUNDS; + + // Use a conservative local stack frame memory allocation. + // Standard timestamp strings comfortably fit within 128 bytes. + char temp_stack_buffer[128]; + char* target_buffer = temp_stack_buffer; + c_size_t allocated_size = sizeof(temp_stack_buffer); + c_size_t final_len = 0; + c_err_t result = C_SUCCESS; + + while (1) { + size_t written = strftime(target_buffer, allocated_size, format, time_info); + + if (written == 0) { + // Check if the format string pattern is intentionally empty "" + if (format[0] == '\0') { + final_len = 0; + break; + } + + // If the timestamp string didn't fit, scale up the workspace dynamically on the heap + c_size_t new_allocated_size = allocated_size * 2; + + // Loop sanity guard limit to prevent infinite allocations on bad layout configurations + if (new_allocated_size > 4096) { + if (target_buffer != temp_stack_buffer) { + free(target_buffer); + } + return C_ERR_INVALID_PARAM; + } + + char* new_buffer = (target_buffer == temp_stack_buffer) + ? (char*)malloc(new_allocated_size) + : (char*)realloc(target_buffer, new_allocated_size); + + if (!new_buffer) { + if (target_buffer != temp_stack_buffer) { + free(target_buffer); + } + return C_ERR_OUT_OF_MEMORY; + } + + // Copy data over if migrating from stack array block allocation initially + if (target_buffer == temp_stack_buffer) { + // No need to copy old data because strftime failed completely anyway + } + + target_buffer = new_buffer; + allocated_size = new_allocated_size; + continue; + } + + final_len = (c_size_t)written; + break; + } + + // Call your existing InsertAt implementation to open the gap and safely shift the array characters downstream + if (final_len > 0) { + result = c_StringBuffer_InsertAt(self, index, target_buffer, final_len); + } + + // Clean up heap space allocations if we outgrew the default 128-byte stack array footprint + if (target_buffer != temp_stack_buffer) { + free(target_buffer); + } + + return result; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_index_t c_StringBuffer_IndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr) { + if (!self || !self->buffer || !substr) return C_ERR_NOT_FOUND; + if (start_index >= self->size) return C_ERR_NOT_FOUND; + + // Utilize optimized standard strstr starting from our targeted index offset + char* match = strstr(self->buffer + start_index, substr); + if (!match) return C_ERR_NOT_FOUND; + + return (c_index_t)(match - self->buffer); +} + +c_index_t c_StringBuffer_IndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target) { + if (!self || !self->buffer) return C_ERR_NOT_FOUND; + if (start_index >= self->size) return C_ERR_NOT_FOUND; + + // memchr is highly optimized by compilers using SIMD assembly operations under the hood + c_size_t search_len = self->size - start_index; + char* match = (char*)memchr(self->buffer + start_index, target, search_len); + if (!match) return C_ERR_NOT_FOUND; + + return (c_index_t)(match - self->buffer); +} + +c_index_t c_StringBuffer_LastIndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr) { + if (!self || !self->buffer || !substr) return C_ERR_NOT_FOUND; + + c_size_t sub_len = strlen(substr); + if (sub_len == 0) return C_ERR_NOT_FOUND; + + // Clamp start_index to structural string boundary maximums + c_size_t upper_bound = (start_index >= self->size) ? (self->size == 0 ? 0 : self->size - 1) : start_index; + if (upper_bound < sub_len - 1) return C_ERR_NOT_FOUND; + + // Scan backwards sequentially to find the last occurrence match context + for (c_size_t i = upper_bound + 1 - sub_len; ; i--) { + if (strncmp(self->buffer + i, substr, sub_len) == 0) { + return (c_index_t)i; + } + if (i == 0) break; // Terminate condition for unsigned down-counting loops + } + + return C_ERR_NOT_FOUND; +} + +c_index_t c_StringBuffer_LastIndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target) { + if (!self || !self->buffer || self->size == 0) return C_ERR_NOT_FOUND; + + c_size_t upper_bound = (start_index >= self->size) ? (self->size - 1) : start_index; + + // Backwards structural loop checking character identities cleanly + for (c_size_t i = upper_bound; ; i--) { + if (self->buffer[i] == target) { + return (c_index_t)i; + } + if (i == 0) break; + } + + return C_ERR_NOT_FOUND; +} + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +c_err_t c_StringBuffer_ReplaceStr(c_StringBuffer_t* self, const char* old_str, const char* new_str) { + if (!self || !old_str || !new_str) return C_ERR_INVALID_PARAM; + + c_size_t old_len = strlen(old_str); + if (old_len == 0) return C_SUCCESS; // Replacing an empty string is a no-op + + c_size_t new_len = strlen(new_str); + + // Pass 1: Count total occurrences to evaluate memory requirements safely + c_size_t occurrences = 0; + const char* scan = self->buffer; + if (scan) { + while ((scan = strstr(scan, old_str)) != NULL) { + occurrences++; + scan += old_len; + } + } + + if (occurrences == 0) return C_SUCCESS; // No matches found + + // Calculate structural payload delta modifications + long long delta = (long long)new_len - (long long)old_len; + c_size_t final_size = self->size + (occurrences * delta); + + // Expand buffer layout upfront if the replacement string expands the footprint + if (delta > 0) { + c_err_t err = c_StringBuffer_EnsureCapacity(self, occurrences * delta); + if (err != C_SUCCESS) return err; + } + + // Pass 2: Apply the substitution matrix via pointer offsets + char* read_ptr = self->buffer; + char* write_ptr = self->buffer; + + // If the string expands, we must write from right-to-left to prevent stomping data. + // However, an easy and clean way to handle all deltas without complex memory logic + // is utilizing a temporary buffer, or shifting segments sequentially. + // Let's implement an in-place single-buffer scan-and-shift variant: + c_size_t current_index = 0; + while (current_index < self->size) { + char* match = strstr(self->buffer + current_index, old_str); + if (!match) break; + + c_index_t match_idx = (c_index_t)(match - self->buffer); + + if (delta != 0) { + // Shift the trailing data behind the old string block configuration + c_size_t tail_len = self->size - (match_idx + old_len); + memmove(self->buffer + match_idx + new_len, self->buffer + match_idx + old_len, tail_len); + } + + // Copy the replacement string elements into the target slot + if (new_len > 0) { + memcpy(self->buffer + match_idx, new_str, new_len); + } + + // Adjust tracking dimensions + self->size += delta; + current_index = match_idx + new_len; + } + + self->buffer[self->size] = '\0'; // Strictly enforce final null-termination + return C_SUCCESS; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#include +#include + +c_err_t c_StringBuffer_TrimLeft(c_StringBuffer_t* self) { + if (!self) return C_ERR_INVALID_PARAM; + if (self->size == 0) return C_SUCCESS; + + c_size_t spaces = 0; + + // Scan forward to count leading whitespace characters + // isspace covers: ' ', '\t', '\n', '\v', '\f', '\r' + while (spaces < self->size && isspace((unsigned char)self->buffer[spaces])) { + spaces++; + } + + if (spaces == 0) return C_SUCCESS; // No leading whitespace found + + // Shift the remaining structural payload left to overwrite the whitespace + c_size_t remaining_bytes = self->size - spaces; + if (remaining_bytes > 0) { + memmove(self->buffer, self->buffer + spaces, remaining_bytes); + } + + self->size = remaining_bytes; + self->buffer[self->size] = '\0'; // Strictly enforce structural null-termination + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_TrimRight(c_StringBuffer_t* self) { + if (!self) return C_ERR_INVALID_PARAM; + if (self->size == 0) return C_SUCCESS; + + // Scan backwards from the tail using unsigned down-counting loop guard rails + c_size_t i = self->size; + while (i > 0 && isspace((unsigned char)self->buffer[i - 1])) { + i--; + } + + // Adjust structural sizes down directly without moving memory arrays + self->size = i; + if (self->buffer && self->capacity > 0) { + self->buffer[self->size] = '\0'; + } + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_Trim(c_StringBuffer_t* self) { + if (!self) return C_ERR_INVALID_PARAM; + + // Performance optimization: Clean up tail bytes first to minimize memory movement blocks + c_err_t err = c_StringBuffer_TrimRight(self); + if (err != C_SUCCESS) return err; + + return c_StringBuffer_TrimLeft(self); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +c_err_t c_StringBuffer_ToLower(c_StringBuffer_t* self) { + if (!self || !self->buffer) return C_ERR_INVALID_PARAM; + + for (c_size_t i = 0; i < self->size; i++) { + self->buffer[i] = (char)tolower((unsigned char)self->buffer[i]); + } + return C_SUCCESS; +} + +c_err_t c_StringBuffer_ToUpper(c_StringBuffer_t* self) { + if (!self || !self->buffer) return C_ERR_INVALID_PARAM; + + for (c_size_t i = 0; i < self->size; i++) { + self->buffer[i] = (char)toupper((unsigned char)self->buffer[i]); + } + return C_SUCCESS; +} + + +c_err_t c_StringBuffer_Split(c_StringBuffer_t* self, const char* delimiter, c_StringBuffer_t** out_tokens, c_size_t* out_count) { + // 1. 严格的参数校验 + if (!self || !self->buffer || !delimiter || !out_tokens || !out_count) { + return C_ERR_INVALID_PARAM; + } + + // 显式将输出重置,防止调用方读取未初始化的脏数据 + *out_tokens = NULL; + *out_count = 0; + + c_size_t delim_len = strlen(delimiter); + if (delim_len == 0) { + return C_ERR_INVALID_PARAM; // 分隔符不能为空字符串 + } + + // 2. 第一轮扫描:计算一共会拆分出多少个 Token,以便一次性分配连续数组空间 + c_size_t token_count = 1; + const char* scan = self->buffer; + while ((scan = strstr(scan, delimiter)) != NULL) { + token_count++; + scan += delim_len; // 跳过当前分隔符继续匹配 + } + + // 3. 一次性分配容纳所有结构体的数组 + c_StringBuffer_t* tokens = (c_StringBuffer_t*)malloc(token_count * sizeof(c_StringBuffer_t)); + if (!tokens) { + return C_ERR_OUT_OF_MEMORY; + } + + // 预先清空结构体数组,使后续的防御性回滚清理更加安全 + for (c_size_t i = 0; i < token_count; i++) { + tokens[i].buffer = NULL; + tokens[i].capacity = 0; + tokens[i].size = 0; + } + + // 4. 第二轮扫描:精准切片并填充到独立的结构体中 + c_size_t current_token = 0; + c_size_t start_idx = 0; + + while (start_idx <= self->size) { + // 寻找下一个分隔符的位置 + char* match = strstr(self->buffer + start_idx, delimiter); + + // 计算当前 Token 的字节长度 + c_size_t token_len = match ? (c_size_t)(match - (self->buffer + start_idx)) : (self->size - start_idx); + + // 初始化子 StringBuffer(分配其内部的 char* 缓冲区) + c_err_t err = c_StringBuffer_Init(&tokens[current_token], token_len); + if (err != C_SUCCESS) goto error_cleanup; + + // 如果长度大于 0,将片段内容追加拷贝进去 + if (token_len > 0) { + err = c_StringBuffer_Append(&tokens[current_token], self->buffer + start_idx, token_len); + if (err != C_SUCCESS) goto error_cleanup; + } + + current_token++; + if (!match) break; // 已处理完最后一个片段,退出循环 + + // 步进索引:当前片段长度 + 分隔符长度 + start_idx += token_len + delim_len; + } + + // 5. 成功赋值输出 + *out_tokens = tokens; + *out_count = token_count; + return C_SUCCESS; + +// 防御性垃圾回收:如果中途任何一个 Token 内存分配失败,完整回滚,绝不泄露 +error_cleanup: + for (c_size_t i = 0; i < token_count; i++) { + // c_StringBuffer_Destroy 内部有对 NULL 的安全校验 + c_StringBuffer_Destroy(&tokens[i]); + } + free(tokens); + return C_ERR_OUT_OF_MEMORY; +} + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_StringBuffer_Join(c_StringBuffer_t* self, const c_StringBuffer_t tokens[], c_size_t count, const char* separator) { + if (!self || (!tokens && count > 0) || !separator) return C_ERR_INVALID_PARAM; + + c_StringBuffer_Clear(self); + if (count == 0) return C_SUCCESS; + + c_size_t sep_len = strlen(separator); + c_size_t total_required_space = 0; + + // Pass 1: Compute exactly how much capacity is needed upfront to prevent intermediate reallocations + for (c_size_t i = 0; i < count; i++) { + total_required_space += tokens[i].size; + if (i < count - 1) { + total_required_space += sep_len; + } + } + + c_err_t err = c_StringBuffer_EnsureCapacity(self, total_required_space); + if (err != C_SUCCESS) return err; + + // Pass 2: Fast sequential data copying into the pre-sized buffer + for (c_size_t i = 0; i < count; i++) { + if (tokens[i].size > 0) { + memcpy(self->buffer + self->size, tokens[i].buffer, tokens[i].size); + self->size += tokens[i].size; + } + + if (i < count - 1 && sep_len > 0) { + memcpy(self->buffer + self->size, separator, sep_len); + self->size += sep_len; + } + } + + self->buffer[self->size] = '\0'; // Strictly enforce final null-termination + return C_SUCCESS; +} + +int c_StringBuffer_Equals(const c_StringBuffer_t* self, const char* string) { + if (!self || !string) return 0; + if (!self->buffer) return (string[0] == '\0'); + + // Optimization: Check sizing footprints first before comparing bytes + c_size_t str_len = strlen(string); + if (self->size != str_len) return 0; + + return (strcmp(self->buffer, string) == 0); +} + +int c_StringBuffer_EqualsIgnoreCase(const c_StringBuffer_t* self, const char* string) { + if (!self || !string) return 0; + if (!self->buffer) return (string[0] == '\0'); + + c_size_t str_len = strlen(string); + if (self->size != str_len) return 0; + + // Character-by-character validation mapped safely onto tolower limits + for (c_size_t i = 0; i < self->size; i++) { + if (tolower((unsigned char)self->buffer[i]) != tolower((unsigned char)string[i])) { + return 0; // Immediate mismatch exit + } + } + + return 1; // Content identities match perfectly +} + +int c_StringBuffer_Compare(const c_StringBuffer_t* self, const char* string) { + // Standardize null pointers to make safety deterministic + const char* s1 = (self && self->buffer) ? self->buffer : ""; + const char* s2 = string ? string : ""; + + return strcmp(s1, s2); +} + +c_err_t c_StringBuffer_Reverse(c_StringBuffer_t* self) { + if (!self) return C_ERR_INVALID_PARAM; + if (self->size <= 1) return C_SUCCESS; // No-op if empty or single character + + c_size_t left = 0; + c_size_t right = self->size - 1; + + // Fast symmetric swap loop executing entirely in-place + while (left < right) { + char temp = self->buffer[left]; + self->buffer[left] = self->buffer[right]; + self->buffer[right] = temp; + + left++; + right--; + } + + // Maintain safety by preserving the existing null-terminator position + self->buffer[self->size] = '\0'; + return C_SUCCESS; +} + + +c_err_t c_StringBuffer_Substr(const c_StringBuffer_t* self, c_size_t index, c_size_t length, c_StringBuffer_t* out_substring) { + if (!self || !out_substring) return C_ERR_INVALID_PARAM; + + // Explicitly zero out the target structure descriptor up front to prevent undefined state access on failure + out_substring->buffer = NULL; + out_substring->capacity = 0; + out_substring->size = 0; + + if (index > self->size) return C_ERR_OUT_OF_BOUNDS; + + // Clamp the target length parameter dynamically if it exceeds the remaining data payload bounds + if (index + length > self->size) { + length = self->size - index; + } + + // Initialize the out string buffer with the exact exact footprint space required + c_err_t err = c_StringBuffer_Init(out_substring, length); + if (err != C_SUCCESS) return err; + + if (length > 0) { + err = c_StringBuffer_Append(out_substring, self->buffer + index, length); + if (err != C_SUCCESS) { + c_StringBuffer_Destroy(out_substring); + return err; + } + } + + return C_SUCCESS; +} + +c_err_t c_StringBuffer_Slice(const c_StringBuffer_t* self, c_size_t start_index, c_size_t end_index, c_StringBuffer_t* out_slice) { + if (!self || !out_slice) return C_ERR_INVALID_PARAM; + + out_slice->buffer = NULL; + out_slice->capacity = 0; + out_slice->size = 0; + + if (start_index > self->size) return C_ERR_OUT_OF_BOUNDS; + + // Clamp end_index if it exceeds the structural size boundary limits + if (end_index > self->size) { + end_index = self->size; + } + + // If indices are out of order or equal, return an empty initialized string buffer instance safely + c_size_t length = (end_index > start_index) ? (end_index - start_index) : 0; + + c_err_t err = c_StringBuffer_Init(out_slice, length); + if (err != C_SUCCESS) return err; + + if (length > 0) { + err = c_StringBuffer_Append(out_slice, self->buffer + start_index, length); + if (err != C_SUCCESS) { + c_StringBuffer_Destroy(out_slice); + return err; + } + } + + return C_SUCCESS; +} + + +c_err_t c_StringBuffer_strtoul(const c_StringBuffer_t* self, c_size_t start_index, int base, unsigned long* out_value, c_size_t* out_end_index) { + if (!self || !self->buffer || !out_value) return C_ERR_INVALID_PARAM; + if (start_index >= self->size) return C_ERR_OUT_OF_BOUNDS; + + // Reset errno before executing standard parsing functions to isolate previous system actions + int current_errno = errno; + errno = 0; + + char* parse_end = NULL; + const char* start_ptr = self->buffer + start_index; + + unsigned long result = strtoul(start_ptr, &parse_end, base); + + // Error Validation Condition 1: Check for standard numerical overflow/underflow + if (errno == ERANGE) { + return C_ERR_OUT_OF_BOUNDS; // Numerical envelope exceeded bounds + } + + // Error Validation Condition 2: No structural digits could be parsed at all + if (parse_end == start_ptr) { + errno = current_errno; // Restore system errno + return C_ERR_INVALID_PARAM; + } + + // Assign the computed scalar result out safely + *out_value = result; + + // Map pointer arithmetic distances back into the context of our indexing structural offset + if (out_end_index) { + *out_end_index = start_index + (c_size_t)(parse_end - start_ptr); + } + + errno = current_errno; // Restore system errno + return C_SUCCESS; +} + diff --git a/cKit/Foundation/c_StringBuffer.h b/cKit/Foundation/c_StringBuffer.h index 4ab2ff7..4378a49 100644 --- a/cKit/Foundation/c_StringBuffer.h +++ b/cKit/Foundation/c_StringBuffer.h @@ -5,6 +5,12 @@ #include #endif /*INCLUDED_C_BASE_H*/ +#ifndef INCLUDED_STDARG_H +#define INCLUDED_STDARG_H +#include +#endif /*INCLUDED_STDARG_H*/ + + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ @@ -38,4 +44,59 @@ c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t length, char* buffer, c_size_t buffer_length); +c_err_t c_StringBuffer_Printf(c_StringBuffer_t* self, const char* format, ...); +c_err_t c_StringBuffer_PrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, ...); + +c_err_t c_StringBuffer_VPrintf(c_StringBuffer_t* self, const char* format, va_list args); +c_err_t c_StringBuffer_VPrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, va_list args); + +c_err_t c_StringBuffer_AppendTimestamp(c_StringBuffer_t* self, const char* format, const struct tm* time_info); +c_err_t c_StringBuffer_AppendCurrentTimestamp(c_StringBuffer_t* self, const char* format, int use_utc); +c_err_t c_StringBuffer_InsertTimestampAt(c_StringBuffer_t* self, c_size_t index, const char* format, const struct tm* time_info); + +c_index_t c_StringBuffer_IndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr); +c_index_t c_StringBuffer_IndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target); +c_index_t c_StringBuffer_LastIndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr); +c_index_t c_StringBuffer_LastIndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target); + +c_err_t c_StringBuffer_ReplaceStr(c_StringBuffer_t* self, const char* old_str, const char* new_str); + +c_err_t c_StringBuffer_Trim(c_StringBuffer_t* self); +c_err_t c_StringBuffer_TrimLeft(c_StringBuffer_t* self); +c_err_t c_StringBuffer_TrimRight(c_StringBuffer_t* self); + +c_err_t c_StringBuffer_ToLower(c_StringBuffer_t* self); +c_err_t c_StringBuffer_ToUpper(c_StringBuffer_t* self); + +/* + * 重新设计的 Split 函数 + * @param self: 原始字符串缓冲区指针 + * @param delimiter: 分隔符字符串(不能为 NULL 或空字符串) + * @param out_tokens: 输出参数,用于接收分配的 c_StringBuffer_t 结构体数组指针 + * @param out_count: 输出参数,用于接收拆分出来的 Token 总数 + */ +c_err_t c_StringBuffer_Split(c_StringBuffer_t* self, const char* delimiter, c_StringBuffer_t** out_tokens, c_size_t* out_count); + +c_err_t c_StringBuffer_Join(c_StringBuffer_t* self, const c_StringBuffer_t tokens[], c_size_t count, const char* separator); + +int c_StringBuffer_Equals(const c_StringBuffer_t* self, const char* string); +int c_StringBuffer_EqualsIgnoreCase(const c_StringBuffer_t* self, const char* string); + +int c_StringBuffer_Compare(const c_StringBuffer_t* self, const char* string); +c_err_t c_StringBuffer_Reverse(c_StringBuffer_t* self); + +c_err_t c_StringBuffer_Substr(const c_StringBuffer_t* self, c_size_t index, c_size_t length, c_StringBuffer_t* out_substring); +c_err_t c_StringBuffer_Slice(const c_StringBuffer_t* self, c_size_t start_index, c_size_t end_index, c_StringBuffer_t* out_slice); + +/* + * Parses an unsigned long value from the buffer starting at a specific index. + * @param self: The string buffer instance. + * @param start_index: The index position to start scanning from. + * @param base: The number base system to parse (0, 2-36). + * @param out_value: Destination pointer for the parsed unsigned long. + * @param out_end_index: Optional destination pointer for the index of the first character after the number. + */ +c_err_t c_StringBuffer_strtoul(const c_StringBuffer_t* self, c_size_t start_index, int base, unsigned long* out_value, c_size_t* out_end_index); + + #endif /*INCLUDED_C_STRINGBUFFER_H*/ diff --git a/cKit/Foundation/c_StringBuffer.t.c b/cKit/Foundation/c_StringBuffer.t.c index 1141c0c..608d77b 100644 --- a/cKit/Foundation/c_StringBuffer.t.c +++ b/cKit/Foundation/c_StringBuffer.t.c @@ -8,126 +8,356 @@ if (condition) { \ printf("\033[32mPASSED\033[0m\n"); \ } else { \ - printf("\033[31mFAILED\033[0m (at Line %d)\n", __LINE__); \ + printf("\033[31mFAILED\033[0m (at %s:%d)\n", __FILE__, __LINE__); \ return C_ERR_FAIL; \ } \ } while(0) -c_err_t c_StringBuffer_UnitTest(void) { - c_StringBuffer_t sb; - c_err_t err; - char copy_target[64]; - - printf("==================================================\n"); - printf(" STARTING C_STRINGBUFFER UNIT TESTING \n"); - printf("==================================================\n"); - - /* 1. API Parameter Defensive Checks (Null Guards) */ - RUN_TEST(c_StringBuffer_Init(NULL, 16) == C_ERR_PARAM, "Init handles NULL self context"); - RUN_TEST(c_StringBuffer_Append(NULL, "a", 1) == C_ERR_PARAM, "Append checks NULL self"); - RUN_TEST(c_StringBuffer_Prepend(NULL, "a", 1) == C_ERR_PARAM, "Prepend checks NULL self"); - RUN_TEST(c_StringBuffer_InsertAt(NULL, 0, "a", 1) == C_ERR_PARAM, "InsertAt checks NULL self"); - RUN_TEST(c_StringBuffer_RemoveAt(NULL, 0, 1) == C_ERR_PARAM, "RemoveAt checks NULL self"); - RUN_TEST(c_StringBuffer_CopyTo(NULL, 0, 1, copy_target, 64) == C_ERR_PARAM, "CopyTo checks NULL self"); - - /* 2. Initialization Test Block (Init) */ - err = c_StringBuffer_Init(&sb, 4); // Initialize with small capacity to force upcoming resizing branches - RUN_TEST(err == C_ERR_OK, "Initialization with tiny explicit capacity returns C_ERR_OK"); - RUN_TEST(sb.size == 0, "Initial tracked contents data size is 0"); - RUN_TEST(sb.capacity == 4, "Initial tracking allocation capacity is 4"); - RUN_TEST(sb.buffer != NULL, "Internal tracking byte storage buffer successfully bound"); - RUN_TEST(sb.buffer[0] == '\0', "Empty buffer is safely terminated with null byte"); - - /* 3. Length-bounded Insertion Operations (Append, Prepend, InsertAt) */ - // Append test - err = c_StringBuffer_Append(&sb, "Trie", 4); - RUN_TEST(err == C_ERR_OK, "Append bounded segment 'Trie'"); - RUN_TEST(sb.size == 4, "Size matches append width"); - RUN_TEST(strcmp(sb.buffer, "Trie") == 0, "Buffer contains exact match string 'Trie'"); - - // Prepend test - err = c_StringBuffer_Prepend(&sb, "Nlp", 3); - RUN_TEST(err == C_ERR_OK, "Prepend bounded segment 'Nlp' to front"); - RUN_TEST(sb.size == 7, "Size extended to 7 bytes total"); - RUN_TEST(strcmp(sb.buffer, "NlpTrie") == 0, "Buffer shifted correctly into 'NlpTrie'"); - - // InsertAt test (Middle shifting memory operation) - err = c_StringBuffer_InsertAt(&sb, 3, "_", 1); - RUN_TEST(err == C_ERR_OK, "InsertAt index 3 inserts an underscore character"); - RUN_TEST(strcmp(sb.buffer, "Nlp_Trie") == 0, "Memory shifted left/right flawlessly: 'Nlp_Trie'"); - - /* 4. Exponential Expansion Threshold Guard Check */ - // Pushing string past current internal storage boundaries to trigger C_ALLOC resizing - err = c_StringBuffer_Append(&sb, "_DataStructure", 14); - RUN_TEST(err == C_ERR_OK, "Forced exponential buffer reallocation with large string append"); - RUN_TEST(sb.size == 22, "Size correctly aggregated up to 22 bytes total"); - RUN_TEST(sb.capacity >= 23, "Capacity upscaled cleanly beyond its initial 4-byte threshold limit"); - RUN_TEST(strcmp(sb.buffer, "Nlp_Trie_DataStructure") == 0, "Post-reallocation string remains integrated and uncorrupted"); - - /* 5. Memory Shift Extraction Operations (RemoveAt) */ - // Current payload structure: "Nlp_Trie_DataStructure" - // Remove mid segment "_DataStructure" starting at index 8 - err = c_StringBuffer_RemoveAt(&sb, 8, 14); - RUN_TEST(err == C_ERR_OK, "RemoveAt clears middle segment '_DataStructure'"); - RUN_TEST(sb.size == 8, "Size downshifted cleanly to 8 bytes"); - RUN_TEST(strcmp(sb.buffer, "Nlp_Trie") == 0, "Character array closed gaps safely to hold 'Nlp_Trie'"); - - // Test automatic length clamping over boundary limit edge cases - err = c_StringBuffer_RemoveAt(&sb, 3, 50); // 50 overshoot actual size limits - RUN_TEST(err == C_ERR_OK, "RemoveAt automatically clamps requesting lengths overflowing edge limits"); - RUN_TEST(sb.size == 3, "Length updated down to index bounds"); - RUN_TEST(strcmp(sb.buffer, "Nlp") == 0, "Buffer contains truncated string 'Nlp'"); - - /* 6. Explicit String Wrapper Interfaces (AppendStr, PrependStr, InsertStrAt) */ - c_StringBuffer_Clear(&sb); - RUN_TEST(sb.size == 0 && sb.buffer[0] == '\0', "Clear flushes buffer structure size indicators cleanly"); - - err = c_StringBuffer_AppendStr(&sb, "Core"); - err |= c_StringBuffer_PrependStr(&sb, "C_"); - err |= c_StringBuffer_InsertStrAt(&sb, "Nlp", 2); // Insert "Nlp" into index 2 ("C_Core" -> "C_NlpCore") - - RUN_TEST(err == C_ERR_OK, "All explicit string wrapper functions evaluated with valid results"); - RUN_TEST(strcmp(sb.buffer, "C_NlpCore") == 0, "String wrapper cascade holds correct output value 'C_NlpCore'"); - - /* 7. Substring Extraction Pipeline Test (CopyTo) */ - // Test slice matching operations - err = c_StringBuffer_CopyTo(&sb, 2, 3, copy_target, sizeof(copy_target)); - RUN_TEST(err == C_ERR_OK, "CopyTo safely slices subset out to isolated external layout target"); - RUN_TEST(strcmp(copy_target, "Nlp") == 0, "External buffer extracted substring captures token 'Nlp' correctly"); - - // Test out of bounds inputs rejection properties - RUN_TEST(c_StringBuffer_CopyTo(&sb, 2, 3, copy_target, 2) == C_ERR_PARAM, "CopyTo blocks actions when external buffer is too small"); - RUN_TEST(c_StringBuffer_CopyTo(&sb, 999, 1, copy_target, sizeof(copy_target)) == C_ERR_PARAM, "CopyTo blocks crazy out of range index arguments"); - - /* 8. Multi-Byte UTF-8 String Asset Integrity Checks */ - c_StringBuffer_Clear(&sb); - err = c_StringBuffer_AppendStr(&sb, "语言"); - err |= c_StringBuffer_PrependStr(&sb, "自然"); - err |= c_StringBuffer_AppendStr(&sb, "处理"); // "自然语言处理" - - RUN_TEST(err == C_ERR_OK, "Piped raw multi-byte Chinese UTF-8 string tokens through buffer channels"); - RUN_TEST(strcmp(sb.buffer, "自然语言处理") == 0, "Raw multi-byte array matches validation configuration stream"); - - /* 9. Destruction Lifecycle Cleanliness Verification */ - c_StringBuffer_Destroy(&sb); - RUN_TEST(sb.buffer == NULL, "Array tracking pointer nullified successfully upon calling destructor"); - RUN_TEST(sb.size == 0 && sb.capacity == 0, "Structural trackers set to 0"); - - // Idempotency execution test sequence - c_StringBuffer_Destroy(&sb); - c_StringBuffer_Destroy(NULL); - printf("[TEST] Double string buffer destruction safety... \033[32mPASSED\033[0m\n"); - - printf("==================================================\n"); - printf("\033[32mSUCCESS: ALL C_STRINGBUFFER TESTS COMPLETED SUCCESSFULLY!\033[0m\n"); - printf("==================================================\n"); - - return C_ERR_OK; +static c_err_t test_harness_vprintf(c_StringBuffer_t* self, const char* format, ...) { + va_list args; + va_start(args, format); + c_err_t err = c_StringBuffer_VPrintf(self, format, args); + va_end(args); + return err; } +static c_err_t test_harness_vprintf_at(c_StringBuffer_t* self, c_size_t index, const char* format, ...) { + va_list args; + va_start(args, format); + c_err_t err = c_StringBuffer_VPrintfAt(self, index, format, args); + va_end(args); + return err; +} + +/* --- Module 1: Structural Allocation Lifecycle Management --- */ +static void test_lifecycle_and_clear(void) { + c_StringBuffer_t sb; + + // Validate NULL parameters are rejected deterministically + assert(c_StringBuffer_Init(NULL, 64) == C_ERR_INVALID_PARAM); + + // Standard allocation flow verification + assert(c_StringBuffer_Init(&sb, 16) == C_SUCCESS); + assert(sb.size == 0); + assert(sb.capacity >= 16); // Implicit null-terminator overhead validation + assert(sb.buffer != NULL); + assert(sb.buffer[0] == '\0'); + + // Data clearing verification + assert(c_StringBuffer_AppendStr(&sb, "DynamicDataPayload") == C_SUCCESS); + assert(sb.size == 18); + c_StringBuffer_Clear(&sb); + assert(sb.size == 0); + assert(sb.buffer[0] == '\0'); // Ensure implicit closure byte remains active + + // Release phase validation + c_StringBuffer_Destroy(&sb); + assert(sb.buffer == NULL); + assert(sb.capacity == 0); + assert(sb.size == 0); + + // Idempotent protection check against multi-free configurations + c_StringBuffer_Destroy(NULL); + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 2: Memory Relocation & Byte Array Mutation Ops --- */ +static void test_array_mutations(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 2) == C_SUCCESS); // Aggressive scaling constraint + + // Check boundary anomalies + assert(c_StringBuffer_Append(NULL, "data", 4) == C_ERR_INVALID_PARAM); + assert(c_StringBuffer_Append(&sb, NULL, 4) == C_ERR_INVALID_PARAM); + assert(c_StringBuffer_Append(&sb, "ZeroOp", 0) == C_ERR_INVALID_PARAM); + + // Append tracking + assert(c_StringBuffer_AppendStr(&sb, "Engine") == C_SUCCESS); + assert(strcmp(sb.buffer, "Engine") == 0); + assert(sb.size == 6); + + // Prepend and structural layout shift tracking + assert(c_StringBuffer_PrependStr(&sb, "Core ") == C_SUCCESS); + assert(strcmp(sb.buffer, "Core Engine") == 0); + assert(sb.size == 11); + + // Index tracking and arbitrary memory slice insertions + assert(c_StringBuffer_InsertStrAt(&sb, "Graphics ", 5) == C_SUCCESS); + assert(strcmp(sb.buffer, "Core Graphics Engine") == 0); + assert(c_StringBuffer_InsertStrAt(&sb, "OOB", 256) == C_ERR_OUT_OF_BOUNDS); + + // Data element contraction testing via RemoveAt + assert(c_StringBuffer_RemoveAt(&sb, 50, 2) == C_ERR_OUT_OF_BOUNDS); + assert(c_StringBuffer_RemoveAt(&sb, 5, 0) == C_SUCCESS); + assert(c_StringBuffer_RemoveAt(&sb, 5, 9) == C_SUCCESS); // Cleaves out "Graphics " + assert(strcmp(sb.buffer, "Core Engine") == 0); + assert(sb.size == 11); + + // Clamping limits validation: Removing past structural layout capacity boundaries + assert(c_StringBuffer_RemoveAt(&sb, 4, 100) == C_SUCCESS); + assert(strcmp(sb.buffer, "Core") == 0); + assert(sb.size == 4); + + // Outbound array replication via CopyTo + char export_buffer[16]; + assert(c_StringBuffer_CopyTo(&sb, 0, 4, export_buffer, sizeof(export_buffer)) == C_SUCCESS); + assert(strcmp(export_buffer, "Core") == 0); + + // Buffer optimization check: Truncation logic preservation on small arrays + assert(c_StringBuffer_CopyTo(&sb, 0, 4, export_buffer, 3) == C_ERR_OUT_OF_BOUNDS); // Destination size limit 3 + // assert(strcmp(export_buffer, "Co") == 0); // Fits "Co" + '\0' safely + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 3: Format Translators & Interleaved Injections --- */ +static void test_formatting_engines(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 8) == C_SUCCESS); + + // Standard Printf string generation + assert(c_StringBuffer_Printf(&sb, "%s = %04d", "Status", 200) == C_SUCCESS); + assert(strcmp(sb.buffer, "Status = 0200") == 0); + + // Reentrant list validation via VPrintf + c_StringBuffer_Clear(&sb); + assert(test_harness_vprintf(&sb, "Float: %.2f", 3.14159) == C_SUCCESS); + assert(strcmp(sb.buffer, "Float: 3.14") == 0); + + // Deep structural data layout testing: PrintfAt string middle-smashes + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendStr(&sb, "Alpha-Gamma") == C_SUCCESS); + + // Inject "Beta-" precisely at index position 6 without breaking string sequence chains + assert(c_StringBuffer_PrintfAt(&sb, 6, "%s-", "Beta") == C_SUCCESS); + assert(strcmp(sb.buffer, "Alpha-Beta-Gamma") == 0); + assert(sb.size == 16); + + // Reentrant multi-layer gap injection testing via VPrintfAt + assert(test_harness_vprintf_at(&sb, 0, "[%c]", 'I') == C_SUCCESS); + assert(strcmp(sb.buffer, "[I]Alpha-Beta-Gamma") == 0); + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 4: Speculative Loop Chronology Modules --- */ +static void test_chronology_modules(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 4) == C_SUCCESS); + + struct tm mock_epoch; + mock_epoch.tm_year = 126; // Year 2026 representation framework + mock_epoch.tm_mon = 7; // August calibration index + mock_epoch.tm_mday = 10; + mock_epoch.tm_hour = 14; + mock_epoch.tm_min = 22; + mock_epoch.tm_sec = 45; + + // Direct temporal formatting validation + assert(c_StringBuffer_AppendTimestamp(&sb, "%Y/%m/%d", &mock_epoch) == C_SUCCESS); + assert(strcmp(sb.buffer, "2026/08/10") == 0); + + // Isolated gap injection validation with temporal entities + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendStr(&sb, "EventOccurred") == C_SUCCESS); + assert(c_StringBuffer_InsertTimestampAt(&sb, 0, "%H:%M:%S ", &mock_epoch) == C_SUCCESS); + assert(strcmp(sb.buffer, "14:22:45 EventOccurred") == 0); + + // Running standard OS system time verification (Ensures dynamic layout executes cleanly) + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendCurrentTimestamp(&sb, "%M", 1) == C_SUCCESS); // UTC trace scan + assert(sb.size == 2); // Double-digit alignment validation + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 5: Lexical Scanners & Backward Lookups --- */ +static void test_lexical_scanners(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 32) == C_SUCCESS); + assert(c_StringBuffer_AppendStr(&sb, "ping-pong-ping-pong") == C_SUCCESS); + + // Linear scanning paths verification + assert(c_StringBuffer_IndexOfStr(&sb, 0, "pong") == 5); + assert(c_StringBuffer_IndexOfStr(&sb, 6, "pong") == 15); // Offset search skip boundaries + assert(c_StringBuffer_IndexOfStr(&sb, 0, "missing") == C_ERR_NOT_FOUND); + assert(c_StringBuffer_IndexOfChar(&sb, 0, '-') == 4); + assert(c_StringBuffer_IndexOfChar(&sb, 0, 'x') == C_ERR_NOT_FOUND); + + // High performance reversed traversal trace verification + assert(c_StringBuffer_LastIndexOfStr(&sb, 19, "ping") == 10); + assert(c_StringBuffer_LastIndexOfStr(&sb, 8, "ping") == 0); // Window limits validation + assert(c_StringBuffer_LastIndexOfChar(&sb, 19, '-') == 14); + assert(c_StringBuffer_LastIndexOfChar(&sb, 2, '-') == C_ERR_NOT_FOUND); + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 6: Matrix Transformations & Space Cleavers --- */ +static void test_transformations_and_cleavers(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 8) == C_SUCCESS); + + // Substitute logic metrics path variations + assert(c_StringBuffer_AppendStr(&sb, "one_two_one") == C_SUCCESS); + assert(c_StringBuffer_ReplaceStr(&sb, "one", "1") == C_SUCCESS); // Footprint size contraction + assert(strcmp(sb.buffer, "1_two_1") == 0); + + assert(c_StringBuffer_ReplaceStr(&sb, "1", "three") == C_SUCCESS); // Footprint size expansion delta + assert(strcmp(sb.buffer, "three_two_three") == 0); + + // Whitespace elimination tracking loops + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendStr(&sb, " \r\n\t TokenPayload \t ") == C_SUCCESS); + + assert(c_StringBuffer_TrimLeft(&sb) == C_SUCCESS); + assert(strcmp(sb.buffer, "TokenPayload \t ") == 0); + + assert(c_StringBuffer_TrimRight(&sb) == C_SUCCESS); + assert(strcmp(sb.buffer, "TokenPayload") == 0); + assert(sb.size == 12); + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 7: Lexical Casers & Coordinate Range Extractions --- */ +static void test_casers_and_extractions(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 16) == C_SUCCESS); + assert(c_StringBuffer_AppendStr(&sb, "xYz987W") == C_SUCCESS); + + // Case conversions + assert(c_StringBuffer_ToUpper(&sb) == C_SUCCESS); + assert(strcmp(sb.buffer, "XYZ987W") == 0); + assert(c_StringBuffer_ToLower(&sb) == C_SUCCESS); + assert(strcmp(sb.buffer, "xyz987w") == 0); + + // In-place byte symmetry reversal loop verification + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendStr(&sb, "radar-test") == C_SUCCESS); + assert(c_StringBuffer_Reverse(&sb) == C_SUCCESS); + assert(strcmp(sb.buffer, "tset-radar") == 0); + + // Slicing metrics via Substr + c_StringBuffer_Clear(&sb); + assert(c_StringBuffer_AppendStr(&sb, "Distributed-Architecture") == C_SUCCESS); + c_StringBuffer_t target_slice; + assert(c_StringBuffer_Substr(&sb, 12, 12, &target_slice) == C_SUCCESS); // Extract "Architecture" + assert(strcmp(target_slice.buffer, "Architecture") == 0); + c_StringBuffer_Destroy(&target_slice); + + // Coordinate clipping window tests via Slice + assert(c_StringBuffer_Slice(&sb, 0, 11, &target_slice) == C_SUCCESS); // Extract "Distributed" + assert(strcmp(target_slice.buffer, "Distributed") == 0); + c_StringBuffer_Destroy(&target_slice); + + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 8: Dual-Scan Pipelines & Structural Join Topologies --- */ +static void test_pipeline_and_joins(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 64) == C_SUCCESS); + assert(c_StringBuffer_AppendStr(&sb, "Alpha::Beta::::Gamma::") == C_SUCCESS); // Multi-byte delimiter with blanks + + c_StringBuffer_t* token_array = NULL; + c_size_t token_count = 0; + + // Process double-scan split array pipeline + assert(c_StringBuffer_Split(&sb, "::", &token_array, &token_count) == C_SUCCESS); + + assert(token_count == 5); + assert(strcmp(token_array[0].buffer, "Alpha") == 0); + assert(strcmp(token_array[1].buffer, "Beta") == 0); + assert(strcmp(token_array[2].buffer, "") == 0); // Gap null evaluation validation + assert(strcmp(token_array[3].buffer, "Gamma") == 0); + assert(strcmp(token_array[4].buffer, "") == 0); // Terminal tracking null check + + // High performance sequential recombination loop testing via Join + c_StringBuffer_t output_combiner; + assert(c_StringBuffer_Init(&output_combiner, 8) == C_SUCCESS); + assert(c_StringBuffer_Join(&output_combiner, token_array, token_count, "=>") == C_SUCCESS); + assert(strcmp(output_combiner.buffer, "Alpha=>Beta=>=>Gamma=>") == 0); + + // Double-scan array deallocation teardown routines + for (c_size_t i = 0; i < token_count; i++) { + c_StringBuffer_Destroy(&token_array[i]); + } + free(token_array); + c_StringBuffer_Destroy(&output_combiner); + c_StringBuffer_Destroy(&sb); +} + +/* --- Module 9: Evaluation Comparators & Alphabetical Sort Anchors --- */ +static void test_comparators(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 16) == C_SUCCESS); + assert(c_StringBuffer_AppendStr(&sb, "Microcontroller-C") == C_SUCCESS); + + // Equality filters verification + assert(c_StringBuffer_Equals(&sb, "Microcontroller-C") == 1); + assert(c_StringBuffer_Equals(&sb, "microcontroller-c") == 0); + assert(c_StringBuffer_EqualsIgnoreCase(&sb, "microcontroller-c") == 1); + assert(c_StringBuffer_Equals(&sb, "Microcontroller") == 0); + + // Lexical lookup evaluation boundaries matching typical strcmp return matrices + assert(c_StringBuffer_Compare(&sb, "Application") > 0); // M > A + assert(c_StringBuffer_Compare(&sb, "Microcontroller-C") == 0); + assert(c_StringBuffer_Compare(&sb, "Zebrafish") < 0); // M < Z + assert(c_StringBuffer_Compare(&sb, NULL) > 0); // Edge-case null baseline swap check + + c_StringBuffer_Destroy(&sb); +} + +static void test_strtoul_conversion(void) { + c_StringBuffer_t sb; + assert(c_StringBuffer_Init(&sb, 32) == C_SUCCESS); + assert(c_StringBuffer_AppendStr(&sb, "Data: 1024, Hex: 0x2A") == C_SUCCESS); + + unsigned long parsed_val = 0; + c_size_t end_idx = 0; + + // Test 1: Parse Base-10 integer from index position 6 ("1024...") + assert(c_StringBuffer_strtoul(&sb, 6, 10, &parsed_val, &end_idx) == C_SUCCESS); + assert(parsed_val == 1024); + assert(end_idx == 10); // Index point of the trailing comma character + + // Test 2: Parse Base-16 hexadecimal starting from index position 17 ("0x2A") + assert(c_StringBuffer_strtoul(&sb, 17, 16, &parsed_val, NULL) == C_SUCCESS); + assert(parsed_val == 42); // 0x2A translates to decimal 42 + + // Test 3: Attempt conversion from non-numeric text index (invalid param error) + assert(c_StringBuffer_strtoul(&sb, 0, 10, &parsed_val, NULL) == C_ERR_INVALID_PARAM); + + c_StringBuffer_Destroy(&sb); +} + + +#define RUN_TEST_CASE(test_func) \ + do { \ + printf("[RUNNING] %-40s ... ", #test_func); \ + fflush(stdout); \ + test_func(); \ + printf("[PASSED]\n"); \ + } while (0) + int main(int argc, char** argv){ - if (c_StringBuffer_UnitTest() != C_ERR_OK) { - return -1; - } - return 0; + printf("=====================================================================\n"); + printf(" LAUNCHING C_STRINGBUFFER CORNER-CASE SPECIFICATION VERIFICATION \n"); + printf("=====================================================================\n"); + + RUN_TEST_CASE(test_lifecycle_and_clear); + RUN_TEST_CASE(test_array_mutations); + RUN_TEST_CASE(test_formatting_engines); + RUN_TEST_CASE(test_chronology_modules); + RUN_TEST_CASE(test_lexical_scanners); + RUN_TEST_CASE(test_transformations_and_cleavers); + RUN_TEST_CASE(test_casers_and_extractions); + RUN_TEST_CASE(test_pipeline_and_joins); + RUN_TEST_CASE(test_comparators); + RUN_TEST_CASE(test_strtoul_conversion); + + printf("=====================================================================\n"); + printf(" [🎉 VERIFIED] Absolute architecture spec checklist matches perfectly. \n"); + printf("=====================================================================\n"); }