From d3f82a7571b394d8e9b6f2791219eb7ad67d6597 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Fri, 10 Nov 2017 21:53:34 +0100 Subject: [PATCH] strvec --- lib/ecoli_strvec.c | 157 +++++++++++++++++++++++++++++++++++++++++---- lib/ecoli_strvec.h | 86 ++++++++++++++++++++++++- lib/ecoli_vec.h | 7 ++ 3 files changed, 237 insertions(+), 13 deletions(-) diff --git a/lib/ecoli_strvec.c b/lib/ecoli_strvec.c index 7011cf3..32208ad 100644 --- a/lib/ecoli_strvec.c +++ b/lib/ecoli_strvec.c @@ -32,6 +32,10 @@ #include #include +#include +#include + +EC_LOG_TYPE_REGISTER(strvec); struct ec_strvec_elt { unsigned int refcnt; @@ -61,18 +65,18 @@ int ec_strvec_add(struct ec_strvec *strvec, const char *s) new_vec = ec_realloc(strvec->vec, sizeof(*strvec->vec) * (strvec->len + 1)); if (new_vec == NULL) - return -ENOMEM; + return -1; strvec->vec = new_vec; elt = ec_malloc(sizeof(*elt)); if (elt == NULL) - return -ENOMEM; + return -1; elt->str = ec_strdup(s); if (elt->str == NULL) { ec_free(elt); - return -ENOMEM; + return -1; } elt->refcnt = 1; @@ -85,18 +89,17 @@ struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off, size_t len) { struct ec_strvec *copy = NULL; - size_t i, veclen; + size_t i; + + if (off + len > ec_strvec_len(strvec)) { + errno = EINVAL; + return NULL; + } copy = ec_strvec(); if (copy == NULL) goto fail; - veclen = ec_strvec_len(strvec); - if (off >= veclen) - len = 0; - else if (off + len > veclen) - len -= (veclen - off); - if (len == 0) return copy; @@ -145,10 +148,13 @@ void ec_strvec_free(struct ec_strvec *strvec) size_t ec_strvec_len(const struct ec_strvec *strvec) { + if (strvec == NULL) + return 0; + return strvec->len; } -char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx) +const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx) { if (strvec == NULL || idx >= strvec->len) return NULL; @@ -176,4 +182,131 @@ void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec) } -/* XXX test case */ +/* LCOV_EXCL_START */ +static int ec_strvec_testcase(void) +{ + struct ec_strvec *strvec = NULL; + struct ec_strvec *strvec2 = NULL; + + strvec = ec_strvec(); + if (strvec == NULL) { + EC_TEST_ERR("cannot create strvec\n"); + goto fail; + } + if (ec_strvec_len(strvec) != 0) { + EC_TEST_ERR("bad strvec len (0)\n"); + goto fail; + } + if (ec_strvec_add(strvec, "0") < 0) { + EC_TEST_ERR("cannot add (0) in strvec\n"); + goto fail; + } + if (ec_strvec_len(strvec) != 1) { + EC_TEST_ERR("bad strvec len (1)\n"); + goto fail; + } + if (ec_strvec_add(strvec, "1") < 0) { + EC_TEST_ERR("cannot add (1) in strvec\n"); + goto fail; + } + if (ec_strvec_len(strvec) != 2) { + EC_TEST_ERR("bad strvec len (2)\n"); + goto fail; + } + if (strcmp(ec_strvec_val(strvec, 0), "0")) { + EC_TEST_ERR("invalid element in strvec (0)\n"); + goto fail; + } + if (strcmp(ec_strvec_val(strvec, 1), "1")) { + EC_TEST_ERR("invalid element in strvec (1)\n"); + goto fail; + } + if (ec_strvec_val(strvec, 2) != NULL) { + EC_TEST_ERR("strvec val should be NULL\n"); + goto fail; + } + + strvec2 = ec_strvec_dup(strvec); + if (strvec2 == NULL) { + EC_TEST_ERR("cannot create strvec2\n"); + goto fail; + } + if (ec_strvec_len(strvec2) != 2) { + EC_TEST_ERR("bad strvec2 len (2)\n"); + goto fail; + } + if (strcmp(ec_strvec_val(strvec2, 0), "0")) { + EC_TEST_ERR("invalid element in strvec2 (0)\n"); + goto fail; + } + if (strcmp(ec_strvec_val(strvec2, 1), "1")) { + EC_TEST_ERR("invalid element in strvec2 (1)\n"); + goto fail; + } + if (ec_strvec_val(strvec2, 2) != NULL) { + EC_TEST_ERR("strvec2 val should be NULL\n"); + goto fail; + } + ec_strvec_free(strvec2); + + strvec2 = ec_strvec_ndup(strvec, 0, 0); + if (strvec2 == NULL) { + EC_TEST_ERR("cannot create strvec2\n"); + goto fail; + } + if (ec_strvec_len(strvec2) != 0) { + EC_TEST_ERR("bad strvec2 len (0)\n"); + goto fail; + } + if (ec_strvec_val(strvec2, 0) != NULL) { + EC_TEST_ERR("strvec2 val should be NULL\n"); + goto fail; + } + ec_strvec_free(strvec2); + + strvec2 = ec_strvec_ndup(strvec, 1, 1); + if (strvec2 == NULL) { + EC_TEST_ERR("cannot create strvec2\n"); + goto fail; + } + if (ec_strvec_len(strvec2) != 1) { + EC_TEST_ERR("bad strvec2 len (1)\n"); + goto fail; + } + if (strcmp(ec_strvec_val(strvec2, 0), "1")) { + EC_TEST_ERR("invalid element in strvec2 (1)\n"); + goto fail; + } + if (ec_strvec_val(strvec2, 1) != NULL) { + EC_TEST_ERR("strvec2 val should be NULL\n"); + goto fail; + } + ec_strvec_free(strvec2); + + strvec2 = ec_strvec_ndup(strvec, 3, 1); + if (strvec2 != NULL) { + EC_TEST_ERR("strvec2 should be NULL\n"); + goto fail; + } + ec_strvec_free(strvec2); + + ec_strvec_dump(stdout, strvec); + ec_strvec_dump(stdout, NULL); + + ec_strvec_free(strvec); + + return 0; + +fail: + ec_strvec_free(strvec); + ec_strvec_free(strvec2); + return -1; +} +/* LCOV_EXCL_STOP */ + +static struct ec_test ec_node_str_test = { + .name = "strvec", + .test = ec_strvec_testcase, +}; + +EC_TEST_REGISTER(ec_node_str_test); diff --git a/lib/ecoli_strvec.h b/lib/ecoli_strvec.h index ee3313e..6d2a5b4 100644 --- a/lib/ecoli_strvec.h +++ b/lib/ecoli_strvec.h @@ -25,19 +25,103 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * Vectors of strings. + * + * The ec_strvec API provide helpers to manipulate string vectors. + * When duplicating vectors, the strings are not duplicated in memory, + * a reference counter is used. + */ + #ifndef ECOLI_STRVEC_ #define ECOLI_STRVEC_ #include +/** + * Allocate a new empty string vector. + * + * @return + * The new strvec object, or NULL on error (errno is set). + */ struct ec_strvec *ec_strvec(void); + +/** + * Add a string in a vector. + * + * @param strvec + * The pointer to the string vector. + * @param s + * The string to be added at the end of the vector. + * @return + * 0 on success or -1 on error (errno is set). + */ int ec_strvec_add(struct ec_strvec *strvec, const char *s); + +/** + * Duplicate a string vector. + * + * @param strvec + * The pointer to the string vector. + * @return + * The duplicated strvec object, or NULL on error (errno is set). + */ struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec); + +/** + * Duplicate a part of a string vector. + * + * @param strvec + * The pointer to the string vector. + * @param off + * The index of the first string to duplicate. + * @param + * The number of strings to duplicate. + * @return + * The duplicated strvec object, or NULL on error (errno is set). + */ struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off, size_t len); + +/** + * Free a string vector. + * + * @param strvec + * The pointer to the string vector. + */ void ec_strvec_free(struct ec_strvec *strvec); + +/** + * Get the length of a string vector. + * + * @param strvec + * The pointer to the string vector. + * @return + * The length of the vector. + */ size_t ec_strvec_len(const struct ec_strvec *strvec); -char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx); + +/** + * Get a string element from a vector. + * + * @param strvec + * The pointer to the string vector. + * @param idx + * The index of the string to get. + * @return + * The string stored at given index, or NULL on error (strvec is NULL + * or invalid index). + */ +const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx); + +/** + * Dump a string vector. + * + * @param out + * The stream where the dump is sent. + * @param strvec + * The pointer to the string vector. + */ void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec); #endif diff --git a/lib/ecoli_vec.h b/lib/ecoli_vec.h index 782ed70..defd652 100644 --- a/lib/ecoli_vec.h +++ b/lib/ecoli_vec.h @@ -25,6 +25,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * Vectors of objects. + * + * The ec_vec API provide helpers to manipulate vectors of objects + * of any kind. + */ + #ifndef ECOLI_VEC_ #define ECOLI_VEC_ -- 2.39.5