diff options
author | LAN-TW <lantw44@gmail.com> | 2013-12-14 15:30:44 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-12-14 15:30:44 +0800 |
commit | aada971bb36304c9eb3bdd2a88993a84139402ca (patch) | |
tree | dc4c0949f584e3361f7d997975a7a3249176eb2c | |
parent | 6bb04f938c70f65d96cf596dd1fbf570dfd07c59 (diff) | |
download | l4basic-aada971bb36304c9eb3bdd2a88993a84139402ca.tar.gz l4basic-aada971bb36304c9eb3bdd2a88993a84139402ca.tar.zst l4basic-aada971bb36304c9eb3bdd2a88993a84139402ca.zip |
Add string vector manager (LbsStrv) and add test suite
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | l4strv.c | 285 | ||||
-rw-r--r-- | l4strv.h | 75 | ||||
-rw-r--r-- | test-strv.c | 188 |
4 files changed, 562 insertions, 7 deletions
@@ -27,24 +27,28 @@ INCLUDEDIR= $(DESTDIR)$(PREFIX)/include # Tasks definition lib_LIBRARIES= libl4basic.a -libl4basic_a_OBJECTS= l4array.o l4array2.o l4file.o l4list.o l4arg.o +libl4basic_a_OBJECTS= l4array.o l4array2.o l4file.o l4strv.o l4arg.o \ + l4list.o libl4basic_a_HEADERS= $(libl4basic_a_OBJECTS:.o=.h) l4common.h -check_PROGRAMS= test-array test-array2 test-file test-list test-arg +check_PROGRAMS= test-array test-array2 test-file test-strv test-arg \ + test-list check_OBJECTS= $(check_PROGRAMS:=.o) # Build dependencies l4array_o_DEPENDS= l4common.h l4array2_o_DEPENDS= l4common.h l4file_o_DEPENDS= l4common.h l4array.o -l4list_o_DEPENDS= l4common.h +l4strv_o_DEPENDS= l4common.h l4array.o l4arg_o_DEPENDS= l4common.h l4array.o +l4list_o_DEPENDS= l4common.h test_array_o_DEPENDS= l4array.o test_array2_o_DEPENDS= l4array2.o test_file_o_DEPENDS= l4file.o l4array.o -test_list_o_DEPENDS= l4list.o +test_strv_o_DEPENDS= l4strv.o l4array.o test_arg_o_DEPENDS= l4arg.o l4array.o +test_list_o_DEPENDS= l4list.o .POSIX: .PHONY: all clean install install-HEADERS install-LIB \ @@ -62,8 +66,9 @@ libl4basic.a: $(libl4basic_a_OBJECTS) l4array.o: l4array.c l4array.h $(l4array_o_DEPENDS) l4array2.o: l4array2.c l4array2.h $(l4array2_o_DEPENDS) l4file.o: l4file.c l4file.h $(l4file_o_DEPENDS) -l4list.o: l4list.c l4list.h $(l4list_o_DEPENDS) +l4strv.o: l4strv.c l4strv.h $(l4strv_o_DEPENDS) l4arg.o: l4arg.c l4arg.h $(l4arg_o_DEPENDS) +l4list.o: l4list.c l4list.h $(l4list_o_DEPENDS) test-array: test-array.o $(test_array_o_DEPENDS) $(CC) $(M_CFLAGS) test-array.o $(test_array_o_DEPENDS) -o $@ $(M_LDFLAGS) @@ -71,10 +76,12 @@ test-array2: test-array2.o $(test_array2_o_DEPENDS) $(CC) $(M_CFLAGS) test-array2.o $(test_array2_o_DEPENDS) -o $@ $(M_LDFLAGS) test-file: test-file.o $(test_file_o_DEPENDS) $(CC) $(M_CFLAGS) test-file.o $(test_file_o_DEPENDS) -o $@ $(M_LDFLAGS) -test-list: test-list.o $(test_list_o_DEPENDS) - $(CC) $(M_CFLAGS) test-list.o $(test_list_o_DEPENDS) -o $@ $(M_LDFLAGS) +test-strv: test-strv.o $(test_strv_o_DEPENDS) + $(CC) $(M_CFLAGS) test-strv.o $(test_strv_o_DEPENDS) -o $@ $(M_LDFLAGS) test-arg: test-arg.o $(test_arg_o_DEPENDS) $(CC) $(M_CFLAGS) test-arg.o $(test_arg_o_DEPENDS) -o $@ $(M_LDFLAGS) +test-list: test-list.o $(test_list_o_DEPENDS) + $(CC) $(M_CFLAGS) test-list.o $(test_list_o_DEPENDS) -o $@ $(M_LDFLAGS) clean: -$(RM) \ diff --git a/l4strv.c b/l4strv.c new file mode 100644 index 0000000..26e9969 --- /dev/null +++ b/l4strv.c @@ -0,0 +1,285 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ + +#include "l4strv.h" + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +LbsStrv* lbs_strv_new_with_max (size_t max) { + LbsStrv* strv = malloc (sizeof (LbsStrv)); + if (strv == NULL) { + return NULL; + } + + if (lbs_array_init (&strv->array, sizeof (LbsArray)) < 0) { + free (strv); + return NULL; + } + + strv->ref_count = 1; + strv->is_alloc = true; + return strv; +} + +int lbs_strv_init_with_max (LbsStrv* strv, size_t max) { + if (lbs_array_init (&strv->array, sizeof (LbsArray)) < 0) { + return -1; + } + + strv->ref_count = 1; + strv->is_alloc = false; + return 0; +} + +void* lbs_strv_ref_generic (void* strv_generic) { + LbsStrv* strv = LBS_STRV (strv_generic); + strv->ref_count++; + return strv; +} + +void lbs_strv_unref_generic (void* strv_generic) { + if (strv_generic == NULL) { + return; + } + LbsStrv* strv = LBS_STRV (strv_generic); + strv->ref_count--; + if (strv->ref_count <= 0) { + lbs_strv_free (strv); + } +} + +void lbs_strv_free_generic (void* strv_generic) { + if (strv_generic == NULL) { + return; + } + LbsStrv* strv = LBS_STRV (strv_generic); + int i = 0; + for (; i < lbs_strv_get_len (strv); i++) { + LbsArray* str_wrapper = lbs_strv_get_str_wrapper (strv, i); + lbs_array_unref (str_wrapper); + } + lbs_array_unref (&strv->array); + if (strv->is_alloc) { + free (strv); + } +} + +char* lbs_strv_dup_str (LbsStrv* strv, size_t stri) { + LbsArray* str_wrapper = lbs_strv_get_str_wrapper (strv, stri); + size_t len = lbs_array_get_len (str_wrapper); + char* str = lbs_array_get_data (str_wrapper); + + char* str_new = malloc (len + sizeof (char)); + strncpy (str_new, str, len); + str_new[len] = '\0'; + + return str_new; +} + +int lbs_strv_append_char (LbsStrv* strv, size_t stri, char chr) { + if (chr == '\0') { + return -1; + } + + if (stri >= lbs_strv_get_len (strv)) { + stri = lbs_strv_get_len (strv); + LbsArray str_struct; + LbsArray* str = &str_struct; + if (lbs_array_init (str, sizeof (char)) < 0) { + return -1; + } + if (lbs_array_append_data (&strv->array, str) < 0) { + lbs_array_unref (str); + return -1; + } + } + LbsArray* str = lbs_strv_get_str_wrapper (strv, stri); + return lbs_array_append_data (str, &chr); +} + +int lbs_strv_append_str (LbsStrv* strv, const char* bstr) { + if (bstr == NULL) { + return -1; + } + + size_t len = strlen (bstr); + char* str_copy = malloc (sizeof (char) * len); + if (str_copy == NULL) { + return -1; + } + strncpy (str_copy, bstr, len); + + LbsArray str_struct, *str = &str_struct; + if (lbs_array_make_struct (str, sizeof (char), len, len, str_copy) == NULL) + { + free (str_copy); + return -1; + } + + if (lbs_array_append_data (&strv->array, &str_struct) < 0) { + lbs_array_unref (str); + free (str_copy); + return -1; + } + + return 0; +} + +int lbs_strv_append_strv (LbsStrv* strv, const char* const* bstrv) { + if (bstrv == NULL) { + return -1; + } + + int i; + for (i = 0; bstrv[i] != NULL; i++) { + if (lbs_strv_append_str (strv, bstrv[i]) < 0) { + return -1; + } + } + return 0; +} + +int lbs_strv_remove_str (LbsStrv* strv) { + size_t len = lbs_strv_get_len (strv); + if (len <= 0) { + return -1; + } + + lbs_array_unref (lbs_strv_get_str_wrapper (strv, len - 1)); + return lbs_array_remove (&strv->array); +} + +int lbs_strv_minimize (LbsStrv* strv) { + if (lbs_array_minimize (&strv->array) < 0) { + return -1; + } + + int i; + size_t len = lbs_strv_get_len (strv); + for (i = 0; i < len; i++) { + LbsArray* str = lbs_strv_get_str_wrapper (strv, i); + if (lbs_array_minimize (str) < 0) { + return -1; + } + } + + return 0; +} + +char** lbs_strv_copy_strv (LbsStrv* strv) { + size_t len = lbs_strv_get_len (strv); + char** bstrv = malloc (sizeof (char*) * (len + 1)); + if (bstrv == NULL) { + return NULL; + } + + int i; + for (i = 0; i < len; i++) { + LbsArray* str = lbs_strv_get_str_wrapper (strv, i); + size_t str_len = lbs_array_get_len (str); + char* bstr = malloc (sizeof (char) * (str_len + 1)); + + strncpy (bstr, lbs_array_get_data (str), str_len); + bstr[str_len] = '\0'; + bstrv[i] = bstr; + } + bstrv[len] = NULL; + return bstrv; +} + +char** lbs_strv_drop_struct (LbsStrv* strv) { + char** bstrv = lbs_strv_copy_strv (strv); + if (bstrv == NULL) { + return NULL; + } + + lbs_strv_free (strv); + return bstrv; +} + +char** lbs_strv_generic_build (const char* str_first, ...) { + LbsArray bstrv_w_struct, *bstrv_w = &bstrv_w_struct; + va_list ap; + char* str; + char* str_copy; + size_t str_len; + + if (lbs_array_init (bstrv_w, sizeof (void*)) < 0) { + return NULL; + } + + va_start (ap, str_first); + + str_len = strlen (str_first); + str_copy = malloc (sizeof (char) * (str_len + 1)); + if (str_copy == NULL) { + lbs_array_unref (bstrv_w); + va_end (ap); + return NULL; + } + strcpy (str_copy, str_first); + + if (lbs_array_append_ptr (bstrv_w, str_copy) < 0) { + free (str_copy); + lbs_array_unref (bstrv_w); + va_end (ap); + return NULL; + } + + + while ((str = va_arg (ap, char*)) != NULL) { + str_len = strlen (str); + str_copy = malloc (sizeof (char) * (str_len + 1)); + if (str_copy == NULL) { + lbs_array_unref (bstrv_w); + va_end (ap); + return NULL; + } + strcpy (str_copy, str); + + if (lbs_array_append_ptr (bstrv_w, str_copy) < 0) { + free (str_copy); + lbs_array_unref (bstrv_w); + va_end (ap); + return NULL; + } + } + if (lbs_array_append_ptr (bstrv_w, NULL) < 0) { + lbs_array_unref (bstrv_w); + va_end (ap); + return NULL; + } + + va_end (ap); + + return lbs_array_drop_struct (bstrv_w); +} + +int lbs_strv_generic_cmp ( + const char* const* bstrv1, const char* const* bstrv2) { + int i; + for (i = 0; bstrv1[i] != NULL && bstrv2[i] != NULL; i++) { + int r = strcmp (bstrv1[i], bstrv2[i]); + if (r != 0) { + return r; + } + } + + if (bstrv1[i] != NULL) { + return 1; + } + if (bstrv2[i] != NULL) { + return -1; + } + + return 0; +} + +void lbs_strv_generic_free (char** bstrv) { + int i; + for (i = 0; bstrv[i] != NULL; i++) { + free (bstrv[i]); + } + free (bstrv); +} diff --git a/l4strv.h b/l4strv.h new file mode 100644 index 0000000..1ce5cfc --- /dev/null +++ b/l4strv.h @@ -0,0 +1,75 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef LBS_STRV_H +#define LBS_STRV_H + +#include <l4common.h> +#include <l4array.h> + +typedef struct LbsStrvStruct { + /*< private >*/ + LbsArray array; /* data */ + unsigned ref_count; /* reference count */ + bool is_alloc; /* is allocated using malloc */ +} LbsStrv; + +#define LBS_STRV(x) ((LbsStrv*)(x)) +#define LBS_STRV_GENERIC(x) ((char**)(x)) +#define LBS_STRV_GENERIC_CONST(x) ((const char* const*)(x)) + +#define lbs_strv_new() (lbs_strv_new_with_max (0)) +LbsStrv* lbs_strv_new_with_max (size_t max); + +#define lbs_strv_init(strv) (lbs_strv_init_with_max (strv, 0)) +int lbs_strv_init_with_max (LbsStrv* strv, size_t max); + +#define lbs_strv_ref(strv) \ + (lbs_strv_ref_generic (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*))) +#define lbs_strv_unref(strv) \ + (lbs_strv_unref_generic (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*))) +void* lbs_strv_ref_generic (void* strv); +void lbs_strv_unref_generic (void* strv); + +#define lbs_strv_free(array) \ + (lbs_strv_free_generic (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*))) +void lbs_strv_free_generic (void* strv); + +#define lbs_strv_get_len(strv) \ + (lbs_array_get_len (&(LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->array))) +#define lbs_strv_get_max(strv) \ + (lbs_array_get_max (&(LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->array))) +#define lbs_strv_get_ref_count(strv) \ + (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->ref_count) +#define lbs_strv_get_is_alloc(strv) \ + (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->is_alloc) +#define lbs_strv_set_len(strv,len) \ + (lbs_array_set_len (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->array, (len))) +#define lbs_strv_set_max(strv,max) \ + (lbs_array_set_max (LBS_COMMON_CHECK_TYPE ((strv), LbsStrv*)->array, (max))) + +char* lbs_strv_dup_str (LbsStrv* strv, size_t stri); +#define lbs_strv_get_str_wrapper(strv,stri) \ + (&(lbs_array_v (&((strv)->array), LbsArray, (stri)))) +#define lbs_strv_get_str_len(strv,stri) \ + (lbs_array_get_len (lbs_strv_get_str_wrapper ((strv), (stri)))) +#define lbs_strv_get_str_not_null_terminated(strv, stri) \ + ((char*)(lbs_array_get_data (lbs_strv_get_str_wrapper ((strv), (stri))))) +#define lbs_strv_char(strv,stri,chri) \ + (lbs_array_v (lbs_strv_get_str_wrapper (strv, stri), char, (chri))) + +int lbs_strv_append_char (LbsStrv* strv, size_t stri, char chr); +int lbs_strv_append_str (LbsStrv* strv, const char* bstr); +int lbs_strv_append_strv (LbsStrv* strv, const char* const* bstrv); +int lbs_strv_remove_str (LbsStrv* strv); +#define lbs_strv_remove_char(strv,stri) \ + (lbs_array_remove (lbs_strv_get_str_wrapper ((strv), (stri)))) + +int lbs_strv_minimize (LbsStrv* strv); +char** lbs_strv_copy_strv (LbsStrv* strv); +char** lbs_strv_drop_struct (LbsStrv* strv); + +char** lbs_strv_generic_build (const char* str, ...); +int lbs_strv_generic_cmp (const char* const* bstrv1, + const char* const* bstrv2); +void lbs_strv_generic_free (char** bstrv); + +#endif /* LBS_STRV_H */ diff --git a/test-strv.c b/test-strv.c new file mode 100644 index 0000000..63fede2 --- /dev/null +++ b/test-strv.c @@ -0,0 +1,188 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#undef NDEBUG +#define _POSIX_C_SOURCE 200809L +#include <l4strv.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void test_strv_new (void) { + const char* tc[] = { + "ABC", "DEF", "GHIJKL", "MNOP", "QRST", "UVWXYZ", NULL + }; + const size_t tc_len = sizeof (tc) / sizeof (char*); + + LbsStrv* strv = lbs_strv_new (); + for (int i = 0; i < tc_len; i++) { + lbs_strv_append_str (strv, tc[i]); + } + + assert (lbs_strv_get_len (strv) == tc_len - 1); + for (int i = 0; i < lbs_strv_get_len (strv); i++) { + char* str = lbs_strv_dup_str (strv, i); + assert (strcmp (str, tc[i]) == 0); + free (str); + } + + assert (lbs_strv_get_ref_count (strv) == 1); + assert (lbs_strv_get_is_alloc (strv) == true); + lbs_strv_unref (strv); + + printf ("%s => PASS!\n", __func__); +} + +void test_strv_init (void) { + const char* tc[] = { + "ABC", "DEF", "GHIJKL", "MNOP", "QRST", "UVWXYZ", NULL + }; + const size_t tc_len = sizeof (tc) / sizeof (char*); + + LbsStrv strv_struct; + LbsStrv* strv = &strv_struct; + lbs_strv_init (strv); + for (int i = 0; i < tc_len; i++) { + lbs_strv_append_str (strv, tc[i]); + } + + assert (lbs_strv_get_len (strv) == tc_len - 1); + for (int i = 0; i < lbs_strv_get_len (strv); i++) { + char* str = lbs_strv_dup_str (strv, i); + assert (strcmp (str, tc[i]) == 0); + free (str); + } + + assert (lbs_strv_get_ref_count (strv) == 1); + assert (lbs_strv_get_is_alloc (strv) == false); + lbs_strv_unref (strv); + + printf ("%s => PASS!\n", __func__); +} + +void test_strv_copy (void) { + const char* tc1[] = { + "ABC", "DEF", "GHIJKL", "MNOP", "QRST", "UVWXYZ", NULL + }; + const size_t tc1_len = sizeof (tc1) / sizeof (char*); + + const char* tc2[] = { + "01234", "5678", "9+_()", "<>?{}[]!@#$%^&*", NULL + }; + const size_t tc2_len = sizeof (tc2) / sizeof (char*); + + LbsStrv* strv = lbs_strv_new (); + lbs_strv_minimize (strv); + lbs_strv_append_strv (strv, tc1); + lbs_strv_append_strv (strv, tc2); + lbs_strv_minimize (strv); + + assert (lbs_strv_get_len (strv) == lbs_strv_get_max (strv)); + assert (lbs_strv_get_len (strv) == tc1_len + tc2_len - 2); + + char** copy1 = lbs_strv_copy_strv (strv); + char** copy2 = lbs_strv_drop_struct (strv); + + int vi = 0; + for (int i = 0; i < tc1_len - 1; i++, vi++) { + assert (strcmp (copy1[vi], tc1[i]) == 0); + assert (strcmp (copy2[vi], tc1[i]) == 0); + } + for (int i = 0; i < tc2_len - 1; i++, vi++) { + assert (strcmp (copy1[vi], tc2[i]) == 0); + assert (strcmp (copy2[vi], tc2[i]) == 0); + } + + lbs_strv_generic_free (copy1); + lbs_strv_generic_free (copy2); + + printf ("%s => PASS!\n", __func__); +} + +void test_strv_ref (void) { + LbsStrv* strv = lbs_strv_new (); + assert (lbs_strv_get_ref_count (strv) == 1); + assert (lbs_strv_ref (strv) == strv); + assert (lbs_strv_get_ref_count (strv) == 2); + lbs_strv_unref (strv); + assert (lbs_strv_get_ref_count (strv) == 1); + lbs_strv_unref (strv); + + printf ("%s => PASS!\n", __func__); +} + +void test_strv_op (void) { + const char* tc[] = { "ABC", "UVWXYZ", NULL }; + LbsStrv* strv = lbs_strv_new (); + lbs_strv_append_char (strv, 0, 'a'); + lbs_strv_append_char (strv, 0, 't'); + lbs_strv_append_char (strv, 0, 's'); + lbs_strv_append_str (strv, "strv"); + lbs_strv_append_strv (strv, tc); + lbs_strv_remove_char (strv, 3); + lbs_strv_remove_char (strv, 3); + lbs_strv_remove_char (strv, 3); + lbs_strv_append_str (strv, "Good"); + lbs_strv_append_str (strv, "AC_AC_AC_AC_AC_AC_AC_AC_AC_AC_AC_AC_AC_AC"); + lbs_strv_remove_str (strv); + + assert (lbs_strv_get_len (strv) == 5); + + assert (lbs_strv_get_str_len (strv, 0) == 3); + assert (memcmp ( + lbs_strv_get_str_not_null_terminated (strv, 0), "ats", 3) == 0); + + assert (lbs_strv_get_str_len (strv, 1) == 4); + assert (memcmp ( + lbs_strv_get_str_not_null_terminated (strv, 1), "strv", 4) == 0); + + assert (lbs_strv_get_str_len (strv, 2) == 3); + assert (memcmp ( + lbs_strv_get_str_not_null_terminated (strv, 2), "ABC", 3) == 0); + + assert (lbs_strv_get_str_len (strv, 3) == 3); + assert (memcmp ( + lbs_strv_get_str_not_null_terminated (strv, 3), "UVW", 3) == 0); + + assert (lbs_strv_get_str_len (strv, 4) == 4); + assert (memcmp ( + lbs_strv_get_str_not_null_terminated (strv, 4), "Good", 4) == 0); + + lbs_strv_unref (strv); + + printf ("%s => PASS!\n", __func__); +} + +void test_strv_generic (void) { + const char* tc[] = { "ABC", "DEF", "GHIJKL", "UVWXYZ", NULL }; + LbsStrv* strv = lbs_strv_new (); + lbs_strv_append_strv (strv, tc); + + char** copy1 = lbs_strv_copy_strv (strv); + char** copy2 = lbs_strv_generic_build (tc[0], tc[1], tc[2], tc[3], tc[4]); + + for (int i = 0; i < 4; i++) { + assert (strcmp (copy1[i], tc[i]) == 0); + assert (strcmp (copy2[i], tc[i]) == 0); + } + + assert (lbs_strv_generic_cmp ( + LBS_STRV_GENERIC_CONST (copy1), + LBS_STRV_GENERIC_CONST (copy2)) == 0); + + lbs_strv_unref (strv); + lbs_strv_generic_free (copy1); + lbs_strv_generic_free (copy2); + + printf ("%s => PASS!\n", __func__); +} + +int main () { + test_strv_new (); + test_strv_init (); + test_strv_copy (); + test_strv_ref (); + test_strv_op (); + test_strv_generic (); + return 0; +} |