This commit is contained in:
2025-08-23 12:59:05 +02:00
commit c2885322fa
7 changed files with 309 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.idea

15
CMakeLists.txt Normal file
View File

@@ -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)

7
library.c Normal file
View File

@@ -0,0 +1,7 @@
#include "library.h"
#include <stdio.h>
void hello(void) {
printf("Hello, World!\n");
}

6
library.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef TSTD_LIBRARY_H
#define TSTD_LIBRARY_H
void hello(void);
#endif // TSTD_LIBRARY_H

102
string.c Normal file
View File

@@ -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';
}
}
}

66
string.h Normal file
View File

@@ -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 <stdlib.h>
#include <string.h>
/**
* @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

112
test/test_main.c Normal file
View File

@@ -0,0 +1,112 @@
//
// Created by tilok on 23.08.2025.
//
#include "string.h"
#include <assert.h>
#include <stdio.h>
#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();
}