BSD 4_4_Lite1 release
[unix-history] / usr / src / bin / sh / expand.c
index c76ba90..edee495 100644 (file)
@@ -1,15 +1,41 @@
 /*-
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)expand.c   5.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)expand.c   8.2 (Berkeley) 10/22/93";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -68,6 +94,7 @@ STATIC void recordregion(int, int, int);
 STATIC void ifsbreakup(char *, struct arglist *);
 STATIC void expandmeta(struct strlist *, int);
 STATIC void expmeta(char *, char *);
 STATIC void ifsbreakup(char *, struct arglist *);
 STATIC void expandmeta(struct strlist *, int);
 STATIC void expmeta(char *, char *);
+STATIC void expari(int);
 STATIC void addfname(char *);
 STATIC struct strlist *expsort(struct strlist *);
 STATIC struct strlist *msort(struct strlist *, int);
 STATIC void addfname(char *);
 STATIC struct strlist *expsort(struct strlist *);
 STATIC struct strlist *msort(struct strlist *, int);
@@ -83,6 +110,7 @@ STATIC void recordregion();
 STATIC void ifsbreakup();
 STATIC void expandmeta();
 STATIC void expmeta();
 STATIC void ifsbreakup();
 STATIC void expandmeta();
 STATIC void expmeta();
+STATIC void expari();
 STATIC void addfname();
 STATIC struct strlist *expsort();
 STATIC struct strlist *msort();
 STATIC void addfname();
 STATIC struct strlist *expsort();
 STATIC struct strlist *msort();
@@ -107,7 +135,7 @@ expandhere(arg, fd)
 
 /*
  * Perform variable substitution and command substitution on an argument,
 
 /*
  * Perform variable substitution and command substitution on an argument,
- * placing the resulting list of arguments in arglist.  If full is true,
+ * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
  * perform splitting and file name expansion.  When arglist is NULL, perform
  * here document expansion.
  */
  * perform splitting and file name expansion.  When arglist is NULL, perform
  * here document expansion.
  */
@@ -165,8 +193,8 @@ expandarg(arg, arglist, flag)
 
 
 /*
 
 
 /*
- * Perform variable and command substitution.  If full is set, output CTLESC
- * characters to allow for further processing.  If full is not set, treat
+ * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing.  Otherwise treat
  * $@ like $* since no splitting will be performed.
  */
 
  * $@ like $* since no splitting will be performed.
  */
 
@@ -174,20 +202,19 @@ STATIC void
 argstr(p, flag)
        register char *p;
        {
 argstr(p, flag)
        register char *p;
        {
-       char c;
-       int sawari = 0;
-       int full = flag & EXP_FULL;  /* is there a later stage? */
-       int vartilde = flag & EXP_VARTILDE;
+       register char c;
+       int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
+       int firsteq = 1;
 
        if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
 
        if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
-               p = exptilde(p, vartilde);
+               p = exptilde(p, flag);
        for (;;) {
                switch (c = *p++) {
                case '\0':
                case CTLENDVAR: /* ??? */
                        goto breakloop;
                case CTLESC:
        for (;;) {
                switch (c = *p++) {
                case '\0':
                case CTLENDVAR: /* ??? */
                        goto breakloop;
                case CTLESC:
-                       if (full)
+                       if (quotes)
                                STPUTC(c, expdest);
                        c = *p++;
                        STPUTC(c, expdest);
                                STPUTC(c, expdest);
                        c = *p++;
                        STPUTC(c, expdest);
@@ -197,16 +224,28 @@ argstr(p, flag)
                        break;
                case CTLBACKQ:
                case CTLBACKQ|CTLQUOTE:
                        break;
                case CTLBACKQ:
                case CTLBACKQ|CTLQUOTE:
-                       expbackq(argbackq->n, c & CTLQUOTE, full);
+                       expbackq(argbackq->n, c & CTLQUOTE, flag);
                        argbackq = argbackq->next;
                        break;
                case CTLENDARI:
                        argbackq = argbackq->next;
                        break;
                case CTLENDARI:
-                       expari();
+                       expari(flag);
                        break;
                case ':':
                        break;
                case ':':
+               case '=':
+                       /*
+                        * sort of a hack - expand tildes in variable
+                        * assignments (after the first '=' and after ':'s).
+                        */
                        STPUTC(c, expdest);
                        STPUTC(c, expdest);
-                       if (vartilde && *p == '~')
-                               p = exptilde(p, vartilde);
+                       if (flag & EXP_VARTILDE && *p == '~') {
+                               if (c == '=') {
+                                       if (firsteq)
+                                               firsteq = 0;
+                                       else
+                                               break;
+                               }
+                               p = exptilde(p, flag);
+                       }
                        break;
                default:
                        STPUTC(c, expdest);
                        break;
                default:
                        STPUTC(c, expdest);
@@ -216,19 +255,20 @@ breakloop:;
 }
 
 STATIC char *
 }
 
 STATIC char *
-exptilde(p, vartilde)
+exptilde(p, flag)
        char *p;
        {
        char c, *startp = p;
        struct passwd *pw;
        char *home;
        char *p;
        {
        char c, *startp = p;
        struct passwd *pw;
        char *home;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
        while (c = *p) {
                switch(c) {
                case CTLESC:
                        return (startp);
                case ':':
 
        while (c = *p) {
                switch(c) {
                case CTLESC:
                        return (startp);
                case ':':
-                       if (vartilde)
+                       if (flag & EXP_VARTILDE)
                                goto done;
                        break;
                case '/':
                                goto done;
                        break;
                case '/':
@@ -250,7 +290,7 @@ done:
                goto lose;
        *p = c;
        while (c = *home++) {
                goto lose;
        *p = c;
        while (c = *home++) {
-               if (SQSYNTAX[c] == CCTL)
+               if (quotes && SQSYNTAX[c] == CCTL)
                        STPUTC(CTLESC, expdest);
                STPUTC(c, expdest);
        }
                        STPUTC(CTLESC, expdest);
                STPUTC(c, expdest);
        }
@@ -265,10 +305,12 @@ lose:
  * Expand arithmetic expression.  Backup to start of expression,
  * evaluate, place result in (backed up) result, adjust string position.
  */
  * Expand arithmetic expression.  Backup to start of expression,
  * evaluate, place result in (backed up) result, adjust string position.
  */
-expari()
+void
+expari(flag)
        {
        {
-       char *p, *start = stackblock();
+       char *p, *start;
        int result;
        int result;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
        /*
         * This routine is slightly over-compilcated for
 
        /*
         * This routine is slightly over-compilcated for
@@ -281,7 +323,8 @@ expari()
         * characters have to be processed left to right.  
         */
        CHECKSTRSPACE(8, expdest);
         * characters have to be processed left to right.  
         */
        CHECKSTRSPACE(8, expdest);
-       USTPUTC('\0', expdest);
+       USTPUTC('\0', expdest); 
+       start = stackblock();
        p = expdest;
        while (*p != CTLARI && p >= start)
                --p;
        p = expdest;
        while (*p != CTLARI && p >= start)
                --p;
@@ -291,7 +334,8 @@ expari()
                for (p = start; *p != CTLARI; p++)
                        if (*p == CTLESC)
                                p++;
                for (p = start; *p != CTLARI; p++)
                        if (*p == CTLESC)
                                p++;
-       rmescapes(p+1);
+       if (quotes)
+               rmescapes(p+1);
        result = arith(p+1);
        fmtstr(p, 10, "%d", result);
        while (*p++)
        result = arith(p+1);
        fmtstr(p, 10, "%d", result);
        while (*p++)
@@ -306,7 +350,7 @@ expari()
  */
 
 STATIC void
  */
 
 STATIC void
-expbackq(cmd, quoted, full)
+expbackq(cmd, quoted, flag)
        union node *cmd;
        {
        struct backcmd in;
        union node *cmd;
        {
        struct backcmd in;
@@ -320,6 +364,7 @@ expbackq(cmd, quoted, full)
        int startloc = dest - stackblock();
        char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
        int saveherefd;
        int startloc = dest - stackblock();
        char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
        int saveherefd;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
        INTOFF;
        saveifs = ifsfirst;
 
        INTOFF;
        saveifs = ifsfirst;
@@ -350,7 +395,7 @@ expbackq(cmd, quoted, full)
                }
                lastc = *p++;
                if (lastc != '\0') {
                }
                lastc = *p++;
                if (lastc != '\0') {
-                       if (full && syntax[lastc] == CCTL)
+                       if (quotes && syntax[lastc] == CCTL)
                                STPUTC(CTLESC, dest);
                        STPUTC(lastc, dest);
                }
                                STPUTC(CTLESC, dest);
                        STPUTC(lastc, dest);
                }
@@ -363,7 +408,7 @@ expbackq(cmd, quoted, full)
        if (in.buf)
                ckfree(in.buf);
        if (in.jp)
        if (in.buf)
                ckfree(in.buf);
        if (in.jp)
-               waitforjob(in.jp);
+               exitstatus = waitforjob(in.jp);
        if (quoted == 0)
                recordregion(startloc, dest - stackblock(), 0);
        TRACE(("evalbackq: size=%d: \"%.*s\"\n",
        if (quoted == 0)
                recordregion(startloc, dest - stackblock(), 0);
        TRACE(("evalbackq: size=%d: \"%.*s\"\n",
@@ -393,6 +438,7 @@ evalvar(p, flag)
        int set;
        int special;
        int startloc;
        int set;
        int special;
        int startloc;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
        varflags = *p++;
        subtype = varflags & VSTYPE;
 
        varflags = *p++;
        subtype = varflags & VSTYPE;
@@ -422,7 +468,7 @@ again: /* jump here after setting a variable with ${var=text} */
                        char const *syntax = (varflags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
 
                        while (*val) {
                        char const *syntax = (varflags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
 
                        while (*val) {
-                               if ((flag & EXP_FULL) && syntax[*val] == CCTL)
+                               if (quotes && syntax[*val] == CCTL)
                                        STPUTC(CTLESC, expdest);
                                STPUTC(*val++, expdest);
                        }
                                        STPUTC(CTLESC, expdest);
                                STPUTC(*val++, expdest);
                        }
@@ -439,10 +485,12 @@ again: /* jump here after setting a variable with ${var=text} */
                } else {
                        char *startp;
                        int saveherefd = herefd;
                } else {
                        char *startp;
                        int saveherefd = herefd;
+                       struct nodelist *saveargbackq = argbackq;
                        herefd = -1;
                        argstr(p, 0);
                        STACKSTRNUL(expdest);
                        herefd = saveherefd;
                        herefd = -1;
                        argstr(p, 0);
                        STACKSTRNUL(expdest);
                        herefd = saveherefd;
+                       argbackq = saveargbackq;
                        startp = stackblock() + startloc;
                        if (subtype == VSASSIGN) {
                                setvar(var, startp, 0);
                        startp = stackblock() + startloc;
                        if (subtype == VSASSIGN) {
                                setvar(var, startp, 0);
@@ -563,9 +611,9 @@ numvar:
                        STPUTC(*p++, expdest);
                break;
        case '-':
                        STPUTC(*p++, expdest);
                break;
        case '-':
-               for (i = 0 ; optchar[i] ; i++) {
-                       if (optval[i])
-                               STPUTC(optchar[i], expdest);
+               for (i = 0 ; i < NOPTS ; i++) {
+                       if (optlist[i].val)
+                               STPUTC(optlist[i].letter, expdest);
                }
                break;
        case '@':
                }
                break;
        case '@':
@@ -721,8 +769,11 @@ expandmeta(str, flag)
                }
                savelastp = exparg.lastp;
                INTOFF;
                }
                savelastp = exparg.lastp;
                INTOFF;
-               if (expdir == NULL)
-                       expdir = ckmalloc(1024); /* I hope this is big enough */
+               if (expdir == NULL) {
+                       int i = strlen(str->text);
+                       expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
+               }
+
                expmeta(expdir, str->text);
                ckfree(expdir);
                expdir = NULL;
                expmeta(expdir, str->text);
                ckfree(expdir);
                expdir = NULL;
@@ -731,12 +782,10 @@ expandmeta(str, flag)
                        /* 
                         * no matches 
                         */
                        /* 
                         * no matches 
                         */
-                       if (! zflag) {
 nometa:
 nometa:
-                               *exparg.lastp = str;
-                               rmescapes(str->text);
-                               exparg.lastp = &str->next;
-                       }
+                       *exparg.lastp = str;
+                       rmescapes(str->text);
+                       exparg.lastp = &str->next;
                } else {
                        *exparg.lastp = NULL;
                        *savelastp = sp = expsort(*savelastp);
                } else {
                        *exparg.lastp = NULL;
                        *savelastp = sp = expsort(*savelastp);
@@ -957,9 +1006,11 @@ patmatch(pattern, string)
        char *pattern;
        char *string;
        {
        char *pattern;
        char *string;
        {
+#ifdef notdef
        if (pattern[0] == '!' && pattern[1] == '!')
                return 1 - pmatch(pattern + 2, string);
        else
        if (pattern[0] == '!' && pattern[1] == '!')
                return 1 - pmatch(pattern + 2, string);
        else
+#endif
                return pmatch(pattern, string);
 }
 
                return pmatch(pattern, string);
 }
 
@@ -1043,7 +1094,7 @@ pmatch(pattern, string)
                                return 0;
                        break;
                }
                                return 0;
                        break;
                }
-dft:       default:
+dft:           default:
                        if (*q++ != c)
                                return 0;
                        break;
                        if (*q++ != c)
                                return 0;
                        break;
@@ -1100,7 +1151,7 @@ casematch(pattern, val)
        argbackq = pattern->narg.backquote;
        STARTSTACKSTR(expdest);
        ifslastp = NULL;
        argbackq = pattern->narg.backquote;
        STARTSTACKSTR(expdest);
        ifslastp = NULL;
-       argstr(pattern->narg.text, 0);
+       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
        STPUTC('\0', expdest);
        p = grabstackstr(expdest);
        result = patmatch(p, val);
        STPUTC('\0', expdest);
        p = grabstackstr(expdest);
        result = patmatch(p, val);