Gmatch did not trim the characters inside a range.
[unix-history] / usr / src / bin / csh / glob.c
index 80a77a3..51214df 100644 (file)
-static char *sccsid = "@(#)glob.c 4.1 %G%";
-#include "sh.h"
-
-/*
- * C Shell
+/*-
+ * Copyright (c) 1980, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
 
  */
 
-int    globcnt;
-
-char   *globchars =    "`{[*?";
-
-char   *gpath, *gpathp, *lastgpathp;
-int    globbed;
-bool   noglob;
-bool   nonomatch;
-char   *entp;
-char   **sortbas;
-
-char **
-glob(v)
-       register char **v;
-{
-       char agpath[BUFSIZ];
-       char *agargv[GAVSIZ];
-
-       gpath = agpath; gpathp = gpath; *gpathp = 0;
-       lastgpathp = &gpath[sizeof agpath - 2];
-       ginit(agargv); globcnt = 0;
-#ifdef GDEBUG
-       printf("glob entered: "); blkpr(v); printf("\n");
-#endif
-       noglob = adrof("noglob") != 0;
-       nonomatch = adrof("nonomatch") != 0;
-       globcnt = noglob | nonomatch;
-       while (*v)
-               collect(*v++);
-#ifdef GDEBUG
-       printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n");
+#ifndef lint
+static char sccsid[] = "@(#)glob.c     5.21 (Berkeley) %G%";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <glob.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
 #endif
 #endif
-       if (globcnt == 0 && (gflag&1)) {
-               blkfree(gargv), gargv = 0;
-               return (0);
-       } else
-               return (gargv = copyblk(gargv));
-}
 
 
-ginit(agargv)
-       char **agargv;
-{
+#include "csh.h"
+#include "extern.h"
 
 
-       agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
-       gnleft = NCARGS - 4;
-}
+static int noglob, nonomatch;
+static int pargsiz, gargsiz;
 
 
-collect(as)
-       register char *as;
-{
-       register int i;
+/*
+ * Values for gflag
+ */
+#define        G_NONE  0               /* No globbing needed                   */
+#define        G_GLOB  1               /* string contains *?[] characters      */
+#define        G_CSH   2               /* string contains ~`{ characters       */
 
 
-       if (any('`', as)) {
-#ifdef GDEBUG
-               printf("doing backp of %s\n", as);
-#endif
-               dobackp(as, 0);
-#ifdef GDEBUG
-               printf("backp done, acollect'ing\n");
-#endif
-               for (i = 0; i < pargc; i++)
-                       if (noglob)
-                               Gcat(pargv[i], "");
-                       else
-                               acollect(pargv[i]);
-               if (pargv)
-                       blkfree(pargv), pargv = 0;
-#ifdef GDEBUG
-               printf("acollect done\n");
-#endif
-       } else if (noglob)
-               Gcat(as, "");
-       else
-               acollect(as);
-}
+#define        GLOBSPACE       100     /* Alloc increment                      */
 
 
-acollect(as)
-       register char *as;
-{
-       register int ogargc = gargc;
-
-       gpathp = gpath; *gpathp = 0; globbed = 0;
-       expand(as);
-       if (gargc == ogargc) {
-               if (nonomatch) {
-                       Gcat(as, "");
-                       sort();
-               }
-       } else
-               sort();
-}
+#define LBRC '{'
+#define RBRC '}'
+#define LBRK '['
+#define RBRK ']'
+#define EOS '\0'
 
 
-sort()
-{
-       register char **p1, **p2, *c;
-       char **Gvp = &gargv[gargc];
-
-       p1 = sortbas;
-       while (p1 < Gvp-1) {
-               p2 = p1;
-               while (++p2 < Gvp)
-                       if (strcmp(*p1, *p2) > 0)
-                               c = *p1, *p1 = *p2, *p2 = c;
-               p1++;
-       }
-       sortbas = Gvp;
-}
+Char  **gargv = NULL;
+long    gargc = 0;
+Char  **pargv = NULL;
+long    pargc = 0;
 
 
-expand(as)
-       char *as;
+/*
+ * globbing is now done in two stages. In the first pass we expand
+ * csh globbing idioms ~`{ and then we proceed doing the normal
+ * globbing if needed ?*[
+ *
+ * Csh type globbing is handled in globexpand() and the rest is
+ * handled in glob() which is part of the 4.4BSD libc.
+ *
+ */
+static Char    *globtilde __P((Char **, Char *));
+static Char    **libglob __P((Char **));
+static Char    **globexpand __P((Char **));
+static int     globbrace __P((Char *, Char *, Char ***));
+static void    pword __P((void));
+static void    psave __P((int));
+static void    backeval __P((Char *, bool));
+
+
+static Char *
+globtilde(nv, s)
+    Char  **nv, *s;
 {
 {
-       register char *cs;
-       register char *sgpathp, *oldcs;
-       struct stat stb;
-
-       sgpathp = gpathp;
-       cs = as;
-       if (*cs == '~' && gpathp == gpath) {
-               addpath('~');
-               for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
-                       addpath(*cs++);
-               if (!*cs || *cs == '/') {
-                       if (gpathp != gpath + 1) {
-                               *gpathp = 0;
-                               if (gethdir(gpath + 1))
-                                       error("Unknown user: %s", gpath + 1);
-                               strcpy(gpath, gpath + 1);
-                       } else
-                               strcpy(gpath, value("home"));
-                       gpathp = strend(gpath);
-               }
-       }
-       while (!any(*cs, globchars)) {
-               if (*cs == 0) {
-                       if (!globbed)
-                               Gcat(gpath, "");
-                       else if (stat(gpath, &stb) >= 0) {
-                               Gcat(gpath, "");
-                               globcnt++;
-                       }
-                       goto endit;
-               }
-               addpath(*cs++);
-       }
-       oldcs = cs;
-       while (cs > as && *cs != '/')
-               cs--, gpathp--;
-       if (*cs == '/')
-               cs++, gpathp++;
-       *gpathp = 0;
-       if (*oldcs == '{') {
-               execbrc(cs, NOSTR);
-               return;
-       }
-       matchdir(cs);
-endit:
-       gpathp = sgpathp;
-       *gpathp = 0;
+    Char    gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
+
+    gstart = gbuf;
+    *gstart++ = *s++;
+    u = s;
+    for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e;
+        *b++ = *s++);
+    *b = EOS;
+    if (gethdir(gstart)) {
+       blkfree(nv);
+       if (*gstart)
+           stderror(ERR_UNKUSER, short2str(gstart));
+       else
+           stderror(ERR_NOHOME);
+    }
+    b = &gstart[Strlen(gstart)];
+    while (*s)
+       *b++ = *s++;
+    *b = EOS;
+    --u;
+    xfree((ptr_t) u);
+    return (Strsave(gstart));
 }
 
 }
 
-matchdir(pattern)
-       char *pattern;
+static int
+globbrace(s, p, bl)
+    Char   *s, *p, ***bl;
 {
 {
-       struct stat stb;
-       struct direct dirbuf[BUFSIZ / sizeof (struct direct)];
-       char d_name[DIRSIZ+1];
-       register int dirf, cnt;
-
-       dirf = open(gpath, 0);
-       if (dirf < 0) {
-               if (globbed)
-                       return;
-               goto patherr;
+    int     i, len;
+    Char   *pm, *pe, *lm, *pl;
+    Char  **nv, **vl;
+    Char    gbuf[MAXPATHLEN];
+    int     size = GLOBSPACE;
+
+    nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
+    *vl = NULL;
+
+    len = 0;
+    /* copy part up to the brace */
+    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
+       continue;
+
+    /* check for balanced braces */
+    for (i = 0, pe = ++p; *pe; pe++)
+       if (*pe == LBRK) {
+           /* Ignore everything between [] */
+           for (++pe; *pe != RBRK && *pe != EOS; pe++)
+               continue;
+           if (*pe == EOS) {
+               blkfree(nv);
+               return (-LBRK);
+           }
        }
        }
-       if (fstat(dirf, &stb) < 0)
-               goto patherr;
-       if (!isdir(stb)) {
-               errno = ENOTDIR;
-               goto patherr;
+       else if (*pe == LBRC)
+           i++;
+       else if (*pe == RBRC) {
+           if (i == 0)
+               break;
+           i--;
        }
        }
-       while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) {
-               register struct direct *ep = dirbuf;
-
-               for (cnt /= sizeof (struct direct); cnt > 0; cnt--, ep++) {
-                       if (ep->d_ino == 0)
-                               continue;
-                       copdent(d_name, ep->d_name);
-                       if (match(d_name, pattern)) {
-                               Gcat(gpath, d_name);
-                               globcnt++;
-                       }
-               }
-       }
-       close(dirf);
-       return;
 
 
-patherr:
-       Perror(gpath);
-}
+    if (i != 0) {
+       blkfree(nv);
+       return (-LBRC);
+    }
 
 
-copdent(to, from)
-       register char *to, *from;
-{
-       register int cnt = DIRSIZ;
-
-       do
-               *to++ = *from++;
-       while (--cnt);
-       *to = 0;
-}
-
-execbrc(p, s)
-       char *p, *s;
-{
-       char restbuf[BUFSIZ + 2];
-       register char *pe, *pm, *pl;
-       int brclev = 0;
-       char *lm, savec, *sgpathp;
-
-       for (lm = restbuf; *p != '{'; *lm++ = *p++)
-               continue;
-       for (pe = ++p; *pe; pe++)
-       switch (*pe) {
-
-       case '{':
-               brclev++;
-               continue;
-
-       case '}':
-               if (brclev == 0)
-                       goto pend;
-               brclev--;
-               continue;
-
-       case '[':
-               for (pe++; *pe && *pe != ']'; pe++)
-                       continue;
-               if (!*pe)
-                       error("Missing ]");
-               continue;
-       }
-pend:
-       if (brclev || !*pe)
-               error("Missing }");
-       for (pl = pm = p; pm <= pe; pm++)
-       switch (*pm & (QUOTE|TRIM)) {
-
-       case '{':
-               brclev++;
+    for (i = 0, pl = pm = p; pm <= pe; pm++)
+       switch (*pm) {
+       case LBRK:
+           for (++pm; *pm != RBRK && *pm != EOS; pm++)
                continue;
                continue;
-
-       case '}':
-               if (brclev) {
-                       brclev--;
-                       continue;
-               }
-               goto doit;
-
-       case ','|QUOTE:
+           if (*pm == EOS) {
+               *vl = NULL;
+               blkfree(nv);
+               return (-RBRK);
+           }
+           break;
+       case LBRC:
+           i++;
+           break;
+       case RBRC:
+           if (i) {
+               i--;
+               break;
+           }
+           /* FALLTHROUGH */
        case ',':
        case ',':
-               if (brclev)
-                       continue;
-doit:
-               savec = *pm;
-               *pm = 0;
-               strcpy(lm, pl);
-               strcat(restbuf, pe + 1);
+           if (i && *pm == ',')
+               break;
+           else {
+               Char    savec = *pm;
+
+               *pm = EOS;
+               (void) Strcpy(lm, pl);
+               (void) Strcat(gbuf, pe + 1);
                *pm = savec;
                *pm = savec;
-               if (s == 0) {
-                       sgpathp = gpathp;
-                       expand(restbuf);
-                       gpathp = sgpathp;
-                       *gpathp = 0;
-               } else if (amatch(s, restbuf))
-                       return (1);
-               sort();
+               *vl++ = Strsave(gbuf);
+               len++;
                pl = pm + 1;
                pl = pm + 1;
-               continue;
-
-       case '[':
-               for (pm++; *pm && *pm != ']'; pm++)
-                       continue;
-               if (!*pm)
-                       error("Missing ]");
-               continue;
+               if (vl == &nv[size]) {
+                   size += GLOBSPACE;
+                   nv = (Char **) xrealloc((ptr_t) nv, (size_t)
+                                           size * sizeof(Char *));
+                   vl = &nv[size - GLOBSPACE];
+               }
+           }
+           break;
        }
        }
-       return (0);
+    *vl = NULL;
+    *bl = nv;
+    return (len);
 }
 
 }
 
-match(s, p)
-       char *s, *p;
+static Char **
+globexpand(v)
+    Char  **v;
 {
 {
-       register int c;
-       register char *sentp;
-       char sglobbed = globbed;
+    Char   *s;
+    Char  **nv, **vl, **el;
+    int     size = GLOBSPACE;
+
+
+    nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
+    *vl = NULL;
+
+    /*
+     * Step 1: expand backquotes.
+     */
+    while (s = *v++) {
+       if (Strchr(s, '`')) {
+           int     i;
+
+           (void) dobackp(s, 0);
+           for (i = 0; i < pargc; i++) {
+               *vl++ = pargv[i];
+               if (vl == &nv[size]) {
+                   size += GLOBSPACE;
+                   nv = (Char **) xrealloc((ptr_t) nv,
+                                           (size_t) size * sizeof(Char *));
+                   vl = &nv[size - GLOBSPACE];
+               }
+           }
+           xfree((ptr_t) pargv);
+           pargv = NULL;
+       }
+       else {
+           *vl++ = Strsave(s);
+           if (vl == &nv[size]) {
+               size += GLOBSPACE;
+               nv = (Char **) xrealloc((ptr_t) nv, (size_t)
+                                       size * sizeof(Char *));
+               vl = &nv[size - GLOBSPACE];
+           }
+       }
+    }
+    *vl = NULL;
+
+    if (noglob)
+       return (nv);
+
+    /*
+     * Step 2: expand braces
+     */
+    el = vl;
+    vl = nv;
+    for (s = *vl; s; s = *++vl) {
+       Char   *b;
+       Char  **vp, **bp;
+
+       if (b = Strchr(s, LBRC)) {
+           Char  **bl;
+           int     len;
+
+           if ((len = globbrace(s, b, &bl)) < 0) {
+               blkfree(nv);
+               stderror(ERR_MISSING, -len);
+           }
+           xfree((ptr_t) s);
+           if (len == 1) {
+               *vl-- = *bl;
+               xfree((ptr_t) bl);
+               continue;
+           }
+           len = blklen(bl);
+           if (&el[len] >= &nv[size]) {
+               int     l, e;
+
+               l = &el[len] - &nv[size];
+               size += GLOBSPACE > l ? GLOBSPACE : l;
+               l = vl - nv;
+               e = el - nv;
+               nv = (Char **) xrealloc((ptr_t) nv, (size_t)
+                                       size * sizeof(Char *));
+               vl = nv + l;
+               el = nv + e;
+           }
+           vp = vl--;
+           *vp = *bl;
+           len--;
+           for (bp = el; bp != vp; bp--)
+               bp[len] = *bp;
+           el += len;
+           vp++;
+           for (bp = bl + 1; *bp; *vp++ = *bp++)
+               continue;
+           xfree((ptr_t) bl);
+       }
 
 
-       if (*s == '.' && *p != '.')
-               return (0);
-       sentp = entp;
-       entp = s;
-       c = amatch(s, p);
-       entp = sentp;
-       globbed = sglobbed;
-       return (c);
+    }
+
+    /*
+     * Step 3: expand ~
+     */
+    vl = nv;
+    for (s = *vl; s; s = *++vl)
+       if (*s == '~')
+           *vl = globtilde(nv, s);
+    vl = nv;
+    return (vl);
 }
 
 }
 
-amatch(s, p)
-       register char *s, *p;
+static Char *
+handleone(str, vl, action)
+    Char   *str, **vl;
+    int     action;
 {
 {
-       register int scc;
-       int ok, lc;
-       char *sgpathp;
-       struct stat stb;
-       int c, cc;
 
 
-       globbed = 1;
-       for (;;) {
-               scc = *s++ & TRIM;
-               switch (c = *p++) {
-
-               case '{':
-                       return (execbrc(p - 1, s - 1));
-
-               case '[':
-                       ok = 0;
-                       lc = 077777;
-                       while (cc = *p++) {
-                               if (cc == ']') {
-                                       if (ok)
-                                               break;
-                                       return (0);
-                               }
-                               if (cc == '-') {
-                                       if (lc <= scc && scc <= *p++)
-                                               ok++;
-                               } else
-                                       if (scc == (lc = cc))
-                                               ok++;
-                       }
-                       if (cc == 0)
-                               error("Missing ]");
-                       continue;
-
-               case '*':
-                       if (!*p)
-                               return (1);
-                       if (*p == '/') {
-                               p++;
-                               goto slash;
-                       }
-                       for (s--; *s; s++)
-                               if (amatch(s, p))
-                                       return (1);
-                       return (0);
-
-               case 0:
-                       return (scc == 0);
-
-               default:
-                       if (c != scc)
-                               return (0);
-                       continue;
-
-               case '?':
-                       if (scc == 0)
-                               return (0);
-                       continue;
-
-               case '/':
-                       if (scc)
-                               return (0);
-slash:
-                       s = entp;
-                       sgpathp = gpathp;
-                       while (*s)
-                               addpath(*s++);
-                       addpath('/');
-                       if (stat(gpath, &stb) == 0 && isdir(stb))
-                               if (*p == 0) {
-                                       Gcat(gpath, "");
-                                       globcnt++;
-                               } else
-                                       expand(p);
-                       gpathp = sgpathp;
-                       *gpathp = 0;
-                       return (0);
-               }
+    Char   *cp, **vlp = vl;
+
+    switch (action) {
+    case G_ERROR:
+       setname(short2str(str));
+       blkfree(vl);
+       stderror(ERR_NAME | ERR_AMBIG);
+       break;
+    case G_APPEND:
+       trim(vlp);
+       str = Strsave(*vlp++);
+       do {
+           cp = Strspl(str, STRspace);
+           xfree((ptr_t) str);
+           str = Strspl(cp, *vlp);
+           xfree((ptr_t) cp);
        }
        }
+       while (*++vlp);
+       blkfree(vl);
+       break;
+    case G_IGNORE:
+       str = Strsave(strip(*vlp));
+       blkfree(vl);
+       break;
+    }
+    return (str);
 }
 
 }
 
-Gmatch(s, p)
-       register char *s, *p;
+static Char **
+libglob(vl)
+    Char  **vl;
 {
 {
-       register int scc;
-       int ok, lc;
-       int c, cc;
-
-       for (;;) {
-               scc = *s++ & TRIM;
-               switch (c = *p++) {
-
-               case '[':
-                       ok = 0;
-                       lc = 077777;
-                       while (cc = *p++) {
-                               if (cc == ']') {
-                                       if (ok)
-                                               break;
-                                       return (0);
-                               }
-                               if (cc == '-') {
-                                       if (lc <= scc && scc <= *p++)
-                                               ok++;
-                               } else
-                                       if (scc == (lc = cc))
-                                               ok++;
-                       }
-                       if (cc == 0)
-                               bferr("Missing ]");
-                       continue;
-
-               case '*':
-                       if (!*p)
-                               return (1);
-                       for (s--; *s; s++)
-                               if (Gmatch(s, p))
-                                       return (1);
-                       return (0);
-
-               case 0:
-                       return (scc == 0);
-
-               default:
-                       if ((c & TRIM) != scc)
-                               return (0);
-                       continue;
-
-               case '?':
-                       if (scc == 0)
-                               return (0);
-                       continue;
-
-               }
+    int     gflgs = GLOB_QUOTE | GLOB_NOCHECK;
+    glob_t  globv;
+    char   *ptr;
+
+    globv.gl_offs = 0;
+    globv.gl_pathv = 0;
+    globv.gl_pathc = 0;
+    nonomatch = adrof(STRnonomatch) != 0;
+    do {
+       ptr = short2qstr(*vl);
+       switch (glob(ptr, gflgs, 0, &globv)) {
+       case GLOB_ABEND:
+           setname(ptr);
+           stderror(ERR_NAME | ERR_GLOB);
+           /* NOTREACHED */
+       case GLOB_NOSPACE:
+           stderror(ERR_NOMEM);
+           /* NOTREACHED */
+       default:
+           break;
+       }
+       if (!nonomatch && (globv.gl_matchc == 0) &&
+           (globv.gl_flags & GLOB_MAGCHAR)) {
+           globfree(&globv);
+           return (NULL);
        }
        }
+       gflgs |= GLOB_APPEND;
+    }
+    while (*++vl);
+    vl = blk2short(globv.gl_pathv);
+    globfree(&globv);
+    return (vl);
 }
 
 }
 
-Gcat(s1, s2)
-       register char *s1, *s2;
+Char   *
+globone(str, action)
+    Char   *str;
+    int     action;
 {
 
 {
 
-       gnleft -= strlen(s1) + strlen(s2) + 1;
-       if (gnleft <= 0 || ++gargc >= GAVSIZ)
-               error("Arguments too long");
-       gargv[gargc] = 0;
-       gargv[gargc - 1] = strspl(s1, s2);
-}
-
-addpath(c)
-       char c;
-{
+    Char   *v[2], **vl, **vo;
 
 
-       if (gpathp >= lastgpathp)
-               error("Pathname too long");
-       *gpathp++ = c;
-       *gpathp = 0;
-}
+    noglob = adrof(STRnoglob) != 0;
+    gflag = 0;
+    v[0] = str;
+    v[1] = 0;
+    tglob(v);
+    if (gflag == G_NONE)
+       return (strip(Strsave(str)));
 
 
-rscan(t, f)
-       register char **t;
-       int (*f)();
-{
-       register char *p, c;
-
-       while (p = *t++) {
-               if (f == tglob)
-                       if (*p == '~')
-                               gflag |= 2;
-                       else if (eq(p, "{") || eq(p, "{}"))
-                               continue;
-               while (c = *p++)
-                       (*f)(c);
+    if (gflag & G_CSH) {
+       /*
+        * Expand back-quote, tilde and brace
+        */
+       vo = globexpand(v);
+       if (noglob || (gflag & G_GLOB) == 0) {
+           if (vo[0] == NULL) {
+               xfree((ptr_t) vo);
+               return (Strsave(STRNULL));
+           }
+           if (vo[1] != NULL)
+               return (handleone(str, vo, action));
+           else {
+               str = strip(vo[0]);
+               xfree((ptr_t) vo);
+               return (str);
+           }
        }
        }
+    }
+    else if (noglob || (gflag & G_GLOB) == 0)
+       return (strip(Strsave(str)));
+    else
+       vo = v;
+
+    vl = libglob(vo);
+    if (gflag & G_CSH)
+       blkfree(vo);
+    if (vl == NULL) {
+       setname(short2str(str));
+       stderror(ERR_NAME | ERR_NOMATCH);
+    }
+    if (vl[0] == NULL) {
+       xfree((ptr_t) vl);
+       return (Strsave(STRNULL));
+    }
+    if (vl[1] != NULL)
+       return (handleone(str, vl, action));
+    else {
+       str = strip(*vl);
+       xfree((ptr_t) vl);
+       return (str);
+    }
 }
 
 }
 
-scan(t, f)
-       register char **t;
-       int (*f)();
+Char  **
+globall(v)
+    Char  **v;
 {
 {
-       register char *p, c;
+    Char  **vl, **vo;
 
 
-       while (p = *t++)
-               while (c = *p)
-                       *p++ = (*f)(c);
+    if (!v || !v[0]) {
+       gargv = saveblk(v);
+       gargc = blklen(gargv);
+       return (gargv);
+    }
+
+    noglob = adrof(STRnoglob) != 0;
+
+    if (gflag & G_CSH)
+       /*
+        * Expand back-quote, tilde and brace
+        */
+       vl = vo = globexpand(v);
+    else
+       vl = vo = saveblk(v);
+
+    if (!noglob && (gflag & G_GLOB)) {
+       vl = libglob(vo);
+       if (gflag & G_CSH)
+           blkfree(vo);
+    }
+
+    gargc = vl ? blklen(vl) : 0;
+    return (gargv = vl);
 }
 
 }
 
-tglob(c)
-       register char c;
+void
+ginit()
 {
 {
-
-       if (any(c, globchars))
-               gflag |= c == '{' ? 2 : 1;
-       return (c);
+    gargsiz = GLOBSPACE;
+    gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
+    gargv[0] = 0;
+    gargc = 0;
 }
 
 }
 
-trim(c)
-       char c;
+void
+rscan(t, f)
+    register Char **t;
+    void    (*f) ();
 {
 {
+    register Char *p;
 
 
-       return (c & TRIM);
+    while (p = *t++)
+       while (*p)
+           (*f) (*p++);
 }
 
 }
 
-tback(c)
-       char c;
+void
+trim(t)
+    register Char **t;
 {
 {
+    register Char *p;
 
 
-       if (c == '`')
-               gflag = 1;
+    while (p = *t++)
+       while (*p)
+           *p++ &= TRIM;
 }
 
 }
 
-char *
-globone(str)
-       register char *str;
+void
+tglob(t)
+    register Char **t;
 {
 {
-       char *gv[2];
-       register char **gvp;
-       register char *cp;
-
-       gv[0] = str;
-       gv[1] = 0;
-       gflag = 0;
-       rscan(gv, tglob);
-       if (gflag) {
-               gvp = glob(gv);
-               if (gvp == 0) {
-                       setname(str);
-                       bferr("No match");
-               }
-               cp = *gvp++;
-               if (cp == 0)
-                       cp = "";
-               else if (*gvp) {
-                       setname(str);
-                       bferr("Ambiguous");
-               } else
-                       cp = strip(cp);
-/*
-               if (cp == 0 || *gvp) {
-                       setname(str);
-                       bferr(cp ? "Ambiguous" : "No output");
-               }
-*/
-               xfree((char *)gargv); gargv = 0;
-       } else {
-               scan(gv, trim);
-               cp = savestr(gv[0]);
-       }
-       return (cp);
+    register Char *p, c;
+
+    while (p = *t++) {
+       if (*p == '~' || *p == '=')
+           gflag |= G_CSH;
+       else if (*p == '{' &&
+                (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
+           continue;
+       while (c = *p++)
+           if (isglob(c))
+               gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
+    }
 }
 
 /*
 }
 
 /*
- * Command substitute cp.  If literal, then this is
- * a substitution from a << redirection, and so we should
- * not crunch blanks and tabs, separating words only at newlines.
+ * Command substitute cp.  If literal, then this is a substitution from a
+ * << redirection, and so we should not crunch blanks and tabs, separating
+ * words only at newlines.
  */
  */
-char **
+Char  **
 dobackp(cp, literal)
 dobackp(cp, literal)
-       char *cp;
-       bool literal;
+    Char   *cp;
+    bool    literal;
 {
 {
-       register char *lp, *rp;
-       char *ep;
-       char word[BUFSIZ];
-       char *apargv[GAVSIZ + 2];
-
-       if (pargv) {
-               abort();
-               blkfree(pargv);
+    register Char *lp, *rp;
+    Char   *ep, word[MAXPATHLEN];
+
+    if (pargv) {
+       abort();
+       blkfree(pargv);
+    }
+    pargsiz = GLOBSPACE;
+    pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
+    pargv[0] = NULL;
+    pargcp = pargs = word;
+    pargc = 0;
+    pnleft = MAXPATHLEN - 4;
+    for (;;) {
+       for (lp = cp; *lp != '`'; lp++) {
+           if (*lp == 0) {
+               if (pargcp != pargs)
+                   pword();
+               return (pargv);
+           }
+           psave(*lp);
        }
        }
-       pargv = apargv;
-       pargv[0] = NOSTR;
-       pargcp = pargs = word;
-       pargc = 0;
-       pnleft = BUFSIZ - 4;
-       for (;;) {
-               for (lp = cp; *lp != '`'; lp++) {
-                       if (*lp == 0) {
-                               if (pargcp != pargs)
-                                       pword();
-#ifdef GDEBUG
-                               printf("leaving dobackp\n");
-#endif
-                               return (pargv = copyblk(pargv));
-                       }
-                       psave(*lp);
-               }
-               lp++;
-               for (rp = lp; *rp && *rp != '`'; rp++)
-                       if (*rp == '\\') {
-                               rp++;
-                               if (!*rp)
-                                       goto oops;
-                       }
+       lp++;
+       for (rp = lp; *rp && *rp != '`'; rp++)
+           if (*rp == '\\') {
+               rp++;
                if (!*rp)
                if (!*rp)
-oops:
-                       error("Unmatched `");
-               ep = savestr(lp);
-               ep[rp - lp] = 0;
-               backeval(ep, literal);
-#ifdef GDEBUG
-               printf("back from backeval\n");
-#endif
-               cp = rp + 1;
-       }
+                   goto oops;
+           }
+       if (!*rp)
+    oops:  stderror(ERR_UNMATCHED, '`');
+       ep = Strsave(lp);
+       ep[rp - lp] = 0;
+       backeval(ep, literal);
+       cp = rp + 1;
+    }
 }
 
 }
 
+static void
 backeval(cp, literal)
 backeval(cp, literal)
-       char *cp;
-       bool literal;
+    Char   *cp;
+    bool    literal;
 {
 {
-       int pvec[2];
-       int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
-       char ibuf[BUFSIZ];
-       register int icnt = 0, c;
-       register char *ip;
-       bool hadnl = 0;
-       char *fakecom[2];
-       struct command faket;
-
-       faket.t_dtyp = TCOM;
-       faket.t_dflg = 0;
-       faket.t_dlef = 0;
-       faket.t_drit = 0;
-       faket.t_dspr = 0;
-       faket.t_dcom = fakecom;
-       fakecom[0] = "` ... `";
-       fakecom[1] = 0;
-       /*
-        * We do the psave job to temporarily change the current job
-        * so that the following fork is considered a separate job.
-        * This is so that when backquotes are used in a
-        * builtin function that calls glob the "current job" is not corrupted.
-        * We only need one level of pushed jobs as long as we are sure to
-        * fork here.
-        */
-       psavejob();
+    register int icnt, c;
+    register Char *ip;
+    struct command faket;
+    bool    hadnl;
+    int     pvec[2], quoted;
+    Char   *fakecom[2], ibuf[BUFSIZ];
+    char    tibuf[BUFSIZ];
+
+    hadnl = 0;
+    icnt = 0;
+    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
+    faket.t_dtyp = NODE_COMMAND;
+    faket.t_dflg = 0;
+    faket.t_dlef = 0;
+    faket.t_drit = 0;
+    faket.t_dspr = 0;
+    faket.t_dcom = fakecom;
+    fakecom[0] = STRfakecom1;
+    fakecom[1] = 0;
+
+    /*
+     * We do the psave job to temporarily change the current job so that the
+     * following fork is considered a separate job.  This is so that when
+     * backquotes are used in a builtin function that calls glob the "current
+     * job" is not corrupted.  We only need one level of pushed jobs as long as
+     * we are sure to fork here.
+     */
+    psavejob();
+
+    /*
+     * It would be nicer if we could integrate this redirection more with the
+     * routines in sh.sem.c by doing a fake execute on a builtin function that
+     * was piped out.
+     */
+    mypipe(pvec);
+    if (pfork(&faket, -1) == 0) {
+       struct wordent paraml;
+       struct command *t;
+
+       (void) close(pvec[0]);
+       (void) dmove(pvec[1], 1);
+       (void) dmove(SHDIAG, 2);
+       initdesc();
        /*
        /*
-        * It would be nicer if we could integrate this redirection more
-        * with the routines in sh.sem.c by doing a fake execute on a builtin
-        * function that was piped out.
+        * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
+        * posted to comp.bugs.4bsd 12 Sep. 1989.
         */
         */
-       mypipe(pvec);
-       if (pfork(&faket, -1) == 0) {
-               struct wordent paraml;
-               struct command *t;
-
-               close(pvec[0]);
-               dmove(pvec[1], 1);
-               dmove(SHDIAG, 2);
-               initdesc();
-               arginp = cp;
-               while (*cp)
-                       *cp++ &= TRIM;
-               lex(&paraml);
-               if (err)
-                       error(err);
-               alias(&paraml);
-               t = syntax(paraml.next, &paraml, 0);
-               if (err)
-                       error(err);
-               if (t)
-                       t->t_dflg |= FPAR;
-               execute(t, -1);
-               exitstat();
-       }
-       xfree(cp);
-       close(pvec[1]);
-       do {
-               int cnt = 0;
-               for (;;) {
-                       if (icnt == 0) {
-                               ip = ibuf;
-                               icnt = read(pvec[0], ip, BUFSIZ);
-                               if (icnt <= 0) {
-                                       c = -1;
-                                       break;
-                               }
-                       }
-                       if (hadnl)
-                               break;
-                       --icnt;
-                       c = (*ip++ & TRIM);
-                       if (c == 0)
-                               break;
-                       if (c == '\n') {
-                               /*
-                                * Continue around the loop one
-                                * more time, so that we can eat
-                                * the last newline without terminating
-                                * this word.
-                                */
-                               hadnl = 1;
-                               continue;
-                       }
-                       if (!quoted && (c == ' ' || c == '\t'))
-                               break;
-                       cnt++;
-                       psave(c | quoted);
+       if (pargv)              /* mg, 21.dec.88 */
+           blkfree(pargv), pargv = 0, pargsiz = 0;
+       /* mg, 21.dec.88 */
+       arginp = cp;
+       while (*cp)
+           *cp++ &= TRIM;
+       (void) lex(&paraml);
+       if (seterr)
+           stderror(ERR_OLD);
+       alias(&paraml);
+       t = syntax(paraml.next, &paraml, 0);
+       if (seterr)
+           stderror(ERR_OLD);
+       if (t)
+           t->t_dflg |= F_NOFORK;
+       (void) signal(SIGTSTP, SIG_IGN);
+       (void) signal(SIGTTIN, SIG_IGN);
+       (void) signal(SIGTTOU, SIG_IGN);
+       execute(t, -1, NULL, NULL);
+       exitstat();
+    }
+    xfree((ptr_t) cp);
+    (void) close(pvec[1]);
+    c = 0;
+    ip = NULL;
+    do {
+       int     cnt = 0;
+
+       for (;;) {
+           if (icnt == 0) {
+               int     i;
+
+               ip = ibuf;
+               do
+                   icnt = read(pvec[0], tibuf, BUFSIZ);
+               while (icnt == -1 && errno == EINTR);
+               if (icnt <= 0) {
+                   c = -1;
+                   break;
                }
                }
+               for (i = 0; i < icnt; i++)
+                   ip[i] = (unsigned char) tibuf[i];
+           }
+           if (hadnl)
+               break;
+           --icnt;
+           c = (*ip++ & TRIM);
+           if (c == 0)
+               break;
+           if (c == '\n') {
                /*
                /*
-                * Unless at end-of-file, we will form a new word
-                * here if there were characters in the word, or in
-                * any case when we take text literally.  If
-                * we didn't make empty words here when literal was
-                * set then we would lose blank lines.
+                * Continue around the loop one more time, so that we can eat
+                * the last newline without terminating this word.
                 */
                 */
-               if (c != -1 && (cnt || literal))
-                       pword();
-               hadnl = 0;
-       } while (c >= 0);
-#ifdef GDEBUG
-       printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
-       printf("also c = %c <%o>\n", c, c);
-#endif
-       close(pvec[0]);
-       pwait();
-       prestjob();
+               hadnl = 1;
+               continue;
+           }
+           if (!quoted && (c == ' ' || c == '\t'))
+               break;
+           cnt++;
+           psave(c | quoted);
+       }
+       /*
+        * Unless at end-of-file, we will form a new word here if there were
+        * characters in the word, or in any case when we take text literally.
+        * If we didn't make empty words here when literal was set then we
+        * would lose blank lines.
+        */
+       if (c != -1 && (cnt || literal))
+           pword();
+       hadnl = 0;
+    } while (c >= 0);
+    (void) close(pvec[0]);
+    pwait();
+    prestjob();
 }
 
 }
 
+static void
 psave(c)
 psave(c)
-       char c;
+    int    c;
 {
 {
-
-       if (--pnleft <= 0)
-               error("Word too long");
-       *pargcp++ = c;
+    if (--pnleft <= 0)
+       stderror(ERR_WTOOLONG);
+    *pargcp++ = c;
 }
 
 }
 
+static void
 pword()
 {
 pword()
 {
+    psave(0);
+    if (pargc == pargsiz - 1) {
+       pargsiz += GLOBSPACE;
+       pargv = (Char **) xrealloc((ptr_t) pargv,
+                                  (size_t) pargsiz * sizeof(Char *));
+    }
+    pargv[pargc++] = Strsave(pargs);
+    pargv[pargc] = NULL;
+    pargcp = pargs;
+    pnleft = MAXPATHLEN - 4;
+}
+
+int
+Gmatch(string, pattern)
+    register Char *string, *pattern;
+{
+    register Char stringc, patternc;
+    int     match;
+    Char    rangec;
+
+    for (;; ++string) {
+       stringc = *string & TRIM;
+       patternc = *pattern++;
+       switch (patternc) {
+       case 0:
+           return (stringc == 0);
+       case '?':
+           if (stringc == 0)
+               return (0);
+           break;
+       case '*':
+           if (!*pattern)
+               return (1);
+           while (*string)
+               if (Gmatch(string++, pattern))
+                   return (1);
+           return (0);
+       case '[':
+           match = 0;
+           while (rangec = *pattern++) {
+               if (rangec == ']')
+                   if (match)
+                       break;
+                   else
+                       return (0);
+               if (match)
+                   continue;
+               if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') {
+                   match = (stringc <= (*pattern & TRIM) &&
+                            (*(pattern - 2) & TRIM) <= stringc);
+                   pattern++;
+               }
+               else
+                   match = (stringc == rangec);
+           }
+           if (rangec == 0)
+               stderror(ERR_NAME | ERR_MISSING, ']');
+           break;
+       default:
+           if ((patternc & TRIM) != stringc)
+               return (0);
+           break;
+
+       }
+    }
+}
+
+void
+Gcat(s1, s2)
+    Char   *s1, *s2;
+{
+    register Char *p, *q;
+    int     n;
+
+    for (p = s1; *p++;);
+    for (q = s2; *q++;);
+    n = (p - s1) + (q - s2) - 1;
+    if (++gargc >= gargsiz) {
+       gargsiz += GLOBSPACE;
+       gargv = (Char **) xrealloc((ptr_t) gargv,
+                                  (size_t) gargsiz * sizeof(Char *));
+    }
+    gargv[gargc] = 0;
+    p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
+    for (q = s1; *p++ = *q++;);
+    for (p--, q = s2; *p++ = *q++;);
+}
+
+#ifdef FILEC
+int
+sortscmp(a, b)
+    register Char **a, **b;
+{
+#if defined(NLS) && !defined(NOSTRCOLL)
+    char    buf[2048];
+
+#endif
 
 
-       psave(0);
-       if (pargc == GAVSIZ)
-               error("Too many words from ``");
-       pargv[pargc++] = savestr(pargs);
-       pargv[pargc] = NOSTR;
-#ifdef GDEBUG
-       printf("got word %s\n", pargv[pargc-1]);
+    if (!a)                    /* check for NULL */
+       return (b ? 1 : 0);
+    if (!b)
+       return (-1);
+
+    if (!*a)                   /* check for NULL */
+       return (*b ? 1 : 0);
+    if (!*b)
+       return (-1);
+
+#if defined(NLS) && !defined(NOSTRCOLL)
+    (void) strcpy(buf, short2str(*a));
+    return ((int) strcoll(buf, short2str(*b)));
+#else
+    return ((int) Strcmp(*a, *b));
 #endif
 #endif
-       pargcp = pargs;
-       pnleft = BUFSIZ - 4;
 }
 }
+#endif /* FILEC */