#include #include #include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #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) { c_size_t needed_capacity = self->size + required_len + 1; // +1 for trailing '\0' if (needed_capacity <= self->capacity) { return C_ERR_OK; } c_size_t new_capacity = self->capacity == 0 ? DEFAULT_INIT_CAPACITY : self->capacity; while (new_capacity < needed_capacity) { new_capacity *= GROWTH_FACTOR; // Exponential doubling strategy } char* new_buffer = (char*)C_ALLOC(new_capacity); if (!new_buffer) { return C_ERR_NOMEM; } if (self->buffer && self->size > 0) { memcpy(new_buffer, self->buffer, self->size); } new_buffer[self->size] = '\0'; C_FREE(self->buffer); self->buffer = new_buffer; self->capacity = new_capacity; return C_ERR_OK; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_err_t c_StringBuffer_Init(c_StringBuffer_t* self, c_size_t capacity) { if (!self) return C_ERR_PARAM; self->size = 0; self->capacity = capacity > 0 ? capacity : DEFAULT_INIT_CAPACITY; // Enforce minimum initial allocation self->buffer = (char*)C_ALLOC(self->capacity); if (!self->buffer) { self->capacity = 0; return C_ERR_NOMEM; } self->buffer[0] = '\0'; return C_ERR_OK; } void c_StringBuffer_Destroy(c_StringBuffer_t* self) { if (!self) return; if (self->buffer) { C_FREE(self->buffer); } self->size = 0; self->capacity = 0; } c_err_t c_StringBuffer_Append(c_StringBuffer_t* self, const char* string, c_size_t length) { if (!self || !self->buffer || !string || length == 0) return C_ERR_PARAM; c_err_t err = c_StringBuffer_EnsureCapacity(self, length); if (err != C_ERR_OK) return err; memcpy(self->buffer + self->size, string, length); self->size += length; self->buffer[self->size] = '\0'; return C_ERR_OK; } c_err_t c_StringBuffer_Prepend(c_StringBuffer_t* self, const char* string, c_size_t length) { return c_StringBuffer_InsertAt(self, 0, string, length); } 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) 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; // Shift memory to the right using memmove to prevent overlapping issues memmove(self->buffer + index + length, self->buffer + index, self->size - index); memcpy(self->buffer + index, string, length); self->size += length; self->buffer[self->size] = '\0'; return C_ERR_OK; } c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t length) { 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) { length = self->size - index; } // Shift trailing memory to the left to close the character gap memmove(self->buffer + index, self->buffer + index + length, self->size - (index + length)); self->size -= length; self->buffer[self->size] = '\0'; return C_ERR_OK; } void c_StringBuffer_Clear(c_StringBuffer_t* self) { if (!self || !self->buffer) return; self->size = 0; self->buffer[0] = '\0'; } /* --- Explicit String-Wrapper Interfaces --- */ c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string) { if (!string) return C_ERR_PARAM; return c_StringBuffer_Append(self, string, strlen(string)); } c_err_t c_StringBuffer_PrependStr(c_StringBuffer_t* self, const char* string) { if (!string) return C_ERR_PARAM; return c_StringBuffer_Prepend(self, string, strlen(string)); } c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c_size_t index) { if (!string) return C_ERR_PARAM; return c_StringBuffer_InsertAt(self, index, string, strlen(string)); } 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) { 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) { length = self->size - index; } // 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_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 if (length > 0) { memcpy(buffer, self->buffer + index, length); } // 5. Always apply a deterministic trailing null terminator buffer[length] = '\0'; 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; }