mirror of
https://github.com/Tilo-K/tstd.git
synced 2026-01-10 23:11:00 +00:00
init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.idea
|
||||||
15
CMakeLists.txt
Normal file
15
CMakeLists.txt
Normal 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
7
library.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "library.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void hello(void) {
|
||||||
|
printf("Hello, World!\n");
|
||||||
|
}
|
||||||
6
library.h
Normal file
6
library.h
Normal 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
102
string.c
Normal 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
66
string.h
Normal 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
112
test/test_main.c
Normal 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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user