diff options
Diffstat (limited to 'contrib/opie/glob.c')
-rw-r--r-- | contrib/opie/glob.c | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/contrib/opie/glob.c b/contrib/opie/glob.c new file mode 100644 index 0000000..342aa92 --- /dev/null +++ b/contrib/opie/glob.c @@ -0,0 +1,667 @@ +/* glob.c: The csh et al glob pattern matching routines. + +%%% copyright-cmetz +This software is Copyright 1996 by Craig Metz, All Rights Reserved. +The Inner Net License Version 2 applies to this software. +You should have received a copy of the license with this software. If +you didn't get a copy, you may request one from <license@inner.net>. + +Portions of this software are Copyright 1995 by Randall Atkinson and Dan +McDonald, All Rights Reserved. All Rights under this copyright are assigned +to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and +License Agreement applies to this software. + + History: + + Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. + Remove useless strings. Prototype right. + Modified at NRL for OPIE 2.0. + Originally from BSD. +*/ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * 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. + */ + +/* + * C-shell glob for random programs. + */ + +#include "opie_cfg.h" + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif /* HAVE_SYS_PARAM_H */ +#include <sys/stat.h> + +#include <dirent.h> +#if HAVE_PWD_H +#include <pwd.h> +#endif /* HAVE_PWD_H */ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#if HAVE_LIMITS_H +#include <limits.h> +#endif /* HAVE_LIMITS_H */ + +#include "opie.h" + +#ifndef NCARGS +#define NCARGS 600 +#endif /* NCARGS */ +#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 short gflag; + +static int letter __P((register char)); +static int digit __P((register char)); +static int any __P((int, char *)); +static int blklen __P((register char **)); +VOIDRET blkfree __P((char **)); +static char *strspl __P((register char *, register char *)); + +static int tglob __P((register char c)); + +extern int errno; +static char *strend __P((char *)); + +static int globcnt; + +static char *globchars = "`{[*?"; +char *globerr = NULL; +char *home = NULL; + +static char *gpath, *gpathp, *lastgpathp; +static int globbed; +static char *entp; +static char **sortbas; + +static int amatch __P((char *p, char *s)); +static int execbrc __P((register char *p, register char *s)); +VOIDRET opiefatal __P((char *)); +char **copyblk __P((char **)); + +static int match FUNCTION((s, p), char *s AND 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); +} + + +static int Gmatch FUNCTION((s, p), register char *s AND register char *p) +{ + 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) + if (ok) + p--; + else + return 0; + 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; + + } + } +} + +static VOIDRET Gcat FUNCTION((s1, s2), register char *s1 AND register 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); + } +} + +static VOIDRET addpath FUNCTION((c), char c) +{ + + if (gpathp >= lastgpathp) + globerr = "Pathname too long"; + else { + *gpathp++ = c; + *gpathp = 0; + } +} + +static VOIDRET rscan FUNCTION((t, f), register char **t AND int (*f)__P((char))) +{ + 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); + } +} + +static int tglob FUNCTION((c), register char c) +{ + if (any(c, globchars)) + gflag |= c == '{' ? 2 : 1; + return (c); +} + +static int letter FUNCTION((c), register char c) +{ + return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); +} + +static int digit FUNCTION((c), register char c) +{ + return (c >= '0' && c <= '9'); +} + +static int any FUNCTION((c, s), int c AND char *s) +{ + while (*s) + if (*s++ == c) + return (1); + return (0); +} + +static int blklen FUNCTION((av), register char **av) +{ + register int i = 0; + + while (*av++) + i++; + return (i); +} + +static char **blkcpy FUNCTION((oav, bv), char **oav AND register char **bv) +{ + register char **av = oav; + + while (*av++ = *bv++) + continue; + return (oav); +} + +VOIDRET blkfree FUNCTION((av0), char **av0) +{ + register char **av = av0; + + while (*av) + free(*av++); +} + +static char *strspl FUNCTION((cp, dp), register char *cp AND register char *dp) +{ + register char *ep = (char *) malloc((unsigned) (strlen(cp) + + strlen(dp) + 1)); + + if (ep == (char *) 0) + opiefatal("Out of memory"); + strcpy(ep, cp); + strcat(ep, dp); + return (ep); +} + +char **copyblk FUNCTION((v), char **v) +{ + register char **nv = (char **) malloc((unsigned) ((blklen(v) + 1) * + sizeof(char **))); + + if (nv == (char **) 0) + opiefatal("Out of memory"); + + return (blkcpy(nv, v)); +} + +static char *strend FUNCTION((cp), register char *cp) +{ + + while (*cp) + cp++; + return (cp); +} + +/* + * Extract a home directory from the password file + * The argument points to a buffer where the name of the + * user whose home directory is sought is currently. + * We write the home directory of the user back there. + */ +static int gethdir FUNCTION((home), char *home) +{ + register struct passwd *pp = getpwnam(home); + + if (!pp || home + strlen(pp->pw_dir) >= lastgpathp) + return (1); + strcpy(home, pp->pw_dir); + return (0); +} + +static VOIDRET ginit FUNCTION((agargv), char **agargv) +{ + agargv[0] = 0; + gargv = agargv; + sortbas = agargv; + gargc = 0; + gnleft = NCARGS - 4; +} + +static VOIDRET sort FUNCTION_NOARGS +{ + 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 VOIDRET matchdir FUNCTION((pattern), char *pattern) +{ + struct stat stb; + + register struct dirent *dp; + + DIR *dirp; + + dirp = opendir(*gpath == '\0' ? "." : gpath); + if (dirp == NULL) { + if (globbed) + return; + goto patherr2; + } +#if !defined(linux) + if (fstat(dirp->dd_fd, &stb) < 0) + goto patherr1; + if (!isdir(stb)) { + errno = ENOTDIR; + goto patherr1; + } +#endif /* !defined(linux) */ + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_ino == 0) + continue; + if (match(dp->d_name, pattern)) { + Gcat(gpath, dp->d_name); + globcnt++; + } + } + closedir(dirp); + return; + +patherr1: + closedir(dirp); +patherr2: + globerr = "Bad directory components"; +} + +static VOIDRET expand FUNCTION((as), char *as) +{ + 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)) + globerr = "Unknown user name after ~"; + strcpy(gpath, gpath + 1); + } else + strcpy(gpath, 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, ((char *) 0)); + return; + } + matchdir(cs); +endit: + gpathp = sgpathp; + *gpathp = 0; +} + +static int execbrc FUNCTION((p, s), char *p AND char *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; + continue; + } +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; + strcpy(lm, pl); + 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++) + continue; + if (!*pm) + pm--; + continue; + } + if (brclev) + goto doit; + return (0); +} + +static VOIDRET acollect FUNCTION((as), register char *as) +{ + register int ogargc = gargc; + + gpathp = gpath; + *gpathp = 0; + globbed = 0; + expand(as); + if (gargc != ogargc) + sort(); +} + +static VOIDRET collect FUNCTION((as), register char *as) +{ + if (eq(as, "{") || eq(as, "{}")) { + Gcat(as, ""); + sort(); + } else + acollect(as); +} + +static int amatch FUNCTION((s, p), register char *s AND register 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 (stat(gpath, &stb) == 0 && isdir(stb)) + if (*p == 0) { + Gcat(gpath, ""); + globcnt++; + } else + expand(p); + gpathp = sgpathp; + *gpathp = 0; + return (0); + } + } +} + + +char **ftpglob FUNCTION((v), register char *v) +{ + char agpath[BUFSIZ]; + char *agargv[GAVSIZ]; + char *vv[2]; + + vv[0] = v; + vv[1] = 0; + gflag = 0; + rscan(vv, tglob); + if (gflag == 0) { + vv[0] = strspl(v, ""); + 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)); +} |