commit 960afa1642f23d71c07be587ccf25c1a41b2fe98
parent 53cf1b1c1c3f0c2b5067afccc2976b99a574a089
Author: tim <tim>
Date: Wed, 14 May 1997 16:13:50 +0000
Initial revision
Diffstat:
A | glob.c | | | 270 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | proto.h | | | 82 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 352 insertions(+), 0 deletions(-)
diff --git a/glob.c b/glob.c
@@ -0,0 +1,270 @@
+/* glob.c: rc's (ugly) globber. This code is not elegant, but it works */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "rc.h"
+#ifdef NODIRENT
+#include <sys/dir.h>
+#define dirent direct /* need to get the struct declaraction right */
+#else
+#include <dirent.h>
+#endif
+
+static List *dmatch(char *, char *, char *);
+static List *doglob(char *, char *);
+static List *lglob(List *, char *, char *, SIZE_T);
+static List *sort(List *);
+
+/*
+ Matches a list of words s against a list of patterns p. Returns true iff
+ a pattern in p matches a word in s. () matches (), but otherwise null
+ patterns match nothing.
+*/
+
+extern bool lmatch(List *s, List *p) {
+ List *q;
+ int i;
+ bool okay;
+ if (s == NULL) {
+ if (p == NULL) /* null matches null */
+ return TRUE;
+ for (; p != NULL; p = p->n) { /* one or more stars match null */
+ if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */
+ okay = TRUE;
+ for (i = 0; p->w[i] != '\0'; i++)
+ if (p->w[i] != '*' || p->m[i] != 1) {
+ okay = FALSE;
+ break;
+ }
+ if (okay)
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ for (; s != NULL; s = s->n)
+ for (q = p; q != NULL; q = q->n)
+ if (match(q->w, q->m, s->w))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ Globs a list; checks to see if each element in the list has a metacharacter. If it
+ does, it is globbed, and the output is sorted.
+*/
+
+extern List *glob(List *s) {
+ List *top, *r;
+ bool meta;
+ for (r = s, meta = FALSE; r != NULL; r = r->n)
+ if (r->m != NULL)
+ meta = TRUE;
+ if (!meta)
+ return s; /* don't copy lists with no metacharacters in them */
+ for (top = r = NULL; s != NULL; s = s->n) {
+ if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
+ if (top == NULL)
+ top = r = nnew(List);
+ else
+ r = r->n = nnew(List);
+ r->w = s->w;
+ } else {
+ if (top == NULL)
+ top = r = sort(doglob(s->w, s->m));
+ else
+ r->n = sort(doglob(s->w, s->m));
+ while (r->n != NULL)
+ r = r->n;
+ }
+ }
+ r->n = NULL;
+ return top;
+}
+
+/* Matches a pattern p against the contents of directory d */
+
+static List *dmatch(char *d, char *p, char *m) {
+ bool matched = FALSE;
+ List *top, *r;
+ static DIR *dirp;
+ static struct dirent *dp;
+ static struct stat s;
+ /* prototypes for XXXdir functions. comment out if necessary */
+ extern DIR *opendir(const char *);
+ extern struct dirent *readdir(DIR *);
+ /*extern int closedir(DIR *);*/
+ int i;
+
+ /*
+ return a match if there are no metacharacters; allows globbing through
+ directories with no read permission. make sure the file exists, though.
+ */
+ matched = TRUE;
+ if (m != NULL)
+ for (i = 0; p[i] != '\0'; i++)
+ if (m[i]) {
+ matched = FALSE;
+ break;
+ }
+
+ if (matched) {
+ char *path = nprint("%s/%s", d, p);
+ if (stat(path, &s) < 0)
+ return NULL;
+ r = nnew(List);
+ r->w = ncpy(p);
+ r->m = NULL;
+ r->n = NULL;
+ return r;
+ }
+
+ top = r = NULL;
+ if ((dirp = opendir(d)) == NULL)
+ return NULL;
+ /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
+ if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) {
+ closedir(dirp);
+ return NULL;
+ }
+ while ((dp = readdir(dirp)) != NULL)
+ if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
+ matched = TRUE;
+ if (top == NULL)
+ top = r = nnew(List);
+ else
+ r = r->n = nnew(List);
+ r->w = ncpy(dp->d_name);
+ r->m = NULL;
+ }
+ closedir(dirp);
+ if (!matched)
+ return NULL;
+ r->n = NULL;
+ return top;
+}
+
+/*
+ lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*"
+ will return a list with all the files in /tmp, /usr, and /bin. NULL on no match.
+ slashcount indicates the number of slashes to stick between the directory and the
+ matched name. e.g., for matching ////tmp/////foo*
+*/
+
+static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
+ List *q, *r, *top, foo;
+ static struct {
+ List l;
+ SIZE_T size;
+ } slash;
+ if (slashcount+1 > slash.size) {
+ slash.size = 2*(slashcount+1);
+ slash.l.w = erealloc(slash.l.w, slash.size);
+ }
+ slash.l.w[slashcount] = '\0';
+ while (slashcount > 0)
+ slash.l.w[--slashcount] = '/';
+ for (top = r = NULL; s != NULL; s = s->n) {
+ q = dmatch(s->w, p, m);
+ if (q != NULL) {
+ foo.w = s->w;
+ foo.m = NULL;
+ foo.n = NULL;
+ if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
+ q = concat(&slash.l, q); /* dir/name with slash */
+ q = concat(&foo, q);
+ if (r == NULL)
+ top = r = q;
+ else
+ r->n = q;
+ while (r->n != NULL)
+ r = r->n;
+ }
+ }
+ return top;
+}
+
+/*
+ Doglob globs a pathname in pattern form against a unix path. Returns the original
+ pattern (cleaned of metacharacters) on failure, or the globbed string(s).
+*/
+
+static List *doglob(char *w, char *m) {
+ static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
+ static SIZE_T dsize = 0;
+ char *d, *p, *md, *mp;
+ SIZE_T psize;
+ char *s = w;
+ List firstdir;
+ List *matched;
+ if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
+ efree(dir); efree(pattern); efree(metadir); efree(metapattern);
+ dir = ealloc(psize);
+ pattern = ealloc(psize);
+ metadir = ealloc(psize);
+ metapattern = ealloc(psize);
+ dsize = psize;
+ }
+ d = dir;
+ p = pattern;
+ md = metadir;
+ mp = metapattern;
+ if (*s == '/')
+ while (*s == '/')
+ *d++ = *s++, *md++ = *m++;
+ else
+ while (*s != '/' && *s != '\0')
+ *d++ = *s++, *md++ = *m++; /* get first directory component */
+ *d = '\0';
+ /*
+ Special case: no slashes in the pattern, i.e., open the current directory.
+ Remember that w cannot consist of slashes alone (the other way *s could be
+ zero) since doglob gets called iff there's a metacharacter to be matched
+ */
+ if (*s == '\0') {
+ matched = dmatch(".", dir, metadir);
+ goto end;
+ }
+ if (*w == '/') {
+ firstdir.w = dir;
+ firstdir.m = metadir;
+ firstdir.n = NULL;
+ matched = &firstdir;
+ } else {
+ /*
+ we must glob against current directory,
+ since the first character is not a slash.
+ */
+ matched = dmatch(".", dir, metadir);
+ }
+ do {
+ SIZE_T slashcount;
+ sigchk();
+ for (slashcount = 0; *s == '/'; s++, m++)
+ slashcount++; /* skip slashes */
+ while (*s != '/' && *s != '\0')
+ *p++ = *s++, *mp++ = *m++; /* get pattern */
+ *p = '\0';
+ matched = lglob(matched, pattern, metapattern, slashcount);
+ p = pattern, mp = metapattern;
+ } while (*s != '\0');
+end: if (matched == NULL) {
+ matched = nnew(List);
+ matched->w = w;
+ matched->m = NULL;
+ matched->n = NULL;
+ }
+ return matched;
+}
+
+static List *sort(List *s) {
+ SIZE_T nel = listnel(s);
+ if (nel > 1) {
+ char **a;
+ List *t;
+ qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp);
+ for (t = s; t != NULL; t = t->n)
+ t->w = *a++;
+ }
+ return s;
+}
diff --git a/proto.h b/proto.h
@@ -0,0 +1,82 @@
+/* proto.h
+ This file provides a definition for size_t and align_t that
+ should work for your system. If it does not, it is up to you to
+ make it the right thing. The problem is that I cannot rely upon
+ <sys/params.h> to do the right thing on machines which don't
+ yet have ansi header files. Note that on many RISC machines,
+ align_t must be at least 32 bits wide, and sparc doubles are
+ aligned on 64 bit boundaries, but of course rc does not use
+ doubles in its code, so the "typedef long ALIGN_T" is good
+ enough in the sparc's case. Also for performance reasons on a
+ VAX one would probably want align_t to be 32 bits wide.
+
+ You can override these definitions with compile-line definitions
+ of the same macros.
+*/
+
+#ifndef ALIGN_T
+typedef long ALIGN_T;
+#endif
+#ifndef SIZE_T
+typedef unsigned int SIZE_T;
+#endif
+#ifndef MODE_T
+typedef short int MODE_T;
+#endif
+#ifndef PID_T
+typedef int PID_T;
+#endif
+#ifndef SIG_ATOMIC_T
+typedef int SIG_ATOMIC_T;
+#endif
+
+/* fake stdlib.h */
+
+extern void exit(int);
+extern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *));
+
+/* fake string.h */
+
+extern int strncmp(const char *, const char *, SIZE_T);
+extern int strcmp(const char *, const char *);
+extern SIZE_T strlen(const char *);
+extern char *strchr(const char *, int);
+extern char *strrchr(const char *, int);
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, SIZE_T);
+extern char *strcat(char *, const char *);
+extern char *strncat(char *, const char *, SIZE_T);
+extern void *memcpy(void *, const void *, SIZE_T);
+extern void *memset(void *, int, SIZE_T);
+
+/* fake unistd.h */
+
+extern PID_T fork(void);
+extern PID_T getpid(void);
+extern char *getenv(const char *);
+extern int chdir(const char *);
+extern int close(int);
+extern int dup(int);
+extern int dup2(int, int);
+extern int execve(const char *, const char **, const char **);
+extern int execl(const char *,...);
+extern int getegid(void);
+extern int geteuid(void);
+extern int getgroups(int, int *);
+/*extern int ioctl(int, long,...);*/ /* too much trouble leaving this uncommented */
+extern int isatty(int);
+#ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */
+extern int mknod(const char *, int, int);
+#endif
+extern int pipe(int *);
+extern int read(int, void *, unsigned int);
+extern int setpgrp(int, PID_T);
+extern int unlink(const char *);
+extern int wait(int *);
+extern int write(int, const void *, unsigned int);
+
+/* fake errno.h for mips (which doesn't declare errno in errno.h!?!?) */
+
+#ifdef host_mips
+extern int errno;
+#endif