See doc/messaging_api.txt for the added functions. All read functions return 1 on success, 0 if end of string is found and -1 on parse error. Additionally, for the numeric/boolean read functions, 2 is returned if the list element is empty. --- doc/messaging_api.txt | 15 +++- src/map-file | 9 ++ src/pulse/message-params.c | 211 +++++++++++++++++++++++++++++++++++++++------ src/pulse/message-params.h | 35 ++++++++ 4 files changed, 242 insertions(+), 28 deletions(-) diff --git a/doc/messaging_api.txt b/doc/messaging_api.txt index 0e6be53f..d080b783 100644 --- a/doc/messaging_api.txt +++ b/doc/messaging_api.txt @@ -27,6 +27,11 @@ the structure pa_message_param_begin_list() - starts a list pa_message_param_end_list() - ends a list pa_message_param_write_string() - writes a string to a pa_message_param structure +pa_message_param_write_double() - writes a double to a pa_message_param structure +pa_message_param_write_int64() - writes an integer to a pa_message_param structure +pa_message_param_write_uint64() - writes an unsigned to a pa_message_param structure +pa_message_param_write_bool() - writes a boolean to a pa_message_param structure +pa_message_param_write_raw() - writes raw a string to a pa_message_param structure For string parameters that contain curly braces, those braces must be escaped by adding a "\" before them. This however means that a trailing backslash would @@ -44,9 +49,15 @@ Other strings can be passed without modification. For reading, the following functions are available: pa_message_param_split_list() - parse message parameter string pa_message_param_read_string() - read a string from a parameter list +pa_message_param_read_double() - read a double from a parameter list +pa_message_param_read_int64() - read an integer from a parameter list +pa_message_param_read_uint64() - read an unsigned from a parameter list +pa_message_param_read_bool() - read a boolean from a parameter list -pa_message_param_read_string() also reverts the changes that -pa_message_param_write_string() might have introduced. +All read functions return 1 on success, 0 if end of string is found and -1 on +parse error. Additionally, for the numeric/boolean read functions, 2 is returned +if the list element is empty. Also pa_message_param_read_string() reverts the +changes that pa_message_param_write_string() might have introduced. Reference: diff --git a/src/map-file b/src/map-file index 372d190d..ab8c21c6 100644 --- a/src/map-file +++ b/src/map-file @@ -228,10 +228,19 @@ pa_mainloop_wakeup; pa_message_param_begin_list; pa_message_param_end_list; pa_message_param_new; +pa_message_param_read_bool; +pa_message_param_read_double; +pa_message_param_read_int64; pa_message_param_read_string; +pa_message_param_read_uint64; pa_message_param_split_list; pa_message_param_to_string; +pa_message_param_write_bool; +pa_message_param_write_double; +pa_message_param_write_int64; +pa_message_param_write_raw; pa_message_param_write_string; +pa_message_param_write_uint64; pa_msleep; pa_operation_cancel; pa_operation_get_state; diff --git a/src/pulse/message-params.c b/src/pulse/message-params.c index c1abf62b..f4d2c048 100644 --- a/src/pulse/message-params.c +++ b/src/pulse/message-params.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <locale.h> #include <sys/types.h> #include <pulse/xmalloc.h> @@ -58,7 +59,7 @@ int pa_message_param_split_list(char *c, char **result, void **state) { /* Empty or no string */ if (!*current || *c == 0) - return 0; + return PA_PARAM_LIST_END; /* Find opening brace */ while (*current != 0) { @@ -75,7 +76,7 @@ int pa_message_param_split_list(char *c, char **result, void **state) { /* unexpected closing brace, parse error */ if (*current == '}' && !found_backslash) - return -1; + return PA_PARAM_PARSE_ERROR; found_backslash = false; current++; @@ -83,7 +84,7 @@ int pa_message_param_split_list(char *c, char **result, void **state) { /* No opening brace found, end of string */ if (*current == 0) - return 0; + return PA_PARAM_LIST_END; *result = current + 1; found_backslash = false; @@ -109,7 +110,7 @@ int pa_message_param_split_list(char *c, char **result, void **state) { /* Parse error, closing brace missing */ if (open_braces != 0) { *result = NULL; - return -1; + return PA_PARAM_PARSE_ERROR; } /* Replace } with 0 */ @@ -117,48 +118,154 @@ int pa_message_param_split_list(char *c, char **result, void **state) { *state = current + 1; - return 1; + return PA_PARAM_OK; } /* Read a string from the parameter list. The state pointer is - * advanced to the next element of the list Escaping is removed + * advanced to the next element of the list. Escaping is removed * from the string. */ int pa_message_param_read_string(char *c, char **result, void **state) { char *start_pos; + char *value, *tmp; int err; pa_assert(result); *result = NULL; - if ((err = pa_message_param_split_list(c, &start_pos, state)) > 0) - *result = pa_xstrdup(start_pos); + if ((err = pa_message_param_split_list(c, &start_pos, state)) != PA_PARAM_OK) + return err; - if (*result) { - char *value, *tmp; + *result = pa_xstrdup(start_pos); + value = *result; - value = *result; + /* Remove leading and trailing quotes if present */ + if (*value == '\'' && value[strlen(value) - 1] == '\'') { + memmove(value, value + 1, strlen(value)); + value[strlen(value) - 1] = 0; + } - /* Remove leading and trailing quotes if present */ - if (*value == '\'' && value[strlen(value) - 1] == '\'') { - memmove(value, value + 1, strlen(value)); - value[strlen(value) - 1] = 0; - } + /* Remove escape character from curly braces if present. */ + while ((tmp = strstr(value, "\\{"))) + memmove(tmp, tmp + 1, strlen(value) - (size_t)(tmp - value)); + while ((tmp = strstr(value, "\\}"))) + memmove(tmp, tmp + 1, strlen(value) - (size_t)(tmp - value)); + + /* Remove trailing 0's. */ + tmp = pa_xstrdup(value); + pa_xfree(value); + + *result = tmp; + + return PA_PARAM_OK; +} + +/* Read a double from the parameter list. The state pointer is + * advanced to the next element of the list. */ +int pa_message_param_read_double(char *c, double *result, void **state) { + char *start_pos, *s; + int err; + struct lconv *locale; + + pa_assert(result); - /* Remove escape character from curly braces if present. */ - while ((tmp = strstr(value, "\\{"))) - memmove(tmp, tmp + 1, strlen(value) - (size_t)(tmp - value)); - while ((tmp = strstr(value, "\\}"))) - memmove(tmp, tmp + 1, strlen(value) - (size_t)(tmp - value)); + *result = 0; - /* Remove trailing 0's. */ - tmp = pa_xstrdup(value); - pa_xfree(value); + if ((err = pa_message_param_split_list(c, &start_pos, state)) != PA_PARAM_OK) + return err; - *result = tmp; + /* Empty element */ + if (strlen(start_pos) == 0) + return PA_PARAM_IS_NULL; + + locale = localeconv(); + + /* Replace decimal point with the correct character for the + * current locale. This assumes that no thousand separator + * is used. */ + for (s = start_pos; *s; s++) { + if (*s == '.' || *s == ',') + *s = *locale->decimal_point; } - return err; + errno = 0; + *result = strtod(start_pos, NULL); + + if (errno != 0) + return PA_PARAM_PARSE_ERROR; + + return PA_PARAM_OK; +} + +/* Read an integer from the parameter list. The state pointer is + * advanced to the next element of the list. */ +int pa_message_param_read_int64(char *c, int64_t *result, void **state) { + char *start_pos; + int err; + + pa_assert(result); + + *result = 0; + + if ((err = pa_message_param_split_list(c, &start_pos, state)) != PA_PARAM_OK) + return err; + + /* Empty element */ + if (strlen(start_pos) == 0) + return PA_PARAM_IS_NULL; + + errno = 0; + *result = strtol(start_pos, NULL, 0); + + if (errno != 0) + return PA_PARAM_PARSE_ERROR; + + return PA_PARAM_OK; +} + +/* Read an unsigned integer from the parameter list. The state pointer is + * advanced to the next element of the list. */ +int pa_message_param_read_uint64(char *c, uint64_t *result, void **state) { + char *start_pos; + int err; + + pa_assert(result); + + *result = 0; + + if ((err = pa_message_param_split_list(c, &start_pos, state)) != PA_PARAM_OK) + return err; + + /* Empty element */ + if (strlen(start_pos) == 0) + return PA_PARAM_IS_NULL; + + errno = 0; + *result = strtoul(start_pos, NULL, 0); + + if (errno != 0) + return PA_PARAM_PARSE_ERROR; + + return PA_PARAM_OK; +} + +/* Read a boolean from the parameter list. The state pointer is + * advanced to the next element of the list. */ +int pa_message_param_read_bool(char *c, bool *result, void **state) { + int err; + uint64_t value; + + pa_assert(result); + + *result = false; + + if ((err = pa_message_param_read_uint64(c, &value, state)) != PA_PARAM_OK) + return err; + + if (value) + *result = true; + + return PA_PARAM_OK; } /* Write functions. The functions are wrapper functions around pa_strbuf, @@ -259,3 +366,55 @@ void pa_message_param_write_string(pa_message_param *param, const char *value, b pa_strbuf_puts(param->buffer, output); pa_xfree(output); } + +/* Writes a raw string to the pa_message_param structure. This is needed + * if a string cannot be written in one step. */ +void pa_message_param_write_raw(pa_message_param *param, const char *value) { + pa_assert(param); + + /* Null value is not written */ + if (!value) + return; + + pa_strbuf_puts(param->buffer, value); +} + +/* Writes a double to a message_param structure, adding curly braces. + * precision gives the number of significant digits, not digits after + * the decimal point. */ +void pa_message_param_write_double(pa_message_param *param, double value, int precision) { + + pa_assert(param); + + /* We do not care about locale because we do not know which locale is + * used on the server side. The decimal point character is converted + * to the server locale by the read function. */ + pa_strbuf_printf(param->buffer, "{%.*g}", precision, value); +} + +/* Writes an integer to a message_param structure, adding curly braces. */ +void pa_message_param_write_int64(pa_message_param *param, int64_t value) { + + pa_assert(param); + + pa_strbuf_printf(param->buffer, "{%li}", value); +} + +/* Writes an unsigned integer to a message_param structure, adding curly braces. */ +void pa_message_param_write_uint64(pa_message_param *param, uint64_t value) { + + pa_assert(param); + + pa_strbuf_printf(param->buffer, "{%lu}", value); +} + +/* Writes a boolean to a message_param structure, adding curly braces. */ +void pa_message_param_write_bool(pa_message_param *param, bool value) { + + pa_assert(param); + + if (value) + pa_strbuf_puts(param->buffer, "{1}"); + else + pa_strbuf_puts(param->buffer, "{0}"); +} diff --git a/src/pulse/message-params.h b/src/pulse/message-params.h index d24b4a54..80419965 100644 --- a/src/pulse/message-params.h +++ b/src/pulse/message-params.h @@ -32,6 +32,14 @@ PA_C_DECL_BEGIN typedef struct pa_message_param pa_message_param; +/* Read function return values */ +enum { + PA_PARAM_PARSE_ERROR = -1, + PA_PARAM_LIST_END = 0, + PA_PARAM_OK = 1, + PA_PARAM_IS_NULL = 2, +}; + /** Read functions */ /** Split message parameter string into list elements */ @@ -40,6 +48,18 @@ int pa_message_param_split_list(char *c, char **result, void **state); /** Read a string from the parameter list. */ int pa_message_param_read_string(char *c, char **result, void **state); +/** Read a double from the parameter list. */ +int pa_message_param_read_double(char *c, double *result, void **state); + +/** Read an integer from the parameter list. */ +int pa_message_param_read_int64(char *c, int64_t *result, void **state); + +/** Read an unsigned integer from the parameter list. */ +int pa_message_param_read_uint64(char *c, uint64_t *result, void **state); + +/** Read a boolean from the parameter list. */ +int pa_message_param_read_bool(char *c, bool *result, void **state); + /** Write functions */ /** Create a new pa_message_param structure */ @@ -57,6 +77,21 @@ void pa_message_param_end_list(pa_message_param *param); /** Append string to parameter list */ void pa_message_param_write_string(pa_message_param *param, const char *value, bool do_escape); +/** Append a double to parameter list */ +void pa_message_param_write_double(pa_message_param *param, double value, int precision); + +/** Append an integer to parameter list */ +void pa_message_param_write_int64(pa_message_param *param, int64_t value); + +/** Append an unsigned integer to parameter list */ +void pa_message_param_write_uint64(pa_message_param *param, uint64_t value); + +/** Append a boolean to parameter list */ +void pa_message_param_write_bool(pa_message_param *param, bool value); + +/** Append a raw string to parameter list */ +void pa_message_param_write_raw(pa_message_param *param, const char *value); + PA_C_DECL_END #endif -- 2.14.1