summaryrefslogtreecommitdiff
path: root/usr.sbin/sup/lib/expand.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sup/lib/expand.c')
-rw-r--r--usr.sbin/sup/lib/expand.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/usr.sbin/sup/lib/expand.c b/usr.sbin/sup/lib/expand.c
new file mode 100644
index 000000000000..ff4b09414c7e
--- /dev/null
+++ b/usr.sbin/sup/lib/expand.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ * expand - expand wildcard filename specifications
+ *
+ * Usage:
+ * int expand(spec, buffer, bufsize);
+ * char *spec, **buffer;
+ * int bufsize;
+ *
+ * Expand takes a file specification, and expands it into filenames
+ * by resolving the characters '*', '?', '[', ']', '{', '}' and '~'
+ * in the same manner as the shell. You provide "buffer", which is
+ * an array of char *'s, and you tell how big it is in bufsize.
+ * Expand will compute the corresponding filenames, and will fill up
+ * the entries of buffer with pointers to malloc'd strings.
+ *
+ * The value returned by expand is the number of filenames found. If
+ * this value is -1, then malloc failed to allocate a string. If the
+ * value is bufsize + 1, then too many names were found and you can try
+ * again with a bigger buffer.
+ *
+ * This routine was basically created from the csh sh.glob.c file with
+ * the following intended differences:
+ *
+ * Filenames are not sorted.
+ * All expanded filenames returned exist.
+ *
+ **********************************************************************
+ * HISTORY
+ * 13-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
+ * Replaced a stat() with lstat() and changed glob() to only call
+ * matchdir() for directories.
+ *
+ * 20-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
+ * Created from csh glob() function and 4.1 expand() function.
+ *
+ **********************************************************************
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <libc.h>
+#include <setjmp.h>
+
+static jmp_buf sjbuf;
+
+static char pathbuf[MAXPATHLEN];
+static char *path, *pathp, *lastpathp;
+
+static char *globchars = "{[*?"; /* meta characters */
+static char *entp; /* current dir entry pointer */
+
+static char **BUFFER; /* pointer to the buffer */
+static int BUFSIZE; /* maximum number in buffer */
+static int bufcnt; /* current number in buffer */
+
+#if __STDC__
+static addone __P((register char *, register char *));
+static addpath __P((char));
+static amatch __P((char *, char *));
+static execbrc __P((char *, char *));
+static gethdir __P((char *));
+static glob __P((char *));
+static matchdir __P((char *));
+static match __P((char *, char *));
+#endif
+
+int expand(spec, buffer, bufsize)
+ register char *spec;
+ char **buffer;
+ int bufsize;
+{
+ pathp = path = pathbuf;
+ *pathp = 0;
+ lastpathp = &path[MAXPATHLEN - 2];
+ BUFFER = buffer;
+ BUFSIZE = bufsize;
+ bufcnt = 0;
+ if (setjmp(sjbuf) == 0)
+ glob(spec);
+ return(bufcnt);
+}
+
+static glob(as)
+ char *as;
+{
+ register char *cs;
+ register char *spathp, *oldcs;
+ struct stat stb;
+
+ spathp = pathp;
+ cs = as;
+ if (*cs == '~' && pathp == path) {
+ if (addpath('~')) goto endit;
+ for (cs++; isalnum(*cs) || *cs == '_' || *cs == '-';)
+ if (addpath(*cs++)) goto endit;
+ if (!*cs || *cs == '/') {
+ if (pathp != path + 1) {
+ *pathp = 0;
+ if (gethdir(path + 1)) goto endit;
+ strcpy(path, path + 1);
+ } else
+ strcpy(path, (char *)getenv("HOME"));
+ pathp = path;
+ while (*pathp) pathp++;
+ }
+ }
+ while (*cs == 0 || index(globchars, *cs) == 0) {
+ if (*cs == 0) {
+ if (lstat(path, &stb) >= 0) addone(path, "");
+ goto endit;
+ }
+ if (addpath(*cs++)) goto endit;
+ }
+ oldcs = cs;
+ while (cs > as && *cs != '/')
+ cs--, pathp--;
+ if (*cs == '/')
+ cs++, pathp++;
+ *pathp = 0;
+ if (*oldcs == '{') {
+ execbrc(cs, NULL);
+ return;
+ }
+ /* this should not be an lstat */
+ if (stat(path, &stb) >= 0 && (stb.st_mode&S_IFMT) == S_IFDIR)
+ matchdir(cs);
+endit:
+ pathp = spathp;
+ *pathp = 0;
+ return;
+}
+
+static matchdir(pattern)
+ char *pattern;
+{
+ register struct direct *dp;
+ DIR *dirp;
+
+ dirp = opendir(path);
+ if (dirp == NULL)
+ return;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_ino == 0) continue;
+ if (match(dp->d_name, pattern))
+ addone(path, dp->d_name);
+ }
+ closedir(dirp);
+ return;
+}
+
+static execbrc(p, s)
+ char *p, *s;
+{
+ char restbuf[MAXPATHLEN + 1];
+ register char *pe, *pm, *pl;
+ int brclev = 0;
+ char *lm, savec, *spathp;
+
+ 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) break;
+ continue;
+ }
+pend:
+ if (brclev || !*pe) return (0);
+ for (pl = pm = p; pm <= pe; pm++)
+ switch (*pm & 0177) {
+ case '{':
+ brclev++;
+ continue;
+ case '}':
+ if (brclev) {
+ brclev--;
+ continue;
+ }
+ goto doit;
+ case ',':
+ if (brclev) continue;
+doit:
+ savec = *pm;
+ *pm = 0;
+ strcpy(lm, pl);
+ strcat(restbuf, pe + 1);
+ *pm = savec;
+ if (s == 0) {
+ spathp = pathp;
+ glob(restbuf);
+ pathp = spathp;
+ *pathp = 0;
+ } else if (amatch(s, restbuf))
+ return (1);
+ pl = pm + 1;
+ continue;
+
+ case '[':
+ for (pm++; *pm && *pm != ']'; pm++)
+ continue;
+ if (!*pm) break;
+ continue;
+ }
+ return (0);
+}
+
+static match(s, p)
+ char *s, *p;
+{
+ register int c;
+ register char *sentp;
+
+ if (*s == '.' && *p != '.') return(0);
+ sentp = entp;
+ entp = s;
+ c = amatch(s, p);
+ entp = sentp;
+ return (c);
+}
+
+static amatch(s, p)
+ register char *s, *p;
+{
+ register int scc;
+ int ok, lc;
+ char *spathp;
+ struct stat stb;
+ int c, cc;
+
+ for (;;) {
+ scc = *s++ & 0177;
+ 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) return (0);
+ 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;
+ spathp = pathp;
+ while (*s)
+ if (addpath(*s++)) goto pathovfl;
+ if (addpath('/')) goto pathovfl;
+ if (stat(path, &stb) >= 0 &&
+ (stb.st_mode&S_IFMT) == S_IFDIR)
+ if (*p == 0)
+ addone(path, "");
+ else
+ glob(p);
+pathovfl:
+ pathp = spathp;
+ *pathp = 0;
+ return (0);
+ }
+ }
+}
+
+static addone(s1, s2)
+ register char *s1, *s2;
+{
+ register char *ep;
+
+ if (bufcnt >= BUFSIZE) {
+ bufcnt = BUFSIZE + 1;
+ longjmp(sjbuf, 1);
+ }
+ ep = (char *)malloc(strlen(s1) + strlen(s2) + 1);
+ if (ep == 0) {
+ bufcnt = -1;
+ longjmp(sjbuf, 1);
+ }
+ BUFFER[bufcnt++] = ep;
+ while (*s1) *ep++ = *s1++;
+ while (*ep++ = *s2++);
+}
+
+static addpath(c)
+ char c;
+{
+ if (pathp >= lastpathp)
+ return(1);
+ *pathp++ = c;
+ *pathp = 0;
+ return(0);
+}
+
+static gethdir(home)
+ char *home;
+{
+ struct passwd *getpwnam();
+ register struct passwd *pp = getpwnam(home);
+
+ if (pp == 0)
+ return(1);
+ strcpy(home, pp->pw_dir);
+ return(0);
+}