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:
M | cstring.3 | | | 54 | +++++++++++++++++++++--------------------------------- |
M | cstring.c | | | 114 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
M | cstring.h | | | 20 | ++++++++------------ |
M | tests/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");