util: return the number of elements from strv_from_string
authorYinon Burgansky <yinonburgansky@gmail.com>
Wed, 5 Oct 2022 15:20:06 +0000 (18:20 +0300)
committerYinon Burgansky <yinonburgansky@gmail.com>
Mon, 7 Nov 2022 20:32:24 +0000 (22:32 +0200)
Signed-off-by: Yinon Burgansky <51504-Yinon@users.noreply.gitlab.freedesktop.org>
src/quirks.c
src/util-prop-parsers.c
src/util-strings.c
src/util-strings.h
test/test-utils.c

index ed1a903..5651c51 100644 (file)
@@ -879,18 +879,15 @@ out:
 static bool
 parse_value_line(struct quirks_context *ctx, struct section *s, const char *line)
 {
-       char **strv;
-       const char *key, *value;
        bool rc = false;
-
-       strv = strv_from_string(line, "=");
-       if (strv[0] == NULL || strv[1] == NULL || strv[2] != NULL) {
+       
+       size_t nelem;
+       char **strv = strv_from_string(line, "=", &nelem);
+       if (!strv || nelem != 2)
                goto out;
-       }
-
 
-       key = strv[0];
-       value = strv[1];
+       const char *key = strv[0];
+       const char *value = strv[1];
        if (strlen(key) == 0 || strlen(value) == 0)
                goto out;
 
index 20d301f..2e4b514 100644 (file)
@@ -176,32 +176,31 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h)
 bool
 parse_calibration_property(const char *prop, float calibration_out[6])
 {
-       int idx;
-       char **strv;
-       float calibration[6];
-
        if (!prop)
                return false;
+       
+       bool rc = false;
 
-       strv = strv_from_string(prop, " ");
-       if (!strv)
-               return false;
+       size_t num_calibration;
+       char **strv = strv_from_string(prop, " ", &num_calibration);
+       if (!strv || num_calibration < 6)
+               goto out;
 
-       for (idx = 0; idx < 6; idx++) {
+       float calibration[6];
+       for (size_t idx = 0; idx < 6; idx++) {
                double v;
-               if (strv[idx] == NULL || !safe_atod(strv[idx], &v)) {
-                       strv_free(strv);
-                       return false;
-               }
+               if (!safe_atod(strv[idx], &v))
+                       goto out;
 
                calibration[idx] = v;
        }
 
-       strv_free(strv);
-
        memcpy(calibration_out, calibration, sizeof(calibration));
+       rc = true;
 
-       return true;
+out:
+       strv_free(strv);
+       return rc;
 }
 
 bool
@@ -367,27 +366,19 @@ parse_evcode_string(const char *s, int *type_out, int *code_out)
 bool
 parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
 {
-       char **strv = NULL;
        bool rc = false;
-       size_t ncodes = 0;
-       size_t idx;
        /* A randomly chosen max so we avoid crazy quirks */
        struct input_event evs[32];
 
        memset(evs, 0, sizeof evs);
 
-       strv = strv_from_string(prop, ";");
-       if (!strv)
-               goto out;
-
-       for (idx = 0; strv[idx]; idx++)
-               ncodes++;
-
-       if (ncodes == 0 || ncodes > ARRAY_LENGTH(evs))
+       size_t ncodes;
+       char **strv = strv_from_string(prop, ";", &ncodes);
+       if (!strv || ncodes == 0 || ncodes > ARRAY_LENGTH(evs))
                goto out;
 
        ncodes = min(*nevents, ncodes);
-       for (idx = 0; strv[idx]; idx++) {
+       for (size_t idx = 0; strv[idx]; idx++) {
                char *s = strv[idx];
 
                int type, code;
@@ -434,24 +425,16 @@ out:
 bool
 parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *nprops)
 {
-       char **strv = NULL;
        bool rc = false;
-       size_t count = 0;
-       size_t idx;
        unsigned int props[INPUT_PROP_CNT]; /* doubling up on quirks is a bug */
 
-       strv = strv_from_string(prop, ";");
-       if (!strv)
-               goto out;
-
-       for (idx = 0; strv[idx]; idx++)
-               count++;
-
-       if (count == 0 || count > ARRAY_LENGTH(props))
+       size_t count;
+       char **strv = strv_from_string(prop, ";", &count);
+       if (!strv || count == 0 || count > ARRAY_LENGTH(props))
                goto out;
 
        count = min(*nprops, count);
-       for (idx = 0; strv[idx]; idx++) {
+       for (size_t idx = 0; strv[idx]; idx++) {
                char *s = strv[idx];
                unsigned int prop;
 
index 33a7ac8..525edc1 100644 (file)
@@ -91,47 +91,54 @@ strv_from_argv(int argc, char **argv)
 /**
  * Return a null-terminated string array with the tokens in the input
  * string, e.g. "one two\tthree" with a separator list of " \t" will return
- * an array [ "one", "two", "three", NULL ].
+ * an array [ "one", "two", "three", NULL ] and num elements 3.
  *
  * Use strv_free() to free the array.
  *
+ * Another example:
+ *   result = strv_from_string("+1-2++3--4++-+5-+-", "+-", &nelem)
+ *   result == [ "1", "2", "3", "4", "5", NULL ] and nelem == 5
+ * 
  * @param in Input string
  * @param separators List of separator characters
+ * @param num_elements Number of elements found in the input string
  *
  * @return A null-terminated string array or NULL on errors
  */
 char **
-strv_from_string(const char *in, const char *separators)
+strv_from_string(const char *in, const char *separators, size_t *num_elements)
 {
-       const char *s, *word;
-       char **strv = NULL;
-       int nelems = 0, idx;
-       size_t l;
-
        assert(in != NULL);
 
-       s = in;
+       
+       const char *s = in;
+       size_t l, nelems = 0;
        while (next_word(&s, &l, separators) != NULL)
-              nelems++;
+               nelems++;
 
-       if (nelems == 0)
+       if (nelems == 0) {
+               *num_elements = 0;
                return NULL;
+       }
 
-       nelems++; /* NULL-terminated */
-       strv = zalloc(nelems * sizeof *strv);
-
-       idx = 0;
+       size_t strv_len = nelems + 1; /* NULL-terminated */
+       char **strv = zalloc(strv_len * sizeof *strv);
 
+       size_t idx = 0;
+       const char *word;
        s = in;
        while ((word = next_word(&s, &l, separators)) != NULL) {
                char *copy = strndup(word, l);
                if (!copy) {
                        strv_free(strv);
+                       *num_elements = 0;
                        return NULL;
                }
 
                strv[idx++] = copy;
        }
+       
+       *num_elements = nelems;
 
        return strv;
 }
index d5a8414..0bbd6f6 100644 (file)
@@ -255,7 +255,7 @@ safe_atod(const char *str, double *val)
 }
 
 char **strv_from_argv(int argc, char **argv);
-char **strv_from_string(const char *in, const char *separator);
+char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
 char *strv_join(char **strv, const char *joiner);
 
 static inline void
@@ -291,33 +291,26 @@ kv_double_from_string(const char *string,
                      struct key_value_double **result_out)
 
 {
-       char **pairs;
-       char **pair;
        struct key_value_double *result = NULL;
-       ssize_t npairs = 0;
-       unsigned int idx = 0;
 
        if (!pair_separator || pair_separator[0] == '\0' ||
            !kv_separator || kv_separator[0] == '\0')
                return -1;
 
-       pairs = strv_from_string(string, pair_separator);
-       if (!pairs)
-               return -1;
-
-       for (pair = pairs; *pair; pair++)
-               npairs++;
-
-       if (npairs == 0)
+       size_t npairs;
+       char **pairs = strv_from_string(string, pair_separator, &npairs);
+       if (!pairs || npairs == 0)
                goto error;
 
        result = zalloc(npairs * sizeof *result);
 
-       for (pair = pairs; *pair; pair++) {
-               char **kv = strv_from_string(*pair, kv_separator);
+       for (size_t idx = 0; idx < npairs; idx++) {
+               char *pair = pairs[idx];
+               size_t nelem;
+               char **kv = strv_from_string(pair, kv_separator, &nelem);
                double k, v;
 
-               if (!kv || !kv[0] || !kv[1] || kv[2] ||
+               if (!kv || nelem != 2 ||
                    !safe_atod(kv[0], &k) ||
                    !safe_atod(kv[1], &v)) {
                        strv_free(kv);
@@ -326,7 +319,6 @@ kv_double_from_string(const char *string,
 
                result[idx].key = k;
                result[idx].value = v;
-               idx++;
 
                strv_free(kv);
        }
index 0ae3668..08bdd59 100644 (file)
@@ -1070,39 +1070,48 @@ START_TEST(strsplit_test)
                const char *string;
                const char *delim;
                const char *results[10];
+               const size_t nresults;
        } tests[] = {
-               { "one two three", " ", { "one", "two", "three", NULL } },
-               { "one", " ", { "one", NULL } },
-               { "one two ", " ", { "one", "two", NULL } },
-               { "one  two", " ", { "one", "two", NULL } },
-               { " one two", " ", { "one", "two", NULL } },
-               { "one", "\t \r", { "one", NULL } },
-               { "one two three", " t", { "one", "wo", "hree", NULL } },
-               { " one two three", "te", { " on", " ", "wo ", "hr", NULL } },
-               { "one", "ne", { "o", NULL } },
-               { "onene", "ne", { "o", NULL } },
-               { NULL, NULL, { NULL }}
+               { "one two three", " ", { "one", "two", "three", NULL }, 3 },
+               { "one two\tthree", " \t", { "one", "two", "three", NULL }, 3 },
+               { "one", " ", { "one", NULL }, 1 },
+               { "one two ", " ", { "one", "two", NULL }, 2 },
+               { "one  two", " ", { "one", "two", NULL }, 2 },
+               { " one two", " ", { "one", "two", NULL }, 2 },
+               { "one", "\t \r", { "one", NULL }, 1 },
+               { "one two three", " t", { "one", "wo", "hree", NULL }, 3 },
+               { " one two three", "te", { " on", " ", "wo ", "hr", NULL }, 4 },
+               { "one", "ne", { "o", NULL }, 1 },
+               { "onene", "ne", { "o", NULL }, 1 },
+               { "+1-2++3--4++-+5-+-", "+-", { "1", "2", "3", "4", "5", NULL }, 5 },
+               /* special cases */
+               { "", " ", { NULL }, 0 },
+               { " ", " ", { NULL }, 0 },
+               { "     ", " ", { NULL }, 0 },
+               { "oneoneone", "one", { NULL} , 0 },
+               { NULL, NULL, { NULL }, 0}
        };
        struct strsplit_test *t = tests;
 
        while (t->string) {
-               char **strv;
-               int idx = 0;
-               strv = strv_from_string(t->string, t->delim);
-               while (t->results[idx]) {
+               size_t nelem;
+               char **strv = strv_from_string(t->string, t->delim, &nelem);
+
+               for (size_t idx = 0; idx < t->nresults; idx++)                  
                        ck_assert_str_eq(t->results[idx], strv[idx]);
-                       idx++;
-               }
-               ck_assert_ptr_eq(strv[idx], NULL);
+               
+               ck_assert_uint_eq(nelem, t->nresults);
+               
+               /* When there are no elements validate return value is Null,
+                  otherwise validate result array is Null terminated. */
+               if(t->nresults == 0)
+                       ck_assert_ptr_null(strv);
+               else
+                       ck_assert_ptr_null(strv[t->nresults]);
+
                strv_free(strv);
                t++;
        }
-
-       /* Special cases */
-       ck_assert_ptr_eq(strv_from_string("", " "), NULL);
-       ck_assert_ptr_eq(strv_from_string(" ", " "), NULL);
-       ck_assert_ptr_eq(strv_from_string("     ", " "), NULL);
-       ck_assert_ptr_eq(strv_from_string("oneoneone", "one"), NULL);
 }
 END_TEST