cstring

Lightweight string library for C
git clone git://git.christosmarg.xyz/cstring.git
Log | Files | Refs | README | LICENSE

commit 9cac873acc706b2a683ed1541c367e38768cb999
parent 9ce134335486b3b6a7337be22a3d00e35c235729
Author: Christos Margiolis <christos@margiolis.net>
Date:   Mon, 19 Oct 2020 04:44:30 +0300

improved style, made indentation 8 spaces

Diffstat:
MLICENSE | 0
MMakefile | 50++++++++++++++++++++++++++------------------------
MREADME.md | 7++++---
Mcstring.3 | 0
Mcstring.c | 442+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mcstring.h | 82++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mtests/Makefile | 40++++++++++++++++++++--------------------
Mtests/test_basic.c | 78+++++++++++++++++++++++++++++++++++++++---------------------------------------
Mtests/test_insert.c | 11++++++-----
9 files changed, 367 insertions(+), 343 deletions(-)

diff --git a/LICENSE b/LICENSE diff --git a/Makefile b/Makefile @@ -1,3 +1,5 @@ +# See LICENSE file for copyright and license details. + LIB = cstring VERSION = 0.1 DIST = ${LIB}-${VERSION} @@ -31,40 +33,40 @@ GZIP = gzip all: options ${LIB} options: - @echo ${LIB} build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" + @echo ${LIB} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" ${LIB}: ${OBJ} - ${AR} ${ARFLAGS} lib${LIB}.a ${OBJ} + ${AR} ${ARFLAGS} lib${LIB}.a ${OBJ} -%.o: %.${EXT} - ${CC} ${CFLAGS} -c $< -o $@ +${OBJ}: ${SRC} + ${CC} ${CFLAGS} -c $< -o $@ dist: clean - ${MKDIR} ${DIST} - ${CP} -R tests ${SRC} ${MAN3} LICENSE Makefile README.md ${DIST} - ${TAR} ${DIST}.tar ${DIST} - ${GZIP} ${DIST}.tar - ${RM_DIR} ${DIST} + ${MKDIR} ${DIST} + ${CP} -R tests ${SRC} ${MAN3} LICENSE Makefile README.md ${DIST} + ${TAR} ${DIST}.tar ${DIST} + ${GZIP} ${DIST}.tar + ${RM_DIR} ${DIST} install: all - ${MKDIR} ${DESTDIR}${LIB_DIR} ${DESTDIR}${INC_DIR} ${DESTDIR}${MAN_DIR} - ${CP} ${LIB}.h ${DESTDIR}${INC_DIR} - ${CP} lib${LIB}.a ${DESTDIR}${LIB_DIR} - ${CP} ${MAN3} ${DESTDIR}${MAN_DIR} - sed "s/VERSION/${VERSION}/g" < ${MAN3} > ${DESTDIR}${MAN_DIR}/${MAN3} - chmod 755 ${DESTDIR}${INC_DIR}/${LIB}.h - chmod 644 ${DESTDIR}${LIB_DIR}/lib${LIB}.a - chmod 644 ${DESTDIR}${MAN_DIR}/${MAN3} + ${MKDIR} ${DESTDIR}${LIB_DIR} ${DESTDIR}${INC_DIR} ${DESTDIR}${MAN_DIR} + ${CP} ${LIB}.h ${DESTDIR}${INC_DIR} + ${CP} lib${LIB}.a ${DESTDIR}${LIB_DIR} + ${CP} ${MAN3} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN3} > ${DESTDIR}${MAN_DIR}/${MAN3} + chmod 755 ${DESTDIR}${INC_DIR}/${LIB}.h + chmod 644 ${DESTDIR}${LIB_DIR}/lib${LIB}.a + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN3} uninstall: - ${RM} ${DESTDIR}${INC_DIR}/${LIB}.h - ${RM} ${DESTDIR}${LIB_DIR}/lib${LIB}.a - ${RM} ${DESTDIR}${MAN_DIR}/${MAN3} + ${RM} ${DESTDIR}${INC_DIR}/${LIB}.h + ${RM} ${DESTDIR}${LIB_DIR}/lib${LIB}.a + ${RM} ${DESTDIR}${MAN_DIR}/${MAN3} clean: - ${RM} ${LIB} ${OBJ} lib${LIB}.a ${DIST}.tar.gz + ${RM} ${LIB} ${OBJ} lib${LIB}.a ${DIST}.tar.gz .PHONY: all options clean dist install uninstall diff --git a/README.md b/README.md @@ -1,7 +1,7 @@ # cstring A simple and lightweight string library for C inspired by C++'s STL `string` class, -but with a lot of additions. +but with a many additions. ## Building @@ -30,7 +30,9 @@ When using this library, you must **always** call the `cstring_create` and `cstr functions whenever you want to make a new instance of `cstring` and stop using it respectively, in order not to cause any memory leaks, as there's no *constructor* and *destructor* to do it for you. -The recommended way of initializing an empty string is by doing `cstring foo = cstring_create(CSTRING_INIT_EMPTY)`. +The recommended way of initializing an empty string is by doing `cstring foo = cstring_create(CSTRING_INIT_EMPTY)`. + +Read the `man` page for more detailed info. ## Functions @@ -104,7 +106,6 @@ The following macros can only be used in debug mode See the test programs in `tests` for more. ```c -#include <stdio.h> #include <cstring.h> /* outputs "Foobar" to the screen */ diff --git a/cstring.3 b/cstring.3 diff --git a/cstring.c b/cstring.c @@ -1,23 +1,25 @@ +/* See LICENSE file for copyright and license details. */ + #include "cstring.h" #define CSTRING_EXCEEDS_CAPACITY(len, cap) ((len) >= (cap)) -#define CSTRING_FIND_OCCURENCE(cs, s, func) do { \ - char *_found; \ - if ((_found = func(cs->str, (s))) != NULL) \ - return (_found - cs->str); \ +#define CSTRING_FIND_OCCURENCE(cs, s, func) do { \ + char *_found; \ + if ((_found = func(cs->str, (s))) != NULL) \ + return (_found - cs->str); \ } while (0) #ifdef CSTRING_DBG -#define CSTRING_FREE(cs) do { \ - CSTRING_DBG_LOG("Before CSTRING_FREE: %s\n", cs->str); \ - if (!cstring_empty(cs)) \ - free(cs->str); \ +#define CSTRING_FREE(cs) do { \ + CSTRING_DBG_LOG("Before CSTRING_FREE: %s\n", cs->str); \ + if (!cstring_empty(cs)) \ + free(cs->str); \ } while (0) #else /* !CSTRING_DBG */ -#define CSTRING_FREE(cs) do { \ - if (!cstring_empty(cs)) \ - free(cs->str); \ +#define CSTRING_FREE(cs) do { \ + if (!cstring_empty(cs)) \ + free(cs->str); \ } while (0) #endif /* CSTRING_DBG */ @@ -31,165 +33,173 @@ static inline int cstring_cmp_char_less(const void *, const void *); static int cstring_is_one_of(char c, const char *s) { - for (; *s; s++) - if (*s == c) - return 1; - return 0; + for (; *s; s++) + if (*s == c) + return 1; + return 0; } static inline int cstring_cmp_greater(const void *lhs, const void *rhs) { - return cstring_greater((cstring *)lhs, (cstring *)rhs); + return cstring_greater((cstring *)lhs, (cstring *)rhs); } static inline int cstring_cmp_less(const void *lhs, const void *rhs) { - return cstring_less((cstring *)lhs, (cstring *)rhs); + return cstring_less((cstring *)lhs, (cstring *)rhs); } static inline int cstring_cmp_char_greater(const void *lhs, const void *rhs) { - return (*(char *)lhs > *(char *)rhs); + return (*(char *)lhs > *(char *)rhs); } static inline int cstring_cmp_char_less(const void *lhs, const void *rhs) { - return (*(char *)lhs < *(char *)rhs); + return (*(char *)lhs < *(char *)rhs); } /* externs */ cstring cstring_create(const char *s) { - cstring cs; - cs.len = strlen(s); - cs.str = cstring_copy(s); - cstring_resize(&cs, cs.len << 1); + cstring cs; + cs.len = strlen(s); + cs.str = cstring_copy(s); + cstring_resize(&cs, cs.len << 1); #ifdef CSTRING_DBG - CSTRING_DBG_LOG_STR_INFO(s, cs.len); - CSTRING_DBG_LOG_CSTR_INFO_NPTR(cs); + CSTRING_DBG_LOG_STR_INFO(s, cs.len); + CSTRING_DBG_LOG_CSTR_INFO_NPTR(cs); #endif /* CSTRING_DBG */ - return cs; + return cs; } void cstring_delete(cstring *cs) { - CSTRING_FREE(cs); - cs->str = NULL; - cs->len = 0; - cs->capacity = 0; + CSTRING_FREE(cs); + cs->str = NULL; + cs->len = 0; + cs->capacity = 0; } void cstring_assign(cstring *cs, const char *s) { - CSTRING_FREE(cs); - cs->str = cstring_copy(s); - cs->len = strlen(s); - if (CSTRING_EXCEEDS_CAPACITY(cs->len, cs->capacity)) - cstring_resize(cs, cs->len << 1); + CSTRING_FREE(cs); + cs->str = cstring_copy(s); + cs->len = strlen(s); + if (CSTRING_EXCEEDS_CAPACITY(cs->len, cs->capacity)) + cstring_resize(cs, cs->len << 1); #ifdef CSTRING_DBG - CSTRING_DBG_LOG_STR_INFO(s, cs->len); - CSTRING_DBG_LOG_CSTR_INFO(cs); + CSTRING_DBG_LOG_STR_INFO(s, cs->len); + CSTRING_DBG_LOG_CSTR_INFO(cs); #endif /* CSTRING_DBG */ } void cstring_insert(cstring *cs, const char *s, size_t i) { - if (!CSTRING_OUT_OF_BOUNDS(cs, i) && s != NULL) { - size_t slen = strlen(s); - size_t newlen = cs->len + slen; + size_t slen, newlen; char *tmp; - CSTRING_MALLOC(tmp, newlen + 1); - memcpy(tmp, cs->str, i); - memcpy(tmp + i, s, slen); - memcpy(tmp + i + slen, cs->str + i, newlen - slen - i + 1); - CSTRING_FREE(cs); - cs->len = newlen; - cs->str = tmp; - cs->str[cs->len] = '\0'; - if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) - cstring_resize(cs, newlen << 1); + + if (!CSTRING_OUT_OF_BOUNDS(cs, i) && s != NULL) { + slen = strlen(s); + newlen = cs->len + slen; + CSTRING_MALLOC(tmp, newlen + 1); + memcpy(tmp, cs->str, i); + memcpy(tmp + i, s, slen); + memcpy(tmp + i + slen, cs->str + i, newlen - slen - i + 1); + CSTRING_FREE(cs); + cs->len = newlen; + cs->str = tmp; + cs->str[cs->len] = '\0'; + if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) + cstring_resize(cs, newlen << 1); #ifdef CSTRING_DBG - CSTRING_DBG_LOG_STR_INFO(s, slen); - CSTRING_DBG_LOG_CSTR_INFO(cs); + CSTRING_DBG_LOG_STR_INFO(s, slen); + CSTRING_DBG_LOG_CSTR_INFO(cs); #endif /* CSTRING_DBG */ - } + } } #ifdef CSTRING_DBG // FIX IT #define CSTRING_DBG_EXPECTED_ERASE_STR(cs, pos, len) do { \ - CSTRING_DBG_LOG("%s", "CSTRING_DBG_EXPECTED_ERASE_STR: "); \ - size_t _i; \ - for (_i = 0; _i < (pos); _i++) \ - printf("%c", cs->str[_i]); \ - for (_i = (pos) + (len); _i < cs->len; _i++) \ - printf("%c", cs->str[_i]); \ - printf("\n"); \ + CSTRING_DBG_LOG("%s", "CSTRING_DBG_EXPECTED_ERASE_STR: "); \ + size_t _i; \ + for (_i = 0; _i < (pos); _i++) \ + printf("%c", cs->str[_i]); \ + for (_i = (pos) + (len); _i < cs->len; _i++) \ + printf("%c", cs->str[_i]); \ + printf("\n"); \ } while (0) #define CSTRING_DBG_EXPECTED_ERASE_LEN(cs, len) \ - CSTRING_DBG_LOG("CSTRING_DBG_EXPECTED_ERASE_LEN: %ld\n", cs->len - len) + CSTRING_DBG_LOG("CSTRING_DBG_EXPECTED_ERASE_LEN: %ld\n", cs->len - len) #endif /* CSTRING_DBG */ void cstring_erase(cstring *cs, size_t pos, size_t len) { - if (!cstring_empty(cs) - && (!CSTRING_OUT_OF_BOUNDS(cs, pos) - || !CSTRING_OUT_OF_BOUNDS(cs, len))) - { + size_t newlen; + char *tmp; + + if (!cstring_empty(cs) + && (!CSTRING_OUT_OF_BOUNDS(cs, pos) + || !CSTRING_OUT_OF_BOUNDS(cs, len))) { #ifdef CSTRING_DBG - CSTRING_DBG_LOG("STR: %s | INDEX: %ld | LEN: %ld\n", cs->str, pos, len); - CSTRING_DBG_EXPECTED_ERASE_STR(cs, pos, len); - CSTRING_DBG_EXPECTED_ERASE_LEN(cs, len); + CSTRING_DBG_LOG("STR: %s | INDEX: %ld | LEN: %ld\n", + cs->str, pos, len); + CSTRING_DBG_EXPECTED_ERASE_STR(cs, pos, len); + CSTRING_DBG_EXPECTED_ERASE_LEN(cs, len); #endif /* CSTRING_DBG */ - size_t newlen = cs->len - len; - char *tmp; - CSTRING_MALLOC(tmp, newlen + 1); - memcpy(tmp, cs->str, pos); - memcpy(tmp + pos, cs->str + pos + len, cs->len - pos - len); - CSTRING_FREE(cs); /* Useless check but keep it for consistency */ - cs->len = newlen; - cs->str = tmp; - cs->str[cs->len] = '\0'; + newlen = cs->len - len; + CSTRING_MALLOC(tmp, newlen + 1); + memcpy(tmp, cs->str, pos); + memcpy(tmp + pos, cs->str + pos + len, cs->len - pos - len); + CSTRING_FREE(cs); /* Useless check but keep it for consistency */ + cs->len = newlen; + cs->str = tmp; + cs->str[cs->len] = '\0'; #ifdef CSTRING_DBG - CSTRING_DBG_LOG_CSTR_INFO(cs); + CSTRING_DBG_LOG_CSTR_INFO(cs); #endif /* CSTRING_DBG */ - } + } } void cstring_erase_matching(cstring *cs, const char *s) { - if (s != NULL) - cstring_erase(cs, cstring_find(cs, s), strlen(s)); + if (s != NULL) + cstring_erase(cs, cstring_find(cs, s), strlen(s)); } void cstring_erase_all_matching(cstring *cs, const char *s) { - if (s != NULL) { - size_t len = strlen(s); - size_t i = cstring_find(cs, s); - for (; i != CSTRING_NPOS; i = cstring_find(cs, s)) - cstring_erase(cs, i, len); - } + size_t len, i; + + if (s != NULL) { + len = strlen(s); + i = cstring_find(cs, s); + for (; i != CSTRING_NPOS; i = cstring_find(cs, s)) + cstring_erase(cs, i, len); + } } void cstring_trim(cstring *cs, const char *s) { - size_t i = cstring_find_first_of(cs, s); - for (; i != CSTRING_NPOS; i = cstring_find_first_of(cs, s)) - cstring_erase(cs, i, 1); + size_t i; + + i = cstring_find_first_of(cs, s); + for (; i != CSTRING_NPOS; i = cstring_find_first_of(cs, s)) + cstring_erase(cs, i, 1); } #ifdef CSTRING_DBG @@ -200,59 +210,58 @@ cstring_trim(cstring *cs, const char *s) void cstring_push_back(cstring *cs, char c) { - if (CSTRING_EXCEEDS_CAPACITY(cs->len, cs->capacity)) - cstring_resize(cs, cs->len << 1); - cs->str[cs->len] = c; - cs->str[++cs->len] = '\0'; + if (CSTRING_EXCEEDS_CAPACITY(cs->len, cs->capacity)) + cstring_resize(cs, cs->len << 1); + cs->str[cs->len] = c; + cs->str[++cs->len] = '\0'; #ifdef CSTRING_DBG - CSTRING_DBG_LOG_CSTR_INFO(cs); + CSTRING_DBG_LOG_CSTR_INFO(cs); #endif /* CSTRING_DBG */ } void cstring_pop_back(cstring *cs) { - if (cs->len > 0) - cs->str[--cs->len] = '\0'; + if (cs->len > 0) + cs->str[--cs->len] = '\0'; } void cstring_replace_char(cstring *cs, size_t i, char c) { - if (!CSTRING_OUT_OF_BOUNDS(cs, i)) - cs->str[i] = c; + if (!CSTRING_OUT_OF_BOUNDS(cs, i)) + cs->str[i] = c; } void cstring_replace_str(cstring *cs, const char *s, size_t pos, size_t olen) { - if (!CSTRING_OUT_OF_BOUNDS(cs, pos) - && !CSTRING_OUT_OF_BOUNDS(cs, olen)) - { - cstring_erase(cs, pos, olen); - cstring_insert(cs, s, pos); - } + if (!CSTRING_OUT_OF_BOUNDS(cs, pos) + && !CSTRING_OUT_OF_BOUNDS(cs, olen)) { + cstring_erase(cs, pos, olen); + cstring_insert(cs, s, pos); + } } cstring cstring_substr(const cstring *cs, size_t pos, size_t len) { - if (CSTRING_OUT_OF_BOUNDS(cs, pos) - || CSTRING_OUT_OF_BOUNDS(cs, len)) - return cstring_create(""); - cstring substr = cstring_create(&cs->str[pos]); - substr.len = len; - substr.str[len] = '\0'; - cstring_shrink_to_fit(&substr); - return substr; + if (CSTRING_OUT_OF_BOUNDS(cs, pos) + || CSTRING_OUT_OF_BOUNDS(cs, len)) + return cstring_create(""); + cstring substr = cstring_create(&cs->str[pos]); + substr.len = len; + substr.str[len] = '\0'; + cstring_shrink_to_fit(&substr); + return substr; } void cstring_swap(cstring *lhs, cstring *rhs) { - cstring tmp = *lhs; - *lhs = *rhs; - *rhs = tmp; + cstring tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; } void @@ -262,16 +271,16 @@ cstring_sort_partial(cstring *cs, enum cstring_sort_flags flags, cstring_sort_callback callback) { - /* maybe chanage out of bounds macro */ - if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_REST) || pos + len > len) - len -= pos; - - if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_ASCENDING)) - qsort(cs + pos, len, sizeof(cstring), cstring_cmp_greater); - else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_DESCENDING)) - qsort(cs + pos, len, sizeof(cstring), cstring_cmp_less); - else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_CALLBACK)) - qsort(cs + pos, len, sizeof(cstring), callback); + /* maybe chanage out of bounds macro */ + if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_REST) || pos + len > len) + len -= pos; + + if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_ASCENDING)) + qsort(cs + pos, len, sizeof(cstring), cstring_cmp_greater); + else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_DESCENDING)) + qsort(cs + pos, len, sizeof(cstring), cstring_cmp_less); + else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_CALLBACK)) + qsort(cs + pos, len, sizeof(cstring), callback); } void @@ -281,104 +290,109 @@ cstring_sort_chars_partial(cstring *cs, enum cstring_sort_flags flags, cstring_sort_callback callback) { - if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_REST) - || CSTRING_OUT_OF_BOUNDS(cs, pos + len)) - len = cs->len - pos; - - if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_ASCENDING)) - qsort(cs->str + pos, len, sizeof(char), cstring_cmp_char_greater); - else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_DESCENDING)) - qsort(cs->str + pos, len, sizeof(char), cstring_cmp_char_less); - else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_CALLBACK)) - qsort(cs->str + pos, len, sizeof(char), callback); + if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_REST) + || CSTRING_OUT_OF_BOUNDS(cs, pos + len)) + len = cs->len - pos; + + if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_ASCENDING)) + qsort(cs->str + pos, len, sizeof(char), cstring_cmp_char_greater); + else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_DESCENDING)) + qsort(cs->str + pos, len, sizeof(char), cstring_cmp_char_less); + else if (CSTRING_FLAG_CHECK(flags, CSTRING_SORT_CALLBACK)) + qsort(cs->str + pos, len, sizeof(char), callback); } void cstring_clear(cstring *cs) { - CSTRING_FREE(cs); - CSTRING_MALLOC(cs->str, 1); - cs->str[0] = '\0'; - cs->len = 0; - cs->capacity = 0; + CSTRING_FREE(cs); + CSTRING_MALLOC(cs->str, 1); + cs->str[0] = '\0'; + cs->len = 0; + cs->capacity = 0; } -#define CSTRING_CHECK(cs, s) \ - if (cstring_empty(cs) || !*(s)) \ - return CSTRING_NPOS +#define CSTRING_CHECK(cs, s) \ + if (cstring_empty(cs) || !*(s)) \ + return CSTRING_NPOS size_t cstring_find(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - CSTRING_FIND_OCCURENCE(cs, s, strstr); - return CSTRING_NPOS; + CSTRING_CHECK(cs, s); + CSTRING_FIND_OCCURENCE(cs, s, strstr); + return CSTRING_NPOS; } +/*SIMPLIFY */ size_t cstring_rfind(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - /*SIMPLIFY */ - int found; - size_t idx = -1; - size_t slen = strlen(s); - size_t i, j; - for (i = 0; i <= cs->len - slen; i++) { - found = 1; - for (j = 0; j < slen; j++) { - if (cs->str[i + j] != s[j]) { - found = 0; - break; - } + size_t idx, slen, i, j; + int found; + + CSTRING_CHECK(cs, s); + idx = -1; + slen = strlen(s); + for (i = 0; i <= cs->len - slen; i++) { + found = 1; + for (j = 0; j < slen; j++) { + if (cs->str[i + j] != s[j]) { + found = 0; + break; + } + } + if (found) + idx = i; } - if (found) - idx = i; - } - return (idx == -1 ? CSTRING_NPOS : idx); + return (idx == -1 ? CSTRING_NPOS : idx); } size_t cstring_find_first_of(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - for (; *s; s++) { - CSTRING_FIND_OCCURENCE(cs, *s, strchr); - } - return CSTRING_NPOS; + CSTRING_CHECK(cs, s); + for (; *s; s++) { + CSTRING_FIND_OCCURENCE(cs, *s, strchr); + } + return CSTRING_NPOS; } size_t cstring_find_first_not_of(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - size_t i = 0; - for (; i < cs->len; i++) - if (!cstring_is_one_of(cs->str[i], s)) - return i; - return CSTRING_NPOS; + size_t i = 0; + + CSTRING_CHECK(cs, s); + for (; i < cs->len; i++) + if (!cstring_is_one_of(cs->str[i], s)) + return i; + return CSTRING_NPOS; } size_t cstring_find_last_of(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - size_t i = *(s + strlen(s)); - for (; i >= 0; i--) { - CSTRING_FIND_OCCURENCE(cs, s[i], strrchr); - } - return CSTRING_NPOS; + size_t i; + + CSTRING_CHECK(cs, s); + i = *(s + strlen(s)); + for (; i >= 0; i--) { + CSTRING_FIND_OCCURENCE(cs, s[i], strrchr); + } + return CSTRING_NPOS; } size_t cstring_find_last_not_of(const cstring *cs, const char *s) { - CSTRING_CHECK(cs, s); - size_t i = cs->len; - for (; i >= 0; i--) - if (!cstring_is_one_of(cs->str[i], s)) - return i; - return CSTRING_NPOS; + size_t i = cs->len; + + CSTRING_CHECK(cs, s); + for (; i >= 0; i--) + if (!cstring_is_one_of(cs->str[i], s)) + return i; + return CSTRING_NPOS; } #undef CSTR_CHECK @@ -386,43 +400,47 @@ cstring_find_last_not_of(const cstring *cs, const char *s) char * cstring_copy(const char *s) { - size_t len = strlen(s); - char *tmp; - CSTRING_MALLOC(tmp, len + 1); - memcpy(tmp, s, len + 1); - tmp[len] = '\0'; /* Add \0 in case s didn't have it */ - return tmp; + size_t len; + char *tmp; + + len = strlen(s); + CSTRING_MALLOC(tmp, len + 1); + memcpy(tmp, s, len + 1); + tmp[len] = '\0'; /* Add \0 in case s didn't have it */ + return tmp; } void cstring_resize(cstring *cs, size_t newcapacity) { + char *tmp; + #ifdef CSTRING_DBG - CSTRING_DBG_LOG("Old capacity: %ld | New capacity: %ld\n", - cs->capacity, newcapacity); + CSTRING_DBG_LOG("Old capacity: %ld | New capacity: %ld\n", + cs->capacity, newcapacity); #endif /* CSTRING_DBG */ - char *tmp; - CSTRING_MALLOC(tmp, newcapacity + 1); /* no +1? */ - memcpy(tmp, cs->str, cs->len + 1); /* copy \0 too */ - CSTRING_FREE(cs); - cs->str = tmp; - cs->str[cs->len] = '\0'; - cs->capacity = newcapacity; + CSTRING_MALLOC(tmp, newcapacity + 1); /* no +1? */ + memcpy(tmp, cs->str, cs->len + 1); /* copy \0 too */ + CSTRING_FREE(cs); + cs->str = tmp; + cs->str[cs->len] = '\0'; + cs->capacity = newcapacity; #ifdef CSTRING_DBG - CSTRING_DBG_LOG_CSTR_INFO(cs); + CSTRING_DBG_LOG_CSTR_INFO(cs); #endif /* CSTRING_DBG */ } cstring * cstring_getline(FILE *fd, cstring *cs, char delim) { - char c; - cstring_clear(cs); - while ((c = fgetc(fd)) != EOF && c != '\n') { - if (c == delim) - break; - else - cstring_push_back(cs, c); - } - return (c == EOF) ? NULL : cs; + char c; + + cstring_clear(cs); + while ((c = fgetc(fd)) != EOF && c != '\n') { + if (c == delim) + break; + else + cstring_push_back(cs, c); + } + return (c == EOF) ? NULL : cs; } diff --git a/cstring.h b/cstring.h @@ -1,3 +1,5 @@ +/* See LICENSE file for copyright and license details. */ + #ifndef CSTRING_H #define CSTRING_H @@ -15,40 +17,40 @@ extern "C" { #define CSTRING_ARR_LEN(arr) ((size_t)sizeof((arr)) / sizeof((arr)[0])) #define CSTRING_FLAG_CHECK(flag, bit) (((flag) & (int)(bit)) == (int)(bit)) -#define CSTRING_MALLOC(ptr, size) do { \ - ptr = (char *)malloc((size)); \ - if (ptr == NULL) \ - fputs("CSTRING_MALLOC(): cannot allocate memory\n", stderr); \ +#define CSTRING_MALLOC(ptr, size) do { \ + ptr = (char *)malloc((size)); \ + if (ptr == NULL) \ + fputs("CSTRING_MALLOC(): cannot allocate memory\n", stderr); \ } while (0) #ifdef CSTRING_DBG -#define CSTRING_DBG_LOG(fmt, ...) \ - fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \ - __FILE__, __LINE__, __func__, __VA_ARGS__) +#define CSTRING_DBG_LOG(fmt, ...) \ + fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \ + __FILE__, __LINE__, __func__, __VA_ARGS__) -#define CSTRING_DBG_LOG_CSTR_INFO(cs) \ - CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ - cs->str, cs->len, cs->capacity) +#define CSTRING_DBG_LOG_CSTR_INFO(cs) \ + CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ + cs->str, cs->len, cs->capacity) -#define CSTRING_DBG_LOG_CSTR_INFO_NPTR(cs) \ - CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ - cs.str, cs.len, cs.capacity) +#define CSTRING_DBG_LOG_CSTR_INFO_NPTR(cs) \ + CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ + cs.str, cs.len, cs.capacity) -#define CSTRING_DBG_LOG_STR_INFO(s, len) \ - CSTRING_DBG_LOG("S: %s | LEN: %ld\n", (s), (len)) +#define CSTRING_DBG_LOG_STR_INFO(s, len) \ + CSTRING_DBG_LOG("S: %s | LEN: %ld\n", (s), (len)) #endif /* CSTRING_DBG */ struct cstring { - char *str; - size_t len; - size_t capacity; + char *str; + size_t len; + size_t capacity; }; enum cstring_sort_flags { - CSTRING_SORT_ASCENDING = 1 << 0, - CSTRING_SORT_DESCENDING = 1 << 1, - CSTRING_SORT_CALLBACK = 1 << 2, - CSTRING_SORT_REST = 1 << 3 + CSTRING_SORT_ASCENDING = 1 << 0, + CSTRING_SORT_DESCENDING = 1 << 1, + CSTRING_SORT_CALLBACK = 1 << 2, + CSTRING_SORT_REST = 1 << 3 }; typedef struct cstring cstring; @@ -111,13 +113,13 @@ static inline int cstring_less_or_equal(const cstring *, const cstring *); static inline void cstring_prepend(cstring *cs, const char *s) { - cstring_insert(cs, s, 0); + cstring_insert(cs, s, 0); } static inline void cstring_append(cstring *cs, const char *s) { - cstring_insert(cs, s, cs->len); + cstring_insert(cs, s, cs->len); } static inline void @@ -126,7 +128,7 @@ cstring_sort(cstring *cs, enum cstring_sort_flags flags, cstring_sort_callback callback) { - cstring_sort_partial(cs, 0, len, flags, callback); + cstring_sort_partial(cs, 0, len, flags, callback); } static inline void @@ -134,91 +136,91 @@ cstring_sort_chars(cstring *cs, enum cstring_sort_flags flags, cstring_sort_callback callback) { - cstring_sort_chars_partial(cs, 0, cs->len, flags, callback); + cstring_sort_chars_partial(cs, 0, cs->len, flags, callback); } static inline void cstring_shrink_to_fit(cstring *cs) { - cstring_resize(cs, cs->len); + cstring_resize(cs, cs->len); } static inline int cstring_empty(const cstring *cs) { - return (cs->str == NULL && cs->len == 0); + return (cs->str == NULL && cs->len == 0); } static inline char cstring_front(const cstring *cs) { - return cs->str[0]; + return cs->str[0]; } static inline char cstring_back(const cstring *cs) { - return (!cstring_empty(cs) ? cs->str[cs->len - 1] : cs->str[0]); + return (!cstring_empty(cs) ? cs->str[cs->len - 1] : cs->str[0]); } static inline int cstring_starts_with_str(const cstring *cs, const char *s) { - return (cstring_find(cs, s) == 0); + return (cstring_find(cs, s) == 0); } static inline int cstring_ends_with_str(const cstring *cs, const char *s) { - return (cstring_find(cs, s) == cs->len - strlen(s)); + return (cstring_find(cs, s) == cs->len - strlen(s)); } static inline int cstring_starts_with_char(const cstring *cs, char c) { - return (cs->str[0] == c); + return (cs->str[0] == c); } static inline int cstring_ends_with_char(const cstring *cs, char c) { - return (cs->str[cs->len] = c); + return (cs->str[cs->len] = c); } static inline void * cstring_data(const cstring *cs) { - return (void *)cs->str; + return (void *)cs->str; } static inline int cstring_equal(const cstring *lhs, const cstring *rhs) { - return (strcmp(lhs->str, rhs->str) == 0); + return (strcmp(lhs->str, rhs->str) == 0); } static inline int cstring_greater(const cstring *lhs, const cstring *rhs) { - return (strcmp(lhs->str, rhs->str) > 0); + return (strcmp(lhs->str, rhs->str) > 0); } static inline int cstring_greater_or_equal(const cstring *lhs, const cstring *rhs) { - return (strcmp(lhs->str, rhs->str) >= 0); + return (strcmp(lhs->str, rhs->str) >= 0); } static inline int cstring_less(const cstring *lhs, const cstring *rhs) { - return (strcmp(lhs->str, rhs->str) < 0); + return (strcmp(lhs->str, rhs->str) < 0); } static inline int cstring_less_or_equal(const cstring *lhs, const cstring *rhs) { - return (strcmp(lhs->str, rhs->str) <= 0); + return (strcmp(lhs->str, rhs->str) <= 0); } #ifdef __cplusplus diff --git a/tests/Makefile b/tests/Makefile @@ -6,33 +6,33 @@ LDFLAGS = -Llib -lcstring all: options ${BINS} options: - @echo "build options:" - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" + @echo "build options:" + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" run: - @echo "---------------------------" - @echo "---------------------------" - @echo "RUNNING: test_basic" - @echo "---------------------------" - @echo "---------------------------" - ./test_basic - - @echo "---------------------------" - @echo "---------------------------" - @echo "RUNNING: test_insert" - @echo "---------------------------" - @echo "---------------------------" - ./test_insert + @echo "---------------------------" + @echo "---------------------------" + @echo "RUNNING: test_basic" + @echo "---------------------------" + @echo "---------------------------" + ./test_basic + + @echo "---------------------------" + @echo "---------------------------" + @echo "RUNNING: test_insert" + @echo "---------------------------" + @echo "---------------------------" + ./test_insert clean: - rm -f ${BINS} *.o + rm -f ${BINS} *.o test_basic: test_basic.c - ${CC} test_basic.c ${CFLAGS} -o test_basic ${LDFLAGS} + ${CC} test_basic.c ${CFLAGS} -o test_basic ${LDFLAGS} test_insert: test_insert.c - ${CC} test_insert.c ${CFLAGS} -o test_insert ${LDFLAGS} + ${CC} test_insert.c ${CFLAGS} -o test_insert ${LDFLAGS} .PHONY: all options run clean diff --git a/tests/test_basic.c b/tests/test_basic.c @@ -1,61 +1,61 @@ -#include "cstring.h" +#include <cstring.h> // Compilation: gcc test_basic.c -lcstring int main(int argc, char **argv) { - cstring s = cstring_create("Hello world"); - printf("cstring_create: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring s = cstring_create("Hello world"); + printf("cstring_create: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_sort_chars(&s, CSTRING_SORT_ASCENDING, NULL); - printf("cstring_sort_chars: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_sort_chars(&s, CSTRING_SORT_ASCENDING, NULL); + printf("cstring_sort_chars: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_assign(&s, "New string"); - printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_assign(&s, "New string"); + printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_append(&s, "Appended text"); - printf("cstring_append: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_append(&s, "Appended text"); + printf("cstring_append: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_prepend(&s, "OK"); - printf("cstring_prepend: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_prepend(&s, "OK"); + printf("cstring_prepend: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_push_back(&s, 'c'); - printf("cstring_push_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_push_back(&s, 'c'); + printf("cstring_push_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_insert(&s, "Inserted text", 4); - printf("cstring_insert: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - - cstring_pop_back(&s); - printf("cstring_pop_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_insert(&s, "Inserted text", 4); + printf("cstring_insert: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + + cstring_pop_back(&s); + printf("cstring_pop_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_clear(&s); - printf("cstring_clear: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_clear(&s); + printf("cstring_clear: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_assign(&s, "CSTRING"); - printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - printf("cstring_front: %c\n", cstring_front(&s)); - printf("cstring_back: %c\n", cstring_back(&s)); + cstring_assign(&s, "CSTRING"); + printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + printf("cstring_front: %c\n", cstring_front(&s)); + printf("cstring_back: %c\n", cstring_back(&s)); - cstring_replace_char(&s, 3, 'x'); - printf("cstring_replace_char: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_replace_char(&s, 3, 'x'); + printf("cstring_replace_char: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_replace_str(&s, "hell", 0, strlen("hell")); - printf("cstring_replace_str: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_replace_str(&s, "hell", 0, strlen("hell")); + printf("cstring_replace_str: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_erase(&s, 1, 4); - printf("cstring_erase: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_erase(&s, 1, 4); + printf("cstring_erase: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_assign(&s, "hello aaaa hello abbb helo hello"); - cstring_erase_all_matching(&s, "hello"); - printf("cstring_erase_all_matching: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_assign(&s, "hello aaaa hello abbb helo hello"); + cstring_erase_all_matching(&s, "hello"); + printf("cstring_erase_all_matching: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_trim(&s, " "); - printf("cstring_trim: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + cstring_trim(&s, " "); + printf("cstring_trim: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_delete(&s); - if (cstring_empty(&s)) - puts("cstring_delete: Deleted string."); + cstring_delete(&s); + if (cstring_empty(&s)) + puts("cstring_delete: Deleted string."); - return 0; + return 0; } diff --git a/tests/test_insert.c b/tests/test_insert.c @@ -1,11 +1,12 @@ -#include <stdio.h> #include <cstring.h> +// Compilation: gcc test_insert.c -lcstring + int main(int argc, char **argv) { - cstring s = cstring_create("HHHHHHEEEEEEEEEEEEEEEEEEEEEYYYYYYYYYYYYYY"); - printf("%s\n", s.str); - cstring_delete(&s); - return 0; + cstring s = cstring_create("HHHHHHEEEEEEEEEEEEEEEEEEEEEYYYYYYYYYYYYYY"); + printf("%s\n", s.str); + cstring_delete(&s); + return 0; }