message-params: Add read functions for arrays
authorGeorg Chini <georg@chini.tk>
Tue, 14 Jan 2020 19:50:24 +0000 (20:50 +0100)
committerTanu Kaskinen <tanuk@iki.fi>
Thu, 3 Dec 2020 14:41:39 +0000 (14:41 +0000)
The following new functions have been added:

pa_message_params_read_double_array() - read an array of double from list
pa_message_params_read_int64_array() - read an array of int64 from list
pa_message_params_read_uint64_array() - read an array of uint64 from list
pa_message_params_read_string_array() - read an array of strings from list

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/51>

src/map-file
src/pulse/message-params.c
src/pulse/message-params.h

index 172fd44..7b1ed52 100644 (file)
@@ -235,10 +235,14 @@ pa_message_params_free;
 pa_message_params_new;
 pa_message_params_read_bool;
 pa_message_params_read_double;
+pa_message_params_read_double_array;
 pa_message_params_read_int64;
+pa_message_params_read_int64_array;
 pa_message_params_read_raw;
 pa_message_params_read_string;
+pa_message_params_read_string_array;
 pa_message_params_read_uint64;
+pa_message_params_read_uint64_array;
 pa_message_params_to_string_free;
 pa_message_params_write_bool;
 pa_message_params_write_double;
index 8885f95..7d2dd80 100644 (file)
@@ -39,6 +39,61 @@ struct pa_message_params {
     pa_strbuf *buffer;
 };
 
+/* Helper functions */
+
+/* Count number of top level elements in parameter list */
+static int count_elements(const char *c) {
+    const char *s;
+    uint32_t element_count;
+    bool found_element, found_backslash;
+    int open_braces;
+
+    if (!c || *c == 0)
+        return PA_MESSAGE_PARAMS_LIST_END;
+
+    element_count = 0;
+    open_braces = 0;
+    found_element = false;
+    found_backslash = false;
+    s = c;
+
+    /* Count elements in list */
+    while (*s != 0) {
+
+        /* Skip escaped curly braces. */
+        if (*s == '\\' && !found_backslash) {
+            found_backslash = true;
+            s++;
+            continue;
+        }
+
+        if (*s == '{' && !found_backslash) {
+            found_element = true;
+            open_braces++;
+        }
+        if (*s == '}' && !found_backslash)
+            open_braces--;
+
+        /* unexpected closing brace, parse error */
+        if (open_braces < 0)
+            return PA_MESSAGE_PARAMS_PARSE_ERROR;
+
+        if (open_braces == 0 && found_element) {
+            element_count++;
+            found_element = false;
+        }
+
+        found_backslash = false;
+        s++;
+    }
+
+    /* missing closing brace, parse error */
+    if (open_braces > 0)
+        return PA_MESSAGE_PARAMS_PARSE_ERROR;
+
+    return element_count;
+}
+
 /* Split the specified string into elements. An element is defined as
  * a sub-string between curly braces. The function is needed to parse
  * the parameters of messages. Each time it is called it returns the
@@ -188,7 +243,7 @@ int pa_message_params_read_double(char *c, double *result, void **state) {
     if (!is_unpacked)
         return PA_MESSAGE_PARAMS_PARSE_ERROR;
 
-    /* Convert to double */
+    /* Get decimal separator for current locale */
     locale = localeconv();
 
     /* Replace decimal point with the correct character for the
@@ -289,6 +344,122 @@ int pa_message_params_read_bool(char *c, bool *result, void **state) {
     return PA_MESSAGE_PARAMS_OK;
 }
 
+/* Converts a parameter list to a string array. Escaping is removed from
+ * the strings. Returns an array of pointers to sub-strings within c in
+ * *results. The returned array must be freed, but not the strings
+ * within the array. The function returns the number of strings in the
+ * array. */
+int pa_message_params_read_string_array(char *c, const char ***results) {
+    void *state = NULL;
+    uint32_t element_count, i;
+    int err;
+    const char **values;
+
+    pa_assert(results);
+
+    /* Count elements, return if no element was found or parse error. */
+    if ((element_count = count_elements(c)) <= 0)
+        return element_count;
+
+    /* Allocate array */
+    values = pa_xmalloc0(element_count * sizeof(char *));
+
+    for (i = 0; (err = pa_message_params_read_string(c, &(values[i]), &state)) > 0; i++)
+        ;
+
+    if (err < 0) {
+        pa_xfree(values);
+        return PA_MESSAGE_PARAMS_PARSE_ERROR;
+    }
+
+    *results = values;
+    return element_count;
+}
+
+/* Converts a parameter list to a double array. */
+int pa_message_params_read_double_array(char *c, double **results) {
+    double  *values;
+    void *state = NULL;
+    uint32_t element_count, i;
+    int err;
+
+    pa_assert(results);
+
+    /* Count elements, return if no element was found or parse error. */
+    if ((element_count = count_elements(c)) <= 0)
+        return element_count;
+
+    /* Allocate array */
+    values = pa_xmalloc0(element_count * sizeof(double));
+
+    for (i = 0; (err = pa_message_params_read_double(c, &(values[i]), &state)) > 0; i++)
+        ;
+
+    if (err < 0) {
+        pa_xfree(values);
+        return PA_MESSAGE_PARAMS_PARSE_ERROR;
+    }
+
+    *results = values;
+    return element_count;
+}
+
+/* Converts a parameter list to an int64 array. */
+int pa_message_params_read_int64_array(char *c, int64_t **results) {
+    int64_t  *values;
+    void *state = NULL;
+    uint32_t element_count, i;
+    int err;
+
+    pa_assert(results);
+
+    /* Count elements, return if no element was found or parse error. */
+    if ((element_count = count_elements(c)) <= 0)
+        return element_count;
+
+    /* Allocate array */
+    values = pa_xmalloc0(element_count * sizeof(int64_t));
+
+    for (i = 0; (err = pa_message_params_read_int64(c, &(values[i]), &state)) > 0; i++)
+        ;
+
+    if (err < 0) {
+        pa_xfree(values);
+        return PA_MESSAGE_PARAMS_PARSE_ERROR;
+    }
+
+    *results = values;
+    return element_count;
+}
+
+/* Converts a parameter list to an uint64 array. */
+int pa_message_params_read_uint64_array(char *c, uint64_t **results) {
+    uint64_t  *values;
+    void *state = NULL;
+    uint32_t element_count, i;
+    int err;
+
+    pa_assert(results);
+
+    /* Count elements, return if no element was found or parse error. */
+    if ((element_count = count_elements(c)) <= 0)
+        return element_count;
+
+    /* Allocate array */
+    values = pa_xmalloc0(element_count * sizeof(uint64_t));
+
+    for (i = 0; (err = pa_message_params_read_uint64(c, &(values[i]), &state)) > 0; i++)
+        ;
+
+    if (err < 0) {
+        pa_xfree(values);
+        return PA_MESSAGE_PARAMS_PARSE_ERROR;
+    }
+
+    *results = values;
+    return element_count;
+}
+
 /* Write functions. The functions are wrapper functions around pa_strbuf,
  * so that the client does not need to use pa_strbuf directly. */
 
index a2e0f9e..3d90eac 100644 (file)
  * the callback, it must be copied using pa_xstrdup().
  * When a read function is called, the state pointer is advanced to the
  * next list element. The variable state points to should be initialized
- * to NULL before the first call.\n
+ * to NULL before the first call.
+ * All read functions except read_raw() preserve a default value passed
+ * in result if the call fails. For the array functions, results must be
+ * initialized prior to the call either to NULL or to an array with default
+ * values. If the function succeeds, the default array will be freed and
+ * the number of elements in the result array is returned.\n\n
  * Write functions operate on a pa_message_params structure which is a
  * wrapper for pa_strbuf. A parameter list or sub-list is started by a
  * call to begin_list() and ended by a call to end_list().
@@ -69,9 +74,19 @@ int pa_message_params_read_bool(char *c, bool *result, void **state);
 /** Read a double from parameter list in c. \since 15.0 */
 int pa_message_params_read_double(char *c, double *result, void **state);
 
+/** Converts a parameter list to a double array. Empty elements in the parameter
+ * list are treated as error. Before the call, results must be initialized, either
+ * to NULL or to an array with default values. \since 15.0 */
+int pa_message_params_read_double_array(char *c, double **results);
+
 /** Read an integer from parameter list in c. \since 15.0 */
 int pa_message_params_read_int64(char *c, int64_t *result, void **state);
 
+/** Converts a parameter list to an int64 array. Empty elements in the parameter
+ * list are treated as error. Before the call, results must be initialized, either
+ * to NULL or to an array with default values. \since 15.0 */
+int pa_message_params_read_int64_array(char *c, int64_t **results);
+
 /** Read raw data from parameter list in c. Used to split a message parameter
  * string into list elements. The string returned in *result must not be freed.  \since 15.0 */
 int pa_message_params_read_raw(char *c, char **result, void **state);
@@ -80,9 +95,21 @@ int pa_message_params_read_raw(char *c, char **result, void **state);
  * will be unescaped. \since 15.0 */
 int pa_message_params_read_string(char *c, const char **result, void **state);
 
+/** Convert a parameter list to a string array. Escaping is removed from
+ * the strings. Returns an array of pointers to sub-strings within c in
+ * *results. The returned array must be freed, but not the strings
+ * within the array. Before the call, results must be initialized, either
+ * to NULL or to an array with default values. \since 15.0 */
+int pa_message_params_read_string_array(char *c, const char ***results);
+
 /** Read an unsigned integer from parameter list in c. \since 15.0 */
 int pa_message_params_read_uint64(char *c, uint64_t *result, void **state);
 
+/** Converts a parameter list to an uint64 array. Empty elements in the parameter
+ * list are treated as error. Before the call, results must be initialized, either
+ * to NULL or to an array with default values. \since 15.0 */
+int pa_message_params_read_uint64_array(char *c, uint64_t **results);
+
 /** @} */
 
 /** @{ \name Write functions */