cstring

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

commit 2d0b7a1fec7fdcd2161b64300260cf0b7c7c457d
parent 82ce1614a60b43996cc101568cd6196b6a26ba23
Author: Christos Margiolis <christos@margiolis.net>
Date:   Sun, 27 Sep 2020 21:16:15 +0300

added first_not_of, last_not_of functions, pending rfind implementation

Diffstat:
Mcstring.3 | 54+++++++++++++++++++++---------------------------------
Mcstring.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mcstring.h | 20++++++++------------
Mtests/test.c | 8+++++++-
4 files changed, 118 insertions(+), 78 deletions(-)

diff --git a/cstring.3 b/cstring.3 @@ -13,7 +13,7 @@ object. Deallocate string. .TP .BR void\ cstring_assign(cstring\ *cs,\ const\ char\ *s) -Assign a new string to the current string. +Assign a new string to current string. .TP .BR void\ cstring_append(cstring\ *cs,\ const\ char\ *s) Append to end of string. @@ -28,13 +28,13 @@ Insert at a specific index. Erase a portion of the string. .TP .BR void\ cstring_erase_matching(cstring\ *cs,\ const\ char\ *s) -Erase first match from the string. +Erase first match from string. .TP .BR void\ cstring_erase_all_matching(cstring\ *cs,\ const\ char\ *s) -Erase all matches from the string. +Erase all matches from string. .TP -.BR void\ cstring_trim(cstring\ *cs,\ char\ c) -Trim character from string. +.BR void\ cstring_trim(cstring\ *cs,\ const\ char\ *s) +Trim characters from string. .TP .BR void\ cstring_push_back(cstring\ *cs,\ char\ c) Add a character at the end of the string. @@ -63,11 +63,17 @@ Erase the whole string. .BR size_t\ cstring_find(const\ cstring\ *cs,\ const\ char\ *s) Find first occurence of a pattern in string. .TP -.BR size_t\ cstring_find_first_of(const\ cstring\ *cs,\ char\ c) -Find first occurence of a character in string. +.BR size_t\ cstring_find_first_of(const\ cstring\ *cs,\ const\ char\ *s) +Find first occurence of specified characters in string. .TP -.BR size_t\ cstring_find_last_of(const\ cstring\ *cs,\ char\ c) -Find last occurence of a character in string. +.BR size_t\ cstring_find_first_not_of(const\ cstring\ *cs,\ const\ char\ *s) +Find the first character that does not match any of the specified characters. +.TP +.BR size_t\ cstring_find_last_of(const\ cstring\ *cs,\ const\ char\ *s) +Find last occurence of specified characters in string. +.TP +.BR size_t\ cstring_find_last_not_of(const\ cstring\ *cs,\ const\ char\ *s) +Find the last character that does not match any of the specified characters. .TP .BR char\ cstring_front(const\ cstring\ *cs) Returns the first character of the string. @@ -111,35 +117,11 @@ Read a line from a 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 @@ -159,5 +141,11 @@ leaks. .P The recommended way of initializing an empty string is by doing .I cstring foo = cstring_create("") +.P +If a function requires a +.I char * +you can access the +.I .str +field and pass it to the function. .SH AUTHORS Christos Margiolis <christos@christosmarg.xyz> diff --git a/cstring.c b/cstring.c @@ -1,12 +1,30 @@ #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) + +static int +cstring_is_one_of(char c, const char *s) +{ + for (; *s; s++) + if (*s == c) + return 1; + return 0; +} + cstring cstring_create(const char *s) { cstring cs; - cs.str = cstring_copy(s); cs.len = strlen(s); - cstring_resize(&cs, cs.len << 1); + cs.capacity = cs.len << 1; + cs.str = (char *)malloc(cs.capacity + 1); + memcpy(cs.str, s, cs.len + 1); + cs.str[cs.len] = '\0'; return cs; } @@ -23,11 +41,11 @@ void cstring_assign(cstring *cs, const char *s) { size_t newlen = strlen(s); + if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) + cstring_resize(cs, newlen << 1); if (!cstring_empty(cs)) free(cs->str); cs->str = cstring_copy(s); cs->len = newlen; - if (CSTRING_EXCEEDS_CAPACITY(newlen, cs->capacity)) - cstring_resize(cs, newlen << 1); } void @@ -40,7 +58,7 @@ cstring_append(cstring *cs, const char *s) strcat(cs->str, s); cs->len = newlen; } - else cstring_assign(cs, s); // TEST + else cstring_assign(cs, s); } void @@ -53,24 +71,21 @@ void cstring_insert(cstring *cs, const char *s, size_t i) { if (!CSTRING_OUT_OF_BOUNDS(cs, i) - && !cstring_empty(cs) + && !cstring_empty(cs) // useless check? && s != NULL) { 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); + char *tmp = (char *)malloc(newlen + 1); + memcpy(tmp, cs->str, i); + memcpy(tmp + i, s, slen); + memcpy(tmp + i + slen, cs->str + i, cs->len); 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); + free(cs->str); cs->len = newlen; + cs->str = tmp; cs->str[cs->len] = '\0'; - free(tmp1); - free(tmp2); } } @@ -83,7 +98,7 @@ cstring_erase(cstring *cs, size_t pos, size_t len) { size_t newlen = cs->len - len; char *tmp = (char *)malloc(newlen + 1); - memcpy(tmp, cs->str, pos + 1); + memcpy(tmp, cs->str, pos); // pos + 1?? memcpy(tmp + pos, cs->str + pos + len, newlen); free(cs->str); cs->len = newlen; @@ -111,10 +126,10 @@ cstring_erase_all_matching(cstring *cs, const char *s) } void -cstring_trim(cstring *cs, char c) +cstring_trim(cstring *cs, const char *s) { - size_t i = cstring_find_first_of(cs, c); - for (; i != CSTRING_NPOS; i = cstring_find_first_of(cs, c)) + 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); } @@ -134,7 +149,7 @@ cstring_pop_back(cstring *cs) char *tmp = (char *)malloc(cs->len); memcpy(tmp, cs->str, cs->len); free(cs->str); - tmp[cs->len--] = '\0'; + tmp[--cs->len] = '\0'; cs->str = tmp; } } @@ -183,7 +198,7 @@ cstring_swap(cstring *lhs, cstring *rhs) void cstring_shrink_to_fit(cstring *cs) { - cs->capacity = cs->len; + cstring_resize(cs, cs->len); } void @@ -206,20 +221,58 @@ cstring_find(const cstring *cs, const char *s) } size_t -cstring_find_first_of(const cstring *cs, char c) +cstring_rfind(const cstring *cs, const char *s) +{ + if (cstring_empty(cs) || !*s) + return CSTRING_NPOS; + /* IMPLEMENT */ + return CSTRING_NPOS; +} + +size_t +cstring_find_first_of(const cstring *cs, const char *s) +{ + if (cstring_empty(cs) || !*s) + return CSTRING_NPOS; + 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) { - if (cstring_empty(cs) || c == '\0') + if (cstring_empty(cs) || !*s) return CSTRING_NPOS; - CSTRING_FIND_OCCURENCE(cs, c, strchr); + 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 -cstring_find_last_of(const cstring *cs, char c) +cstring_find_last_of(const cstring *cs, const char *s) { - if (cstring_empty(cs) || c == '\0') + if (cstring_empty(cs) || !*s) return CSTRING_NPOS; - CSTRING_FIND_OCCURENCE(cs, c, strrchr); + size_t 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) +{ + if (cstring_empty(cs) || !*s) + return CSTRING_NPOS; + size_t i = cs->len; + for (; i >= 0; i--) + if (!cstring_is_one_of(cs->str[i], s)) + return i; return CSTRING_NPOS; } @@ -279,12 +332,9 @@ void cstring_resize(cstring *cs, size_t newcapacity) { if (!cstring_empty(cs)) { - char *tmp = (char *)malloc(newcapacity + 1); - memcpy(tmp, cs->str, cs->len + 1); - free(cs->str); - tmp[cs->len] = '\0'; - cs->str = tmp; cs->capacity = newcapacity; + cs->str = (char *)realloc(cs->str, cs->capacity + 1); + cs->str[cs->len] = '\0'; } } diff --git a/cstring.h b/cstring.h @@ -6,14 +6,7 @@ #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) // MAYBE NEEDS +1 +#define CSTRING_OUT_OF_BOUNDS(cs, pos) ((pos) > cs->len) typedef struct cstring { char *str; @@ -26,11 +19,11 @@ extern void cstring_delete(cstring *); extern void cstring_assign(cstring *, const char *); extern void cstring_append(cstring *, const char *); extern void cstring_prepend(cstring *, const char *); -extern void cstring_insert(cstring *, const char *, size_t); // FIX +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 *, 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); @@ -40,8 +33,11 @@ extern void cstring_swap(cstring *, cstring *); extern void cstring_shrink_to_fit(cstring *); extern void cstring_clear(cstring *); 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 size_t cstring_rfind(const cstring *, const char *); /* implement */ +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 char cstring_front(const cstring *); extern char cstring_back(const cstring *); extern int cstring_empty(const cstring *); diff --git a/tests/test.c b/tests/test.c @@ -44,9 +44,15 @@ main(int argc, char **argv) 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, ' '); + 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_prepend(&s, "OK"); + printf("cstring_prepend: %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");