diff --git a/bsd_src/glob.c b/bsd_src/glob.c new file mode 100644 index 0000000..4dec543 --- /dev/null +++ b/bsd_src/glob.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * C-shell glob for random programs. + */ + +#include "tweak.h" +#include "client_def.h" +#include "c_extern.h" +#include "bsd_extern.h" + +#ifdef HAVE_LIMITS_H +#include +#endif + +#ifdef HAVE_SYS_SYSLIMITS_H +#include +#endif + +#ifdef STDC_HEADERS +#include +#endif +#include "my-string.h" + +#ifndef NCARGS +#define NCARGS ARG_MAX +#endif + +#define QUOTE 0200 +#define TRIM 0177 +#define eq(a,b) (strcmp(a, b)==0) +#define GAVSIZ (NCARGS/6) +#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) + +static char **gargv; /* Pointer to the (stack) arglist */ +static int gargc; /* Number args in gargv */ +static int gnleft; +static int gflag; +const char *globerr; + +static int globcnt; + +const char *globchars = "`{[*?"; + +static char *gpath, *gpathp, *lastgpathp; +static int globbed; +static char *entp; +static char **sortbas; + +static int any PROTO2(register int, c, register const char *, s) +{ + while (*s) + if (*s++ == c) return(1); + return(0); +} + +static int tglob PROTO1(char, c) +{ + if (any(c, globchars)) + gflag |= c == '{' ? 2 : 1; + return (c); +} + +static int addpath PROTO1(char, c) +{ + if (gpathp >= lastgpathp) globerr = "Pathname too long"; + else { + *gpathp++ = c; + *gpathp = 0; + } + return(0); +} + +static int ginit PROTO1(char **, agargv) +{ + agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; + gnleft = NCARGS - 4; + return(0); +} + +static void sort PROTO0((void)) +{ + 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; +} + +static char *strspl PROTO2(register char *, cp, register const char *, dp) +{ + register char *ep = (char *)malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); + + if (ep == (char *)0) { + perror("Out of memory 1"); + exit(1); + } + (void) strcpy(ep, cp); + (void) strcat(ep, dp); + return (ep); +} + +static int Gcat PROTO2(char *, s1, const char *, s2) +{ + register int len = strlen(s1) + strlen(s2) + 1; + + if (len >= gnleft || gargc >= GAVSIZ - 1) globerr = "Arguments too long"; + else { + gargc++; + gnleft -= len; + gargv[gargc] = 0; + gargv[gargc - 1] = strspl(s1, s2); + } + return(0); +} + +static int execbrc PROTO0((char *, char *)); +void matchdir PROTO0((char *)); + +static void expand PROTO1(char *, as) +{ + register char *cs; + register char *sgpathp, *oldcs; + struct stat stb; + + sgpathp = gpathp; + cs = as; + while (!any(*cs, globchars)) { + if (*cs == 0) { + if (!globbed) Gcat(gpath, ""); + else if (util_stat(gpath, &stb) >= 0) { + Gcat(gpath, ""); + globcnt++; + } + break; + } + addpath(*cs++); + } + if(*cs) { + oldcs = cs; + while (cs > as && *cs != '/') { + cs--; gpathp--; + } + if (*cs == '/') { + cs++; gpathp++; + } + *gpathp = 0; + if (*oldcs == '{') { + (void) execbrc(cs, ((char *)0)); + return; + } + matchdir(cs); + } + gpathp = sgpathp; + *gpathp = 0; +} + +static int amatch PROTO2(char *, s, char *, p) +{ + 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) { + if (ok) p--; + else return 0; + } + continue; + case '*': + if (!*p) return (1); + if (*p == '/') { + p++; + goto slash; + } + s--; + do { + if (amatch(s, p)) return (1); + } while (*s++); + 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 (util_stat(gpath, &stb) == 0 && isdir(stb)) + { + if (*p == 0) { + Gcat(gpath, ""); + globcnt++; + } else expand(p); + } + gpathp = sgpathp; + *gpathp = 0; + return (0); + } + } +} + +static int match PROTO2(char *, s, char *, p) +{ + register int c; + register char *sentp; + char sglobbed = globbed; + + if (*s == '.' && *p != '.') return (0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + globbed = sglobbed; + return (c); +} + +void matchdir PROTO1(char *, pattern) +{ + struct stat stb; + register struct rdirent *dp; + RDIR *dirp; + + dirp = util_opendir(gpath); + if (dirp == NULL) { + if (globbed) return; + globerr = "Bad directory components"; + return; + } + if (util_stat(gpath, &stb) < 0) { + util_closedir(dirp); + globerr = "Bad directory components"; + } + if (!isdir(stb)) { + errno = ENOTDIR; + util_closedir(dirp); + globerr = "Bad directory components"; + } + while ((dp = util_readdir(dirp)) != NULL) { + if (dp->d_fileno == 0) continue; + if (match(dp->d_name, pattern)) { + Gcat(gpath, dp->d_name); + globcnt++; + } + } + util_closedir(dirp); +} + +static int execbrc PROTO2(char *, p, char *, s) +{ + char restbuf[BUFSIZ + 2]; + register char *pe, *pm, *pl; + int brclev = 0; + char *lm, savec, *sgpathp; + + for (lm = restbuf; *p != '{'; *lm++ = *p++); + for (pe = ++p; *pe; pe++) + switch (*pe) { + case '{': + brclev++; + continue; + case '}': + if (brclev == 0) goto pend; + brclev--; + continue; + case '[': + for (pe++; *pe && *pe != ']'; pe++); + } +pend: + brclev = 0; + for (pl = pm = p; pm <= pe; pm++) + switch (*pm & (QUOTE|TRIM)) { + case '{': + brclev++; + continue; + case '}': + if (brclev) { + brclev--; + continue; + } + goto doit; + case ','|QUOTE: + case ',': + if (brclev) continue; +doit: + savec = *pm; + *pm = 0; + (void) strcpy(lm, pl); + (void) strcat(restbuf, pe + 1); + *pm = savec; + if (s == 0) { + sgpathp = gpathp; + expand(restbuf); + gpathp = sgpathp; + *gpathp = 0; + } else if (amatch(s, restbuf)) return (1); + sort(); + pl = pm + 1; + if (brclev) return (0); + continue; + case '[': + for (pm++; *pm && *pm != ']'; pm++); + if (!*pm) pm--; + continue; + } + if (brclev) goto doit; + return (0); +} + +static void acollect PROTO1(register char *, as) +{ + register int ogargc = gargc; + + gpathp = gpath; *gpathp = 0; globbed = 0; + expand(as); + if (gargc != ogargc) sort(); +} + +static void collect PROTO1(register char *, as) +{ + if (eq(as, "{") || eq(as, "{}")) { + Gcat(as, ""); + sort(); + } else acollect(as); +} + +static void blkfree PROTO1(char **, av0) +{ + register char **av = av0; + + while (*av) free(*av++); +} + +static int blklen PROTO1(register char **, av) +{ + register int i = 0; + + while (*av++) i++; + return (i); +} + +static char **blkcpy PROTO2(char **, oav, register char **, bv) +{ + register char **av = oav; + + while ( (*av++ = *bv++) ) continue; + return (oav); +} + +static char **copyblk PROTO1(register char **, v) +{ + register char **nv; + + nv = (char **)malloc((unsigned)((blklen(v) + 1) * sizeof(char **))); + if (nv == (char **)0) { + perror("Out of memory 2"); + exit(2); + } + return (blkcpy(nv, v)); +} + +#ifdef PROTOTYPES +typedef int (*charfunc) (char) ; +static void rscan (register char **t, charfunc f) +#else +static void rscan(t, f) + register char **t; + int (*f)(); +#endif +{ + register char *p, c; + + while ((p = *t++)) { +#ifdef PROTOTYPES + if (f == (charfunc) tglob) +#else + if (f == tglob) +#endif + { + if (*p == '~') gflag |= 2; + else if (eq(p, "{") || eq(p, "{}")) continue; + } + while ( (c = *p++) ) (*f)(c); + } +} + +char **glob PROTO1(register char *, v) +{ + char agpath[BUFSIZ]; + char *agargv[GAVSIZ]; + char *vv[2]; + vv[0] = v; + vv[1] = 0; + gflag = 0; +#ifdef PROTOTYPES + rscan(vv, (charfunc) tglob); +#else + rscan(vv, tglob); +#endif + if (gflag == 0) return (copyblk(vv)); + + globerr = 0; + gpath = agpath; gpathp = gpath; *gpathp = 0; + lastgpathp = &gpath[sizeof agpath - 2]; + ginit(agargv); globcnt = 0; + collect(v); + if (globcnt == 0 && (gflag&1)) { + blkfree(gargv), gargv = 0; + return (0); + } else return (gargv = copyblk(gargv)); +}