cstring

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

commit 22060bd2333f19c4dbd47606a9bedddcf4b2a9ab
parent e86d615950a8a019265783f3fc8091ba104f2ce4
Author: Christos Margiolis <christos@margiolis.net>
Date:   Thu,  1 Oct 2020 22:53:08 +0300

added debug mode and macros, still pending push_back/resize fix

Diffstat:
MMakefile | 4++--
Mcstring.3 | 29+++++++++++++++++++++++++++++
Mcstring.c | 37++++++++++++++++++++++++++++---------
Mcstring.h | 20++++++++++++++++++++
Mtests/test.c | 9+++++----
5 files changed, 84 insertions(+), 15 deletions(-)

diff --git a/Makefile b/Makefile @@ -12,7 +12,7 @@ AR = ar ARFLAGS = rs CC = gcc CPPFLAGS += -Iinclude -pedantic -CFLAGS += -Wall -std=c99 -O3 +CFLAGS += -Wall -std=c99 -O3 -DCSTRING_DBG LDFLAGS += -Llib #LDLIBS += @@ -39,7 +39,7 @@ install: all ${CP} ${MAN3} ${DESTDIR}${MAN_DIR} chmod 644 ${DESTDIR}${MAN_DIR}/${MAN3} -uninstall: all +uninstall: sudo ${RM} ${DESTDIR}${HDR_DIR}/${LIB}.h sudo ${RM} ${DESTDIR}${LIB_DIR}/lib${LIB}.a sudo ${RM} ${DESTDIR}${MAN_DIR}/${MAN3} diff --git a/cstring.3 b/cstring.3 @@ -125,11 +125,40 @@ stream. Similar behavior to Check if .I pos is out of bounds. +.TP +.BR CSTRING_MALLOC(ptr,\ size) +Allocate memory with error cheking. +.P +The following macros can only be used in debug mode: +.TP +.BR CSTRING_DBG_LOG(fmt,\ ...) +Prints a message in the format of "DEBUG: file:line:func(): msg". +.TP +.BR CSTRING_DBG_LOG_STR_INFO(cs) +Uses +.I CSTRING_DBG_LOG +to print all the contents of a +.I cstring +struct. The argument has to be a pointer. +.TP +.BR CSTRING_DBG_LOG_STR_INFO_NPTR(cs) +Uses +.I CSTRING_DBG_LOG +to print all the contents of a +.I cstring +struct. The argument has to be a non-pointer. .SH CONSTANTS .TP .BR CSTRING_NPOS This constant signifies that a pattern hasn't been found inside the string. It's value is -1. +.SH OPTIONS +.TP +.BR CSTRING_DEBUG +Runs in debug mode if it is defined. In order to define it compile +the library with the +.I -DCSTRING_DEBUG +option. .SH USAGE You must .B always diff --git a/cstring.c b/cstring.c @@ -23,6 +23,9 @@ 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_NPTR(cs); +#endif /* CSTRING_DBG */ return cs; } @@ -44,6 +47,9 @@ cstring_assign(cstring *cs, const char *s) if (!cstring_empty(cs)) free(cs->str); cs->str = cstring_copy(s); cs->len = newlen; +#ifdef CSTRING_DBG + CSTRING_DBG_LOG_STR_INFO(cs); +#endif /* CSTRING_DBG */ } void @@ -52,16 +58,20 @@ 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; - char *tmp = (char *)malloc(newlen + 1); - memcpy(tmp, cs->str, i); - memcpy(tmp + i, s, slen); - memcpy(tmp + slen + i, cs->str + i , newlen - slen - i); + char *tmp; + CSTRING_MALLOC(tmp, newlen + 1); if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) cstring_resize(cs, newlen << 1); + memcpy(tmp, cs->str, i); + memcpy(tmp + i, s, slen); + memcpy(tmp + slen + i, cs->str + i, newlen - slen - i); free(cs->str); cs->len = newlen; cs->str = tmp; cs->str[cs->len] = '\0'; +#ifdef CSTRING_DBG + CSTRING_DBG_LOG_STR_INFO(cs); +#endif /* CSTRING_DBG */ } } @@ -73,7 +83,8 @@ cstring_erase(cstring *cs, size_t pos, size_t len) && !CSTRING_OUT_OF_BOUNDS(cs, len)) { size_t newlen = cs->len - len; - char *tmp = (char *)malloc(newlen + 1); + char *tmp; + CSTRING_MALLOC(tmp, newlen + 1); memcpy(tmp, cs->str, pos); // pos + 1?? memcpy(tmp + pos, cs->str + pos + len, newlen); free(cs->str); @@ -116,13 +127,17 @@ 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_STR_INFO(cs); +#endif /* CSTRING_DBG */ } void cstring_pop_back(cstring *cs) { if (cs->len > 0) { - char *tmp = (char *)malloc(cs->len); + char *tmp; + CSTRING_MALLOC(tmp, cs->len); memcpy(tmp, cs->str, cs->len); free(cs->str); tmp[--cs->len] = '\0'; @@ -175,7 +190,7 @@ void cstring_clear(cstring *cs) { if (!cstring_empty(cs)) free(cs->str); - cs->str = (char *)malloc(1); + CSTRING_MALLOC(cs->str, 1); cs->str[0] = '\0'; cs->len = 0; cs->capacity = 0; @@ -264,7 +279,8 @@ char * cstring_copy(const char *s) { size_t len = strlen(s); - char *tmp = (char *)malloc(len + 1); + char *tmp; + CSTRING_MALLOC(tmp, len + 1); memcpy(tmp, s, len + 1); tmp[len] = '\0'; return tmp; @@ -273,8 +289,11 @@ cstring_copy(const char *s) void cstring_resize(cstring *cs, size_t newcapacity) { - cs->str = (char *)realloc(cs->str, newcapacity); + cs->str = (char *)realloc(cs->str, newcapacity + 1); cs->capacity = newcapacity; +#ifdef CSTRING_DBG + CSTRING_DBG_LOG_STR_INFO(cs); +#endif /* CSTRING_DBG */ } cstring * diff --git a/cstring.h b/cstring.h @@ -12,6 +12,26 @@ extern "C" { #define CSTRING_NPOS -1 #define CSTRING_OUT_OF_BOUNDS(cs, pos) ((pos) > cs->len) +#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_STR_INFO(cs) \ + CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ + cs->str, cs->len, cs->capacity) + +#define CSTRING_DBG_LOG_STR_INFO_NPTR(cs) \ + CSTRING_DBG_LOG("STR: %s | LEN: %ld | CAP: %ld\n", \ + cs.str, cs.len, cs.capacity) +#endif /* CSTRING_DBG */ + typedef struct cstring { char *str; size_t len; diff --git a/tests/test.c b/tests/test.c @@ -17,6 +17,10 @@ main(int argc, char **argv) cstring_prepend(&s, "OK"); printf("cstring_prepend: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); + // BUG + /*for (int i = 0; i < 50; i++)*/ + /*cstring_push_back(&s, 'c');*/ + cstring_push_back(&s, 'c'); printf("cstring_push_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); @@ -50,11 +54,8 @@ main(int argc, char **argv) cstring_trim(&s, " "); printf("cstring_trim: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_insert(&s, "New text", 2); - printf("cstring_insert: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - cstring_delete(&s); - if (cstring_empty(&s)) printf("cstring_delete: Deleted string.\n"); + if (cstring_empty(&s)) puts("cstring_delete: Deleted string."); return 0; }