feat: (str) str_append_*

This commit is contained in:
thetek 2023-02-14 13:03:11 +01:00
parent 60845b521c
commit df4d6036fc
3 changed files with 93 additions and 8 deletions

View File

@ -10,10 +10,12 @@ typedef struct
size_t cap; size_t cap;
} str_t; } str_t;
void str_new (str_t *str); int str_new (str_t *str);
void str_new_cap (str_t *str, size_t want_cap); int str_new_cap (str_t *str, size_t want_cap);
int str_new_from (str_t *str, const char *src); int str_new_from (str_t *str, const char *src);
int str_new_from_len (str_t *str, const char *src, size_t len); int str_new_from_len (str_t *str, const char *src, size_t len);
void str_free (str_t *str); void str_free (str_t *str);
int str_append (str_t *str, const char *src);
int str_append_len (str_t *str, const char *src, size_t len);
#endif // CUTILS_STR_H_ #endif // CUTILS_STR_H_

View File

@ -1,34 +1,43 @@
#include "str.h" #include "str.h"
#include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "common.h" #include "common.h"
#define STR_MIN_ALLOC 64 #define STR_MIN_ALLOC 64
void int
str_new (str_t *str) str_new (str_t *str)
{ {
if (!str)
return errno = EINVAL, -1;
str->str = smalloc (STR_MIN_ALLOC * sizeof (char)); str->str = smalloc (STR_MIN_ALLOC * sizeof (char));
str->str[0] = '\0';
str->len = 0; str->len = 0;
str->cap = STR_MIN_ALLOC; str->cap = STR_MIN_ALLOC;
return 0;
} }
void int
str_new_cap (str_t *str, size_t want_cap) str_new_cap (str_t *str, size_t want_cap)
{ {
size_t cap; size_t cap;
if (!str)
return errno = EINVAL, -1;
cap = max (next_pow_of_two (want_cap), STR_MIN_ALLOC); cap = max (next_pow_of_two (want_cap), STR_MIN_ALLOC);
str->str = smalloc (cap); str->str = smalloc (cap);
str->str[0] = '\0';
str->len = 0; str->len = 0;
str->cap = cap; str->cap = cap;
return 0;
} }
inline int inline int
str_new_from (str_t *str, const char *src) str_new_from (str_t *str, const char *src)
{ {
if (src) if (str && src)
return str_new_from_len (str, src, strlen (src)), 0; return str_new_from_len (str, src, strlen (src));
else else
return errno = EINVAL, -1; return errno = EINVAL, -1;
} }
@ -38,13 +47,14 @@ str_new_from_len (str_t *str, const char *src, size_t len)
{ {
size_t cap; size_t cap;
if (!src) if (!str || !src)
return errno = EINVAL, -1; return errno = EINVAL, -1;
cap = max (next_pow_of_two (len + 1), STR_MIN_ALLOC); cap = max (next_pow_of_two (len + 1), STR_MIN_ALLOC);
str->str = smalloc (cap * sizeof (char)); str->str = smalloc (cap * sizeof (char));
str->len = len; str->len = len;
str->cap = cap; str->cap = cap;
strcpy (str->str, src); strncpy (str->str, src, len);
str->str[len] = '\0';
return 0; return 0;
} }
@ -54,3 +64,28 @@ str_free (str_t *str)
if (str) if (str)
free (str->str); free (str->str);
} }
inline int
str_append (str_t *str, const char *src)
{
if (str && src)
return str_append_len (str, src, strlen (src));
else
return errno = EINVAL, -1;
}
int
str_append_len (str_t *str, const char *src, size_t len)
{
size_t cap;
if (!str || !src)
return errno = EINVAL, -1;
cap = max (next_pow_of_two (str->len + len + 1), STR_MIN_ALLOC);
str->str = srealloc (str->str, cap * sizeof (char));
strncpy (str->str + str->len, src, len);
str->len += len;
str->cap = cap;
str->str[str->len] = '\0';
return 0;
}

View File

@ -7,6 +7,8 @@
#define CUTILS_DEBUG_TRACE #define CUTILS_DEBUG_TRACE
#include "debug.h" #include "debug.h"
#include "log.h" #include "log.h"
#include "common.h"
#include "str.h"
#include "test.h" #include "test.h"
test_results_t test_results_t
@ -50,6 +52,51 @@ test_cstr (void)
return test_group_get_results (&group); return test_group_get_results (&group);
} }
test_results_t
test_str (void)
{
test_group_t group;
str_t str;
int res;
char *s;
group = test_group_new ();
res = str_new (&str);
test_add (&group, test_assert (str.str != NULL && str.cap > 0), "str_new");
str_free (&str);
res = str_new_cap (&str, 1000);
test_add (&group, test_assert (str.cap == next_pow_of_two (1000)), "str_new_cap");
str_free (&str);
s = "Hello, World!\n";
res = str_new_from (&str, s);
test_add (&group, test_assert (!strcmp (str.str, s)), "str_new_from .str");
test_add (&group, test_assert (str.len == strlen (s)), "str_new_from .len");
test_add (&group, test_assert (str.cap >= str.len), "str_new_from .cap");
test_add (&group, test_assert (res >= 0), "str_new_from success return value");
str_free (&str);
res = str_new_from (&str, NULL);
test_add (&group, test_assert (res < 0), "str_new_from failure return value");
if (res >= 0)
str_free (&str);
s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
str_new_from (&str, s);
res = str_append (&str, s);
test_add (&group, test_assert (!strncmp (str.str, s, strlen (s)) && !strncmp (str.str + strlen (s), s, strlen (s))), "str_append .str");
test_add (&group, test_assert (str.len = 2 * strlen (s)), "str_append .len");
test_add (&group, test_assert (str.cap = next_pow_of_two (2 * strlen (s))), "str_append .cap");
test_add (&group, test_assert (res >= 0), "str_append success return value");
res = str_append (&str, NULL);
test_add (&group, test_assert (res < 0), "str_append failure return value");
str_free (&str);
return test_group_get_results (&group);
}
int int
main (void) main (void)
{ {
@ -57,6 +104,7 @@ main (void)
suite = test_suite_new (); suite = test_suite_new ();
test_suite_add (&suite, test_cstr); test_suite_add (&suite, test_cstr);
test_suite_add (&suite, test_str);
test_suite_run (&suite); test_suite_run (&suite);
test_suite_free (&suite); test_suite_free (&suite);