Compare commits

...

9 Commits

Author SHA1 Message Date
db208bd912 remove strcmp and fix hidden bugs 2025-06-02 23:50:20 +02:00
e25b8236e4 switch from assert to if + return 2025-05-28 20:21:24 +02:00
77ccd59ce3 new untested code 2025-05-28 19:32:15 +02:00
fec9f2633d Portable Makefile 2025-05-28 19:31:56 +02:00
61a398f402 new strops_remove_at_pos_char_inplace 2025-05-21 21:07:14 +02:00
d31bc73884 not implementing those 2025-05-21 20:49:17 +02:00
5b4a3f84e5 remove url stuff
I recommend using libcurl or similar for that
2025-05-21 20:36:47 +02:00
c3824e1dc7 remove string.h dependency 2025-05-21 20:34:11 +02:00
7e26a39ec6 new strops_copy_amount 2025-05-21 17:54:43 +02:00
4 changed files with 148 additions and 250 deletions

View File

@ -1,4 +1,6 @@
tests : libstrops.a libstrops.so
.POSIX :
tests : libstrops.a libstrops.so strops.h
gcc -ansi -I . -L. -o tests tests.c -Wl,-Bstatic -lstrops -Wl,-Bdynamic
# gcc -ansi -I . -L. -o tests tests.c -lstrops
@ -8,6 +10,18 @@ libstrops.so : strops.o
libstrops.a : strops.o
ar cr libstrops.a strops.o
strops.o : strops.c strops.h
gcc -c -fPIC -ansi -ggdb -o strops.o strops.c
# gcc -c -ansi -O2 -pipe -o strops.o strops.c
strops.o : strops.c
# gcc -c -ansi -fPIC -ggdb -o strops.o strops.c
gcc -c -ansi -fpic -O2 -pipe -o strops.o strops.c
.PHONY : install uninstall
install: libstrops.a libstrops.so strops.h
sudo mv libstrops.a /usr/local/lib
sudo mv libstrops.so /usr/local/lib
sudo cp strops.h /usr/local/include
uninstall:
sudo rm /usr/local/lib/libstrops.a
sudo rm /usr/local/lib/libstrops.so
sudo rm /usr/local/include/strops.h

202
strops.c
View File

@ -1,8 +1,6 @@
#include "strops.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
/* Function template
@ -39,13 +37,58 @@ char* strops_copy(const char* string) {
for(i = 0; i < length; i++) {
result[i] = string[i];
}
result[i] = '\0';
return result;
}
char strops_contains_char(const char* string, char char_to_search) {
char* strops_copy_amount(const char* string, ull_t amount) {
if (!string) {
return 0;
}
if (amount > strops_length(string)) {
return 0;
}
char* result = malloc(amount);
ull_t i;
for (i = 0; i < strops_length(string); i++) {
for(i = 0; i < amount; i++) {
result[i] = string[i];
}
result[i] = '\0';
return result;
}
ull_t strops_first_pos_of_char(const char* string, char char_to_search) {
ull_t i;
for (i = 0; string[i] != char_to_search; i++) {}
return i;
}
ull_t strops_first_pos_of_string(const char* string, const char* string_to_search) {
bool_t contains_string;
ull_t sts_length = strops_length(string_to_search);
ull_t l = strops_length(string) - sts_length + 1;
ull_t i, j;
for (i = 0; i < l; i++) {
contains_string = 1;
for(j = 0; j < sts_length; j++) {
if (string[i + j] != string_to_search[j]) {
contains_string = 0;
break;
}
}
if (contains_string) {
break;
}
}
return i;
}
bool_t strops_contains_char(const char* string, char char_to_search) {
ull_t i;
for (i = 0; i < strops_length(string) + 1; i++) {
if (string[i] == char_to_search) {
return 1;
}
@ -53,8 +96,8 @@ char strops_contains_char(const char* string, char char_to_search) {
return 0;
}
char strops_contains_string(const char* string, const char* string_to_search) {
char contains_string = 0;
bool_t strops_contains_string(const char* string, const char* string_to_search) {
bool_t contains_string = 0;
ull_t sts_length = strops_length(string_to_search);
ull_t l = strops_length(string) - sts_length + 1;
ull_t i, j;
@ -73,6 +116,36 @@ char strops_contains_string(const char* string, const char* string_to_search) {
return contains_string;
}
bool_t strops_equals(const char* string1, const char* string2) {
if (strops_length(string1) != strops_length(string2)) {
return 0;
}
bool_t equal = 1;
ull_t i;
for (i = 0; i < strops_length(string1); i++) {
if (string1[i] != string2[i]) {
equal = 0;
break;
}
}
return equal;
}
bool_t strops_starts_with(const char* string1, const char* string2) {
if (strops_length(string1) < strops_length(string2)) {
return 0;
}
bool_t starts_with = 1;
ull_t i;
for (i = 0; i < strops_length(string2); i++) {
if (string1[i] != string2[i]) {
starts_with = 0;
break;
}
}
return starts_with;
}
char* strops_to_lowercase(const char* string) {
char* result = strops_copy(string);
ull_t i;
@ -95,7 +168,7 @@ char* strops_to_uppercase(const char* string) {
return result;
}
int strops_is_lowercase(const char* string) {
bool_t strops_is_lowercase(const char* string) {
ull_t i;
for (i = 0; i < strops_length(string); i++) {
if (!(string[i] >= 'a' && string[i] <= 'z')) {
@ -105,7 +178,7 @@ int strops_is_lowercase(const char* string) {
return 1;
}
int strops_is_uppercase(const char* string) {
bool_t strops_is_uppercase(const char* string) {
ull_t i;
for (i = 0; i < strops_length(string); i++) {
if (!(string[i] >= 'A' && string[i] <= 'Z')) {
@ -142,20 +215,21 @@ char* strops_remove_at_pos_char(const char* string, ull_t pos) {
return result;
}
char* strops_remove_at_pos_string(const char* string, const char* string_to_remove, ull_t pos) {
char* result = strops_copy(string);
return result;
}
char* strops_replace_at_pos_string(const char* string, const char* string_to_remove, const char* string_to_insert, ull_t pos) {
char* result = strops_copy(string);
return result;
void strops_remove_at_pos_char_inplace(char* string, ull_t pos) {
assert(pos <= strops_length(string) && "pos needs to be inside string");
ull_t length = strops_length(string);
string[pos] = 0;
ull_t i;
for (i = pos; i < length; i++) {
string[i] = string[i + 1];
}
}
char* strops_trim_right_whitespace(const char* string) {
char* result = strops_copy(string);
while (strchr("\t\n\v\f\r ", result[strops_length(result) - 1]) != NULL) {
result = strops_remove_at_pos_char(result, strops_length(result) - 1);
char* tmp;
while (strops_contains_char("\t\n\v\f\r ", result[strops_length(result) - 1])) {
strops_remove_at_pos_char_inplace(result, strops_length(result) - 1);
}
result = realloc(result, strops_length(result));
return result;
@ -163,8 +237,8 @@ char* strops_trim_right_whitespace(const char* string) {
char* strops_trim_left_whitespace(const char* string) {
char* result = strops_copy(string);
while (strchr("\t\n\v\f\r ", result[0]) != NULL) {
result = strops_remove_at_pos_char(result, 0);
while (strops_contains_char("\t\n\v\f\r ", result[0])) {
strops_remove_at_pos_char_inplace(result, 0);
}
result = realloc(result, strops_length(result));
return result;
@ -181,8 +255,8 @@ char* strops_trim_both_whitespace(const char* string) {
char* strops_trim_right_chars(const char* string, const char* chars_to_remove) {
char* result = strops_copy(string);
while (strchr(chars_to_remove, result[strops_length(result) - 1]) != NULL) {
result = strops_remove_at_pos_char(result, strops_length(result) - 1);
while (strops_contains_char(chars_to_remove, result[strops_length(result) - 1])) {
strops_remove_at_pos_char_inplace(result, strops_length(result) - 1);
}
result = realloc(result, strops_length(result));
return result;
@ -190,8 +264,8 @@ char* strops_trim_right_chars(const char* string, const char* chars_to_remove) {
char* strops_trim_left_chars(const char* string, const char* chars_to_remove) {
char* result = strops_copy(string);
while (strchr(chars_to_remove, result[0]) != NULL) {
result = strops_remove_at_pos_char(result, 0);
while (strops_contains_char(chars_to_remove, result[0])) {
strops_remove_at_pos_char_inplace(result, 0);
}
result = realloc(result, strops_length(result));
return result;
@ -212,10 +286,10 @@ char* strops_trim_right_string(const char* string, const char* string_to_remove)
ull_t offset = strops_length(result) - strops_length(string_to_remove);
char* tmp = result + offset;
while (strcmp(tmp, string_to_remove) == 0) {
while (strops_equals(tmp, string_to_remove)) {
ull_t i;
for (i = 0; i < strops_length(string_to_remove); i++) {
result = strops_remove_at_pos_char(result, offset);
strops_remove_at_pos_char_inplace(result, offset);
}
offset = strops_length(result) - strops_length(string_to_remove);
tmp = result + offset;
@ -227,16 +301,13 @@ char* strops_trim_right_string(const char* string, const char* string_to_remove)
char* strops_trim_left_string(const char* string, const char* string_to_remove) {
assert(strops_length(string) >= strops_length(string_to_remove) && "string_to_remove cannot be bigger than string");
char* result = strops_copy(string);
char* tmp = strops_copy(string_to_remove);
while (strcmp(tmp, string_to_remove) == 0) {
while (strops_first_pos_of_string(result, string_to_remove) == 0) {
ull_t i;
for (i = 0; i < strops_length(string_to_remove); i++) {
result = strops_remove_at_pos_char(result, 0);
strops_remove_at_pos_char_inplace(result, 0);
}
memcpy(tmp, result, strops_length(string_to_remove));
}
free(tmp);
result = realloc(result, strops_length(result));
return result;
}
@ -253,10 +324,10 @@ char* strops_trim_both_string(const char* string, const char* string_to_remove)
char* strops_remove_chars(const char* string, const char* chars_to_remove) {
char* result = strops_copy(string);
ull_t i;
ull_t i, j;
for (i = 0; i < strops_length(chars_to_remove); i++) {
while (strchr(result, chars_to_remove[i]) != NULL) {
result = strops_remove_at_pos_char(result, strops_length(result) - strops_length(strchr(result, chars_to_remove[i])));
while (strops_contains_char(result, chars_to_remove[i])) {
strops_remove_at_pos_char_inplace(result, strops_first_pos_of_char(result, chars_to_remove[i]));
}
}
result = realloc(result, strops_length(result));
@ -267,11 +338,11 @@ char* strops_remove_string(const char* string, const char* string_to_remove) {
assert(strops_length(string) >= strops_length(string_to_remove) && "string_to_remove cannot be bigger than string");
char* result = strops_copy(string);
while (strstr(result, string_to_remove) != NULL) {
ull_t offset = strops_length(result) - strops_length(strstr(result, string_to_remove));
while (strops_contains_string(result, string_to_remove)) {
ull_t offset = strops_first_pos_of_string(result, string_to_remove);
ull_t i;
for (i = 0; i < strops_length(string_to_remove); i++) {
result = strops_remove_at_pos_char(result, offset);
strops_remove_at_pos_char_inplace(result, offset);
}
}
result = realloc(result, strops_length(result));
@ -284,82 +355,35 @@ ull_t strops_word_count(const char* string) {
ull_t i = 0;
ull_t beginning_of_word = 0;
ull_t end_of_word = end_of_word;
while (i < strops_length(string) - 1) {
for (; i < strops_length(string); i++) {
for (; i < strops_length(tmp); i++) {
if ((tmp[i] >= 'A' && tmp[i] <= 'Z') || (tmp[i] >= 'a' && tmp[i] <= 'z')) {
beginning_of_word = i;
break;
}
}
if (strchr("\t\n\v\f\r ", tmp[beginning_of_word - 1]) == NULL) {
if (!strops_contains_char("\t\n\v\f\r ", tmp[beginning_of_word - 1])) {
continue;
}
for (i = beginning_of_word; i < strops_length(string); i++) {
for (i = beginning_of_word; i < strops_length(tmp); i++) {
if (!(tmp[i] >= 'A' && tmp[i] <= 'Z') && !(tmp[i] >= 'a' && tmp[i] <= 'z')) {
end_of_word = i;
break;
}
}
if (strchr("\t\n\v\f\r ", tmp[end_of_word + 1]) == NULL) {
if (!strops_contains_char("\t\n\v\f\r ", tmp[i + 1])) {
continue;
}
if (end_of_word - beginning_of_word < 2) {
if (i - beginning_of_word < 2) {
continue;
}
i = end_of_word;
word_count++;
}
free(tmp);
return word_count;
}
/* TODO: verify that this is correct */
int strops_is_url_encoded(const char* string) {
if (strchr(string, '%') != NULL) {
return 1;
}
return 0;
}
char* strops_url_encode(const char* string) {
if (strops_is_url_encoded(string)) { return 0; }
/* multiplied by 3, because example: ( => %28. Three times the chars */
char* result = strops_copy(string);
char* unsafe_chars = "()";
char replacement[4];
replacement[0] = '%';
replacement[3] = '\0';
ull_t i, j;
for (i = 0; i < strops_length(unsafe_chars); i++) {
j = 0;
while (strchr(result, unsafe_chars[i]) != NULL) {
if (result[j] == unsafe_chars[i]) {
char bad = result[j];
sprintf(replacement + 1, "%02X", bad);
result = strops_remove_at_pos_char(result, j);
result = strops_insert_at_pos_string(result, replacement, j);
j += 2;
} else {
j += 1;
}
}
}
result = realloc(result, strops_length(result));
return result;
}
char* strops_url_decode(const char* string) {
if (!strops_is_url_encoded(string)) { return 0; }
char* result = strops_copy(string);
result = realloc(result, strops_length(result));
return result;
}

View File

@ -4,27 +4,34 @@
#include <stddef.h>
/*
ATTENTION! THIS LIBRARY CURRENTLY LEAKS MEMORY!
Functions that return char*, return a new heap-allocated string.
The user of this library is responsible for freeing the memory of the result.
No function modifies the input string. The input string is copied at the beginning of a function.
Only 7-Bit Ascii is supported.
*/
typedef unsigned long long ull_t;
typedef unsigned char bool_t;
char contains_char(const char* string, char char_to_search);
char contains_string(const char* string, const char* string_to_search);
ull_t strops_length(const char* string);
char* strops_copy(const char* string);
char* strops_copy_amount(const char* string, ull_t amount);
ull_t strops_first_pos_of_char(const char* string, char char_to_search);
ull_t strops_first_pos_of_string(const char* string, const char* string_to_search);
bool_t strops_contains_char(const char* string, char char_to_search);
bool_t strops_contains_string(const char* string, const char* string_to_search);
bool_t strops_equals(const char* string1, const char* string2);
bool_t strops_starts_with(const char* string1, const char* string2);
char* strops_to_lowercase(const char* string);
char* strops_to_uppercase(const char* string);
int strops_is_lowercase(const char* string);
int strops_is_uppercase(const char* string);
bool_t strops_is_lowercase(const char* string);
bool_t strops_is_uppercase(const char* string);
char* strops_insert_at_pos_string(const char* string, const char* string_to_insert, ull_t pos);
char* strops_remove_at_pos_char(const char* string, ull_t pos);
char* strops_remove_at_pos_string(const char* string, const char* string_to_remove, ull_t pos);
char* strops_replace_at_pos_string(const char* string, const char* string_to_remove, const char* string_to_insert, ull_t pos);
void strops_remove_at_pos_char_inplace(char* string, ull_t pos);
char* strops_trim_right_whitespace(const char* string);
char* strops_trim_left_whitespace(const char* string);
@ -43,18 +50,5 @@ char* strops_remove_string(const char* string, const char* string_to_remove);
ull_t strops_word_count(const char* string);
int strops_is_url_encoded(const char* string);
/*
https://www.w3schools.com/tags/ref_urlencode.asp
PLEASE NEVER USE THEM WITHOUT UNDERSTANDING THEIR ISSUES!
They will fully remove the following '%20 %21 %22 %23 %24 %26 %27 %28 %29 %2A %2C %2E %2F \
%3B %3C %3E %3F %5B %5C %5D %5E %60 %7B %7C %7D %7E'
These will get turned into their ascii counterpart '%25 %2B %2D %2E %2F %3A %3D %40 %5F'
They will return NULL on failure
*/
char* strops_url_encode(const char* string);
char* strops_url_decode(const char* string);
#endif /* STROPS_H */

138
tests.c
View File

@ -1,7 +1,6 @@
#include "strops.h"
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
/* https://gist.githubusercontent.com/rexim/b5b0c38f53157037923e7cdd77ce685d/raw/86c3db57f485f3b6f7958f308ba7126fa81282d8/da_append.c */
#define da_append(xs, x) \
@ -80,7 +79,7 @@ int test_contains_string() {
char result;
input = "I suck at C";
expected = 1;
result = strops_contains_string(input, "C");
result = strops_contains_string(input, "suck");
if (result != expected) {
printf("test_ failed\n");
printf("Got = %d\nExpected = %d\n", result, expected);
@ -217,38 +216,6 @@ int test_remove_at_pos_char() {
return ret;
}
int test_remove_at_pos_string() {
int ret = 1;
char* input;
char* expected;
char* result;
input = "NULL BRUH NULL";
expected = "NULL NULL";
result = strops_remove_at_pos_string(input, " BRUH", 4);
if (strcmp(result, expected) != 0) {
printf("test_remove_at_pos_string failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
return ret;
}
int test_replace_at_pos_string() {
int ret = 1;
char* input;
char* expected;
char* result;
input = "What happened in Tiananmen Square in 1989";
expected = "Nothing happened in Tiananmen Square in 1989";
result = strops_replace_at_pos_string(input, "What", "Nothing", 0);
if (strcmp(result, expected) != 0) {
printf("test_replace_at_pos_string failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
return ret;
}
int test_trim_right_whitespace() {
int ret = 1;
char* input;
@ -441,107 +408,12 @@ int test_word_count() {
return ret;
}
int test_is_url_encoded() {
int ret = 1;
char* input;
int expected;
int result;
input = "(artist)";
expected = 0;
result = strops_is_url_encoded(input);
if (result != expected) {
printf("test_is_url_encoded failed\n");
printf("Got = %d\nExpected = %d\n", result, expected);
ret = 0;
}
input = "%28artist%29";
expected = 1;
result = strops_is_url_encoded(input);
if (result != expected) {
printf("test_is_url_encoded failed\n");
printf("Got = %d\nExpected = %d\n", result, expected);
ret = 0;
}
return ret;
}
int test_url_encode() {
int ret = 1;
char* input;
char* expected;
char* result;
input = "(artist)";
expected = "%28artist%29";
result = strops_url_encode(input);
if (result == NULL) {
printf("test_url_encode failed\n");
printf("Got = NULL\nExpected = '%s'\n", expected);
return 0;
}
if (strcmp(result, expected) != 0) {
printf("test_url_encode failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
input = "()";
expected = "%28%29";
result = strops_url_encode(input);
if (result == NULL) {
printf("test_url_encode failed\n");
printf("Got = NULL\nExpected = '%s'\n", expected);
return 0;
}
if (strcmp(result, expected) != 0) {
printf("test_url_encode failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
return ret;
}
int test_url_decode() {
int ret = 1;
char* input;
char* expected;
char* result;
input = "%28artist%29";
expected = "(artist)";
result = strops_url_decode(input);
if (result == NULL) {
printf("test_url_decode failed\n");
printf("Got = NULL\nExpected = '%s'\n", expected);
return 0;
}
if (strcmp(result, expected) != 0) {
printf("test_url_decode failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
input = "%28%29";
expected = "()";
result = strops_url_decode(input);
if (result == NULL) {
printf("test_url_decode failed\n");
printf("Got = NULL\nExpected = '%s'\n", expected);
return 0;
}
if (strcmp(result, expected) != 0) {
printf("test_url_decode failed\n");
printf("Got = '%s'\nExpected = '%s'\n", result, expected);
ret = 0;
}
return ret;
}
int main() {
Tests tests = { 0 };
da_append(&tests, test_contains_char);
da_append(&tests, test_contains_string);
da_append(&tests, test_to_lowercase);
da_append(&tests, test_to_uppercase);
da_append(&tests, test_is_lowercase);
@ -549,8 +421,6 @@ int main() {
da_append(&tests, test_insert_at_pos_string);
da_append(&tests, test_remove_at_pos_char);
da_append(&tests, test_remove_at_pos_string);
da_append(&tests, test_replace_at_pos_string);
da_append(&tests, test_trim_right_whitespace);
da_append(&tests, test_trim_left_whitespace);
@ -569,10 +439,6 @@ int main() {
da_append(&tests, test_word_count);
da_append(&tests, test_is_url_encoded);
da_append(&tests, test_url_encode);
da_append(&tests, test_url_decode);
size_t i;
for (i = 0; i < tests.count; i++) {
tests.amount_successful += tests.items[i]();