X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/1c15e88899094343f75aeba04122cd96a96b428e..refs/tags/BSD-4_3_Net_2:/usr/src/lib/libc/gen/glob.c diff --git a/usr/src/lib/libc/gen/glob.c b/usr/src/lib/libc/gen/glob.c index 178a10b220..f53af54f4a 100644 --- a/usr/src/lib/libc/gen/glob.c +++ b/usr/src/lib/libc/gen/glob.c @@ -5,37 +5,56 @@ * This code is derived from software contributed to Berkeley by * Guido van Rossum. * - * Redistribution and use in source and binary forms are permitted provided - * that: (1) source distributions retain this entire copyright notice and - * comment, and (2) distributions including binaries display the following - * acknowledgement: ``This product includes software developed by the - * University of California, Berkeley and its contributors'' in the - * documentation or other materials provided with the distribution and in - * all advertising materials mentioning features or use of this software. - * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * 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. */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)glob.c 5.3 (Berkeley) 6/23/90"; +static char sccsid[] = "@(#)glob.c 5.12 (Berkeley) 6/24/91"; #endif /* LIBC_SCCS and not lint */ /* - * Glob: the interface is a superset of the one defined in POSIX 1003.2, - * draft 9. + * glob(3) -- a superset of the one defined in POSIX 1003.2. * * The [!...] convention to negate a range is supported (SysV, Posix, ksh). * * Optional extra services, controlled by flags not defined by POSIX: - * GLOB_QUOTE: escaping convention: \ inhibits any special meaning - the following character might have (except \ at end of - * string is kept); + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * gl_matchc: + * Number of matches in the current invocation of glob. */ +#include #include #include #include @@ -44,10 +63,7 @@ static char sccsid[] = "@(#)glob.c 5.3 (Berkeley) 6/23/90"; #include #include #include - -char *malloc(), *realloc(); - -typedef int bool_t; +#include #define DOLLAR '$' #define DOT '.' @@ -63,23 +79,37 @@ typedef int bool_t; #define TILDE '~' #define UNDERSCORE '_' -#define METABIT 0x80 -#define META(c) ((c)|METABIT) +#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) #define M_ALL META('*') #define M_END META(']') #define M_NOT META('!') #define M_ONE META('?') #define M_RNG META('-') #define M_SET META('[') -#define ismeta(c) (((c)&METABIT) != 0) - -static -compare(p, q) - void **p, **q; -{ - return(strcmp(*(char **)p, *(char **)q)); -} - +#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 int g_lstat __P((Char *, struct stat *)); +static DIR *g_opendir __P((Char *)); +static Char *g_strchr __P((Char *, int)); +static int g_stat __P((Char *, struct stat *)); +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 match __P((Char *, Char *, Char *)); +#ifdef DEBUG +static void qprintf __P((Char *)); +#endif /* * The main glob() routine: compiles the pattern (optionally processing @@ -89,92 +119,110 @@ compare(p, q) * to find no matches. */ glob(pattern, flags, errfunc, pglob) - char *pattern; - int flags, (*errfunc)(); + const char *pattern; + int flags, (*errfunc) __P((char *, int)); glob_t *pglob; { - int err, oldpathc; - char *bufnext, *bufend, *compilebuf, *compilepat, *patnext; - char c, patbuf[MAXPATHLEN+1]; + const u_char *compilepat, *patnext; + int c, err, oldpathc; + Char *bufnext, *bufend, *compilebuf, *qpatnext, patbuf[MAXPATHLEN+1]; - patnext = pattern; + patnext = (u_char *) pattern; if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; if (!(flags & GLOB_DOOFFS)) pglob->gl_offs = 0; } - pglob->gl_flags = flags; + pglob->gl_flags = flags & ~GLOB_MAGCHAR; pglob->gl_errfunc = errfunc; oldpathc = pglob->gl_pathc; + pglob->gl_matchc = 0; bufnext = patbuf; - bufend = bufnext+MAXPATHLEN; - + bufend = bufnext + MAXPATHLEN; compilebuf = bufnext; compilepat = patnext; - while (bufnext < bufend && (c = *patnext++) != EOS) { + if (flags & GLOB_QUOTE) { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } + else + *bufnext++ = c; + } + else + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + *bufnext = EOS; + + bufnext = patbuf; + qpatnext = patbuf; + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { switch (c) { case LBRACKET: - c = *patnext; + pglob->gl_flags |= GLOB_MAGCHAR; + c = *qpatnext; if (c == NOT) - ++patnext; - if (*patnext == EOS || - strchr(patnext+1, RBRACKET) == NULL) { + ++qpatnext; + if (*qpatnext == EOS || + g_strchr(qpatnext+1, RBRACKET) == NULL) { *bufnext++ = LBRACKET; if (c == NOT) - --patnext; + --qpatnext; break; } *bufnext++ = M_SET; if (c == NOT) *bufnext++ = M_NOT; - c = *patnext++; + c = *qpatnext++; do { - /* todo: quoting */ - *bufnext++ = c; - if (*patnext == RANGE && - (c = patnext[1]) != RBRACKET) { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { *bufnext++ = M_RNG; - *bufnext++ = c; - patnext += 2; + *bufnext++ = CHAR(c); + qpatnext += 2; } - } while ((c = *patnext++) != RBRACKET); + } while ((c = *qpatnext++) != RBRACKET); *bufnext++ = M_END; break; case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; *bufnext++ = M_ONE; break; - case QUOTE: - if (!(flags & GLOB_QUOTE)) - *bufnext++ = QUOTE; - else { - if ((c = *patnext++) == EOS) { - c = QUOTE; - --patnext; - } - *bufnext++ = c; - } - break; case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; *bufnext++ = M_ALL; break; default: - *bufnext++ = c; + *bufnext++ = CHAR(c); break; } } *bufnext = EOS; +#ifdef DEBUG + qprintf(patbuf); +#endif if ((err = glob1(patbuf, pglob)) != 0) return(err); if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) { - if (!(flags & GLOB_QUOTE)) - (void)strcpy(compilebuf, compilepat); + if (!(flags & GLOB_QUOTE)) { + Char *dp = compilebuf; + const u_char *sp = compilepat; + while (*dp++ = *sp++); + } else { /* - * copy pattern, interpreting quotes; this is slightly + * Copy pattern, interpreting quotes; this is slightly * different than the interpretation of quotes above * -- which should prevail? */ @@ -183,63 +231,74 @@ glob(pattern, flags, errfunc, pglob) if (*++compilepat == EOS) --compilepat; } - *compilebuf++ = *compilepat++; + *compilebuf++ = (u_char)*compilepat++; } *compilebuf = EOS; } return(globextend(patbuf, pglob)); - } else if (!(flags & GLOB_NOSORT)) - qsort((char*) (pglob->gl_pathv + pglob->gl_offs + oldpathc), - pglob->gl_pathc - oldpathc, sizeof(char*), compare); + } else if (!(flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); return(0); } +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + static glob1(pattern, pglob) - char *pattern; + Char *pattern; glob_t *pglob; { - char pathbuf[MAXPATHLEN+1]; + Char pathbuf[MAXPATHLEN+1]; - /* - * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ if (*pattern == EOS) return(0); return(glob2(pathbuf, pathbuf, pattern, pglob)); } /* - * functions glob2 and glob3 are mutually recursive; there is one level - * of recursion for each segment in the pattern that contains one or - * more meta characters. + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. */ static glob2(pathbuf, pathend, pattern, pglob) - char *pathbuf, *pathend, *pattern; + Char *pathbuf, *pathend, *pattern; glob_t *pglob; { - struct stat sbuf; - bool_t anymeta = 0; - char *p, *q; + struct stat sb; + Char *p, *q; + int anymeta; /* - * loop over pattern segments until end of pattern or until + * Loop over pattern segments until end of pattern or until * segment with meta character found. */ - for (;;) { - if (*pattern == EOS) { /* end of pattern? */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ *pathend = EOS; - if (stat(pathbuf, &sbuf) != 0) - return(0); /* need error call here? */ - if ((pglob->gl_flags & GLOB_MARK) && - pathend[-1] != SEP && S_ISDIR(sbuf.st_mode)) { + if (g_stat(pathbuf, &sb)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) + || (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb) == 0) && + S_ISDIR(sb.st_mode)))) { *pathend++ = SEP; *pathend = EOS; } + ++pglob->gl_matchc; return(globextend(pathbuf, pglob)); } - /* find end of next segment, copy tentatively to pathend */ + /* Find end of next segment, copy tentatively to pathend. */ q = pathend; p = pattern; while (*p != EOS && *p != SEP) { @@ -248,12 +307,12 @@ glob2(pathbuf, pathend, pattern, pglob) *q++ = *p++; } - if (!anymeta) { /* no expansion, do next segment */ + if (!anymeta) { /* No expansion, do next segment. */ pathend = q; pattern = p; while (*pattern == SEP) *pathend++ = *pattern++; - } else /* need expansion, recurse */ + } else /* Need expansion, recurse. */ return(glob3(pathbuf, pathend, pattern, p, pglob)); } /* NOTREACHED */ @@ -261,18 +320,18 @@ glob2(pathbuf, pathend, pattern, pglob) static glob3(pathbuf, pathend, pattern, restpattern, pglob) - char *pathbuf, *pathend, *pattern, *restpattern; + Char *pathbuf, *pathend, *pattern, *restpattern; glob_t *pglob; { - extern int errno; + register struct dirent *dp; DIR *dirp; - struct dirent *dp; int len, err; *pathend = EOS; errno = 0; - if (!(dirp = opendir(pathbuf))) - /* todo: don't call for ENOENT or ENOTDIR? */ + + if (!(dirp = g_opendir(pathbuf))) + /* TODO: don't call for ENOENT or ENOTDIR? */ if (pglob->gl_errfunc && (*pglob->gl_errfunc)(pathbuf, errno) || (pglob->gl_flags & GLOB_ERR)) @@ -282,20 +341,26 @@ glob3(pathbuf, pathend, pattern, restpattern, pglob) err = 0; - /* search directory for matching names */ + /* Search directory for matching names. */ while ((dp = readdir(dirp))) { - /* initial DOT must be matched literally */ + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ if (dp->d_name[0] == DOT && *pattern != DOT) continue; - if (!match(dp->d_name, pattern, restpattern)) + for (sc = (u_char *) dp->d_name, dc = pathend; + *dc++ = *sc++;); + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; continue; - len = dp->d_namlen; - (void)strcpy(pathend, dp->d_name); - err = glob2(pathbuf, pathend+len, restpattern, pglob); + } + err = glob2(pathbuf, --dc, restpattern, pglob); if (err) break; } - /* todo: check error from readdir? */ + + /* TODO: check error from readdir? */ (void)closedir(dirp); return(err); } @@ -313,20 +378,21 @@ glob3(pathbuf, pathend, pattern, restpattern, pglob) * * Invariant of the glob_t structure: * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and - * gl_pathv points to (gl_offs + gl_pathc + 1) items. + * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ -static +static int globextend(path, pglob) - char *path; + Char *path; glob_t *pglob; { register char **pathv; register int i; - u_int copysize, newsize; + u_int newsize; char *copy; + Char *p; newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - pathv = (char **)realloc((char *)(pathv = pglob->gl_pathv), newsize); + pathv = (char **)realloc((char *)pglob->gl_pathv, newsize); if (pathv == NULL) return(GLOB_NOSPACE); @@ -338,13 +404,13 @@ globextend(path, pglob) } pglob->gl_pathv = pathv; - copysize = strlen(path) + 1; - if ((copy = malloc(copysize)) != NULL) { - (void)strcpy(copy, path); + for (p = path; *p++;); + if ((copy = malloc(p - path)) != NULL) { + g_Ctoc(path, copy); pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; } pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - return((copy == NULL) ? GLOB_NOSPACE : 0); + return(copy == NULL ? GLOB_NOSPACE : 0); } @@ -352,23 +418,22 @@ globextend(path, pglob) * pattern matching function for filenames. Each occurrence of the * * pattern causes a recursion level. */ -static bool_t +static match(name, pat, patend) - register char *name, *pat, *patend; + register Char *name, *pat, *patend; { - bool_t ok, negate_range; - char c, k; + int ok, negate_range; + Char c, k; while (pat < patend) { c = *pat++; - switch (c & 0xff) { + switch (c & M_MASK) { case M_ALL: if (pat == patend) return(1); - for (; *name != EOS; ++name) { + for (; *name != EOS; ++name) if (match(name, pat, patend)) return(1); - } return(0); case M_ONE: if (*name++ == EOS) @@ -377,17 +442,15 @@ match(name, pat, patend) case M_SET: ok = 0; k = *name++; - if (negate_range = (*pat & 0xff) == M_NOT) + if (negate_range = ((*pat & M_MASK) == M_NOT)) ++pat; - while (((c = *pat++) & 0xff) != M_END) { - if ((*pat & 0xff) == M_RNG) { + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { if (c <= k && k <= pat[1]) ok = 1; pat += 2; - } - else if (c == k) + } else if (c == k) ok = 1; - } if (ok == negate_range) return(0); break; @@ -400,7 +463,7 @@ match(name, pat, patend) return(*name == EOS); } -/* free allocated data belonging to a glob_t structure */ +/* Free allocated data belonging to a glob_t structure. */ void globfree(pglob) glob_t *pglob; @@ -412,7 +475,82 @@ globfree(pglob) pp = pglob->gl_pathv + pglob->gl_offs; for (i = pglob->gl_pathc; i--; ++pp) if (*pp) - (void)free(*pp); - (void)free((char *)pp); + free(*pp); + free(pglob->gl_pathv); } } + +static DIR * +g_opendir(str) + register Char *str; +{ + char buf[MAXPATHLEN]; + + if (!*str) + return(opendir(".")); + g_Ctoc(str, buf); + return(opendir(buf)); +} + +static int +g_lstat(fn, sb) + register Char *fn; + struct stat *sb; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb) + register Char *fn; + struct stat *sb; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +static void +g_Ctoc(str, buf) + register Char *str; + char *buf; +{ + register char *dc; + + for (dc = buf; *dc++ = *str++;); +} + +#ifdef DEBUG +static void +qprintf(s) + register Char *s; +{ + register Char *p; + + for (p = s; *p; p++) + (void)printf("%c", *p & 0xff); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_META ? '_' : ' '); + (void)printf("\n"); +} +#endif