OSDN Git Service

ucm: Improve cset command parsing
authorTakashi Iwai <tiwai@suse.de>
Fri, 10 Aug 2012 12:14:28 +0000 (14:14 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 10 Aug 2012 12:14:28 +0000 (14:14 +0200)
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>
src/control/ctlparse.c
src/ucm/main.c

index a16f96a..b0c4ef3 100644 (file)
@@ -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,
index 4b37776..bd5c348 100644 (file)
@@ -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)