]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/cli.c
Rename getenv() to getenv_char()
[z180-stamp.git] / avr / cli.c
index 08e70387df9f7e5518c7e6efc08904f284658a03..8763ed1dff7a775c59af2522ed29d0e2ed5ec4a2 100644 (file)
--- a/avr/cli.c
+++ b/avr/cli.c
@@ -1,3 +1,16 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
 #include "common.h"
 
 #include <string.h>
@@ -14,6 +27,9 @@
 #include "con-utils.h"
 #include "cli.h"
 
+
+/* FIXME: Quoting problems */
+
 #define DEBUG_PARSER   0       /* set to 1 to debug */
 
 #define debug_parser(fmt, args...)             \
 
 static int cli_parse_line(char *line, char *argv[])
 {
-       static const FLASH char delim[] = {" \t"};
-
-       char *ptr;
+       uint_fast8_t state = 0;
        uint_fast8_t nargs = 0;
+       char *inp, *outp;
+       char c, quote;
+
+       debug_parser("%s: \"%s\"\n", __func__, line);
+
+       for (outp = inp = line, quote = '\0'; (c = *inp) != '\0'; inp++) {
+
+               switch (state) {
+               case 0:                                         /* before arg string, waiting for arg start */
+                       if (isblank(c))
+                               continue;
+
+                       argv[nargs++] = inp;    /* begin of argument string     */
+                       outp = inp;
+                       state = 1;
+                       /* fall thru */
+
+               case 1:                                         /* in arg string, waiting for end of arg string */
+                       if (c == '\\') {
+                               ++state;
+                               continue;
+                       }
+                       if (c == '\"' || c == '\'') {
+                               quote = c;
+                               state = 3;
+                               continue;
+                       }
+                       if (isblank(c)) {
+                               c = '\0';
+                               state = 0;
+                       }
+                       break;
 
-       debug_parser("parse_line: \"%s\"\n", line);
+               case 3:                                         /* in quote */
+                       if (c == '\\' && quote == '\"') {
+                               ++state;
+                               continue;
+                       }
+                       if (c == quote) {
+                               state = 1;
+                               continue;
+                       }
+                       break;
+
+               case 2:                                         /* waiting for next char */
+               case 4:
+                       --state;
+                       break;
+
+               }
 
-       ptr = strtok_P(line, delim);
-       while(nargs < CONFIG_SYS_MAXARGS && ptr != NULL) {
-               argv[nargs++] = ptr;
-               ptr = strtok_P(NULL, delim);
+               if (nargs > CONFIG_SYS_MAXARGS) {
+                       --nargs;
+                       break;
+               }
+               *outp++ = c;
        }
 
-       if (ptr != NULL)
+       if (*inp != '\0')
                printf_P(PSTR("** Too many args (max. %d) **\n"), CONFIG_SYS_MAXARGS);
 
+       *outp = '\0';
        argv[nargs] = NULL;
-       debug_parser("parse_line: nargs=%d\n", nargs);
-
+       debug_parser("%s: nargs=%d\n", __func__, nargs);
+#if 0
+       for (int i = 0; i < nargs; i++)
+               debug_parser("%s: arg %d: >%s<\n", __func__, i, argv[i]);
+#endif
        return nargs;
+
 }
 
-static void process_macros(const char *input, char *output)
+static
+void append_char(uint_fast8_t pass, char **p, char c)
 {
-       char c, prev;
-       const char *varname_start = NULL;
-#if 0 && (CONFIG_SYS_CBSIZE < __UINT_FAST8_MAX__)
-       uint_fast8_t inputcnt = strlen(input);
-       uint_fast8_t outputcnt = CONFIG_SYS_CBSIZE;
-#else
-       int inputcnt = strlen(input);
-       int outputcnt = CONFIG_SYS_CBSIZE;
-#endif
-       uint_fast8_t state = 0;         /* 0 = waiting for '$'  */
 
-       /* 1 = waiting for '{' */
-       /* 2 = waiting for '}' */
-       /* 3 = waiting for '''  */
-       char *output_start = output;
+       if (pass) {
+               **p = c;
+       }
+       ++(*p);
+}
 
-       debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input),
-                    input);
+static
+char *process_macros(char *input, char *output)
+{
+       char c, prev, *inp, *outp;
+       const char *varname = NULL;
+
+       for(uint_fast8_t pass = 0; pass < 2; pass++)
+       {
+               uint_fast8_t state = 0;
+               /* 0 = waiting for '$'  */
+               /* 1 = waiting for '{' */
+               /* 2 = waiting for '}' */
+               /* 3 = waiting for ''' */
+
+               if (pass == 0) {
+                       outp = output;
+               } else {
+                       int outputlen = outp - output;
+                       outp = xrealloc(output, outputlen);
+                       output = outp;
+               }
 
-       prev = '\0';            /* previous character   */
+               inp = input;
 
-       while (inputcnt && outputcnt) {
-               c = *input++;
-               inputcnt--;
+               debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n",
+                                               strlen(inp), inp);
 
-               if (state != 3) {
-                       /* remove one level of escape characters */
-                       if ((c == '\\') && (prev != '\\')) {
-                               if (inputcnt-- == 0)
-                                       break;
-                               prev = c;
-                               c = *input++;
-                       }
-               }
+               for (prev = '\0'; (c = *inp++) != '\0'; prev = c) {
 
-               switch (state) {
-               case 0: /* Waiting for (unescaped) $    */
-                       if ((c == '\'') && (prev != '\\')) {
-                               state = 3;
-                               break;
-                       }
-                       if ((c == '$') && (prev != '\\')) {
-                               state++;
-                       } else {
-                               *(output++) = c;
-                               outputcnt--;
-                       }
-                       break;
-               case 1: /* Waiting for (        */
-                       if (c == '{') {
-                               state++;
-                               varname_start = input;
-                       } else {
-                               state = 0;
-                               *(output++) = '$';
-                               outputcnt--;
 
-                               if (outputcnt) {
-                                       *(output++) = c;
-                                       outputcnt--;
+
+                       switch (state) {
+                       case 0: /* Waiting for (unescaped) $    */
+                               if ((c == '\'') && (prev != '\\')) {
+                                       state = 3;
+                                       break;
                                }
+                               if ((c == '$') && (prev != '\\')) {
+                                       state++;
+                                       continue;
+                               }
+                               break;
+                       case 1: /* Waiting for {        */
+                               if (c == '{') {
+                                       state++;
+                                       varname = inp;
+                                       continue;
+                               } else {
+                                       state = 0;
+                                       append_char(pass, &outp, '$');
+                               }
+                               break;
+                       case 2: /* Waiting for }        */
+                               if (c == '}') {
+                                       /* Terminate variable name */
+                                       *(inp-1) = '\0';
+                                       const char *envval = getenv_char(varname);
+                                       *(inp-1) = '}';
+                                       /* Copy into the line if it exists */
+                                       if (envval != NULL)
+                                               while (*envval)
+                                                       append_char(pass, &outp, *(envval++));
+                                       /* Look for another '$' */
+                                       state = 0;
+                               }
+                               continue;
+                       case 3: /* Waiting for '        */
+                               if (c == '\'')
+                                       state = 0;
+                               break;
                        }
-                       break;
-               case 2: /* Waiting for )        */
-                       if (c == '}') {
-                               char envname[CONFIG_SYS_ENV_NAMELEN+1], *envval;
-                               /* Varname # of chars */
-                               uint_fast8_t envcnt = input - varname_start - 1;
-                               if (envcnt > CONFIG_SYS_ENV_NAMELEN)
-                                       envcnt = CONFIG_SYS_ENV_NAMELEN;
-
-                               memcpy(envname, varname_start, envcnt);
-                               envname[envcnt] = '\0';
-
-                               /* Get its value */
-                               envval = getenv(envname);
-
-                               /* Copy into the line if it exists */
-                               if (envval != NULL)
-                                       while ((*envval) && outputcnt) {
-                                               *(output++) = *(envval++);
-                                               outputcnt--;
-                                       }
-                               /* Look for another '$' */
-                               state = 0;
-                       }
-                       break;
-               case 3: /* Waiting for '        */
-                       if ((c == '\'') && (prev != '\\')) {
-                               state = 0;
-                       } else {
-                               *(output++) = c;
-                               outputcnt--;
-                       }
-                       break;
+                       append_char(pass, &outp, c);
                }
-               prev = c;
-       }
 
-       if (outputcnt)
-               *output = 0;
-       else
-               *(output - 1) = 0;
+               append_char(pass, &outp, 0);
+       }
 
        debug_parser("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
-                    strlen(output_start), output_start);
+                    strlen(output), output);
+
+       return output;
 }
 
 /**
@@ -159,7 +210,7 @@ static void process_macros(const char *input, char *output)
  * WARNING:
  *
  * We must create a temporary copy of the command since the command we get
- * may be the result from getenv(), which returns a pointer directly to
+ * may be the result from getenv_char(), which returns a pointer directly to
  * the environment data, which may change magicly when the command we run
  * creates or modifies environment variables (like "bootp" does).
  *
@@ -174,7 +225,7 @@ static int cli_run_command(const char *cmd, int flag)
        char *cmdbuf;                   /* working copy of cmd          */
        char *token;                    /* start of token in cmdbuf     */
        char *sep;                      /* end of token (separator) in cmdbuf */
-       char *finaltoken;
+       char *finaltoken = NULL;        /* token after macro expansion  */
        char *str;
        char *argv[CONFIG_SYS_MAXARGS + 1];     /* NULL terminated      */
        int argc;
@@ -190,8 +241,7 @@ static int cli_run_command(const char *cmd, int flag)
                return -1;      /* empty command */
 
        cmdbuf = strdup(cmd);
-       finaltoken = xmalloc(CONFIG_SYS_CBSIZE);
-       if (!finaltoken)
+       if (!cmdbuf)
                return -1;      /* not enough memory */
 
        str = cmdbuf;
@@ -208,12 +258,13 @@ static int cli_run_command(const char *cmd, int flag)
                 */
                for (inquotes = 0, sep = str; *sep; sep++) {
                        if ((*sep == '\'') &&
-                           (*(sep - 1) != '\\'))
+                           (sep != str) &&                             /* past string start */
+                           (*(sep - 1) != '\\'))               /* and NOT escaped */
                                inquotes = !inquotes;
 
                        if (!inquotes &&
-                           (*sep == ';' || *sep == '\n') &&    /* separator            */
-                           (sep != str) &&                     /* past string start    */
+                           (*sep == ';' || *sep == '\n') &&    /* separator */
+                           (sep != str) &&                             /* past string start */
                            (*(sep - 1) != '\\'))               /* and NOT escaped */
                                break;
                }
@@ -231,7 +282,7 @@ static int cli_run_command(const char *cmd, int flag)
                debug_parser("token: \"%s\"\n", token);
 
                /* find macros in this token and replace them */
-               process_macros(token, finaltoken);
+               finaltoken = process_macros(token, finaltoken);
 
                /* Extract arguments */
                argc = cli_parse_line(finaltoken, argv);
@@ -265,7 +316,7 @@ static int cli_run_command_list(const char *cmd)
 
 
 /*
- * Run a command using the selected parser.
+ * Run a command.
  *
  * @param cmd  Command to run
  * @param flag Execution flags (CMD_FLAG_...)
@@ -347,9 +398,9 @@ command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        for (i = 1; i < argc; ++i) {
                char *arg;
 
-               arg = getenv(argv[i]);
+               arg = getenv_char(argv[i]);
                if (arg == NULL) {
-                       printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+                       printf_P(PSTR("## Error: \"%s\" is not set\n"), argv[i]);
                        return CMD_RET_FAILURE;
                }
 
@@ -358,4 +409,3 @@ command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        }
        return CMD_RET_SUCCESS;
 }
-