-static char *sccsid = "@(#)glob.c 4.6 %G%";
-
-#include "sh.h"
-#include <sys/dir.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");
+#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
- 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");
-#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], "");
- sortbas = &gargv[gargc];
- } else
- acollect(pargv[i]);
- if (pargv)
- blkfree(pargv), pargv = 0;
-#ifdef GDEBUG
- printf("acollect done\n");
-#endif
- } else if (noglob || eq(as, "{") || eq(as, "{}")) {
- Gcat(as, "");
- sort();
- } 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;
- register struct direct *dp;
- DIR *dirp;
- register int cnt;
-
- dirp = opendir(gpath);
- if (dirp == NULL) {
- if (globbed)
- return;
- goto patherr2;
- }
- if (fstat(dirp->dd_fd, &stb) < 0)
- goto patherr1;
- if (!isdir(stb)) {
- errno = ENOTDIR;
- goto patherr1;
+ 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);
+ }
}
- while ((dp = readdir(dirp)) != NULL) {
- if (dp->d_ino == 0)
- continue;
- if (match(dp->d_name, pattern)) {
- Gcat(gpath, dp->d_name);
- globcnt++;
- }
+ else if (*pe == LBRC)
+ i++;
+ else if (*pe == RBRC) {
+ if (i == 0)
+ break;
+ i--;
}
- closedir(dirp);
- return;
-patherr1:
- closedir(dirp);
-patherr2:
- Perror(gpath);
-}
-
-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;
+ if (i != 0) {
+ blkfree(nv);
+ return (-LBRC);
+ }
- case '}':
- if (brclev == 0)
- goto pend;
- brclev--;
+ for (i = 0, pl = pm = p; pm <= pe; pm++)
+ switch (*pm) {
+ case LBRK:
+ for (++pm; *pm != RBRK && *pm != EOS; pm++)
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++;
- 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 ',':
- 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;
- 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;
- 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 & TRIM) != 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;
+
+ if (!v || !v[0]) {
+ gargv = saveblk(v);
+ gargc = blklen(gargv);
+ return (gargv);
+ }
- while (p = *t++)
- while (c = *p)
- *p++ = (*f)(c);
+ 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)
- 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)
-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)
- 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;
+ 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();
/*
- * 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.
+ * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
+ * posted to comp.bugs.4bsd 12 Sep. 1989.
*/
- 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;
-
- close(pvec[0]);
- dmove(pvec[1], 1);
- dmove(SHDIAG, 2);
- initdesc();
- arginp = cp;
- while (*cp)
- *cp++ &= TRIM;
- lex(¶ml);
- if (err)
- error(err);
- alias(¶ml);
- t = syntax(paraml.next, ¶ml, 0);
- if (err)
- error(err);
- if (t)
- t->t_dflg |= FPAR;
- signal(SIGTSTP, SIG_IGN);
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- 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(¶ml);
+ if (seterr)
+ stderror(ERR_OLD);
+ alias(¶ml);
+ t = syntax(paraml.next, ¶ml, 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)
- char c;
+ int c;
{
-
- if (--pnleft <= 0)
- error("Word too long");
- *pargcp++ = c;
+ if (--pnleft <= 0)
+ stderror(ERR_WTOOLONG);
+ *pargcp++ = c;
}
+static void
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
- pargcp = pargs;
- pnleft = BUFSIZ - 4;
}
+#endif /* FILEC */