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*46597Sdonn static char sccsid[] = "@(#)glob.c 5.4 (Berkeley) 02/23/91"; 1340087Sbostic #endif /* LIBC_SCCS and not lint */ 1440087Sbostic 1540087Sbostic /* 1640087Sbostic * Glob: the interface is a superset of the one defined in POSIX 1003.2, 1740087Sbostic * draft 9. 1840087Sbostic * 1940087Sbostic * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 2040087Sbostic * 2140087Sbostic * Optional extra services, controlled by flags not defined by POSIX: 2240087Sbostic * GLOB_QUOTE: escaping convention: \ inhibits any special meaning 2340087Sbostic the following character might have (except \ at end of 2440087Sbostic * string is kept); 2540087Sbostic */ 2640087Sbostic 2740087Sbostic #include <sys/param.h> 2840087Sbostic #include <sys/stat.h> 2940087Sbostic #include <dirent.h> 3040087Sbostic #include <glob.h> 3140087Sbostic #include <ctype.h> 3240087Sbostic #include <errno.h> 3340087Sbostic #include <string.h> 3440087Sbostic #include <stdio.h> 35*46597Sdonn #include <stdlib.h> 3640087Sbostic 3740087Sbostic typedef int bool_t; 3840087Sbostic 39*46597Sdonn static glob1(); 40*46597Sdonn static glob2(); 41*46597Sdonn static glob3(); 42*46597Sdonn static globextend(); 43*46597Sdonn static bool_t match(); 44*46597Sdonn 4540087Sbostic #define DOLLAR '$' 4640087Sbostic #define DOT '.' 4740087Sbostic #define EOS '\0' 4840087Sbostic #define LBRACKET '[' 4940087Sbostic #define NOT '!' 5040087Sbostic #define QUESTION '?' 5140087Sbostic #define QUOTE '\\' 5240087Sbostic #define RANGE '-' 5340087Sbostic #define RBRACKET ']' 5440087Sbostic #define SEP '/' 5540087Sbostic #define STAR '*' 5640087Sbostic #define TILDE '~' 5740087Sbostic #define UNDERSCORE '_' 5840087Sbostic 5940087Sbostic #define METABIT 0x80 6040087Sbostic #define META(c) ((c)|METABIT) 6140087Sbostic #define M_ALL META('*') 6240087Sbostic #define M_END META(']') 6340087Sbostic #define M_NOT META('!') 6440087Sbostic #define M_ONE META('?') 6540087Sbostic #define M_RNG META('-') 6640087Sbostic #define M_SET META('[') 6740087Sbostic #define ismeta(c) (((c)&METABIT) != 0) 6840087Sbostic 6940087Sbostic static 7040087Sbostic compare(p, q) 7143531Sbostic void **p, **q; 7240087Sbostic { 7343531Sbostic return(strcmp(*(char **)p, *(char **)q)); 7440087Sbostic } 7540087Sbostic 7640087Sbostic 7740087Sbostic /* 7840087Sbostic * The main glob() routine: compiles the pattern (optionally processing 7940087Sbostic * quotes), calls glob1() to do the real pattern matching, and finally 8040087Sbostic * sorts the list (unless unsorted operation is requested). Returns 0 8140087Sbostic * if things went well, nonzero if errors occurred. It is not an error 8240087Sbostic * to find no matches. 8340087Sbostic */ 8440087Sbostic glob(pattern, flags, errfunc, pglob) 85*46597Sdonn const char *pattern; 86*46597Sdonn int flags; 87*46597Sdonn int (*errfunc) __P((char *, int)); 8840087Sbostic glob_t *pglob; 8940087Sbostic { 9040087Sbostic int err, oldpathc; 91*46597Sdonn char *bufnext, *bufend, *compilebuf; 92*46597Sdonn const char *compilepat, *patnext; 9340087Sbostic char c, patbuf[MAXPATHLEN+1]; 9440087Sbostic 9540087Sbostic patnext = pattern; 9640087Sbostic if (!(flags & GLOB_APPEND)) { 9740087Sbostic pglob->gl_pathc = 0; 9840087Sbostic pglob->gl_pathv = NULL; 9940087Sbostic if (!(flags & GLOB_DOOFFS)) 10040087Sbostic pglob->gl_offs = 0; 10140087Sbostic } 10240087Sbostic pglob->gl_flags = flags; 10340087Sbostic pglob->gl_errfunc = errfunc; 10440087Sbostic oldpathc = pglob->gl_pathc; 10540087Sbostic 10640087Sbostic bufnext = patbuf; 10740087Sbostic bufend = bufnext+MAXPATHLEN; 10840087Sbostic 10940087Sbostic compilebuf = bufnext; 11040087Sbostic compilepat = patnext; 11140087Sbostic while (bufnext < bufend && (c = *patnext++) != EOS) { 11240087Sbostic switch (c) { 11340087Sbostic case LBRACKET: 11440087Sbostic c = *patnext; 11540087Sbostic if (c == NOT) 11640087Sbostic ++patnext; 11740087Sbostic if (*patnext == EOS || 11840087Sbostic strchr(patnext+1, RBRACKET) == NULL) { 11940087Sbostic *bufnext++ = LBRACKET; 12040087Sbostic if (c == NOT) 12140087Sbostic --patnext; 12240087Sbostic break; 12340087Sbostic } 12440087Sbostic *bufnext++ = M_SET; 12540087Sbostic if (c == NOT) 12640087Sbostic *bufnext++ = M_NOT; 12740087Sbostic c = *patnext++; 12840087Sbostic do { 12940087Sbostic /* todo: quoting */ 13040087Sbostic *bufnext++ = c; 13140087Sbostic if (*patnext == RANGE && 13240087Sbostic (c = patnext[1]) != RBRACKET) { 13340087Sbostic *bufnext++ = M_RNG; 13440087Sbostic *bufnext++ = c; 13540087Sbostic patnext += 2; 13640087Sbostic } 13740087Sbostic } while ((c = *patnext++) != RBRACKET); 13840087Sbostic *bufnext++ = M_END; 13940087Sbostic break; 14040087Sbostic case QUESTION: 14140087Sbostic *bufnext++ = M_ONE; 14240087Sbostic break; 14340087Sbostic case QUOTE: 14440087Sbostic if (!(flags & GLOB_QUOTE)) 14540087Sbostic *bufnext++ = QUOTE; 14640087Sbostic else { 14740087Sbostic if ((c = *patnext++) == EOS) { 14840087Sbostic c = QUOTE; 14940087Sbostic --patnext; 15040087Sbostic } 15140087Sbostic *bufnext++ = c; 15240087Sbostic } 15340087Sbostic break; 15440087Sbostic case STAR: 15540087Sbostic *bufnext++ = M_ALL; 15640087Sbostic break; 15740087Sbostic default: 15840087Sbostic *bufnext++ = c; 15940087Sbostic break; 16040087Sbostic } 16140087Sbostic } 16240087Sbostic *bufnext = EOS; 16340087Sbostic 16440087Sbostic if ((err = glob1(patbuf, pglob)) != 0) 16540087Sbostic return(err); 16640087Sbostic 16740087Sbostic if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) { 16840087Sbostic if (!(flags & GLOB_QUOTE)) 16940087Sbostic (void)strcpy(compilebuf, compilepat); 17040087Sbostic else { 17140087Sbostic /* 17240087Sbostic * copy pattern, interpreting quotes; this is slightly 17340087Sbostic * different than the interpretation of quotes above 17440087Sbostic * -- which should prevail? 17540087Sbostic */ 17640087Sbostic while (*compilepat != EOS) { 17740087Sbostic if (*compilepat == QUOTE) { 17840087Sbostic if (*++compilepat == EOS) 17940087Sbostic --compilepat; 18040087Sbostic } 18140087Sbostic *compilebuf++ = *compilepat++; 18240087Sbostic } 18340087Sbostic *compilebuf = EOS; 18440087Sbostic } 18540087Sbostic return(globextend(patbuf, pglob)); 18640087Sbostic } else if (!(flags & GLOB_NOSORT)) 18740087Sbostic qsort((char*) (pglob->gl_pathv + pglob->gl_offs + oldpathc), 18840087Sbostic pglob->gl_pathc - oldpathc, sizeof(char*), compare); 18940087Sbostic return(0); 19040087Sbostic } 19140087Sbostic 19240087Sbostic static 19340087Sbostic glob1(pattern, pglob) 19440087Sbostic char *pattern; 19540087Sbostic glob_t *pglob; 19640087Sbostic { 19740087Sbostic char pathbuf[MAXPATHLEN+1]; 19840087Sbostic 19940087Sbostic /* 20040087Sbostic * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 20140087Sbostic if (*pattern == EOS) 20240087Sbostic return(0); 20340087Sbostic return(glob2(pathbuf, pathbuf, pattern, pglob)); 20440087Sbostic } 20540087Sbostic 20640087Sbostic /* 20740087Sbostic * functions glob2 and glob3 are mutually recursive; there is one level 20840087Sbostic * of recursion for each segment in the pattern that contains one or 20940087Sbostic * more meta characters. 21040087Sbostic */ 21140087Sbostic static 21240087Sbostic glob2(pathbuf, pathend, pattern, pglob) 21340087Sbostic char *pathbuf, *pathend, *pattern; 21440087Sbostic glob_t *pglob; 21540087Sbostic { 21640087Sbostic struct stat sbuf; 21740087Sbostic bool_t anymeta = 0; 21840087Sbostic char *p, *q; 21940087Sbostic 22040087Sbostic /* 22140087Sbostic * loop over pattern segments until end of pattern or until 22240087Sbostic * segment with meta character found. 22340087Sbostic */ 22440087Sbostic for (;;) { 22540087Sbostic if (*pattern == EOS) { /* end of pattern? */ 22640087Sbostic *pathend = EOS; 22740087Sbostic if (stat(pathbuf, &sbuf) != 0) 22840087Sbostic return(0); /* need error call here? */ 22940087Sbostic if ((pglob->gl_flags & GLOB_MARK) && 23040087Sbostic pathend[-1] != SEP && S_ISDIR(sbuf.st_mode)) { 23140087Sbostic *pathend++ = SEP; 23240087Sbostic *pathend = EOS; 23340087Sbostic } 23440087Sbostic return(globextend(pathbuf, pglob)); 23540087Sbostic } 23640087Sbostic 23740087Sbostic /* find end of next segment, copy tentatively to pathend */ 23840087Sbostic q = pathend; 23940087Sbostic p = pattern; 24040087Sbostic while (*p != EOS && *p != SEP) { 24140087Sbostic if (ismeta(*p)) 24240087Sbostic anymeta = 1; 24340087Sbostic *q++ = *p++; 24440087Sbostic } 24540087Sbostic 24640087Sbostic if (!anymeta) { /* no expansion, do next segment */ 24740087Sbostic pathend = q; 24840087Sbostic pattern = p; 24940087Sbostic while (*pattern == SEP) 25040087Sbostic *pathend++ = *pattern++; 25140087Sbostic } else /* need expansion, recurse */ 25240087Sbostic return(glob3(pathbuf, pathend, pattern, p, pglob)); 25340087Sbostic } 25440087Sbostic /* NOTREACHED */ 25540087Sbostic } 25640087Sbostic 25740087Sbostic static 25840087Sbostic glob3(pathbuf, pathend, pattern, restpattern, pglob) 25940087Sbostic char *pathbuf, *pathend, *pattern, *restpattern; 26040087Sbostic glob_t *pglob; 26140087Sbostic { 26240087Sbostic extern int errno; 26340087Sbostic DIR *dirp; 26440087Sbostic struct dirent *dp; 26540087Sbostic int len, err; 26640087Sbostic 26740087Sbostic *pathend = EOS; 26840087Sbostic errno = 0; 26940087Sbostic if (!(dirp = opendir(pathbuf))) 27040087Sbostic /* todo: don't call for ENOENT or ENOTDIR? */ 27140087Sbostic if (pglob->gl_errfunc && 27240087Sbostic (*pglob->gl_errfunc)(pathbuf, errno) || 27340087Sbostic (pglob->gl_flags & GLOB_ERR)) 27440087Sbostic return(GLOB_ABEND); 27540087Sbostic else 27640087Sbostic return(0); 27740087Sbostic 27840087Sbostic err = 0; 27940087Sbostic 28040087Sbostic /* search directory for matching names */ 28140087Sbostic while ((dp = readdir(dirp))) { 28240087Sbostic /* initial DOT must be matched literally */ 28340087Sbostic if (dp->d_name[0] == DOT && *pattern != DOT) 28440087Sbostic continue; 28540087Sbostic if (!match(dp->d_name, pattern, restpattern)) 28640087Sbostic continue; 28740087Sbostic len = dp->d_namlen; 28840087Sbostic (void)strcpy(pathend, dp->d_name); 28940087Sbostic err = glob2(pathbuf, pathend+len, restpattern, pglob); 29040087Sbostic if (err) 29140087Sbostic break; 29240087Sbostic } 29340087Sbostic /* todo: check error from readdir? */ 29440087Sbostic (void)closedir(dirp); 29540087Sbostic return(err); 29640087Sbostic } 29740087Sbostic 29840087Sbostic 29940087Sbostic /* 30040087Sbostic * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 30140087Sbostic * add the new item, and update gl_pathc. 30240087Sbostic * 30340087Sbostic * This assumes the BSD realloc, which only copies the block when its size 30440087Sbostic * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 30540087Sbostic * behavior. 30640087Sbostic * 30740087Sbostic * Return 0 if new item added, error code if memory couldn't be allocated. 30840087Sbostic * 30940087Sbostic * Invariant of the glob_t structure: 31040087Sbostic * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 31140087Sbostic * gl_pathv points to (gl_offs + gl_pathc + 1) items. 31240087Sbostic */ 31340087Sbostic static 31440087Sbostic globextend(path, pglob) 31540087Sbostic char *path; 31640087Sbostic glob_t *pglob; 31740087Sbostic { 31840087Sbostic register char **pathv; 31940087Sbostic register int i; 32040087Sbostic u_int copysize, newsize; 32140087Sbostic char *copy; 32240087Sbostic 32340087Sbostic newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 32440087Sbostic pathv = (char **)realloc((char *)(pathv = pglob->gl_pathv), newsize); 32540087Sbostic if (pathv == NULL) 32640087Sbostic return(GLOB_NOSPACE); 32740087Sbostic 32840087Sbostic if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 32940087Sbostic /* first time around -- clear initial gl_offs items */ 33040087Sbostic pathv += pglob->gl_offs; 33140087Sbostic for (i = pglob->gl_offs; --i >= 0; ) 33240087Sbostic *--pathv = NULL; 33340087Sbostic } 33440087Sbostic pglob->gl_pathv = pathv; 33540087Sbostic 33640087Sbostic copysize = strlen(path) + 1; 33740087Sbostic if ((copy = malloc(copysize)) != NULL) { 33840087Sbostic (void)strcpy(copy, path); 33940087Sbostic pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 34040087Sbostic } 34140087Sbostic pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 34240087Sbostic return((copy == NULL) ? GLOB_NOSPACE : 0); 34340087Sbostic } 34440087Sbostic 34540087Sbostic 34640087Sbostic /* 34740087Sbostic * pattern matching function for filenames. Each occurrence of the * 34840087Sbostic * pattern causes a recursion level. 34940087Sbostic */ 35040087Sbostic static bool_t 35140087Sbostic match(name, pat, patend) 35240087Sbostic register char *name, *pat, *patend; 35340087Sbostic { 35440087Sbostic bool_t ok, negate_range; 35540087Sbostic char c, k; 35640087Sbostic 35740087Sbostic while (pat < patend) { 35840087Sbostic c = *pat++; 35940087Sbostic switch (c & 0xff) { 36040087Sbostic case M_ALL: 36140087Sbostic if (pat == patend) 36240087Sbostic return(1); 36340087Sbostic for (; *name != EOS; ++name) { 36440087Sbostic if (match(name, pat, patend)) 36540087Sbostic return(1); 36640087Sbostic } 36740087Sbostic return(0); 36840087Sbostic case M_ONE: 36940087Sbostic if (*name++ == EOS) 37040087Sbostic return(0); 37140087Sbostic break; 37240087Sbostic case M_SET: 37340087Sbostic ok = 0; 37440087Sbostic k = *name++; 37540087Sbostic if (negate_range = (*pat & 0xff) == M_NOT) 37640087Sbostic ++pat; 37740087Sbostic while (((c = *pat++) & 0xff) != M_END) { 37840087Sbostic if ((*pat & 0xff) == M_RNG) { 37940087Sbostic if (c <= k && k <= pat[1]) 38040087Sbostic ok = 1; 38140087Sbostic pat += 2; 38240087Sbostic } 38340087Sbostic else if (c == k) 38440087Sbostic ok = 1; 38540087Sbostic } 38640087Sbostic if (ok == negate_range) 38740087Sbostic return(0); 38840087Sbostic break; 38940087Sbostic default: 39040087Sbostic if (*name++ != c) 39140087Sbostic return(0); 39240087Sbostic break; 39340087Sbostic } 39440087Sbostic } 39540087Sbostic return(*name == EOS); 39640087Sbostic } 39740087Sbostic 39840087Sbostic /* free allocated data belonging to a glob_t structure */ 39940087Sbostic void 40040087Sbostic globfree(pglob) 40140087Sbostic glob_t *pglob; 40240087Sbostic { 40340087Sbostic register int i; 40440087Sbostic register char **pp; 40540087Sbostic 40640087Sbostic if (pglob->gl_pathv != NULL) { 40740087Sbostic pp = pglob->gl_pathv + pglob->gl_offs; 40840087Sbostic for (i = pglob->gl_pathc; i--; ++pp) 40940087Sbostic if (*pp) 41040087Sbostic (void)free(*pp); 41140087Sbostic (void)free((char *)pp); 41240087Sbostic } 41340087Sbostic } 414