rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit 960afa1642f23d71c07be587ccf25c1a41b2fe98
parent 53cf1b1c1c3f0c2b5067afccc2976b99a574a089
Author: tim <tim>
Date:   Wed, 14 May 1997 16:13:50 +0000

Initial revision

Diffstat:
Aglob.c | 270+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aproto.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