ucm: Improve cset command parsing

The cset command parsing in ucm/main.c assumes implicitly that the
argument contains no space, thus an example below wouldn't work:
    cset "name='Input Select' Digital Mic"

This patch introduces a new internal API function
__snd_ctl_ascii_elem_id_parse() to improve the cset parser.

Reported-by: Tanu Kaskinen <tanu.kaskinen@digia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2012-08-10 14:14:28 +02:00
parent c34f74c818
commit 58d10c09e1
2 changed files with 46 additions and 24 deletions

View file

@ -143,21 +143,19 @@ char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id)
return strdup(buf); return strdup(buf);
} }
/** #ifndef DOC_HIDDEN
* \brief parse ASCII string as CTL element identifier /* used by UCM parser, too */
* \param dst destination CTL identifier int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str,
* \param str source ASCII string const char **ret_ptr)
* \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)
{ {
int c, size, numid; int c, size, numid;
int err = -EINVAL;
char *ptr; char *ptr;
while (*str == ' ' || *str == '\t') while (isspace(*str))
str++; str++;
if (!(*str)) if (!(*str))
return -EINVAL; goto out;
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */ snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */
while (*str) { while (*str) {
if (!strncasecmp(str, "numid=", 6)) { 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); numid = atoi(str);
if (numid <= 0) { if (numid <= 0) {
fprintf(stderr, "amixer: Invalid numid %d\n", numid); fprintf(stderr, "amixer: Invalid numid %d\n", numid);
return -EINVAL; goto out;
} }
snd_ctl_elem_id_set_numid(dst, atoi(str)); snd_ctl_elem_id_set_numid(dst, atoi(str));
while (isdigit(*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); snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER);
str += 9; str += 9;
} else { } else {
return -EINVAL; goto out;
} }
} else if (!strncasecmp(str, "name=", 5)) { } else if (!strncasecmp(str, "name=", 5)) {
char buf[64]; 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 == ',') { if (*str == ',') {
str++; str++;
} else { } else {
/* when ret_ptr is given, allow to terminate gracefully
* at the next space letter
*/
if (ret_ptr && isspace(*str))
break;
if (*str) 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, static int get_ctl_enum_item_index(snd_ctl_t *handle,

View file

@ -31,6 +31,7 @@
*/ */
#include "ucm_local.h" #include "ucm_local.h"
#include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <pthread.h> #include <pthread.h>
@ -158,9 +159,13 @@ static int open_ctl(snd_use_case_mgr_t *uc_mgr,
return 0; 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) static int execute_cset(snd_ctl_t *ctl, char *cset)
{ {
char *pos; const char *pos;
int err; int err;
snd_ctl_elem_id_t *id; snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *value; 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_value_malloc(&value);
snd_ctl_elem_info_malloc(&info); snd_ctl_elem_info_malloc(&info);
pos = strrchr(cset, ' '); err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
if (pos == NULL) { if (err < 0)
goto __fail;
while (*pos && isspace(*pos))
pos++;
if (!*pos) {
uc_error("undefined value for cset >%s<", cset); uc_error("undefined value for cset >%s<", cset);
err = -EINVAL; err = -EINVAL;
goto __fail; 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_value_set_id(value, id);
snd_ctl_elem_info_set_id(info, id); snd_ctl_elem_info_set_id(info, id);
err = snd_ctl_elem_read(ctl, value); 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); err = snd_ctl_elem_info(ctl, info);
if (err < 0) if (err < 0)
goto __fail; 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) if (err < 0)
goto __fail; goto __fail;
err = snd_ctl_elem_write(ctl, value); err = snd_ctl_elem_write(ctl, value);
@ -196,9 +201,6 @@ static int execute_cset(snd_ctl_t *ctl, char *cset)
goto __fail; goto __fail;
err = 0; err = 0;
__fail: __fail:
if (pos != NULL)
*pos = ' ';
if (id != NULL) if (id != NULL)
free(id); free(id);
if (value != NULL) if (value != NULL)