Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libc/gen/glob.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -p -r1.3 -r1.4 --- src/lib/libc/gen/glob.c 1993/08/26 00:44:46 1.3 +++ src/lib/libc/gen/glob.c 1993/11/06 01:10:18 1.4 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Guido van Rossum. @@ -35,8 +35,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)glob.c 5.18 (Berkeley) 12/4/92";*/ -static char *rcsid = "$Id: glob.c,v 1.3 1993/08/26 00:44:46 jtc Exp $"; +/* from: static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; */ +static char *rcsid = "$Id: glob.c,v 1.4 1993/11/06 01:10:18 cgd Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -56,19 +56,26 @@ static char *rcsid = "$Id: glob.c,v 1.3 * not contain any magic characters. [Used in csh style globbing] * GLOB_ALTDIRFUNC: * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b * gl_matchc: * Number of matches in the current invocation of glob. */ #include #include -#include -#include + #include +#include #include -#include +#include +#include #include #include +#include +#include #define DOLLAR '$' #define DOT '.' @@ -83,14 +90,34 @@ static char *rcsid = "$Id: glob.c,v 1.3 #define STAR '*' #define TILDE '~' #define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG #define M_QUOTE 0x8000 #define M_PROTECT 0x4000 #define M_MASK 0xffff #define M_ASCII 0x00ff -#define CHAR(c) ((c)&M_ASCII) -#define META(c) ((c)|M_QUOTE) +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) #define M_ALL META('*') #define M_END META(']') #define M_NOT META('!') @@ -99,38 +126,38 @@ static char *rcsid = "$Id: glob.c,v 1.3 #define M_SET META('[') #define ismeta(c) (((c)&M_QUOTE) != 0) -typedef u_short Char; static int compare __P((const void *, const void *)); -static void g_Ctoc __P((Char *, char *)); +static void g_Ctoc __P((const Char *, char *)); static int g_lstat __P((Char *, struct stat *, glob_t *)); static DIR *g_opendir __P((Char *, glob_t *)); static Char *g_strchr __P((Char *, int)); +#ifdef notdef +static Char *g_strcat __P((Char *, const Char *)); +#endif static int g_stat __P((Char *, struct stat *, glob_t *)); +static int glob0 __P((const Char *, glob_t *)); static int glob1 __P((Char *, glob_t *)); static int glob2 __P((Char *, Char *, Char *, glob_t *)); static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); -static int globextend __P((Char *, glob_t *)); +static int globextend __P((const Char *, glob_t *)); +static const Char * globtilde __P((const Char *, Char *, glob_t *)); +static int globexp1 __P((const Char *, glob_t *)); +static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); static int match __P((Char *, Char *, Char *)); #ifdef DEBUG -static void qprintf __P((Char *)); +static void qprintf __P((const char *, Char *)); #endif -/* - * The main glob() routine: compiles the pattern (optionally processing - * quotes), calls glob1() to do the real pattern matching, and finally - * sorts the list (unless unsorted operation is requested). Returns 0 - * if things went well, nonzero if errors occurred. It is not an error - * to find no matches. - */ +int glob(pattern, flags, errfunc, pglob) const char *pattern; - int flags, (*errfunc) __P((char *, int)); + int flags, (*errfunc) __P((const char *, int)); glob_t *pglob; { - const u_char *compilepat, *patnext; - int c, err, oldpathc; - Char *bufnext, *bufend, *compilebuf, *qpatnext, patbuf[MAXPATHLEN+1]; + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; patnext = (u_char *) pattern; if (!(flags & GLOB_APPEND)) { @@ -141,13 +168,10 @@ glob(pattern, flags, errfunc, pglob) } pglob->gl_flags = flags & ~GLOB_MAGCHAR; pglob->gl_errfunc = errfunc; - oldpathc = pglob->gl_pathc; pglob->gl_matchc = 0; bufnext = patbuf; bufend = bufnext + MAXPATHLEN; - compilebuf = bufnext; - compilepat = patnext; if (flags & GLOB_QUOTE) { /* Protect the quoted characters. */ while (bufnext < bufend && (c = *patnext++) != EOS) @@ -166,8 +190,221 @@ glob(pattern, flags, errfunc, pglob) *bufnext++ = c; *bufnext = EOS; + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN + 1]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, pglob) + const Char *pattern; + Char *patbuf; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; + *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ + if ((h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } + else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while ((*b++ = *p++) != EOS) + continue; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN+1]; + + qpatnext = globtilde(pattern, patbuf, pglob); + oldpathc = pglob->gl_pathc; bufnext = patbuf; - qpatnext = patbuf; + /* We don't need to check for buffer overflow any more. */ while ((c = *qpatnext++) != EOS) { switch (c) { @@ -176,7 +413,7 @@ glob(pattern, flags, errfunc, pglob) if (c == NOT) ++qpatnext; if (*qpatnext == EOS || - g_strchr(qpatnext+1, RBRACKET) == NULL) { + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { *bufnext++ = LBRACKET; if (c == NOT) --qpatnext; @@ -217,7 +454,7 @@ glob(pattern, flags, errfunc, pglob) } *bufnext = EOS; #ifdef DEBUG - qprintf(patbuf); + qprintf("glob0:", patbuf); #endif if ((err = glob1(patbuf, pglob)) != 0) @@ -230,30 +467,11 @@ glob(pattern, flags, errfunc, pglob) * GLOB_NOMAGIC is there just for compatibility with csh. */ if (pglob->gl_pathc == oldpathc && - ((flags & GLOB_NOCHECK) || - ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { - if (!(flags & GLOB_QUOTE)) { - Char *dp = compilebuf; - const u_char *sp = compilepat; - while (*dp++ = *sp++); - } - else { - /* - * Copy pattern, interpreting quotes; this is slightly - * different than the interpretation of quotes above - * -- which should prevail? - */ - while (*compilepat != EOS) { - if (*compilepat == QUOTE) { - if (*++compilepat == EOS) - --compilepat; - } - *compilebuf++ = (u_char)*compilepat++; - } - *compilebuf = EOS; - } - return(globextend(patbuf, pglob)); - } else if (!(flags & GLOB_NOSORT)) + ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR)))) + return(globextend(pattern, pglob)); + else if (!(pglob->gl_flags & GLOB_NOSORT)) qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, pglob->gl_pathc - oldpathc, sizeof(char *), compare); return(0); @@ -266,7 +484,7 @@ compare(p, q) return(strcmp(*(char **)p, *(char **)q)); } -static +static int glob1(pattern, pglob) Char *pattern; glob_t *pglob; @@ -284,7 +502,7 @@ glob1(pattern, pglob) * of recursion for each segment in the pattern that contains one or more * meta characters. */ -static +static int glob2(pathbuf, pathend, pattern, pglob) Char *pathbuf, *pathend, *pattern; glob_t *pglob; @@ -335,17 +553,24 @@ glob2(pathbuf, pathend, pattern, pglob) /* NOTREACHED */ } -static +static int glob3(pathbuf, pathend, pattern, restpattern, pglob) Char *pathbuf, *pathend, *pattern, *restpattern; glob_t *pglob; { register struct dirent *dp; - struct dirent *(*readdirfunc)(); DIR *dirp; - int len, err; + int err; char buf[MAXPATHLEN]; + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc)(); + *pathend = EOS; errno = 0; @@ -375,7 +600,8 @@ glob3(pathbuf, pathend, pattern, restpat if (dp->d_name[0] == DOT && *pattern != DOT) continue; for (sc = (u_char *) dp->d_name, dc = pathend; - *dc++ = *sc++;); + (*dc++ = *sc++) != EOS;) + continue; if (!match(pathend, pattern, restpattern)) { *pathend = EOS; continue; @@ -409,17 +635,19 @@ glob3(pathbuf, pathend, pattern, restpat */ static int globextend(path, pglob) - Char *path; + const Char *path; glob_t *pglob; { register char **pathv; register int i; u_int newsize; char *copy; - Char *p; + const Char *p; newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - pathv = (char **)realloc((char *)pglob->gl_pathv, newsize); + pathv = pglob->gl_pathv ? + realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); if (pathv == NULL) return(GLOB_NOSPACE); @@ -431,7 +659,8 @@ globextend(path, pglob) } pglob->gl_pathv = pathv; - for (p = path; *p++;); + for (p = path; *p++;) + continue; if ((copy = malloc(p - path)) != NULL) { g_Ctoc(path, copy); pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; @@ -445,7 +674,7 @@ globextend(path, pglob) * pattern matching function for filenames. Each occurrence of the * * pattern causes a recursion level. */ -static +static int match(name, pat, patend) register Char *name, *pat, *patend; { @@ -471,7 +700,7 @@ match(name, pat, patend) ok = 0; if ((k = *name++) == EOS) return(0); - if (negate_range = ((*pat & M_MASK) == M_NOT)) + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) ++pat; while (((c = *pat++) & M_MASK) != M_END) if ((*pat & M_MASK) == M_RNG) { @@ -515,14 +744,15 @@ g_opendir(str, pglob) glob_t *pglob; { char buf[MAXPATHLEN]; - char *dirname; if (!*str) strcpy(buf, "."); else g_Ctoc(str, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) return((*pglob->gl_opendir)(buf)); + return(opendir(buf)); } @@ -566,23 +796,44 @@ g_strchr(str, ch) return (NULL); } +#ifdef notdef +static Char * +g_strcat(dst, src) + Char *dst; + const Char* src; +{ + Char *sdst = dst; + + while (*dst++) + continue; + --dst; + while((*dst++ = *src++) != EOS) + continue; + + return (sdst); +} +#endif + static void g_Ctoc(str, buf) - register Char *str; + register const Char *str; char *buf; { register char *dc; - for (dc = buf; *dc++ = *str++;); + for (dc = buf; (*dc++ = *str++) != EOS;) + continue; } #ifdef DEBUG static void -qprintf(s) +qprintf(str, s) + const char *str; register Char *s; { register Char *p; + (void)printf("%s:\n", str); for (p = s; *p; p++) (void)printf("%c", CHAR(*p)); (void)printf("\n");