[alsa-devel] [PATCH] ucm: Allow cset commands to have values with spaces.
An example: cset "name='Input Select' Digital Mic"
The old parsing code interpreted "name='Input Select' Digital" as the element id, which of course didn't work.
Signed-off-by: Tanu Kaskinen tanu.kaskinen@digia.com --- src/ucm/main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/ucm/main.c b/src/ucm/main.c index 4b37776..05a7b0a 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -170,8 +170,23 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' '); - if (pos == NULL) { + /* Find the space after the element id, taking quoting with + single-quotes into account. */ + for (pos = cset; *pos != '\0'; pos += strcspn(pos, "' ")) { + if (*pos == ' ') + break; + if (*pos == ''') { + pos++; + pos += strcspn(pos, "'"); + if (*pos == '\0') { + uc_error("invalid element id (closing single-quote not found): %s", cset); + err = -EINVAL; + goto __fail; + } + pos++; + } + } + if (*pos == '\0') { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail;
At Thu, 9 Aug 2012 16:43:31 +0300, Tanu Kaskinen wrote:
An example: cset "name='Input Select' Digital Mic"
The old parsing code interpreted "name='Input Select' Digital" as the element id, which of course didn't work.
Signed-off-by: Tanu Kaskinen tanu.kaskinen@digia.com
src/ucm/main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/ucm/main.c b/src/ucm/main.c index 4b37776..05a7b0a 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -170,8 +170,23 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' ');
- if (pos == NULL) {
- /* Find the space after the element id, taking quoting with
single-quotes into account. */
- for (pos = cset; *pos != '\0'; pos += strcspn(pos, "' ")) {
if (*pos == ' ')
break;
if (*pos == '\'') {
A double-quote can be supported easily here...
Takashi
pos++;
pos += strcspn(pos, "'");
if (*pos == '\0') {
uc_error("invalid element id (closing single-quote not found): %s", cset);
err = -EINVAL;
goto __fail;
}
pos++;
}
- }
- if (*pos == '\0') { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail;
-- 1.7.9.5
On Thu, 2012-08-09 at 16:07 +0200, Takashi Iwai wrote:
At Thu, 9 Aug 2012 16:43:31 +0300, Tanu Kaskinen wrote:
@@ -170,8 +170,23 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' ');
- if (pos == NULL) {
- /* Find the space after the element id, taking quoting with
single-quotes into account. */
- for (pos = cset; *pos != '\0'; pos += strcspn(pos, "' ")) {
if (*pos == ' ')
break;
if (*pos == '\'') {
A double-quote can be supported easily here...
True, I'll post v2 soon.
At Thu, 9 Aug 2012 17:44:12 +0300, Kaskinen Tanu wrote:
On Thu, 2012-08-09 at 16:07 +0200, Takashi Iwai wrote:
At Thu, 9 Aug 2012 16:43:31 +0300, Tanu Kaskinen wrote:
@@ -170,8 +170,23 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' ');
- if (pos == NULL) {
- /* Find the space after the element id, taking quoting with
single-quotes into account. */
- for (pos = cset; *pos != '\0'; pos += strcspn(pos, "' ")) {
if (*pos == ' ')
break;
if (*pos == '\'') {
A double-quote can be supported easily here...
True, I'll post v2 soon.
On the second thought, parsing the string intensively at that point doesn't make sense. The string will be parsed anyway in snd_ctl_ascii_elem_id_parse(), then why not just let it give the next pointer from there?
Below is a quick hack (untested at all!). Could you check whether it works?
Takashi
--- diff --git a/src/control/ctlparse.c b/src/control/ctlparse.c index a16f96a..b0c4ef3 100644 --- a/src/control/ctlparse.c +++ b/src/control/ctlparse.c @@ -143,21 +143,19 @@ char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id) return strdup(buf); }
-/** - * \brief parse ASCII string as CTL element identifier - * \param dst destination CTL identifier - * \param str source ASCII string - * \return zero on success, otherwise a negative error code - */ -int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) +#ifndef DOC_HIDDEN +/* used by UCM parser, too */ +int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, + const char **ret_ptr) { int c, size, numid; + int err = -EINVAL; char *ptr;
- while (*str == ' ' || *str == '\t') + while (isspace(*str)) str++; if (!(*str)) - return -EINVAL; + goto out; snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */ while (*str) { if (!strncasecmp(str, "numid=", 6)) { @@ -165,7 +163,7 @@ int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) numid = atoi(str); if (numid <= 0) { fprintf(stderr, "amixer: Invalid numid %d\n", numid); - return -EINVAL; + goto out; } snd_ctl_elem_id_set_numid(dst, atoi(str)); while (isdigit(*str)) @@ -191,7 +189,7 @@ int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER); str += 9; } else { - return -EINVAL; + goto out; } } else if (!strncasecmp(str, "name=", 5)) { char buf[64]; @@ -239,11 +237,33 @@ int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) if (*str == ',') { str++; } else { + /* when ret_ptr is given, allow to terminate gracefully + * at the next space letter + */ + if (ret_ptr && isspace(*str)) + break; if (*str) - return -EINVAL; + goto out; } } - return 0; + err = 0; + + out: + if (ret_ptr) + *ret_ptr = str; + return err; +} +#endif + +/** + * \brief parse ASCII string as CTL element identifier + * \param dst destination CTL identifier + * \param str source ASCII string + * \return zero on success, otherwise a negative error code + */ +int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) +{ + return __snd_ctl_ascii_elem_id_parse(dst, str, NULL); }
static int get_ctl_enum_item_index(snd_ctl_t *handle, diff --git a/src/ucm/main.c b/src/ucm/main.c index 4b37776..bd5c348 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -31,6 +31,7 @@ */
#include "ucm_local.h" +#include <ctype.h> #include <stdarg.h> #include <pthread.h>
@@ -158,9 +159,13 @@ static int open_ctl(snd_use_case_mgr_t *uc_mgr, return 0; }
+extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, + const char *str, + const char **ret_ptr); + static int execute_cset(snd_ctl_t *ctl, char *cset) { - char *pos; + const char *pos; int err; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *value; @@ -170,16 +175,16 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' '); - if (pos == NULL) { + err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); + if (err < 0) + goto __fail; + while (*pos && isspace(*pos)) + pos++; + if (!*pos) { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail; } - *pos = '\0'; - err = snd_ctl_ascii_elem_id_parse(id, cset); - if (err < 0) - goto __fail; snd_ctl_elem_value_set_id(value, id); snd_ctl_elem_info_set_id(info, id); err = snd_ctl_elem_read(ctl, value); @@ -188,7 +193,7 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) err = snd_ctl_elem_info(ctl, info); if (err < 0) goto __fail; - err = snd_ctl_ascii_value_parse(ctl, value, info, pos + 1); + err = snd_ctl_ascii_value_parse(ctl, value, info, pos); if (err < 0) goto __fail; err = snd_ctl_elem_write(ctl, value); @@ -196,9 +201,6 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) goto __fail; err = 0; __fail: - if (pos != NULL) - *pos = ' '; - if (id != NULL) free(id); if (value != NULL)
On Thu, 2012-08-09 at 17:12 +0200, Takashi Iwai wrote:
At Thu, 9 Aug 2012 17:44:12 +0300, Kaskinen Tanu wrote:
On Thu, 2012-08-09 at 16:07 +0200, Takashi Iwai wrote:
At Thu, 9 Aug 2012 16:43:31 +0300, Tanu Kaskinen wrote:
@@ -170,8 +170,23 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' ');
- if (pos == NULL) {
- /* Find the space after the element id, taking quoting with
single-quotes into account. */
- for (pos = cset; *pos != '\0'; pos += strcspn(pos, "' ")) {
if (*pos == ' ')
break;
if (*pos == '\'') {
A double-quote can be supported easily here...
True, I'll post v2 soon.
On the second thought, parsing the string intensively at that point doesn't make sense. The string will be parsed anyway in snd_ctl_ascii_elem_id_parse(), then why not just let it give the next pointer from there?
Below is a quick hack (untested at all!). Could you check whether it works?
It does :)
An example: cset "name='Input Select' Digital Mic"
The old parsing code interpreted "name='Input Select' Digital" as the element id, which of course didn't work.
Signed-off-by: Tanu Kaskinen tanu.kaskinen@digia.com --- src/ucm/main.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/ucm/main.c b/src/ucm/main.c index 4b37776..518349a 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -162,6 +162,7 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) { char *pos; int err; + int nulled = 0; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *value; snd_ctl_elem_info_t *info; @@ -170,13 +171,28 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info);
- pos = strrchr(cset, ' '); - if (pos == NULL) { + /* Find the space after the element id, taking quoting into account. */ + for (pos = cset; *pos != ' ' && *pos != '\0'; pos += strcspn(pos, " '"")) { + if (*pos == ''' || *pos == '"') { + char quote = *pos; + + pos++; + pos = strchr(pos, quote); + if (pos == NULL) { + uc_error("invalid element id (closing quote not found): %s", cset); + err = -EINVAL; + goto __fail; + } + pos++; + } + } + if (*pos == '\0') { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail; } *pos = '\0'; + nulled = 1; err = snd_ctl_ascii_elem_id_parse(id, cset); if (err < 0) goto __fail; @@ -196,7 +212,7 @@ static int execute_cset(snd_ctl_t *ctl, char *cset) goto __fail; err = 0; __fail: - if (pos != NULL) + if (nulled) *pos = ' ';
if (id != NULL)
participants (3)
-
Kaskinen Tanu
-
Takashi Iwai
-
Tanu Kaskinen