cstring

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

commit 3db911364bcc348ddcb9f71077743d065cc0847f
parent fb54a79b85158d77c21d18220c33226aaa78f48d
Author: Christos Margiolis <christos@margiolis.net>
Date:   Mon, 10 May 2021 03:18:59 +0300

removed CSTRING_DBG

Diffstat:
MREADME | 9---------
Mcstring.3 | 99+++++++++++++++++++++++++++----------------------------------------------------
Mcstring.c | 129++++++++++++++++++++++++++-----------------------------------------------------
Mcstring.h | 121+++++++++++++++++++++++++++++++------------------------------------------------
Mtests/Makefile | 4++--
5 files changed, 126 insertions(+), 236 deletions(-)

diff --git a/README b/README @@ -24,8 +24,6 @@ If you want to uninstall the library do: # sudo make uninstall A file using `cstring` has to be linked using the `-lcstring` linker flag. -In case you want to run your project in debug mode, compile the library using -the `-DCSTRING_DBG` option. Usage ----- @@ -96,13 +94,6 @@ Macros - `CSTRING_ARR_LEN`: Determine an array's length. The macro must be called in the same function the array is declared. - `CSTRING_MALLOC`: Allocate memory with error checking. -The following macros can only be used in debug mode: - -- `CSTIRNG_DBG_LOG`: Prints a message in the format of `DEBUG: file:line:func(): msg`. -- `CSTRING_DBG_LOG_CSTR_INFO`: Prints all the contents of a `cstring` struct. The argument *has* to be a pointer. -- `CSTRING_DBG_LOG_CSTR_INFO_NPTR`: Like `CSTRING_DBG_LOG_CSTR_INFO` but the argument has to be a non-pointer. -- `CSTRING_DBG_LOG_STR_INFO`: Print contents of a normal string. - Constants --------- - `CSTRING_NPOS`: Signifies that a pattern hasn't been found inside the string. Its value is -1. diff --git a/cstring.3 b/cstring.3 @@ -4,6 +4,8 @@ .Nm cstring .Nd A simple and lightweight string library for C inspired by C++'s STL string class +.Sh LIBRARY +C String (-lcstring) .Sh SYNOPSIS #include <cstring.h> .Sh DESCRIPTION @@ -12,38 +14,42 @@ The .Nm library offers a lightweight and fast way to manage strings with a wide range of useful functions. -.Pp -A program using -.Nm -has to be linked using the -.Ar \-lcstring -option. -.Pp -In case you want to run the program in debug mode, compile -it with the -.Ar \-DCSTRING_DBG -option. -.Sh STRUCTURES + .Bl -tag -width Ds typedef struct _cstring { - size_t len; /* string length */ - size_t capacity; /* string capacity */ - char *str; /* contents of string */ - -CSTRING_SORT_ASCENDING 0x01 /* sort in ascending order */ -.br -CSTRING_SORT_DESCENDING 0x02 /* sort in descending order */ -.br -CSTRING_SORT_CALLBACK 0x04 /* sort using a callback function */ -.br -CSTRING_SORT_REST 0x10 /* sort the rest of the array */ -.br + size_t len; /* string length */ + size_t capacity; /* string capacity */ + char *str; /* contents of string */ +CSTRING_SORT_ASCENDING 0x01 /* sort in ascending order */ +CSTRING_SORT_DESCENDING 0x02 /* sort in descending order */ +CSTRING_SORT_CALLBACK 0x04 /* sort using a callback function */ +CSTRING_SORT_REST 0x10 /* sort the rest of the array */ } cstring; -.Sh TYPEDEFS -.Bl -tag -width Ds -Short typedef for the cstring structure. + .It typedef\ int\ (*cstring_sort_callback)(const void *, const void *); Used in sort functions. + +.Sh USAGE +You must +.Ar always +call the +.Fn cstring_create +and +.Fn cstring_delete +functions whenever you want to make a new instance of +.Ar cstring +and stop using it respectively, in order to not cause any memory +leaks. +.Pp +The recommended way of initializing an empty string is by doing +.Ar cstring foo = cstring_create(CSTRING_INIT_EMPTY) +.Pp +If a function requires a +.Ar char * +you can access the +.Ar .str +field and pass it to the function. + .Sh FUNCTIONS .Bl -tag -width Ds .It void Fn cstring_create "const char *s" @@ -217,30 +223,13 @@ Check if .Ar pos is out of bounds (pos > len). -.It Fn CSTRING_ARR_LEN "arr" +.It Fn CSTRING_ARR_LEN "x" Determine an array's length. The macro must be called in the same function the array is declared. .It Fn CSTRING_MALLOC "ptr" "size" Allocate memory with error cheking. -.Pp -The following macros can only be used in debug mode: -.It Fn CSTRING_DBG_LOG "fmt" "..." -Prints a message in the format of "DEBUG: file:line:func(): msg". - -.It Fn CSTRING_DBG_LOG_CSTR_INFO "cs" -Print all the contents of a -.Ar cstring -struct. The argument has to be a pointer. - -.It Fn CSTRING_DBG_LOG_CSTR_INFO_NPTR "cs" -Like -.Fn CSTRING_DBG_LOG_CSTR_INFO -but the argument has to be a non-pointer. -.It Fn CSTRING_DBG_LOG_STR_INFO "s" "len" -Print contents of a normal string. - .Sh CONSTANTS .Bl -tag -width Ds .It CSTRING_NPOS @@ -252,25 +241,5 @@ Used with .Fn cstring_create in case the string is to be initliazed as empty. -.Sh USAGE -You must -.Ar always -call the -.Fn cstring_create -and -.Fn cstring_delete -functions whenever you want to make a new instance of -.Ar cstring -and stop using it respectively, in order to not cause any memory -leaks. -.Pp -The recommended way of initializing an empty string is by doing -.Ar cstring foo = cstring_create(CSTRING_INIT_EMPTY) -.Pp -If a function requires a -.Ar char * -you can access the -.Ar .str -field and pass it to the function. .Sh AUTHORS .An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/cstring.c b/cstring.c @@ -2,28 +2,16 @@ #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); \ -} 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); \ -} while (0) -#else /* !CSTRING_DBG */ -#define CSTRING_FREE(cs) do { \ - if (!cstring_empty(cs)) \ - free(cs->str); \ +#define FIND_OCC(cs, s, f) do { \ + char *_found; \ + if ((_found = f(cs->str, (s))) != NULL) \ + return (_found - cs->str); \ } while (0) -#endif /* CSTRING_DBG */ /* statics */ static int cstring_is_one_of(char, const char *); +static void *emalloc(size_t); +static void csfree(cstring *); static inline int cstring_cmp_greater(const void *, const void *); static inline int cstring_cmp_less(const void *, const void *); static inline int cstring_cmp_char_greater(const void *, const void *); @@ -38,6 +26,25 @@ cstring_is_one_of(char c, const char *s) return 0; } +static void * +emalloc(size_t nb) +{ + void *p; + + if ((p= malloc(nb)) == NULL) { + perror("malloc"); + exit(1); + } + return p; +} + +static void +csfree(cstring *cs) +{ + if (!cstring_empty(cs)) + free(cs->str); +} + static inline int cstring_cmp_greater(const void *lhs, const void *rhs) { @@ -70,17 +77,13 @@ cstring_create(const char *s) 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); -#endif /* CSTRING_DBG */ return cs; } void cstring_delete(cstring *cs) { - CSTRING_FREE(cs); + csfree(cs); cs->str = NULL; cs->len = 0; cs->capacity = 0; @@ -89,15 +92,11 @@ cstring_delete(cstring *cs) void cstring_assign(cstring *cs, const char *s) { - CSTRING_FREE(cs); + csfree(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); -#endif /* CSTRING_DBG */ } void @@ -109,39 +108,19 @@ cstring_insert(cstring *cs, const char *s, size_t i) if (!CSTRING_OUT_OF_BOUNDS(cs->len, i) && s != NULL) { slen = strlen(s); newlen = cs->len + slen; - CSTRING_MALLOC(tmp, newlen + 1); + tmp = emalloc(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); + csfree(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); -#endif /* CSTRING_DBG */ } } -#ifdef CSTRING_DBG -// FIXME -#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"); \ -} while (0) - -#define CSTRING_DBG_EXPECTED_ERASE_LEN(cs, 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) { @@ -151,23 +130,14 @@ cstring_erase(cstring *cs, size_t pos, size_t len) if (!cstring_empty(cs) && (!CSTRING_OUT_OF_BOUNDS(cs->len, pos) || !CSTRING_OUT_OF_BOUNDS(cs->len, 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); -#endif /* CSTRING_DBG */ newlen = cs->len - len; - CSTRING_MALLOC(tmp, newlen + 1); + tmp = emalloc(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 */ + csfree(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); -#endif /* CSTRING_DBG */ } } @@ -201,11 +171,6 @@ cstring_trim(cstring *cs, const char *s) cstring_erase(cs, i, 1); } -#ifdef CSTRING_DBG -#undef CSTRING_DBG_EXPECTED_ERASE_STR -#undef CSTRING_DBG_EXPECTED_ERASE_LEN -#endif /* CSTRING_DBG */ - void cstring_push_back(cstring *cs, char c) { @@ -213,9 +178,6 @@ cstring_push_back(cstring *cs, char c) 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); -#endif /* CSTRING_DBG */ } void @@ -296,8 +258,8 @@ cstring_sort_chars_partial(cstring *cs, size_t pos, size_t len, int flags, void cstring_clear(cstring *cs) { - CSTRING_FREE(cs); - CSTRING_MALLOC(cs->str, 1); + csfree(cs); + cs->str = emalloc(1); cs->str[0] = '\0'; cs->len = 0; cs->capacity = 0; @@ -311,7 +273,7 @@ size_t cstring_find(const cstring *cs, const char *s) { CSTRING_CHECK(cs, s); - CSTRING_FIND_OCCURENCE(cs, s, strstr); + FIND_OCC(cs, s, strstr); return CSTRING_NPOS; } @@ -344,7 +306,7 @@ cstring_find_first_of(const cstring *cs, const char *s) { CSTRING_CHECK(cs, s); for (; *s; s++) { - CSTRING_FIND_OCCURENCE(cs, *s, strchr); + FIND_OCC(cs, *s, strchr); } return CSTRING_NPOS; } @@ -369,7 +331,7 @@ cstring_find_last_of(const cstring *cs, const char *s) CSTRING_CHECK(cs, s); i = *(s + strlen(s)); for (; i >= 0; i--) { - CSTRING_FIND_OCCURENCE(cs, s[i], strrchr); + FIND_OCC(cs, s[i], strrchr); } return CSTRING_NPOS; } @@ -391,7 +353,7 @@ cstring_find_last_not_of(const cstring *cs, const char *s) int cstring_ends_with_str(const cstring *cs, const char *s) { - /* avoid cstring_substr */ + /* TODO: avoid cstring_substr */ cstring sub; size_t slen; int found; @@ -410,9 +372,9 @@ cstring_copy(const char *s) char *tmp; len = strlen(s); - CSTRING_MALLOC(tmp, len + 1); + tmp = emalloc(len + 1); memcpy(tmp, s, len + 1); - tmp[len] = '\0'; /* Add \0 in case s didn't have it */ + tmp[len] = '\0'; /* Add \0 in case `s` didn't have it */ return tmp; } @@ -421,19 +383,12 @@ 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); -#endif /* CSTRING_DBG */ - CSTRING_MALLOC(tmp, newcapacity + 1); /* no +1? */ - memcpy(tmp, cs->str, cs->len + 1); /* copy \0 too */ - CSTRING_FREE(cs); + tmp = emalloc(newcapacity + 1); + memcpy(tmp, cs->str, cs->len + 1); + csfree(cs); cs->str = tmp; cs->str[cs->len] = '\0'; cs->capacity = newcapacity; -#ifdef CSTRING_DBG - CSTRING_DBG_LOG_CSTR_INFO(cs); -#endif /* CSTRING_DBG */ } cstring * diff --git a/cstring.h b/cstring.h @@ -1,6 +1,6 @@ /* See LICENSE file for copyright and license details. */ -#ifndef CSTRING_H -#define CSTRING_H +#ifndef _CSTRING_H_ +#define _CSTRING_H_ #include <stdio.h> #include <stdlib.h> @@ -13,30 +13,7 @@ extern "C" { #define CSTRING_NPOS -1 #define CSTRING_INIT_EMPTY "" #define CSTRING_OUT_OF_BOUNDS(len, pos) ((pos) > (len)) -#define CSTRING_ARR_LEN(arr) ((size_t)sizeof((arr)) / sizeof((arr)[0])) - -#define CSTRING_MALLOC(ptr, size) do { \ - ptr = 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_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_STR_INFO(s, len) \ - CSTRING_DBG_LOG("S: %s | LEN: %ld\n", (s), (len)) -#endif /* CSTRING_DBG */ +#define CSTRING_ARR_LEN(x) (sizeof((x)) / sizeof((x)[0])) typedef struct _cstring { size_t len; /* strlen of str */ @@ -51,54 +28,52 @@ typedef struct _cstring { typedef int (*cstring_sort_callback)(const void *, const void *); -extern cstring cstring_create(const char *); -extern void cstring_delete(cstring *); -extern void cstring_assign(cstring *, const char *); -extern void cstring_insert(cstring *, const char *, size_t); -extern void cstring_erase(cstring *, size_t, size_t); -extern void cstring_erase_matching(cstring *, const char *); -extern void cstring_erase_all_matching(cstring *, const char *); -extern void cstring_trim(cstring *, const char *); -extern void cstring_push_back(cstring *, char); -extern void cstring_pop_back(cstring *); -extern void cstring_replace_char(cstring *, size_t, char); -extern void cstring_replace_str(cstring *, const char *, size_t, size_t); -extern cstring cstring_substr(const cstring *, size_t, size_t); -extern void cstring_swap(cstring *, cstring *); -extern void cstring_sort_partial(cstring *, size_t, size_t, int, - cstring_sort_callback); -extern void cstring_sort_chars_partial(cstring *cs, size_t, size_t, int, - cstring_sort_callback); -extern void cstring_clear(cstring *); -extern size_t cstring_find(const cstring *, const char *); -extern size_t cstring_rfind(const cstring *, const char *); -extern size_t cstring_find_first_of(const cstring *, const char *); -extern size_t cstring_find_first_not_of(const cstring *,const char *); -extern size_t cstring_find_last_of(const cstring *, const char *); -extern size_t cstring_find_last_not_of(const cstring *, const char *); -extern int cstring_ends_with_str(const cstring *, const char *); -extern char *cstring_copy(const char *); -extern void cstring_resize(cstring *, size_t); -extern cstring *cstring_getline(FILE *, cstring *, char); +extern cstring cstring_create(const char *); +extern void cstring_delete(cstring *); +extern void cstring_assign(cstring *, const char *); +extern void cstring_insert(cstring *, const char *, size_t); +extern void cstring_erase(cstring *, size_t, size_t); +extern void cstring_erase_matching(cstring *, const char *); +extern void cstring_erase_all_matching(cstring *, const char *); +extern void cstring_trim(cstring *, const char *); +extern void cstring_push_back(cstring *, char); +extern void cstring_pop_back(cstring *); +extern void cstring_replace_char(cstring *, size_t, char); +extern void cstring_replace_str(cstring *, const char *, size_t, size_t); +extern cstring cstring_substr(const cstring *, size_t, size_t); +extern void cstring_swap(cstring *, cstring *); +extern void cstring_sort_partial(cstring *, size_t, size_t, int, cstring_sort_callback); +extern void cstring_sort_chars_partial(cstring *cs, size_t, size_t, int, cstring_sort_callback); +extern void cstring_clear(cstring *); +extern size_t cstring_find(const cstring *, const char *); +extern size_t cstring_rfind(const cstring *, const char *); +extern size_t cstring_find_first_of(const cstring *, const char *); +extern size_t cstring_find_first_not_of(const cstring *,const char *); +extern size_t cstring_find_last_of(const cstring *, const char *); +extern size_t cstring_find_last_not_of(const cstring *, const char *); +extern int cstring_ends_with_str(const cstring *, const char *); +extern char *cstring_copy(const char *); +extern void cstring_resize(cstring *, size_t); +extern cstring *cstring_getline(FILE *, cstring *, char); /* static inlines */ -static inline void cstring_prepend(cstring *, const char *); -static inline void cstring_append(cstring *, const char *); -static inline void cstring_sort(cstring *, size_t, int, cstring_sort_callback); -static inline void cstring_sort_chars(cstring *, int, cstring_sort_callback); -static inline void cstring_shrink_to_fit(cstring *); -static inline int cstring_empty(const cstring *); -static inline char cstring_front(const cstring *); -static inline char cstring_back(const cstring *); -static inline int cstring_starts_with_str(const cstring *, const char *); -static inline int cstring_starts_with_char(const cstring *, char); -static inline int cstring_ends_with_char(const cstring *, char); -static inline void *cstring_data(const cstring *); -static inline int cstring_equal(const cstring *, const cstring *); -static inline int cstring_greater(const cstring *, const cstring *); -static inline int cstring_greater_or_equal(const cstring *, const cstring *); -static inline int cstring_less(const cstring *, const cstring *); -static inline int cstring_less_or_equal(const cstring *, const cstring *); +static inline void cstring_prepend(cstring *, const char *); +static inline void cstring_append(cstring *, const char *); +static inline void cstring_sort(cstring *, size_t, int, cstring_sort_callback); +static inline void cstring_sort_chars(cstring *, int, cstring_sort_callback); +static inline void cstring_shrink_to_fit(cstring *); +static inline int cstring_empty(const cstring *); +static inline char cstring_front(const cstring *); +static inline char cstring_back(const cstring *); +static inline int cstring_starts_with_str(const cstring *, const char *); +static inline int cstring_starts_with_char(const cstring *, char); +static inline int cstring_ends_with_char(const cstring *, char); +static inline void *cstring_data(const cstring *); +static inline int cstring_equal(const cstring *, const cstring *); +static inline int cstring_greater(const cstring *, const cstring *); +static inline int cstring_greater_or_equal(const cstring *, const cstring *); +static inline int cstring_less(const cstring *, const cstring *); +static inline int cstring_less_or_equal(const cstring *, const cstring *); static inline void cstring_prepend(cstring *cs, const char *s) @@ -205,4 +180,4 @@ cstring_less_or_equal(const cstring *lhs, const cstring *rhs) } #endif /* __cplusplus */ -#endif /* CSTRING_H */ +#endif /* _CSTRING_H_ */ diff --git a/tests/Makefile b/tests/Makefile @@ -3,9 +3,9 @@ .POSIX: BINS = test_basic test_insert -CC = gcc +CC = cc CFLAGS = -Wall -std=c99 -pedantic -O3 -LDFLAGS = -Llib -lcstring +LDFLAGS = -Llib -L/usr/local/lib -I/usr/local/include -lcstring all: options ${BINS}