140087Sbostic /* 240087Sbostic * Copyright (c) 1989 The Regents of the University of California. 340087Sbostic * All rights reserved. 440087Sbostic * 540087Sbostic * This code is derived from software contributed to Berkeley by 640087Sbostic * Guido van Rossum. 740087Sbostic * 842625Sbostic * %sccs.include.redist.c% 940087Sbostic */ 1040087Sbostic 1140087Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*57006Sbostic static char sccsid[] = "@(#)glob.c 5.18 (Berkeley) 12/04/92"; 1340087Sbostic #endif /* LIBC_SCCS and not lint */ 1440087Sbostic 1540087Sbostic /* 1650050Sbostic * glob(3) -- a superset of the one defined in POSIX 1003.2. 1740087Sbostic * 1840087Sbostic * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 1940087Sbostic * 2040087Sbostic * Optional extra services, controlled by flags not defined by POSIX: 2147590Sbostic * 2247590Sbostic * GLOB_QUOTE: 2347590Sbostic * Escaping convention: \ inhibits any special meaning the following 2447590Sbostic * character might have (except \ at end of string is retained). 2547590Sbostic * GLOB_MAGCHAR: 2648540Sbostic * Set in gl_flags if pattern contained a globbing character. 2750420Sbostic * GLOB_NOMAGIC: 2850420Sbostic * Same as GLOB_NOCHECK, but it will only append pattern if it did 2950420Sbostic * not contain any magic characters. [Used in csh style globbing] 3056942Smckusick * GLOB_ALTDIRFUNC: 3156942Smckusick * Use alternately specified directory access functions. 3247590Sbostic * gl_matchc: 3347590Sbostic * Number of matches in the current invocation of glob. 3440087Sbostic */ 3540087Sbostic 3640087Sbostic #include <sys/param.h> 3740087Sbostic #include <sys/stat.h> 3840087Sbostic #include <dirent.h> 3940087Sbostic #include <glob.h> 4040087Sbostic #include <ctype.h> 4140087Sbostic #include <errno.h> 4240087Sbostic #include <string.h> 4340087Sbostic #include <stdio.h> 4446597Sdonn #include <stdlib.h> 4540087Sbostic 4640087Sbostic #define DOLLAR '$' 4740087Sbostic #define DOT '.' 4840087Sbostic #define EOS '\0' 4940087Sbostic #define LBRACKET '[' 5040087Sbostic #define NOT '!' 5140087Sbostic #define QUESTION '?' 5240087Sbostic #define QUOTE '\\' 5340087Sbostic #define RANGE '-' 5440087Sbostic #define RBRACKET ']' 5540087Sbostic #define SEP '/' 5640087Sbostic #define STAR '*' 5740087Sbostic #define TILDE '~' 5840087Sbostic #define UNDERSCORE '_' 5940087Sbostic 6050049Sbostic #define M_QUOTE 0x8000 6150049Sbostic #define M_PROTECT 0x4000 6248540Sbostic #define M_MASK 0xffff 6350121Sbostic #define M_ASCII 0x00ff 6448540Sbostic 6550121Sbostic #define CHAR(c) ((c)&M_ASCII) 6650049Sbostic #define META(c) ((c)|M_QUOTE) 6740087Sbostic #define M_ALL META('*') 6840087Sbostic #define M_END META(']') 6940087Sbostic #define M_NOT META('!') 7040087Sbostic #define M_ONE META('?') 7140087Sbostic #define M_RNG META('-') 7240087Sbostic #define M_SET META('[') 7350049Sbostic #define ismeta(c) (((c)&M_QUOTE) != 0) 7440087Sbostic 7550050Sbostic typedef u_short Char; 7650049Sbostic 7750050Sbostic static int compare __P((const void *, const void *)); 7850050Sbostic static void g_Ctoc __P((Char *, char *)); 7956942Smckusick static int g_lstat __P((Char *, struct stat *, glob_t *)); 8056942Smckusick static DIR *g_opendir __P((Char *, glob_t *)); 8150050Sbostic static Char *g_strchr __P((Char *, int)); 8256942Smckusick static int g_stat __P((Char *, struct stat *, glob_t *)); 8350050Sbostic static int glob1 __P((Char *, glob_t *)); 8450050Sbostic static int glob2 __P((Char *, Char *, Char *, glob_t *)); 8550050Sbostic static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); 8650050Sbostic static int globextend __P((Char *, glob_t *)); 8750050Sbostic static int match __P((Char *, Char *, Char *)); 8850049Sbostic #ifdef DEBUG 8950050Sbostic static void qprintf __P((Char *)); 9050049Sbostic #endif 9150049Sbostic 9240087Sbostic /* 9340087Sbostic * The main glob() routine: compiles the pattern (optionally processing 9440087Sbostic * quotes), calls glob1() to do the real pattern matching, and finally 9540087Sbostic * sorts the list (unless unsorted operation is requested). Returns 0 9640087Sbostic * if things went well, nonzero if errors occurred. It is not an error 9740087Sbostic * to find no matches. 9840087Sbostic */ 9940087Sbostic glob(pattern, flags, errfunc, pglob) 10046597Sdonn const char *pattern; 10150050Sbostic int flags, (*errfunc) __P((char *, int)); 10240087Sbostic glob_t *pglob; 10340087Sbostic { 10450121Sbostic const u_char *compilepat, *patnext; 10550117Sbostic int c, err, oldpathc; 10650050Sbostic Char *bufnext, *bufend, *compilebuf, *qpatnext, patbuf[MAXPATHLEN+1]; 10740087Sbostic 10850121Sbostic patnext = (u_char *) pattern; 10940087Sbostic if (!(flags & GLOB_APPEND)) { 11040087Sbostic pglob->gl_pathc = 0; 11140087Sbostic pglob->gl_pathv = NULL; 11240087Sbostic if (!(flags & GLOB_DOOFFS)) 11340087Sbostic pglob->gl_offs = 0; 11440087Sbostic } 11547590Sbostic pglob->gl_flags = flags & ~GLOB_MAGCHAR; 11640087Sbostic pglob->gl_errfunc = errfunc; 11740087Sbostic oldpathc = pglob->gl_pathc; 11847590Sbostic pglob->gl_matchc = 0; 11940087Sbostic 12040087Sbostic bufnext = patbuf; 12150049Sbostic bufend = bufnext + MAXPATHLEN; 12250050Sbostic compilebuf = bufnext; 12350050Sbostic compilepat = patnext; 12450049Sbostic if (flags & GLOB_QUOTE) { 12550050Sbostic /* Protect the quoted characters. */ 12650049Sbostic while (bufnext < bufend && (c = *patnext++) != EOS) 12750049Sbostic if (c == QUOTE) { 12850049Sbostic if ((c = *patnext++) == EOS) { 12950049Sbostic c = QUOTE; 13050049Sbostic --patnext; 13150049Sbostic } 13250049Sbostic *bufnext++ = c | M_PROTECT; 13350049Sbostic } 13450049Sbostic else 13550049Sbostic *bufnext++ = c; 13650049Sbostic } 13750049Sbostic else 13850049Sbostic while (bufnext < bufend && (c = *patnext++) != EOS) 13950049Sbostic *bufnext++ = c; 14050049Sbostic *bufnext = EOS; 14140087Sbostic 14250049Sbostic bufnext = patbuf; 14350049Sbostic qpatnext = patbuf; 14450050Sbostic /* We don't need to check for buffer overflow any more. */ 14550049Sbostic while ((c = *qpatnext++) != EOS) { 14640087Sbostic switch (c) { 14740087Sbostic case LBRACKET: 14850049Sbostic c = *qpatnext; 14940087Sbostic if (c == NOT) 15050049Sbostic ++qpatnext; 15150049Sbostic if (*qpatnext == EOS || 15250050Sbostic g_strchr(qpatnext+1, RBRACKET) == NULL) { 15340087Sbostic *bufnext++ = LBRACKET; 15440087Sbostic if (c == NOT) 15550049Sbostic --qpatnext; 15640087Sbostic break; 15740087Sbostic } 15840087Sbostic *bufnext++ = M_SET; 15940087Sbostic if (c == NOT) 16040087Sbostic *bufnext++ = M_NOT; 16150049Sbostic c = *qpatnext++; 16240087Sbostic do { 16350121Sbostic *bufnext++ = CHAR(c); 16450049Sbostic if (*qpatnext == RANGE && 16550049Sbostic (c = qpatnext[1]) != RBRACKET) { 16640087Sbostic *bufnext++ = M_RNG; 16750121Sbostic *bufnext++ = CHAR(c); 16850049Sbostic qpatnext += 2; 16940087Sbostic } 17050049Sbostic } while ((c = *qpatnext++) != RBRACKET); 17150420Sbostic pglob->gl_flags |= GLOB_MAGCHAR; 17240087Sbostic *bufnext++ = M_END; 17340087Sbostic break; 17440087Sbostic case QUESTION: 17547590Sbostic pglob->gl_flags |= GLOB_MAGCHAR; 17640087Sbostic *bufnext++ = M_ONE; 17740087Sbostic break; 17840087Sbostic case STAR: 17947590Sbostic pglob->gl_flags |= GLOB_MAGCHAR; 18056373Sbostic /* collapse adjacent stars to one, 18156373Sbostic * to avoid exponential behavior 18256373Sbostic */ 18356373Sbostic if (bufnext == patbuf || bufnext[-1] != M_ALL) 18456373Sbostic *bufnext++ = M_ALL; 18540087Sbostic break; 18640087Sbostic default: 18750121Sbostic *bufnext++ = CHAR(c); 18840087Sbostic break; 18940087Sbostic } 19040087Sbostic } 19140087Sbostic *bufnext = EOS; 19250049Sbostic #ifdef DEBUG 19350049Sbostic qprintf(patbuf); 19450049Sbostic #endif 19540087Sbostic 19640087Sbostic if ((err = glob1(patbuf, pglob)) != 0) 19740087Sbostic return(err); 19840087Sbostic 19950420Sbostic /* 20050420Sbostic * If there was no match we are going to append the pattern 20150420Sbostic * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 20250420Sbostic * and the pattern did not contain any magic characters 20350420Sbostic * GLOB_NOMAGIC is there just for compatibility with csh. 20450420Sbostic */ 20550420Sbostic if (pglob->gl_pathc == oldpathc && 20650420Sbostic ((flags & GLOB_NOCHECK) || 20750420Sbostic ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { 20848540Sbostic if (!(flags & GLOB_QUOTE)) { 20950050Sbostic Char *dp = compilebuf; 21050121Sbostic const u_char *sp = compilepat; 21150121Sbostic while (*dp++ = *sp++); 21248540Sbostic } 21340087Sbostic else { 21440087Sbostic /* 21550050Sbostic * Copy pattern, interpreting quotes; this is slightly 21640087Sbostic * different than the interpretation of quotes above 21740087Sbostic * -- which should prevail? 21840087Sbostic */ 21940087Sbostic while (*compilepat != EOS) { 22040087Sbostic if (*compilepat == QUOTE) { 22140087Sbostic if (*++compilepat == EOS) 22240087Sbostic --compilepat; 22340087Sbostic } 22448540Sbostic *compilebuf++ = (u_char)*compilepat++; 22540087Sbostic } 22640087Sbostic *compilebuf = EOS; 22740087Sbostic } 22840087Sbostic return(globextend(patbuf, pglob)); 22948540Sbostic } else if (!(flags & GLOB_NOSORT)) 23050050Sbostic qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 23150050Sbostic pglob->gl_pathc - oldpathc, sizeof(char *), compare); 23240087Sbostic return(0); 23340087Sbostic } 23440087Sbostic 23550050Sbostic static int 23650050Sbostic compare(p, q) 23750050Sbostic const void *p, *q; 23850050Sbostic { 23950050Sbostic return(strcmp(*(char **)p, *(char **)q)); 24050050Sbostic } 24150050Sbostic 24240087Sbostic static 24340087Sbostic glob1(pattern, pglob) 24450050Sbostic Char *pattern; 24540087Sbostic glob_t *pglob; 24640087Sbostic { 24750050Sbostic Char pathbuf[MAXPATHLEN+1]; 24840087Sbostic 24950050Sbostic /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 25040087Sbostic if (*pattern == EOS) 25140087Sbostic return(0); 25240087Sbostic return(glob2(pathbuf, pathbuf, pattern, pglob)); 25340087Sbostic } 25440087Sbostic 25540087Sbostic /* 25650050Sbostic * The functions glob2 and glob3 are mutually recursive; there is one level 25750050Sbostic * of recursion for each segment in the pattern that contains one or more 25850050Sbostic * meta characters. 25940087Sbostic */ 26040087Sbostic static 26140087Sbostic glob2(pathbuf, pathend, pattern, pglob) 26250050Sbostic Char *pathbuf, *pathend, *pattern; 26340087Sbostic glob_t *pglob; 26440087Sbostic { 26550050Sbostic struct stat sb; 26650050Sbostic Char *p, *q; 26748540Sbostic int anymeta; 26840087Sbostic 26940087Sbostic /* 27050050Sbostic * Loop over pattern segments until end of pattern or until 27140087Sbostic * segment with meta character found. 27240087Sbostic */ 27348357Sbostic for (anymeta = 0;;) { 27450050Sbostic if (*pattern == EOS) { /* End of pattern? */ 27540087Sbostic *pathend = EOS; 27656942Smckusick if (g_lstat(pathbuf, &sb, pglob)) 27748357Sbostic return(0); 27848540Sbostic 27948540Sbostic if (((pglob->gl_flags & GLOB_MARK) && 28050050Sbostic pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) 28150050Sbostic || (S_ISLNK(sb.st_mode) && 28256942Smckusick (g_stat(pathbuf, &sb, pglob) == 0) && 28350050Sbostic S_ISDIR(sb.st_mode)))) { 28440087Sbostic *pathend++ = SEP; 28540087Sbostic *pathend = EOS; 28640087Sbostic } 28747590Sbostic ++pglob->gl_matchc; 28840087Sbostic return(globextend(pathbuf, pglob)); 28940087Sbostic } 29040087Sbostic 29150050Sbostic /* Find end of next segment, copy tentatively to pathend. */ 29240087Sbostic q = pathend; 29340087Sbostic p = pattern; 29440087Sbostic while (*p != EOS && *p != SEP) { 29540087Sbostic if (ismeta(*p)) 29640087Sbostic anymeta = 1; 29740087Sbostic *q++ = *p++; 29840087Sbostic } 29940087Sbostic 30050050Sbostic if (!anymeta) { /* No expansion, do next segment. */ 30140087Sbostic pathend = q; 30240087Sbostic pattern = p; 30340087Sbostic while (*pattern == SEP) 30440087Sbostic *pathend++ = *pattern++; 30550050Sbostic } else /* Need expansion, recurse. */ 30640087Sbostic return(glob3(pathbuf, pathend, pattern, p, pglob)); 30740087Sbostic } 30840087Sbostic /* NOTREACHED */ 30940087Sbostic } 31040087Sbostic 31140087Sbostic static 31240087Sbostic glob3(pathbuf, pathend, pattern, restpattern, pglob) 31350050Sbostic Char *pathbuf, *pathend, *pattern, *restpattern; 31440087Sbostic glob_t *pglob; 31540087Sbostic { 31650050Sbostic register struct dirent *dp; 31756942Smckusick struct dirent *(*readdirfunc)(); 31840087Sbostic DIR *dirp; 31940087Sbostic int len, err; 320*57006Sbostic char buf[MAXPATHLEN]; 32140087Sbostic 32240087Sbostic *pathend = EOS; 32340087Sbostic errno = 0; 32448540Sbostic 325*57006Sbostic if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 32650050Sbostic /* TODO: don't call for ENOENT or ENOTDIR? */ 327*57006Sbostic if (pglob->gl_errfunc) { 328*57006Sbostic g_Ctoc(pathbuf, buf); 329*57006Sbostic if (pglob->gl_errfunc(buf, errno) || 330*57006Sbostic pglob->gl_flags & GLOB_ERR) 331*57006Sbostic return (GLOB_ABEND); 332*57006Sbostic } 333*57006Sbostic return(0); 334*57006Sbostic } 33540087Sbostic 33640087Sbostic err = 0; 33740087Sbostic 33850050Sbostic /* Search directory for matching names. */ 33956942Smckusick if (pglob->gl_flags & GLOB_ALTDIRFUNC) 34056942Smckusick readdirfunc = pglob->gl_readdir; 34156942Smckusick else 34256942Smckusick readdirfunc = readdir; 34356942Smckusick while ((dp = (*readdirfunc)(dirp))) { 34450121Sbostic register u_char *sc; 34550050Sbostic register Char *dc; 34650050Sbostic 34750050Sbostic /* Initial DOT must be matched literally. */ 34840087Sbostic if (dp->d_name[0] == DOT && *pattern != DOT) 34940087Sbostic continue; 35050121Sbostic for (sc = (u_char *) dp->d_name, dc = pathend; 35150121Sbostic *dc++ = *sc++;); 35248540Sbostic if (!match(pathend, pattern, restpattern)) { 35348540Sbostic *pathend = EOS; 35440087Sbostic continue; 35548540Sbostic } 35648540Sbostic err = glob2(pathbuf, --dc, restpattern, pglob); 35740087Sbostic if (err) 35840087Sbostic break; 35940087Sbostic } 36050050Sbostic 36156942Smckusick if (pglob->gl_flags & GLOB_ALTDIRFUNC) 36256942Smckusick (*pglob->gl_closedir)(dirp); 36356942Smckusick else 36456942Smckusick closedir(dirp); 36540087Sbostic return(err); 36640087Sbostic } 36740087Sbostic 36840087Sbostic 36940087Sbostic /* 37040087Sbostic * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 37140087Sbostic * add the new item, and update gl_pathc. 37240087Sbostic * 37340087Sbostic * This assumes the BSD realloc, which only copies the block when its size 37440087Sbostic * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 37540087Sbostic * behavior. 37640087Sbostic * 37740087Sbostic * Return 0 if new item added, error code if memory couldn't be allocated. 37840087Sbostic * 37940087Sbostic * Invariant of the glob_t structure: 38040087Sbostic * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 38150050Sbostic * gl_pathv points to (gl_offs + gl_pathc + 1) items. 38240087Sbostic */ 38348540Sbostic static int 38440087Sbostic globextend(path, pglob) 38550050Sbostic Char *path; 38640087Sbostic glob_t *pglob; 38740087Sbostic { 38840087Sbostic register char **pathv; 38940087Sbostic register int i; 39048540Sbostic u_int newsize; 39140087Sbostic char *copy; 39250050Sbostic Char *p; 39340087Sbostic 39440087Sbostic newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 39548540Sbostic pathv = (char **)realloc((char *)pglob->gl_pathv, newsize); 39640087Sbostic if (pathv == NULL) 39740087Sbostic return(GLOB_NOSPACE); 39840087Sbostic 39940087Sbostic if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 40040087Sbostic /* first time around -- clear initial gl_offs items */ 40140087Sbostic pathv += pglob->gl_offs; 40240087Sbostic for (i = pglob->gl_offs; --i >= 0; ) 40340087Sbostic *--pathv = NULL; 40440087Sbostic } 40540087Sbostic pglob->gl_pathv = pathv; 40640087Sbostic 40748540Sbostic for (p = path; *p++;); 40848540Sbostic if ((copy = malloc(p - path)) != NULL) { 40950050Sbostic g_Ctoc(path, copy); 41040087Sbostic pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 41140087Sbostic } 41240087Sbostic pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 41350050Sbostic return(copy == NULL ? GLOB_NOSPACE : 0); 41440087Sbostic } 41540087Sbostic 41640087Sbostic 41740087Sbostic /* 41840087Sbostic * pattern matching function for filenames. Each occurrence of the * 41940087Sbostic * pattern causes a recursion level. 42040087Sbostic */ 42148540Sbostic static 42240087Sbostic match(name, pat, patend) 42350050Sbostic register Char *name, *pat, *patend; 42440087Sbostic { 42548540Sbostic int ok, negate_range; 42650050Sbostic Char c, k; 42740087Sbostic 42840087Sbostic while (pat < patend) { 42940087Sbostic c = *pat++; 43048540Sbostic switch (c & M_MASK) { 43140087Sbostic case M_ALL: 43240087Sbostic if (pat == patend) 43340087Sbostic return(1); 43456373Sbostic do 43556373Sbostic if (match(name, pat, patend)) 43656373Sbostic return(1); 43756373Sbostic while (*name++ != EOS); 43840087Sbostic return(0); 43940087Sbostic case M_ONE: 44040087Sbostic if (*name++ == EOS) 44140087Sbostic return(0); 44240087Sbostic break; 44340087Sbostic case M_SET: 44440087Sbostic ok = 0; 44552339Sbostic if ((k = *name++) == EOS) 44652339Sbostic return(0); 44748540Sbostic if (negate_range = ((*pat & M_MASK) == M_NOT)) 44840087Sbostic ++pat; 44950050Sbostic while (((c = *pat++) & M_MASK) != M_END) 45048540Sbostic if ((*pat & M_MASK) == M_RNG) { 45140087Sbostic if (c <= k && k <= pat[1]) 45240087Sbostic ok = 1; 45340087Sbostic pat += 2; 45450050Sbostic } else if (c == k) 45540087Sbostic ok = 1; 45640087Sbostic if (ok == negate_range) 45740087Sbostic return(0); 45840087Sbostic break; 45940087Sbostic default: 46040087Sbostic if (*name++ != c) 46140087Sbostic return(0); 46240087Sbostic break; 46340087Sbostic } 46440087Sbostic } 46540087Sbostic return(*name == EOS); 46640087Sbostic } 46740087Sbostic 46850050Sbostic /* Free allocated data belonging to a glob_t structure. */ 46940087Sbostic void 47040087Sbostic globfree(pglob) 47140087Sbostic glob_t *pglob; 47240087Sbostic { 47340087Sbostic register int i; 47440087Sbostic register char **pp; 47540087Sbostic 47640087Sbostic if (pglob->gl_pathv != NULL) { 47740087Sbostic pp = pglob->gl_pathv + pglob->gl_offs; 47840087Sbostic for (i = pglob->gl_pathc; i--; ++pp) 47940087Sbostic if (*pp) 48050050Sbostic free(*pp); 48150049Sbostic free(pglob->gl_pathv); 48240087Sbostic } 48340087Sbostic } 48450050Sbostic 48550050Sbostic static DIR * 48656942Smckusick g_opendir(str, pglob) 48750050Sbostic register Char *str; 48856942Smckusick glob_t *pglob; 48950050Sbostic { 49050050Sbostic char buf[MAXPATHLEN]; 49156942Smckusick char *dirname; 49250050Sbostic 49350050Sbostic if (!*str) 49456942Smckusick strcpy(buf, "."); 49556942Smckusick else 49656942Smckusick g_Ctoc(str, buf); 49756942Smckusick if (pglob->gl_flags & GLOB_ALTDIRFUNC) 49856942Smckusick return((*pglob->gl_opendir)(buf)); 49950050Sbostic return(opendir(buf)); 50050050Sbostic } 50150050Sbostic 50250050Sbostic static int 50356942Smckusick g_lstat(fn, sb, pglob) 50450050Sbostic register Char *fn; 50550050Sbostic struct stat *sb; 50656942Smckusick glob_t *pglob; 50750050Sbostic { 50850050Sbostic char buf[MAXPATHLEN]; 50950050Sbostic 51050050Sbostic g_Ctoc(fn, buf); 51156942Smckusick if (pglob->gl_flags & GLOB_ALTDIRFUNC) 51256942Smckusick return((*pglob->gl_lstat)(buf, sb)); 51350050Sbostic return(lstat(buf, sb)); 51450050Sbostic } 51550050Sbostic 51650050Sbostic static int 51756942Smckusick g_stat(fn, sb, pglob) 51850050Sbostic register Char *fn; 51950050Sbostic struct stat *sb; 52056942Smckusick glob_t *pglob; 52150050Sbostic { 52250050Sbostic char buf[MAXPATHLEN]; 52350050Sbostic 52450050Sbostic g_Ctoc(fn, buf); 52556942Smckusick if (pglob->gl_flags & GLOB_ALTDIRFUNC) 52656942Smckusick return((*pglob->gl_stat)(buf, sb)); 52750050Sbostic return(stat(buf, sb)); 52850050Sbostic } 52950050Sbostic 53050050Sbostic static Char * 53150050Sbostic g_strchr(str, ch) 53250050Sbostic Char *str; 53350050Sbostic int ch; 53450050Sbostic { 53550050Sbostic do { 53650050Sbostic if (*str == ch) 53750050Sbostic return (str); 53850050Sbostic } while (*str++); 53950050Sbostic return (NULL); 54050050Sbostic } 54150050Sbostic 54250050Sbostic static void 54350050Sbostic g_Ctoc(str, buf) 54450050Sbostic register Char *str; 54550050Sbostic char *buf; 54650050Sbostic { 54750050Sbostic register char *dc; 54850050Sbostic 54950050Sbostic for (dc = buf; *dc++ = *str++;); 55050050Sbostic } 55150050Sbostic 55250050Sbostic #ifdef DEBUG 55350050Sbostic static void 55450050Sbostic qprintf(s) 55550050Sbostic register Char *s; 55650050Sbostic { 55750050Sbostic register Char *p; 55850050Sbostic 55950050Sbostic for (p = s; *p; p++) 560*57006Sbostic (void)printf("%c", CHAR(*p)); 56150050Sbostic (void)printf("\n"); 56250050Sbostic for (p = s; *p; p++) 56350050Sbostic (void)printf("%c", *p & M_PROTECT ? '"' : ' '); 56450050Sbostic (void)printf("\n"); 56550050Sbostic for (p = s; *p; p++) 566*57006Sbostic (void)printf("%c", ismeta(*p) ? '_' : ' '); 56750050Sbostic (void)printf("\n"); 56850050Sbostic } 56950050Sbostic #endif 570