From c2885322faaa8a1445729ccbd110038744fa4729 Mon Sep 17 00:00:00 2001 From: Tilo K Date: Sat, 23 Aug 2025 12:59:05 +0200 Subject: [PATCH] init --- .gitignore | 1 + CMakeLists.txt | 15 +++++++ library.c | 7 +++ library.h | 6 +++ string.c | 102 ++++++++++++++++++++++++++++++++++++++++++ string.h | 66 ++++++++++++++++++++++++++++ test/test_main.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 309 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 library.c create mode 100644 library.h create mode 100644 string.c create mode 100644 string.h create mode 100644 test/test_main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6acce80 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 4.0) +project(tstd C) + +set(CMAKE_C_STANDARD 23) + +add_library(tstd STATIC library.c + string.h + string.c) + + +add_executable(test_tstd test/test_main.c) +target_link_libraries(test_tstd tstd) + +enable_testing() +add_test(NAME tstd_tests COMMAND test_tstd) \ No newline at end of file diff --git a/library.c b/library.c new file mode 100644 index 0000000..2814686 --- /dev/null +++ b/library.c @@ -0,0 +1,7 @@ +#include "library.h" + +#include + +void hello(void) { + printf("Hello, World!\n"); +} \ No newline at end of file diff --git a/library.h b/library.h new file mode 100644 index 0000000..5f40554 --- /dev/null +++ b/library.h @@ -0,0 +1,6 @@ +#ifndef TSTD_LIBRARY_H +#define TSTD_LIBRARY_H + +void hello(void); + +#endif // TSTD_LIBRARY_H \ No newline at end of file diff --git a/string.c b/string.c new file mode 100644 index 0000000..b32ffb4 --- /dev/null +++ b/string.c @@ -0,0 +1,102 @@ +#include "string.h" + + +size_t 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; +} + +size_t 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; +} + +size_t str_split_by_char(const char* str, const char delimiter, char*** result) { + const size_t size = str_count_occurrences(str, delimiter); + char** parts = malloc((size+1) * sizeof(char*)); + int curr_part_idx = 0; + int last_part_end = 0; + int idx = 0; + while (str[idx] != '\0') { + if (str[idx] == delimiter) { + const int len = idx - last_part_end; + char* part = malloc(sizeof(char) * (len+1)); + 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)); + 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; +} + +size_t str_split_by_substring(const char* str, const char* substr, char*** result) { + const size_t size = str_count_occurrences_of_substring(str, substr); + char** parts = malloc((size+1) * sizeof(char*)); + 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)); + 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)); + memcpy(part, &str[last_part_end], len); + part[len] = '\0'; + + parts[curr_part_idx++] = part; + + *result = parts; + return curr_part_idx; +} + +void str_to_upper(char* str) { + for (int i = 0; str[i] != '\0'; i++) { + if (str[i] >= 'a' && str[i] <= 'z') { + str[i] -= 'a' - 'A'; + } + } +} + +void str_to_lower(char* str) { + for (int i = 0; str[i] != '\0'; i++) { + if (str[i] >= 'A' && str[i] <= 'Z') { + str[i] += 'a' - 'A'; + } + } +} \ No newline at end of file diff --git a/string.h b/string.h new file mode 100644 index 0000000..d75de0b --- /dev/null +++ b/string.h @@ -0,0 +1,66 @@ +/** +* @file string.h + * @brief String utilities + * @date 2025-08-23 + * @author Tilo + */ + +#ifndef TSTD_STRING_H +#define TSTD_STRING_H +#include +#include + +/** + * @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 str_count_occurrences(const char* str, char c); + +/** + * @breif Count the number of times a substring occurs. + * @param str + * @param substr The substring to be matches/*** + * @return The number of occurrences + */ +size_t str_count_occurrences_of_substring(const char* str, const char* substr); + +/** + * @brief Split a string by a delimiter. + * + * This copies all the parts. You should probably free them after. + * + * @param str Input/output string buffer (modified in-place). + * @param delimiter Delimiter character. + * @param[out] result On success, set to a malloc'd array of char* tokens. + * @return Number of tokens on success; 0 if str is empty; (size_t)-1 on error. + */ +size_t str_split_by_char(const char* str,char delimiter, char*** result); + +/** + * @brief Splits a string into parts separated by a given substring. + * + * This copies all the parts. You should probably free them after. + * + * @param str Null-terminated input string to be split (must not be NULL). + * @param substr Null-terminated substring used as the delimiter (must not be NULL). + * @param result Pointer to a dynamically allocated array of null-terminated strings. + * The caller is responsible for freeing the allocated memory. + * @return Number of parts the string has been split into. + */ +size_t str_split_by_substring(const char* str, const char* substr, char*** result); + +/** + * @brief Convert all lowercase letters in a string to uppercase. + * @param str Null-terminated input string (must not be NULL). The string is modified in place. + */ +void str_to_upper(char* str); + +/** + * @brief Converts all uppercase alphabetic characters in a C string to lowercase. + * @param str Null-terminated input string to be modified in-place (must not be NULL). + */ +void str_to_lower(char* str); + +#endif //TSTD_STRING_H diff --git a/test/test_main.c b/test/test_main.c new file mode 100644 index 0000000..2502dd1 --- /dev/null +++ b/test/test_main.c @@ -0,0 +1,112 @@ +// +// Created by tilok on 23.08.2025. +// + +#include "string.h" +#include +#include + +#include "../string.h" + +int test_count_occurrences() { + const char* test_str = "11abababb111"; + + const size_t num_a = str_count_occurrences(test_str, 'a'); + const size_t num_b = str_count_occurrences(test_str, 'b'); + const size_t num_one = str_count_occurrences(test_str, '1'); + + assert(num_a == 3); + assert(num_b == 4); + assert(num_one == 5); + + return 0; +} + + +int test_count_occurrences_by_substring() { + const char* test_str = "Hello, test. test"; + + const size_t num_hello = str_count_occurrences_of_substring(test_str, "Hello"); + const size_t num_test = str_count_occurrences_of_substring(test_str, "test"); + + assert(num_hello == 1); + assert(num_test == 2); + + return 0; +} + +int test_split_function() { + char* test_str = "this,is,a,test"; + char** parts = nullptr; + const size_t size = str_split_by_char(test_str, ',', &parts); + assert(parts != NULL); + + assert(size == 4); + assert(strcmp(parts[0], "this") == 0); + assert(strcmp(parts[1], "is") == 0); + assert(strcmp(parts[2], "a") == 0); + assert(strcmp(parts[3], "test") == 0); + + for (int i = 0; i < size; i++) { + free(parts[i]); + } + free(parts); + + return 0; +} + + +int test_split_function_by_substring() { + char* test_str = "thissplitissplitasplittest"; + char** parts = nullptr; + const size_t size = str_split_by_substring(test_str, "split", &parts); + assert(parts != NULL); + + printf("size: %llu\n", size); + + assert(size == 4); + assert(strcmp(parts[0], "this") == 0); + assert(strcmp(parts[1], "is") == 0); + assert(strcmp(parts[2], "a") == 0); + assert(strcmp(parts[3], "test") == 0); + + for (int i = 0; i < size; i++) { + free(parts[i]); + } + free(parts); + + return 0; +} + +int test_string_to_upper() { + char test_str[] = "Hello, test. test"; + str_to_upper(test_str); + assert(strcmp(test_str, "HELLO, TEST. TEST") == 0); + + return 0; +} + +int test_string_to_lower() { + char test_str[] = "Hello, test. test"; + str_to_lower(test_str); + assert(strcmp(test_str, "hello, test. test") == 0); + + return 0; +} + +int test_string_functions() { + int result = 0; + + result += test_split_function(); + result += test_count_occurrences(); + result += test_count_occurrences_by_substring(); + result += test_split_function_by_substring(); + result += test_string_to_upper(); + result += test_string_to_lower(); + + return result; +} + +int main() { + return test_string_functions(); +} \ No newline at end of file