Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sh Yet another foray into the mysterious world of $@ -- ...



details:   https://anonhg.NetBSD.org/src/rev/ad9ce4f66c78
branches:  trunk
changeset: 446377:ad9ce4f66c78
user:      kre <kre%NetBSD.org@localhost>
date:      Mon Dec 03 06:41:30 2018 +0000

description:
Yet another foray into the mysterious world of $@ -- this time
to fix the (unusual) idiom "${1+$@}"  (the quotes are part of it).
This seems to have broken about 5 or 6 years ago (somewhere
between -6 and -7), I believe.

Note this is not the same as "$@" and also not the same as ${1+"$@"}
(much more common idioms) which both worked.

Also attempt to deal with "" more correctly, especially when it
appears adjacent to "$@" (or one of the similar constructs.)

This stuff is still all as ugly and hackish (and fragile) as is
possible to imagine, but in an effort to allow some of the weirdness
to eventually go away, the parser output has been made more
regular and all quoted (parts of) words always now start with
CTLQUOTEMARK and end with CTLQUOTEEND regardless of where the
quotes appear.

This allows us to tell the difference between """$@" and "$@"
which was impossible before - yet they are required to generate
different output when there are no args (when "$@" simply vanishes).

Needless to say that change had ramifications all over the place.
To simplify any similar change in the future, there are some new
macros that can generally be used to detect the "noise" data when
processing words, rather than open coding that every time (which
meant that there would *always* be one which missed getting
updated...)

Several other bugs (of my making, and older ones) are also fixed.

The aim is that (aside from anything that is detecting the cases
that were broken before - which were all unlikely uses of sh
syntax) these changes should have no external visible impact.

Sure...

diffstat:

 bin/sh/expand.c |  88 ++++++++++++++++++++++++++++++++++++++++----------------
 bin/sh/parser.c |  20 +++++-------
 2 files changed, 72 insertions(+), 36 deletions(-)

diffs (truncated from 396 to 300 lines):

diff -r b29ea8fe820d -r ad9ce4f66c78 bin/sh/expand.c
--- a/bin/sh/expand.c   Mon Dec 03 06:40:26 2018 +0000
+++ b/bin/sh/expand.c   Mon Dec 03 06:41:30 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: expand.c,v 1.128 2018/11/18 17:23:37 kre Exp $ */
+/*     $NetBSD: expand.c,v 1.129 2018/12/03 06:41:30 kre Exp $ */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)expand.c   8.5 (Berkeley) 5/15/95";
 #else
-__RCSID("$NetBSD: expand.c,v 1.128 2018/11/18 17:23:37 kre Exp $");
+__RCSID("$NetBSD: expand.c,v 1.129 2018/12/03 06:41:30 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -127,6 +127,16 @@
 #define        NULLTERM_4_TRACE(p)     do { /* nothing */ } while (/*CONSTCOND*/0)
 #endif
 
+#define        IS_BORING(_ch)                                          \
+       ((_ch) == CTLQUOTEMARK || (_ch) == CTLQUOTEEND || (_ch) == CTLNONL)
+#define        SKIP_BORING(p)                                          \
+       do {                                                    \
+               char _ch;                                       \
+                                                               \
+               while ((_ch = *(p)), IS_BORING(_ch))            \
+                       (p)++;                                  \
+       } while (0)
+
 /*
  * Expand shell variables and backquotes inside a here document.
  */
@@ -271,6 +281,8 @@
                        STPUTC('\n', expdest);  /* no line_number++ */
                        break;
                case CTLQUOTEEND:
+                       if ((flag & EXP_SPLIT) != 0)
+                               STPUTC(c, expdest);
                        ifs_split = EXP_IFS_SPLIT;
                        break;
                case CTLESC:
@@ -284,11 +296,13 @@
                case CTLVAR: {
 #ifdef DEBUG
                        unsigned int pos = expdest - stackblock();
+                       NULLTERM_4_TRACE(expdest);
 #endif
                        p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
                        NULLTERM_4_TRACE(expdest);
                        VTRACE(DBG_EXPAND, ("argstr evalvar "
-                          "added \"%s\" to expdest\n",
+                          "added %zd \"%s\" to expdest\n",
+                          (size_t)(expdest - (stackblock() + pos)),
                           stackblock() + pos));
                        break;
                }
@@ -810,7 +824,7 @@
                abort();
        }
 
-recordleft:
+ recordleft:
        *loc = c;
        amount = ((str - 1) - (loc - startp)) - expdest;
        STADJUST(amount, expdest);
@@ -818,7 +832,7 @@
                *startp++ = *loc++;
        return 1;
 
-recordright:
+ recordright:
        amount = loc - expdest;
        STADJUST(amount, expdest);
        STPUTC('\0', expdest);
@@ -897,6 +911,10 @@
                }
        }
 
+       if (!set && subtype != VSPLUS && special && *var == '@')
+               if (startloc > 0 && expdest[-1] == CTLQUOTEMARK)
+                       expdest--, startloc--;
+
        if (set && subtype != VSPLUS) {
                /* insert the value of the variable */
                if (special) {
@@ -936,9 +954,7 @@
        }
 
 
-       if (flag & EXP_IN_QUOTES)
-               apply_ifs = 0;
-       else if (varflags & VSQUOTE) {
+       if (varflags & VSQUOTE) {
                if  (*var == '@' && shellparam.nparam != 1)
                    apply_ifs = 1;
                else {
@@ -949,6 +965,8 @@
                    flag |= EXP_IN_QUOTES;
                    apply_ifs = 0;
                }
+       } else if (flag & EXP_IN_QUOTES) {
+               apply_ifs = 0;
        } else
                apply_ifs = 1;
 
@@ -1111,6 +1129,12 @@
        int i;
        int sep;
        char **ap;
+#ifdef DEBUG
+       char *start = expdest;
+#endif
+
+       VTRACE(DBG_EXPAND, ("varvalue(%c%s, sub=%d, fl=%#x)", *name,
+           quoted ? ", quoted" : "", subtype, flag));
 
        if (subtype == VSLENGTH)        /* no magic required ... */
                flag &= ~EXP_FULL;
@@ -1147,9 +1171,17 @@
                        if (optlist[optorder[i]].val)
                                STPUTC(optlist[optorder[i]].letter, expdest);
                }
+               VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
                return;
        case '@':
                if (flag & EXP_SPLIT && quoted) {
+                       VTRACE(DBG_EXPAND, (": $@ split (%d)\n",
+                           shellparam.nparam));
+               /* GROSS HACK */
+                       if (shellparam.nparam == 0 &&
+                               expdest[-1] == CTLQUOTEMARK)
+                                       expdest--;
+               /* KCAH SSORG */
                        for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
                                STRTODEST(p);
                                if (*ap)
@@ -1175,6 +1207,7 @@
                              && !quoted && **ap != '\0')
                                STPUTC('\0', expdest);
                }
+               VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
                return;
        default:
                if (is_digit(*name)) {
@@ -1193,12 +1226,15 @@
                                return;
                        STRTODEST(p);
                }
+               VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
                return;
        }
        /*
         * only the specials with an int value arrive here
         */
+       VTRACE(DBG_EXPAND, ("(%d)", num));
        expdest = cvtnum(num, expdest);
+       VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
 }
 
 
@@ -1274,7 +1310,7 @@
                while (p < string + ifsp->endoff) {
                        had_param_ch = 1;
                        q = p;
-                       if (*p == CTLNONL) {
+                       if (IS_BORING(*p)) {
                                p++;
                                continue;
                        }
@@ -1335,6 +1371,9 @@
                }
        }
 
+       while (*start == CTLQUOTEEND)
+               start++;
+
        /*
         * Save anything left as an argument.
         * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
@@ -1391,7 +1430,7 @@
                for (;;) {                      /* fast check for meta chars */
                        if ((c = *p++) == '\0')
                                goto nometa;
-                       if (c == '*' || c == '?' || c == '[' || c == '!')
+                       if (c == '*' || c == '?' || c == '[' /* || c == '!' */)
                                break;
                }
                savelastp = exparg.lastp;
@@ -1466,7 +1505,7 @@
                        if (*q == '!' || *q == '^')
                                q++;
                        for (;;) {
-                               while (*q == CTLQUOTEMARK || *q == CTLNONL)
+                               while (IS_BORING(*q))
                                        q++;
                                if (*q == ']') {
                                        q++;
@@ -1518,7 +1557,7 @@
                        }
                } else if (*p == '\0')
                        break;
-               else if (*p == CTLQUOTEMARK || *p == CTLNONL)
+               else if (IS_BORING(*p))
                        continue;
                else if (*p == CTLESC)
                        p++;
@@ -1532,7 +1571,7 @@
                if (enddir != expdir)
                        metaflag++;
                for (p = name ; ; p++) {
-                       if (*p == CTLQUOTEMARK || *p == CTLNONL)
+                       if (IS_BORING(*p))
                                continue;
                        if (*p == CTLESC)
                                p++;
@@ -1548,7 +1587,7 @@
        if (start != name) {
                p = name;
                while (p < start) {
-                       while (*p == CTLQUOTEMARK || *p == CTLNONL)
+                       while (IS_BORING(*p))
                                p++;
                        if (*p == CTLESC)
                                p++;
@@ -1575,7 +1614,7 @@
        }
        matchdot = 0;
        p = start;
-       while (*p == CTLQUOTEMARK || *p == CTLNONL)
+       while (IS_BORING(*p))
                p++;
        if (*p == CTLESC)
                p++;
@@ -1767,6 +1806,7 @@
                                goto backtrack;
                        break;
                case CTLQUOTEMARK:
+               case CTLQUOTEEND:
                case CTLNONL:
                        continue;
                case '?':
@@ -1781,7 +1821,7 @@
                        c = *p;
                        while (c == CTLQUOTEMARK || c == '*')
                                c = *++p;
-                       if (c != CTLESC &&  c != CTLQUOTEMARK && c != CTLNONL &&
+                       if (c != CTLESC && !IS_BORING(c) &&
                            c != '?' && c != '*' && c != '[') {
                                while (*q != c) {
                                        if (squoted && *q == CTLESC &&
@@ -1828,13 +1868,11 @@
                        if (*endp == '!' || *endp == '^')
                                endp++;
                        for (;;) {
-                               while (*endp == CTLQUOTEMARK || *endp==CTLNONL)
+                               while (IS_BORING(*endp))
                                        endp++;
                                if (*endp == '\0')
                                        goto dft;       /* no matching ] */
-                               if (*endp == CTLESC)
-                                       endp++;
-                               if (*++endp == ']')
+                               if (*endp++ == ']')
                                        break;
                        }
                        /* end shortcut */
@@ -1856,7 +1894,7 @@
                        chr = (unsigned char)*q++;
                        c = *p++;
                        do {
-                               if (c == CTLQUOTEMARK || c == CTLNONL)
+                               if (IS_BORING(c))
                                        continue;
                                if (c == '\0') {
                                        p = savep, q = saveq;
@@ -1930,13 +1968,13 @@
        char *p, *q;
 
        p = str;
-       while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLNONL) {
+       while (*p != CTLESC && !IS_BORING(*p)) {
                if (*p++ == '\0')
                        return;
        }
        q = p;
        while (*p) {
-               if (*p == CTLQUOTEMARK || *p == CTLNONL) {
+               if (IS_BORING(*p)) {
                        p++;
                        continue;
                }
@@ -1969,7 +2007,7 @@
        int nls = 0, holdnl = 0, holdlast;
 
        p = str;
-       while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLNONL) {
+       while (*p != CTLESC && !IS_BORING(*p)) {



Home | Main Index | Thread Index | Old Index