+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
/*
* Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
* All rights reserved.
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
+#include <termios.h>
+#include <errno.h>
#include <netinet/in.h>
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
* tokens, else the number of matched tokens, else -1.
*/
static int
-match_inst(cmdline_parse_inst_t *inst, const char *buf, unsigned int nb_match_token,
- void * result_buf)
+match_inst(cmdline_parse_inst_t *inst, const char *buf,
+ unsigned int nb_match_token, void *resbuf, unsigned resbuf_size)
{
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)
if ( isendofline(*buf) || iscomment(*buf) )
break;
- n = token_hdr.ops->parse(token_p, buf, (result_buf ? result_buf+token_hdr.offset : NULL));
- if ( n < 0 )
+ n = cmdline_unquote_token(token_str, sizeof(token_str), buf);
+ if (n == -EINVAL)
+ return -EINVAL;
+
+ if (resbuf == NULL)
+ res = token_hdr.ops->parse(token_p, token_str, NULL, 0);
+ else {
+ unsigned rb_sz;
+ void *rb = (char *)resbuf + token_hdr.offset;
+ if (token_hdr.offset > resbuf_size)
+ return -ENOBUFS;
+ rb_sz = resbuf_size - token_hdr.offset;
+ res = token_hdr.ops->parse(token_p, token_str,
+ rb, rb_sz);
+ }
+
+ if (res < 0)
break;
+
debug_printf("TK parsed (len=%d)\n", n);
i++;
buf += n;
/* 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) {
unsigned int inst_num=0;
cmdline_parse_inst_t *inst;
const char *curbuf;
- char result_buf[BUFSIZ]; /* XXX align, size zé in broblém */
+ char result_buf[CMDLINE_MAX_DSTBUF_SIZE];
void (*f)(void *, struct cmdline *, void *) = NULL;
void *data = NULL;
int comment = 0;
debug_printf("INST %d\n", inst_num);
/* fully parsed */
- tok = match_inst(inst, buf, 0, result_buf);
+ tok = match_inst(inst, buf, 0, result_buf, sizeof(result_buf));
if (tok > 0) /* we matched at least one token */
err = CMDLINE_PARSE_BAD_ARGS;
}
}
}
+ else if (tok == -EINVAL) {
+ err = CMDLINE_PARSE_UNTERMINATED_QUOTE;
+ f = NULL;
+ debug_printf("Unterminated quote\n");
+ break;
+ }
inst_num ++;
inst = ctx[inst_num];
cmdline_complete(struct cmdline *cl, const char *buf, int *state,
char *dst, unsigned int size)
{
- const char *incomplete_token = buf;
+ const char *partial_tok = buf;
unsigned int inst_num = 0;
cmdline_parse_inst_t *inst;
cmdline_parse_token_hdr_t *token_p;
struct cmdline_token_hdr token_hdr;
- char tmpbuf[64], completion_buf[64];
- unsigned int incomplete_token_len;
- int completion_len = -1;
+ char tmpbuf[64], comp_buf[64];
+ unsigned int partial_tok_len;
+ int comp_len = -1;
int nb_token = 0;
unsigned int i, n;
int l;
unsigned int nb_completable;
unsigned int nb_non_completable;
- unsigned int local_state=0;
+ int local_state = 0;
char *help_str;
cmdline_parse_ctx_t *ctx = cl->ctx;
debug_printf("%s called\n", __FUNCTION__);
+ memset(&token_hdr, 0, sizeof(token_hdr));
+
/* count the number of complete token to parse */
for (i=0 ; buf[i] ; i++) {
if (!isblank2(buf[i]) && isblank2(buf[i+1]))
nb_token++;
if (isblank2(buf[i]) && !isblank2(buf[i+1]))
- incomplete_token = buf+i+1;
+ partial_tok = buf+i+1;
}
- incomplete_token_len = strlen(incomplete_token);
+ partial_tok_len = strlen(partial_tok);
/* first call -> do a first pass */
if (*state <= 0) {
debug_printf("try complete <%s>\n", buf);
- debug_printf("there is %d complete tokens, <%s> is incomplete\n", nb_token, incomplete_token);
+ debug_printf("there is %d complete tokens, <%s> is incomplete\n",
+ nb_token, partial_tok);
nb_completable = 0;
nb_non_completable = 0;
inst = ctx[inst_num];
while (inst) {
/* parse the first tokens of the inst */
- if (nb_token && match_inst(inst, buf, nb_token, NULL))
+ if (nb_token && match_inst(inst, buf, nb_token, NULL, 0))
goto next;
debug_printf("instruction match \n");
debug_printf("%d choices for this token\n", n);
for (i=0 ; i<n ; i++) {
- if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf, sizeof(tmpbuf)) < 0)
+ if (token_hdr.ops->complete_get_elt(token_p, i,
+ tmpbuf,
+ sizeof(tmpbuf)) < 0)
continue;
- strcat(tmpbuf, " "); /* we have at least room for one char */
+
+ /* we have at least room for one char */
+ strcat(tmpbuf, " ");
+
debug_printf(" choice <%s>\n", tmpbuf);
- /* does the completion match the beginning of the word ? */
- if (!strncmp(incomplete_token, tmpbuf, incomplete_token_len)) {
- if (completion_len == -1) {
- strcpy(completion_buf, tmpbuf+incomplete_token_len);
- completion_len = strlen(tmpbuf+incomplete_token_len);
+
+ /* does the completion match the
+ * beginning of the word ? */
+ if (!strncmp(partial_tok, tmpbuf,
+ partial_tok_len)) {
+ if (comp_len == -1) {
+ strcpy(comp_buf,
+ tmpbuf + partial_tok_len);
+ comp_len =
+ strlen(tmpbuf +
+ partial_tok_len);
}
else {
- completion_len = nb_common_chars(completion_buf,
- tmpbuf+incomplete_token_len);
- completion_buf[completion_len] = 0;
+ comp_len =
+ nb_common_chars(comp_buf,
+ tmpbuf+partial_tok_len);
+ comp_buf[comp_len] = 0;
}
nb_completable++;
}
inst = ctx[inst_num];
}
- debug_printf("total choices %d for this completion\n", nb_completable);
+ debug_printf("total choices %d for this completion\n",
+ nb_completable);
/* no possible completion */
if (nb_completable == 0 && nb_non_completable == 0)
return 0;
/* if multichoice is not required */
- if (*state == 0 && incomplete_token_len > 0) {
+ if (*state == 0 && partial_tok_len > 0) {
/* one or several choices starting with the
same chars */
- if (completion_len > 0) {
- if (completion_len + 1 > size)
+ if (comp_len > 0) {
+ if ((unsigned)(comp_len + 1) > size)
return 0;
- strcpy(dst, completion_buf);
+ strcpy(dst, comp_buf);
return 2;
}
}
/* we need to redo it */
inst = ctx[inst_num];
- if (nb_token && match_inst(inst, buf, nb_token, NULL))
+ if (nb_token && match_inst(inst, buf, nb_token, NULL, 0))
goto next2;
token_p = inst->tokens[nb_token];
}
(*state)++;
if (token_p && token_hdr.ops->get_help) {
- token_hdr.ops->get_help(token_p, tmpbuf, sizeof(tmpbuf));
+ token_hdr.ops->get_help(token_p, tmpbuf,
+ sizeof(tmpbuf));
help_str = inst->help_str;
if (help_str)
- snprintf(dst, size, "[%s]: %s", tmpbuf, help_str);
+ snprintf(dst, size, "[%s]: %s", tmpbuf,
+ help_str);
else
- snprintf(dst, size, "[%s]: No help", tmpbuf);
+ snprintf(dst, size, "[%s]: No help",
+ tmpbuf);
}
else {
snprintf(dst, size, "[RETURN]");
/* several choices */
for (i=0 ; i<n ; i++) {
- if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf, sizeof(tmpbuf)) < 0)
+ if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf,
+ sizeof(tmpbuf)) < 0)
continue;
- strcat(tmpbuf, " "); /* we have at least room for one char */
+ /* we have at least room for one char */
+ strcat(tmpbuf, " ");
+
debug_printf(" choice <%s>\n", tmpbuf);
- /* does the completion match the beginning of the word ? */
- if (!strncmp(incomplete_token, tmpbuf, incomplete_token_len)) {
+
+ /* does the completion match the beginning of
+ * the word ? */
+ if (!strncmp(partial_tok, tmpbuf,
+ partial_tok_len)) {
if (local_state < *state) {
local_state++;
continue;
(*state)++;
l=snprintf(dst, size, "%s", tmpbuf);
if (l>=0 && token_hdr.ops->get_help) {
- token_hdr.ops->get_help(token_p, tmpbuf, sizeof(tmpbuf));
+ token_hdr.ops->get_help(token_p, tmpbuf,
+ sizeof(tmpbuf));
help_str = inst->help_str;
if (help_str)
- snprintf(dst+l, size-l, "[%s]: %s", tmpbuf, help_str);
+ snprintf(dst+l, size-l, "[%s]: %s",
+ tmpbuf, help_str);
else
- snprintf(dst+l, size-l, "[%s]: No help", tmpbuf);
+ snprintf(dst+l, size-l,
+ "[%s]: No help", tmpbuf);
}
return 1;