]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/cli.c
process_macros: reduce heap usage and fragmentation
[z180-stamp.git] / avr / cli.c
index 08e70387df9f7e5518c7e6efc08904f284658a03..b310f793d97eb54d85db24129eecc4bb6996687b 100644 (file)
--- a/avr/cli.c
+++ b/avr/cli.c
@@ -43,114 +43,107 @@ static int cli_parse_line(char *line, char *argv[])
        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;
-
-       debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input),
-                    input);
-
-       prev = '\0';            /* previous character   */
-
-       while (inputcnt && outputcnt) {
-               c = *input++;
-               inputcnt--;
-
-               if (state != 3) {
-                       /* remove one level of escape characters */
-                       if ((c == '\\') && (prev != '\\')) {
-                               if (inputcnt-- == 0)
-                                       break;
-                               prev = c;
-                               c = *input++;
-                       }
+
+       if (pass) {
+               **p = c;
+       }
+       ++(*p);
+}
+
+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;
                }
 
-               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--;
+               inp = input;
+               prev = '\0';            /* previous character   */
+
+               debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(inp),
+                            inp);
+
+               while ((c = *inp++) != '\0') {
+
+                       if (state != 3) {
+                               /* remove one level of escape characters */
+                               if ((c == '\\') && (prev != '\\')) {
+                                       if (*inp == '\0')
+                                               break;
+                                       prev = c;
+                                       c = *inp++;
                                }
                        }
-                       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--;
+
+                       switch (state) {
+                       case 0: /* Waiting for (unescaped) $    */
+                               if ((c == '\'') && (prev != '\\')) {
+                                       state = 3;
+                                       break;
+                               }
+                               if ((c == '$') && (prev != '\\'))
+                                       state++;
+                               else
+                                       append_char(pass, &outp, c);
+                               break;
+                       case 1: /* Waiting for {        */
+                               if (c == '{') {
+                                       state++;
+                                       varname = inp;
+                               } else {
+                                       state = 0;
+                                       append_char(pass, &outp, '$');
+                                       append_char(pass, &outp, c);
+                               }
+                               break;
+                       case 2: /* Waiting for }        */
+                               if (c == '}') {
+                                       /* Terminate variable name */
+                                       *(inp-1) = '\0';
+                                       const char *envval = getenv(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;
+                               }
+                               break;
+                       case 3: /* Waiting for '        */
+                               if ((c == '\'') && (prev != '\\'))
+                                       state = 0;
+                               else
+                                       append_char(pass, &outp, c);
+                               break;
                        }
-                       break;
+                       prev = 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;
 }
 
 /**
@@ -174,7 +167,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 +183,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;
@@ -231,7 +223,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);