From: Olivier Matz <zer0@droids-corp.org>
Date: Fri, 10 Nov 2017 20:53:34 +0000 (+0100)
Subject: strvec
X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=d3f82a7571b394d8e9b6f2791219eb7ad67d6597;p=protos%2Flibecoli.git

strvec
---

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 <ecoli_malloc.h>
 #include <ecoli_strvec.h>
+#include <ecoli_test.h>
+#include <ecoli_log.h>
+
+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 <stdio.h>
 
+/**
+ * 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_