mirror of
https://codeberg.org/Tilo-K/tk_sfl.git
synced 2026-10-18 13:57:10 +00:00
feat: add tk_strings
This commit is contained in:
2 files changed
+303
No files matched your search
+23
@@ -22,3 +22,26 @@ int main() {
|
||||
|
||||
Define DEBUG to initalize memory with OXFE, to detect uninitialized memory.
|
||||
Define DEBUG AND TK_MEMORY_TRACK to catch memory leaks when calling tk_check_memory_leaks().
|
||||
|
||||
|
||||
*** tk_strings.h ***
|
||||
```
|
||||
#define TK_STRINGS_IMPLEMENTATION
|
||||
#include "tk_strings.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
char str[] = " Hello, World ";
|
||||
tk_str_to_lower(str);
|
||||
|
||||
char* trimmed = tk_str_trim(str);
|
||||
uint8_t contains = tk_str_contains(trimmed, "hello");
|
||||
|
||||
free(trimmed);
|
||||
return contains ? 0 : 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
String utilities include counting characters/substrings, splitting by character or substring, case conversion, concatenation, trimming, and substring checks.
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
#ifndef TK_STRINGS_H
|
||||
#define TK_STRINGS_H
|
||||
|
||||
/**
|
||||
* @file tk_strings.h
|
||||
* @brief Single-header string utilities.
|
||||
*
|
||||
* Define TK_STRINGS_IMPLEMENTATION in exactly one translation unit before
|
||||
* including this file to include the implementation.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Count occurrences of a character in a C string.
|
||||
* @param str Null-terminated input string. Must not be NULL.
|
||||
* @param c Character to count.
|
||||
* @return Number of times c appears in str.
|
||||
*/
|
||||
size_t tk_str_count_occurrences(const char* str, char c);
|
||||
|
||||
/**
|
||||
* @brief Count occurrences of a substring in a C string.
|
||||
* @param str Null-terminated input string. Must not be NULL.
|
||||
* @param substr Null-terminated substring to count. Must not be NULL or empty.
|
||||
* @return Number of times substr appears in str.
|
||||
*/
|
||||
size_t tk_str_count_occurrences_of_substring(const char* str, const char* substr);
|
||||
|
||||
/**
|
||||
* @brief Split a string by a delimiter character.
|
||||
*
|
||||
* This copies all parts. The caller is responsible for freeing each string in
|
||||
* result and the result array itself.
|
||||
*
|
||||
* @param str Null-terminated input string. Must not be NULL.
|
||||
* @param delimiter Delimiter character.
|
||||
* @param[out] result On success, set to a malloc'd array of char* parts.
|
||||
* @return Number of parts. An empty string returns one empty part. If the
|
||||
* result array allocation fails, returns 0. If a part allocation fails, returns
|
||||
* the number of parts allocated so far and result points to that partial array.
|
||||
*/
|
||||
size_t tk_str_split_by_char(const char* str, char delimiter, char*** result);
|
||||
|
||||
/**
|
||||
* @brief Split a string by a delimiter substring.
|
||||
*
|
||||
* This copies all parts. The caller is responsible for freeing each string in
|
||||
* result and the result array itself.
|
||||
*
|
||||
* @param str Null-terminated input string. Must not be NULL.
|
||||
* @param substr Null-terminated delimiter substring. Must not be NULL or empty.
|
||||
* @param[out] result On success, set to a malloc'd array of char* parts.
|
||||
* @return Number of parts. If the result array allocation fails, returns 0. If
|
||||
* a part allocation fails, returns the number of parts allocated so far and
|
||||
* result points to that partial array.
|
||||
*/
|
||||
size_t tk_str_split_by_substring(const char* str, const char* substr, char*** result);
|
||||
|
||||
/**
|
||||
* @brief Convert all lowercase ASCII letters in a string to uppercase.
|
||||
* @param str Null-terminated string to modify in place. Must not be NULL.
|
||||
*/
|
||||
void tk_str_to_upper(char* str);
|
||||
|
||||
/**
|
||||
* @brief Convert all uppercase ASCII letters in a string to lowercase.
|
||||
* @param str Null-terminated string to modify in place. Must not be NULL.
|
||||
*/
|
||||
void tk_str_to_lower(char* str);
|
||||
|
||||
/**
|
||||
* @brief Concatenate two null-terminated strings into a newly allocated string.
|
||||
* @param str1 First input string. Must not be NULL.
|
||||
* @param str2 Second input string. Must not be NULL.
|
||||
* @return Newly allocated concatenated string, or NULL on allocation error.
|
||||
*/
|
||||
char* tk_str_concat(const char* str1, const char* str2);
|
||||
|
||||
/**
|
||||
* @brief Trim leading and trailing whitespace from a string.
|
||||
* @param str Null-terminated input string. Must not be NULL, empty, or all whitespace.
|
||||
* @return Newly allocated trimmed string, or NULL on allocation error.
|
||||
*/
|
||||
char* tk_str_trim(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Check whether a string contains a substring.
|
||||
* @param str Null-terminated input string. Must not be NULL.
|
||||
* @param substr Null-terminated substring to search for. Must not be NULL.
|
||||
* @return 1 if str contains substr, 0 otherwise.
|
||||
*/
|
||||
uint8_t tk_str_contains(const char* str, const char* substr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TK_STRINGS_H */
|
||||
|
||||
#ifdef TK_STRINGS_IMPLEMENTATION
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
inline size_t tk_str_count_occurrences(const char* str, const char c) {
|
||||
size_t i = 0;
|
||||
size_t count = 0;
|
||||
while (str[i] != '\0') {
|
||||
if (str[i] == c) {
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inline size_t tk_str_count_occurrences_of_substring(const char* str, const char* substr) {
|
||||
size_t i = 0;
|
||||
size_t count = 0;
|
||||
while (str[i] != '\0') {
|
||||
if (strstr(&str[i], substr) == &str[i]) {
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
inline size_t tk_str_split_by_char(const char* str, const char delimiter, char*** result) {
|
||||
const size_t size = tk_str_count_occurrences(str, delimiter);
|
||||
char** parts = malloc((size + 1) * sizeof(char*));
|
||||
if (parts == NULL) {
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t curr_part_idx = 0;
|
||||
size_t last_part_end = 0;
|
||||
size_t idx = 0;
|
||||
while (str[idx] != '\0') {
|
||||
if (str[idx] == delimiter) {
|
||||
const size_t len = idx - last_part_end;
|
||||
char* part = malloc(sizeof(char) * (len + 1));
|
||||
if (part == NULL) {
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
memcpy(part, &str[last_part_end], len);
|
||||
part[idx - last_part_end] = '\0';
|
||||
|
||||
parts[curr_part_idx++] = part;
|
||||
last_part_end = idx;
|
||||
last_part_end++;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
char* part = malloc(sizeof(char) * (idx - last_part_end + 1));
|
||||
if (part == NULL) {
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
memcpy(part, &str[last_part_end], idx - last_part_end);
|
||||
part[idx - last_part_end] = '\0';
|
||||
parts[curr_part_idx++] = part;
|
||||
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
|
||||
inline size_t tk_str_split_by_substring(const char* str, const char* substr, char*** result) {
|
||||
const size_t size = tk_str_count_occurrences_of_substring(str, substr);
|
||||
char** parts = malloc((size + 1) * sizeof(char*));
|
||||
if (parts == NULL) {
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t curr_part_idx = 0;
|
||||
size_t last_part_end = 0;
|
||||
size_t idx = 0;
|
||||
|
||||
while (str[idx] != '\0') {
|
||||
if (strstr(&str[idx], substr) == &str[idx]) {
|
||||
const size_t len = idx - last_part_end;
|
||||
char* part = malloc(sizeof(char) * (len + 1));
|
||||
if (part == NULL) {
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
memcpy(part, &str[last_part_end], len);
|
||||
part[len] = '\0';
|
||||
|
||||
parts[curr_part_idx++] = part;
|
||||
last_part_end = idx;
|
||||
last_part_end += strlen(substr);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
const size_t len = idx - last_part_end;
|
||||
char* part = malloc(sizeof(char) * (len + 1));
|
||||
if (part == NULL) {
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
memcpy(part, &str[last_part_end], len);
|
||||
part[len] = '\0';
|
||||
|
||||
parts[curr_part_idx++] = part;
|
||||
|
||||
*result = parts;
|
||||
return curr_part_idx;
|
||||
}
|
||||
|
||||
inline void tk_str_to_upper(char* str) {
|
||||
for (size_t i = 0; str[i] != '\0'; i++) {
|
||||
if (str[i] >= 'a' && str[i] <= 'z') {
|
||||
str[i] -= 'a' - 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void tk_str_to_lower(char* str) {
|
||||
for (size_t i = 0; str[i] != '\0'; i++) {
|
||||
if (str[i] >= 'A' && str[i] <= 'Z') {
|
||||
str[i] += 'a' - 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline char* tk_str_concat(const char* str1, const char* str2) {
|
||||
const size_t len1 = strlen(str1);
|
||||
const size_t len2 = strlen(str2);
|
||||
|
||||
char* result = malloc(sizeof(char) * (len1 + len2 + 1));
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(result, str1, len1);
|
||||
memcpy(&result[len1], str2, len2);
|
||||
result[len1 + len2] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline bool tk_internal_str_char_is_rubbish(const char c) {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||
}
|
||||
|
||||
inline char* tk_str_trim(const char* str) {
|
||||
size_t start = 0;
|
||||
size_t end = strlen(str) - 1;
|
||||
while (tk_internal_str_char_is_rubbish(str[start])) {
|
||||
start++;
|
||||
}
|
||||
while (tk_internal_str_char_is_rubbish(str[end])) {
|
||||
end--;
|
||||
}
|
||||
|
||||
char* new_str = malloc(sizeof(char) * (end - start + 2));
|
||||
if (new_str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(new_str, &str[start], end - start + 1);
|
||||
new_str[end - start + 1] = '\0';
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
inline uint8_t tk_str_contains(const char* str, const char* substr) {
|
||||
return strstr(str, substr) != NULL;
|
||||
}
|
||||
|
||||
#endif /* TK_STRINGS_IMPLEMENTATION */
|
||||
Reference in new issue
Block a user