ash: code shrink around varvalue
authorRon Yorston <rmy@pobox.com>
Mon, 18 May 2015 07:49:28 +0000 (09:49 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 18 May 2015 07:49:28 +0000 (09:49 +0200)
Based on commit c989d72 from git://git.kernel.org/pub/scm/utils/dash/dash.git
by Herbert Xu

function                                             old     new   delta
strtodest                                              -      40     +40
memtodest                                            123     147     +24
parse_command                                       1443    1440      -3
readtoken1                                          3205    3199      -6
argstr                                              1203    1180     -23
varvalue                                             788     660    -128
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/4 up/down: 64/-160)           Total: -96 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index 7af8842bb2389127dfdbb0188d07ccc5f26187c3..a81922adddbe4f31824ede768384851cf52e4e1e 100644 (file)
@@ -5539,6 +5539,11 @@ ash_arith(const char *s)
 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
 
+/* Add CTLESC when necessary. */
+#define QUOTES_ESC     (EXP_FULL | EXP_CASE | EXP_REDIR)
+/* Do not skip NUL characters. */
+#define QUOTES_KEEPNUL EXP_TILDE
+
 /*
  * Structure specifying which parts of the string should be searched
  * for IFS characters.
@@ -5695,29 +5700,34 @@ preglob(const char *pattern, int quoted, int flag)
 static void
 memtodest(const char *p, size_t len, int syntax, int quotes)
 {
-       char *q = expdest;
+       char *q;
+
+       if (!len)
+               return;
 
-       q = makestrspace(quotes ? len * 2 : len, q);
+       q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
 
-       while (len--) {
+       do {
                unsigned char c = *p++;
-               if (c == '\0')
-                       continue;
-               if (quotes) {
+               if (c) {
                        int n = SIT(c, syntax);
-                       if (n == CCTL || n == CBACK)
+                       if ((quotes & QUOTES_ESC) &&
+                                       (n == CCTL || n == CBACK))
                                USTPUTC(CTLESC, q);
-               }
+               } else if (!(quotes & QUOTES_KEEPNUL))
+                       continue;
                USTPUTC(c, q);
-       }
+       } while (--len);
 
        expdest = q;
 }
 
-static void
+static size_t
 strtodest(const char *p, int syntax, int quotes)
 {
-       memtodest(p, strlen(p), syntax, quotes);
+       size_t len = strlen(p);
+       memtodest(p, len, syntax, quotes);
+       return len;
 }
 
 /*
@@ -5790,7 +5800,7 @@ exptilde(char *startp, char *p, int flags)
        char *name;
        struct passwd *pw;
        const char *home;
-       int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int quotes = flags & QUOTES_ESC;
 
        name = p + 1;
 
@@ -6043,7 +6053,7 @@ argstr(char *p, int flags, struct strlist *var_str_list)
                '\0'
        };
        const char *reject = spclchars;
-       int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
+       int quotes = flags & QUOTES_ESC;
        int breakall = flags & EXP_WORD;
        int inquotes;
        size_t length;
@@ -6608,13 +6618,16 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
        const char *p;
        int num;
        int i;
-       int sepq = 0;
        ssize_t len = 0;
-       int subtype = varflags & VSTYPE;
-       int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int sep;
        int quoted = varflags & VSQUOTE;
+       int subtype = varflags & VSTYPE;
+       int discard = subtype == VSPLUS || subtype == VSLENGTH;
+       int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
        int syntax = quoted ? DQSYNTAX : BASESYNTAX;
 
+       sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+
        switch (*name) {
        case '$':
                num = rootpid;
@@ -6649,7 +6662,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                break;
        case '@': {
                char **ap;
-               int sep;
+               char sepc;
 
                if (quoted && (flags & EXP_FULL)) {
                        /* note: this is not meant as PEOF value */
@@ -6659,39 +6672,20 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                /* fall through */
        case '*':
                sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
-               i = SIT(sep, syntax);
-               if (quotes && (i == CCTL || i == CBACK))
-                       sepq = 1;
  param:
                ap = shellparam.p;
+               sepc = sep;
                if (!ap)
                        return -1;
                while ((p = *ap++) != NULL) {
-                       size_t partlen;
-
-                       partlen = strlen(p);
-                       len += partlen;
-
-                       if (!(subtype == VSPLUS || subtype == VSLENGTH))
-                               memtodest(p, partlen, syntax, quotes);
+                       len += strtodest(p, syntax, quotes);
 
                        if (*ap && sep) {
-                               char *q;
-
                                len++;
-                               if (subtype == VSPLUS || subtype == VSLENGTH) {
-                                       continue;
-                               }
-                               q = expdest;
-                               if (sepq)
-                                       STPUTC(CTLESC, q);
-                               /* note: may put NUL despite sep != 0
-                                * (see sep = 1 << CHAR_BIT above) */
-                               STPUTC(sep, q);
-                               expdest = q;
+                               memtodest(&sepc, 1, syntax, quotes);
                        }
                }
-               return len;
+               break;
        } /* case '@' and '*' */
        case '0':
        case '1':
@@ -6740,9 +6734,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                if (!p)
                        return -1;
 
-               len = strlen(p);
-               if (!(subtype == VSPLUS || subtype == VSLENGTH))
-                       memtodest(p, len, syntax, quotes);
+               len = strtodest(p, syntax, quotes);
 #if ENABLE_UNICODE_SUPPORT
                if (subtype == VSLENGTH && len > 0) {
                        reinit_unicode_for_ash();
@@ -6751,10 +6743,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                        }
                }
 #endif
-               return len;
+               break;
        }
 
-       if (subtype == VSPLUS || subtype == VSLENGTH)
+       if (discard)
                STADJUST(-len, expdest);
        return len;
 }
@@ -6870,7 +6862,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
                patloc = expdest - (char *)stackblock();
                if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
                                startloc, varflags,
-                               /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
+                               /* quotes: */ flags & QUOTES_ESC,
                                var_str_list)
                ) {
                        int amount = expdest - (