~crm/cstring

3db911364bcc348ddcb9f71077743d065cc0847f — Christos Margiolis 3 years ago fb54a79
removed CSTRING_DBG
5 files changed, 126 insertions(+), 236 deletions(-)

M README
M cstring.3
M cstring.c
M cstring.h
M tests/Makefile
M README => README +0 -9
@@ 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.

M cstring.3 => cstring.3 +34 -65
@@ 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

M cstring.c => cstring.c +42 -87
@@ 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 *

M cstring.h => cstring.h +48 -73
@@ 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_ */

M tests/Makefile => tests/Makefile +2 -2
@@ 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}