cstring

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

commit 7d2d6077216e8b55332366757c81d18bbf38f9f7
parent 76e965dfaa56d81fff432641517a0b1e69b53463
Author: Christos Margiolis <christos@margiolis.net>
Date:   Tue, 22 Sep 2020 20:07:02 +0300

removed cstring_exists, added some utility macros, implemented a few find functions

Diffstat:
Mcstring.3 | 48++++++++++++++++++++++++++++++++++++++++++++++--
Mcstring.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mcstring.h | 16+++++++++++++++-
Mtest.c | 3---
4 files changed, 113 insertions(+), 18 deletions(-)

diff --git a/cstring.3 b/cstring.3 @@ -30,11 +30,20 @@ Remove the last character in the string. .BR void\ cstring_replace_char(cstring\ *,\ const\ char\ *) Replace character at a specific index. .TP +.BR cstring\ cstring_substr(cstring\ *,\ size_t\ ,\ size_t) +Extract a substring from current string. +.TP .BR void\ cstring_clear(cstring\ *) Erase the whole string. .TP -.BR int\ cstring_exists(const\ cstring\ *,\ const\ char\ *) -Check to see if a (sub)string exists in the string. +.BR size_t\ cstring_find(const\ cstring\ *,\ const\ char\ *) +Find first occurence of a pattern in string. +.TP +.BR size_t\ cstring_find_first_of(const\ cstring\ *,\ char) +Find first occurence of a character in string. +.TP +.BR size_t\ cstring_find_last_of(const\ cstring\ *,\ char) +Find last occurence of a character in string. .TP .BR char\ cstring_front(const\ cstring\ *) Returns the first character of the string. @@ -61,6 +70,41 @@ Read a line from a .I FILE stream. Similar behavior to .I stdio's\ getline +.SH MACROS +The following macros should be used carefully +.TP +.BR CSTRING_OUT_OF_BOUNDS(cs,\ pos) +Check if +.I pos +is out of bounds. +.TP +.BR CSTRING_EXCEEDS_CAPACITY(len,\ cap) +Check if +.I len +is more than +.I cap +in order to resize the string. +.TP +.BR CSTRING_FIND_OCCURENCE(cs,\ s,\ func) +Although it should be used internally, this macro +returns the index at which +.I s +occurs in the string according to +.I func +which is used as a callback function, although it is +meant to support +.I strstr +, +.I strchr +and +.I strrchr +from +.I string.h +.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 USAGE You must .B always diff --git a/cstring.c b/cstring.c @@ -26,7 +26,8 @@ cstring_assign(cstring *cs, const char *s) if (!cstring_empty(cs)) free(cs->str); cs->str = cstring_copy(s); cs->len = newlen; - if (newlen >= cs->capacity) cstring_resize(cs, newlen << 1); + if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) + cstring_resize(cs, newlen << 1); } void @@ -34,7 +35,8 @@ cstring_append(cstring *cs, const char *s) { if (!cstring_empty(cs)) { size_t newlen = cs->len + strlen(s); - if (newlen >= cs->capacity) cstring_resize(cs, newlen << 1); + if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) + cstring_resize(cs, newlen << 1); strcat(cs->str, s); cs->len = newlen; } @@ -43,14 +45,15 @@ cstring_append(cstring *cs, const char *s) void cstring_insert(cstring *cs, const char *s, size_t i) { - if (!cstring_empty(cs) && i < cs->len) { + if (!cstring_empty(cs) && !CSTRING_OUT_OF_BOUNDS(cs, i)) { size_t slen = strlen(s); size_t newlen = cs->len + slen; char *tmp1 = (char *)malloc(i + 1); char *tmp2 = (char *)malloc(cs->len - i + 1); memcpy(tmp1, cs->str, i + 1); memcpy(tmp2, cs->str + i, cs->len + 1); - if (newlen >= cs->capacity) cstring_resize(cs, newlen << 1); + if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) + cstring_resize(cs, newlen << 1); memcpy(cs->str, tmp1, i + 1); memcpy(cs->str + i, s, slen + 1); memcpy(cs->str + slen + i, tmp2, cs->len - i + 1); @@ -64,8 +67,9 @@ cstring_insert(cstring *cs, const char *s, size_t i) void cstring_push_back(cstring *cs, char c) { - if (cs->len + 1 >= cs->capacity) cstring_resize(cs, (cs->len + 1) << 1); - cs->str[cs->len] = c; + if (CSTRING_EXCEEDS_CAPACITY(cs->len + 1, cs->capacity)) + cstring_resize(cs, (cs->len + 1) << 1); + cs->str[cs->len] = c; cs->str[++cs->len] = '\0'; } @@ -84,22 +88,58 @@ cstring_pop_back(cstring *cs) void cstring_replace_char(cstring *cs, size_t i, char c) { - if (i < cs->len) cs->str[i] = c; + if (!CSTRING_OUT_OF_BOUNDS(cs, i)) + cs->str[i] = c; +} + +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) + || len < pos) + return cstring_create(""); + cstring substr = cstring_create(&cs->str[pos]); + substr.len = len; + substr.str[len] = '\0'; + // maybe cstring_resize + return substr; } void cstring_clear(cstring *cs) { if (!cstring_empty(cs)) free(cs->str); - cs->str = (char *)malloc(1); + cs->str = (char *)malloc(1); cs->str[0] = '\0'; - cs->len = 0; + cs->len = 0; } -int -cstring_exists(const cstring *cs, const char *s) +size_t +cstring_find(const cstring *cs, const char *s) +{ + if (cstring_empty(cs) || !*s) + return CSTRING_NPOS; + CSTRING_FIND_OCCURENCE(cs, s, strstr); + return CSTRING_NPOS; +} + +size_t +cstring_find_first_of(const cstring *cs, char c) +{ + if (cstring_empty(cs) || c == '\0') + return CSTRING_NPOS; + CSTRING_FIND_OCCURENCE(cs, c, strchr); + return CSTRING_NPOS; +} + +size_t +cstring_find_last_of(const cstring *cs, char c) { - return (strstr(cs->str, s) != NULL); + if (cstring_empty(cs) || c == '\0') + return CSTRING_NPOS; + CSTRING_FIND_OCCURENCE(cs, c, strrchr); + return CSTRING_NPOS; } char diff --git a/cstring.h b/cstring.h @@ -5,6 +5,16 @@ #include <stdlib.h> #include <string.h> +#define CSTRING_NPOS -1 + +#define CSTRING_OUT_OF_BOUNDS(cs, pos) ((pos) > cs->len) +#define CSTRING_EXCEEDS_CAPACITY(len, cap) ((len) >= (cap)) + +#define CSTRING_FIND_OCCURENCE(cs, s, func) \ + char *_found; \ + if ((_found = func(cs->str, (s))) != NULL) \ + return (_found - cs->str + 1) + typedef struct cstring { char *str; size_t len; @@ -19,14 +29,18 @@ extern void cstring_insert(cstring *, const char *, size_t); extern void cstring_push_back(cstring *, char); extern void cstring_pop_back(cstring *); extern void cstring_replace_char(cstring *, size_t, char); +extern cstring cstring_substr(const cstring *, size_t, size_t); extern void cstring_clear(cstring *); -extern int cstring_exists(const cstring *, const char *); +extern size_t cstring_find(const cstring *, const char *); +extern size_t cstring_find_first_of(const cstring *, char); +extern size_t cstring_find_last_of(const cstring *, char); extern char cstring_front(const cstring *); extern char cstring_back(const cstring *); extern int cstring_empty(const cstring *); extern char *cstring_copy(const char *); extern void cstring_resize(cstring *, size_t); extern cstring *cstring_getline(FILE *, cstring *, char); +//extern cstring *cstring_tok(const cstring *, const char *); /* might be useless */ extern int cstring_equal(const cstring *, const cstring *); diff --git a/test.c b/test.c @@ -14,9 +14,6 @@ main(int argc, char **argv) cstring_assign(&s, "New string"); printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); - if (cstring_exists(&s, "string")) - printf("cstring_exists: \"string\" exists!\n"); - cstring_push_back(&s, 'c'); printf("cstring_push_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity);