cmdline: allow quoted strings
authorOlivier Matz <zer0@droids-corp.org>
Tue, 28 Dec 2010 22:49:35 +0000 (23:49 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Sun, 13 Mar 2011 10:03:24 +0000 (11:03 +0100)
Signed-off-by: Olivier Matz <zer0@droids-corp.org>
src/extension_example/parse_obj_list.c
src/genconf/parse_confnode.c
src/lib/cmdline.c
src/lib/cmdline_parse.c
src/lib/cmdline_parse.h
src/lib/cmdline_parse_etheraddr.c
src/lib/cmdline_parse_ipaddr.c
src/lib/cmdline_parse_num.c
src/lib/cmdline_parse_string.c

index 0781987..21fc019 100644 (file)
@@ -46,7 +46,7 @@ struct cmdline_token_ops token_obj_list_ops = {
        .get_help = get_help_obj_list,
 };
 
-int 
+int
 parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
 {
        struct token_obj_list *tk2 = (struct token_obj_list *)tk;
@@ -54,27 +54,21 @@ parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        struct object *o;
        unsigned int token_len = 0;
 
-       if (*buf == 0)
-               return -1;
-
-       while(!cmdline_isendoftoken(buf[token_len]))
-               token_len++;
+       token_len = strlen(buf);
 
        SLIST_FOREACH(o, tkd->list, next) {
-               if (token_len != strlen(o->name))
-                       continue;
-               if (strncmp(buf, o->name, token_len))
+               if (strcmp(buf, o->name))
                        continue;
                break;
        }
        if (!o) /* not found */
                return -1;
-        
+
        /* store the address of object in structure */
        if (res)
                *(struct object **)res = o;
 
-        return token_len;
+       return token_len;
 }
 
 int complete_get_nb_obj_list(cmdline_parse_token_hdr_t *tk)
@@ -90,7 +84,7 @@ int complete_get_nb_obj_list(cmdline_parse_token_hdr_t *tk)
        return ret;
 }
 
-int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, int idx, 
+int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, int idx,
                              char *dstbuf, unsigned int size)
 {
        struct token_obj_list *tk2 = (struct token_obj_list *)tk;
index b4da9dd..5c8202b 100644 (file)
@@ -142,20 +142,13 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        struct confnode *n;
        struct confnode_list l;
        unsigned int token_len = 0;
-       char token[BUFSIZ];
+       char token[CMDLINE_MAX_TOKEN_SIZE];
 
-       if (*buf == 0)
+       /* if token is too big... */
+       token_len = snprintf(token, sizeof(token), "%s", buf);
+       if (token_len >= sizeof(token))
                return -1;
 
-       while(!cmdline_isendoftoken(buf[token_len]))
-               token_len++;
-
-       if (token_len > sizeof(token) - 1)
-               return -1;
-
-       memcpy(token, buf, token_len);
-       token[token_len] = '\0';
-
        TAILQ_INIT(&l);
 
        /* absolute path */
@@ -181,7 +174,7 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        if (res)
                *(struct confnode **)res = TAILQ_FIRST(&l);
 
-        return token_len;
+       return token_len;
 }
 
 int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk)
index 9ad2bbe..d44e44b 100644 (file)
@@ -86,6 +86,8 @@ cmdline_valid_buffer(struct rdline *rdl, const char *buf,
                cmdline_printf(cl, "Command not found\n");
        else if (ret == CMDLINE_PARSE_BAD_ARGS)
                cmdline_printf(cl, "Bad arguments\n");
+       else if (ret == CMDLINE_PARSE_UNTERMINATED_QUOTE)
+               cmdline_printf(cl, "Unterminated quote\n");
 }
 
 static int
index 215077e..37ccc23 100644 (file)
@@ -64,6 +64,7 @@
 #include <inttypes.h>
 #include <ctype.h>
 #include <termios.h>
+#include <errno.h>
 
 #include <netinet/in.h>
 
@@ -123,6 +124,77 @@ nb_common_chars(const char * s1, const char * s2)
        return i;
 }
 
+/* quote a string and escape original quotes */
+int cmdline_quote_token(char *dst, unsigned dstlen, const char *src)
+{
+       unsigned s = 0, d = 0;
+
+       /* the 2 quotes + '\0' */
+       if (dstlen < 3)
+               return -EMSGSIZE;
+
+       dst[d++] = '"';
+       while (src[s] != '\0') {
+               if (d >= (dstlen-2))
+                       return -EMSGSIZE;
+
+               if (src[s] == '"')
+                       dst[d++] = '\\';
+               if (src[s] == '\\' && src[s+1] == '"')
+                       dst[d++] = '\\';
+
+               dst[d++] = src[s++];
+       }
+
+       if (d >= (dstlen-2))
+               return -EMSGSIZE;
+       dst[d++] = '"';
+       dst[d++] = '\0';
+       return s;
+}
+
+/* remove quote and stop when we reach the end of token */
+// XXX ret val comment
+int cmdline_unquote_token(char *dst, unsigned dstlen,
+                         const char *src)
+{
+       unsigned s = 0, d = 0;
+       int quoted = 0;
+
+       while (src[s] != '\0') {
+               if (d >= dstlen)
+                       return -EMSGSIZE;
+
+               if (cmdline_isendoftoken(src[s]) && quoted == 0)
+                       break;
+
+               if (src[s] == '\\' && src[s+1] == '"') {
+                       dst[d++] = '"';
+                       s += 2;
+                       continue;
+               }
+               if (src[s] == '\\' && src[s+1] == '\\') {
+                       dst[d++] = '\\';
+                       s += 2;
+                       continue;
+               }
+               if (src[s] == '"') {
+                       s++;
+                       quoted = !quoted;
+                       continue;
+               }
+               dst[d++] = src[s++];
+       }
+
+       if (quoted)
+               return -EINVAL;
+
+       if (d >= (dstlen-1))
+               return -EMSGSIZE;
+       dst[d++] = '\0';
+       return  s;
+}
+
 /**
  * try to match the buffer with an instruction (only the first
  * nb_match_token tokens if != 0). Return 0 if we match all the
@@ -135,8 +207,9 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,
        unsigned int token_num=0;
        cmdline_parse_token_hdr_t * token_p;
        unsigned int i=0;
-       int n = 0;
+       int n = 0, res;
        struct cmdline_token_hdr token_hdr;
+       char token_str[128];
 
        token_p = inst->tokens[token_num];
        if (token_p)
@@ -154,14 +227,17 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,
                if ( isendofline(*buf) || iscomment(*buf) )
                        break;
 
+               n = cmdline_unquote_token(token_str, sizeof(token_str), buf);
+               if (n == -EINVAL)
+                       return -EINVAL;
+
                if (result_buf)
-                       n = token_hdr.ops->parse(token_p, buf,
+                       res = token_hdr.ops->parse(token_p, token_str,
                                                 (char *)result_buf +
                                                 token_hdr.offset);
                else
-                       n = token_hdr.ops->parse(token_p, buf, NULL);
-
-               if (n < 0)
+                       res = token_hdr.ops->parse(token_p, token_str, NULL);
+               if (res < 0)
                        break;
 
                debug_printf("TK parsed (len=%d)\n", n);
@@ -176,7 +252,7 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,
 
        /* does not match */
        if (i==0)
-               return -1;
+               return -ENOENT;
 
        /* in case we want to match a specific num of token */
        if (nb_match_token) {
@@ -294,6 +370,12 @@ cmdline_parse(struct cmdline *cl, const char * buf)
                                }
                        }
                }
+               else if (tok == -EINVAL) {
+                       err = CMDLINE_PARSE_UNTERMINATED_QUOTE;
+                       f = NULL;
+                       debug_printf("Unterminated quote\n");
+                       break;
+               }
 
                inst_num ++;
                inst = ctx[inst_num];
index 30fe8e9..146f15c 100644 (file)
 #define CMDLINE_PARSE_AMBIGUOUS     -1
 #define CMDLINE_PARSE_NOMATCH       -2
 #define CMDLINE_PARSE_BAD_ARGS      -3
+#define CMDLINE_PARSE_UNTERMINATED_QUOTE -4
 
 /* return status for completion */
 #define CMDLINE_PARSE_COMPLETE_FINISHED 0
 #define CMDLINE_PARSE_COMPLETE_AGAIN    1
 #define CMDLINE_PARSE_COMPLETED_BUFFER  2
 
+#define CMDLINE_MAX_TOKEN_SIZE 128 /* including '\0' */
+
 /**
  * Stores a pointer to the ops struct, and the offset: the place to
  * write the parsed result in the destination structure.
@@ -178,4 +181,10 @@ int cmdline_complete(struct cmdline *cl, const char *buf, int *state,
  * isendofline(c)) */
 int cmdline_isendoftoken(char c);
 
+/* quote a string and escape original quotes */
+int cmdline_quote_token(char *dst, unsigned dstlen, const char *src);
+
+/* remove quote and stop when we reach the end of token */
+int cmdline_unquote_token(char *dst, unsigned dstlen, const char *src);
+
 #endif /* _CMDLINE_PARSE_H_ */
index 2cefc62..e0528c5 100644 (file)
@@ -117,18 +117,11 @@ cmdline_parse_etheraddr(__attribute__((unused)) cmdline_parse_token_hdr_t *tk,
        struct ether_addr *etheraddr = res;
        struct ether_addr *tmp;
 
-       if (! *buf)
-               return -1;
-
-       while (!cmdline_isendoftoken(buf[token_len]))
-               token_len++;
-
        /* if token is too big... */
-       if (token_len >= ETHER_ADDRSTRLEN)
+       token_len = snprintf(ether_str, sizeof(ether_str), "%s", buf);
+       if (token_len >= sizeof(ether_str))
                return -1;
 
-       snprintf(ether_str, token_len+1, "%s", buf);
-
        tmp = my_ether_aton(ether_str);
        if (tmp == NULL)
                return -1;
index 276d644..37b2f3b 100644 (file)
@@ -299,18 +299,11 @@ cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        char *prefix, *prefix_end;
        long prefixlen;
 
-       if (! *buf)
-               return -1;
-
-       while (!cmdline_isendoftoken(buf[token_len]))
-               token_len++;
-
        /* if token is too big... */
-       if (token_len >= INET6_ADDRSTRLEN+4)
+       token_len = snprintf(ip_str, sizeof(ip_str), "%s", buf);
+       if (token_len >= sizeof(ip_str))
                return -1;
 
-       snprintf(ip_str, token_len+1, "%s", buf);
-
        /* convert the network prefix */
        if (tk2->ipaddr_data.flags & CMDLINE_IPADDR_NETWORK) {
                prefix = strrchr(ip_str, '/');
index f6eeb8b..cd3ca1e 100644 (file)
@@ -137,7 +137,7 @@ cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res)
 
        memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
 
-       while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
+       while (st != ERROR && c != '\0') {
                debug_printf("%c %x -> ", c, c);
                switch (st) {
                case START:
index f8fd44b..775024c 100644 (file)
@@ -102,60 +102,51 @@ get_next_token(const char *s)
        return NULL;
 }
 
+static int parse_fixed_string(struct cmdline_token_string_data *sd,
+                             const char *buf, unsigned token_len)
+{
+       unsigned int conf_token_len;
+       const char *str;
+
+       str = sd->str;
+       for (str = sd->str; str != NULL ; str = get_next_token(str)) {
+
+               conf_token_len = get_token_len(str);
+
+               /* if token from config is too big... */
+               if (conf_token_len >= STR_TOKEN_SIZE - 1)
+                       continue;
+
+               /* compare conf token and user token */
+               if (token_len == conf_token_len &&
+                   strncmp(buf, str, token_len) == 0)
+                       return 0;
+       }
+
+       return -1;
+}
+
 int
 cmdline_parse_string(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
 {
        struct cmdline_token_string *tk2 = (struct cmdline_token_string *)tk;
        struct cmdline_token_string_data *sd = &tk2->string_data;;
        unsigned int token_len;
-       const char *str;
 
-       if (! *buf)
+       token_len = strlen(buf);
+
+       if (token_len >= (STR_TOKEN_SIZE - 1) || token_len == 0)
                return -1;
 
        /* fixed string */
        if (sd->str) {
-               str = sd->str;
-               do {
-                       token_len = get_token_len(str);
-
-                       /* if token is too big... */
-                       if (token_len >= STR_TOKEN_SIZE - 1) {
-                               continue;
-                       }
-
-                       if ( strncmp(buf, str, token_len) ) {
-                               continue;
-                       }
-
-                       if ( !cmdline_isendoftoken(*(buf+token_len)) ) {
-                               continue;
-                       }
-
-                       break;
-               } while ( (str = get_next_token(str)) != NULL );
-
-               if (!str)
+               if (parse_fixed_string(sd, buf, token_len) < 0)
                        return -1;
        }
-       /* unspecified string */
-       else {
-               token_len=0;
-               while(!cmdline_isendoftoken(buf[token_len]) &&
-                     token_len < (STR_TOKEN_SIZE-1))
-                       token_len++;
-
-               /* return if token too long */
-               if (token_len >= STR_TOKEN_SIZE - 1) {
-                       return -1;
-               }
-       }
 
-       if (res) {
-               /* we are sure that token_len is < STR_TOKEN_SIZE-1 */
-               strncpy(res, buf, token_len);
-               *((char *)res + token_len) = 0;
-       }
+       /* we already checked that token_len is < STR_TOKEN_SIZE-1 */
+       if (res)
+               strcpy(res, buf);
 
        return token_len;
 }