glob.c revision 100616
159243Sobrien/* 259243Sobrien * Copyright (c) 1989 The Regents of the University of California. 359243Sobrien * All rights reserved. 459243Sobrien * 559243Sobrien * This code is derived from software contributed to Berkeley by 659243Sobrien * Guido van Rossum. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#if defined(LIBC_SCCS) && !defined(lint) 3359243Sobrienstatic char sccsid[] = "@(#)glob.c 5.12 (Berkeley) 6/24/91"; 3459243Sobrien#endif /* LIBC_SCCS and not lint */ 3559243Sobrien/* 3659243Sobrien * Glob: the interface is a superset of the one defined in POSIX 1003.2, 3759243Sobrien * draft 9. 3859243Sobrien * 3959243Sobrien * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 4059243Sobrien * 4159243Sobrien * Optional extra services, controlled by flags not defined by POSIX: 4259243Sobrien * 4359243Sobrien * GLOB_QUOTE: 4459243Sobrien * Escaping convention: \ inhibits any special meaning the following 4559243Sobrien * character might have (except \ at end of string is retained). 4659243Sobrien * GLOB_MAGCHAR: 4759243Sobrien * Set in gl_flags if pattern contained a globbing character. 4859243Sobrien * GLOB_ALTNOT: 4959243Sobrien * Use ^ instead of ! for "not". 5059243Sobrien * gl_matchc: 5159243Sobrien * Number of matches in the current invocation of glob. 5259243Sobrien */ 5359243Sobrien 5459243Sobrien#ifdef notdef 5559243Sobrien#include <sys/types.h> 5659243Sobrien#include <sys/param.h> 5759243Sobrien#include <sys/stat.h> 5859243Sobrien#include <dirent.h> 5959243Sobrien#include <ctype.h> 6059243Sobrientypedef void * ptr_t; 6159243Sobrien#endif 6269408Sache#ifdef WINNT_NATIVE 6359243Sobrien #pragma warning(disable:4244) 6469408Sache#endif /* WINNT_NATIVE */ 6559243Sobrien 6659243Sobrien#define Char __Char 6759243Sobrien#include "sh.h" 6859243Sobrien#undef Char 6959243Sobrien#undef QUOTE 7059243Sobrien#undef TILDE 7159243Sobrien#undef META 7259243Sobrien#undef CHAR 7359243Sobrien#undef ismeta 7459243Sobrien#undef Strchr 7559243Sobrien 7659243Sobrien#include "glob.h" 7759243Sobrien 7859243Sobrien#ifndef S_ISDIR 7959243Sobrien#define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) 8059243Sobrien#endif 8159243Sobrien 8259243Sobrien#if !defined(S_ISLNK) && defined(S_IFLNK) 8359243Sobrien#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) 8459243Sobrien#endif 8559243Sobrien 8659243Sobrien#if !defined(S_ISLNK) && !defined(lstat) 8759243Sobrien#define lstat stat 8859243Sobrien#endif 8959243Sobrien 9059243Sobrientypedef unsigned short Char; 9159243Sobrien 9259243Sobrienstatic int glob1 __P((Char *, glob_t *, int)); 9359243Sobrienstatic int glob2 __P((Char *, Char *, Char *, glob_t *, int)); 9459243Sobrienstatic int glob3 __P((Char *, Char *, Char *, Char *, 9559243Sobrien glob_t *, int)); 9659243Sobrienstatic int globextend __P((Char *, glob_t *)); 9759243Sobrienstatic int match __P((Char *, Char *, Char *, int)); 9859243Sobrien#ifndef __clipper__ 9959243Sobrienstatic int compare __P((const ptr_t, const ptr_t)); 10059243Sobrien#endif 10159243Sobrienstatic DIR *Opendir __P((Char *)); 10259243Sobrien#ifdef S_IFLNK 10359243Sobrienstatic int Lstat __P((Char *, struct stat *)); 10459243Sobrien#endif 10559243Sobrienstatic int Stat __P((Char *, struct stat *sb)); 10659243Sobrienstatic Char *Strchr __P((Char *, int)); 10759243Sobrien#ifdef DEBUG 10859243Sobrienstatic void qprintf __P((Char *)); 10959243Sobrien#endif 11059243Sobrien 11159243Sobrien#define DOLLAR '$' 11259243Sobrien#define DOT '.' 11359243Sobrien#define EOS '\0' 11459243Sobrien#define LBRACKET '[' 11559243Sobrien#define NOT '!' 11659243Sobrien#define ALTNOT '^' 11759243Sobrien#define QUESTION '?' 11859243Sobrien#define QUOTE '\\' 11959243Sobrien#define RANGE '-' 12059243Sobrien#define RBRACKET ']' 12159243Sobrien#define SEP '/' 12259243Sobrien#define STAR '*' 12359243Sobrien#define TILDE '~' 12459243Sobrien#define UNDERSCORE '_' 12559243Sobrien 12659243Sobrien#define M_META 0x8000 12759243Sobrien#define M_PROTECT 0x4000 12859243Sobrien#define M_MASK 0xffff 12959243Sobrien#define M_ASCII 0x00ff 13059243Sobrien 13159243Sobrien#define CHAR(c) ((c)&M_ASCII) 13259243Sobrien#define META(c) ((c)|M_META) 13359243Sobrien#define M_ALL META('*') 13459243Sobrien#define M_END META(']') 13559243Sobrien#define M_NOT META('!') 13659243Sobrien#define M_ALTNOT META('^') 13759243Sobrien#define M_ONE META('?') 13859243Sobrien#define M_RNG META('-') 13959243Sobrien#define M_SET META('[') 14059243Sobrien#define ismeta(c) (((c)&M_META) != 0) 14159243Sobrien 14259243Sobrien#ifndef BUFSIZE 14359243Sobrien#define GLOBBUFLEN MAXPATHLEN 14459243Sobrien#else 14559243Sobrien#define GLOBBUFLEN BUFSIZE 14659243Sobrien#endif 14759243Sobrien 14859243Sobrienint 14959243Sobrienglobcharcoll(c1, c2) 15059243Sobrien int c1, c2; 15159243Sobrien{ 15259243Sobrien#if defined(NLS) && defined(LC_COLLATE) && !defined(NOSTRCOLL) 15359243Sobrien char s1[2], s2[2]; 15459243Sobrien 15559243Sobrien if (c1 == c2) 15659243Sobrien return (0); 15759415Sobrien /* 15859415Sobrien * From kevin lyda <kevin@suberic.net>: 15959415Sobrien * strcoll does not guarantee case sorting, so we pre-process now: 16059415Sobrien */ 16159415Sobrien if (islower(c1) && isupper(c2)) 16259415Sobrien return (1); 16359243Sobrien s1[0] = c1; 16459243Sobrien s2[0] = c2; 16559243Sobrien s1[1] = s2[1] = '\0'; 16659243Sobrien return strcoll(s1, s2); 16759243Sobrien#else 16859243Sobrien return (c1 - c2); 16959243Sobrien#endif 17059243Sobrien} 17159243Sobrien 17259243Sobrien/* 17359243Sobrien * Need to dodge two kernel bugs: 17459243Sobrien * opendir("") != opendir(".") 17559243Sobrien * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels. 17659243Sobrien * POSIX specifies that they should be ignored in directories. 17759243Sobrien */ 17859243Sobrien 17959243Sobrienstatic DIR * 18059243SobrienOpendir(str) 18159243Sobrien register Char *str; 18259243Sobrien{ 18359243Sobrien char buf[GLOBBUFLEN]; 18459243Sobrien register char *dc = buf; 18559243Sobrien#if defined(hpux) || defined(__hpux) 18659243Sobrien struct stat st; 18759243Sobrien#endif 18859243Sobrien 18959243Sobrien if (!*str) 19059243Sobrien return (opendir(".")); 19159243Sobrien while ((*dc++ = *str++) != '\0') 19259243Sobrien continue; 19359243Sobrien#if defined(hpux) || defined(__hpux) 19459243Sobrien /* 19559243Sobrien * Opendir on some device files hangs, so avoid it 19659243Sobrien */ 19759243Sobrien if (stat(buf, &st) == -1 || !S_ISDIR(st.st_mode)) 19859243Sobrien return NULL; 19959243Sobrien#endif 20059243Sobrien return (opendir(buf)); 20159243Sobrien} 20259243Sobrien 20359243Sobrien#ifdef S_IFLNK 20459243Sobrienstatic int 20559243SobrienLstat(fn, sb) 20659243Sobrien register Char *fn; 20759243Sobrien struct stat *sb; 20859243Sobrien{ 20959243Sobrien char buf[GLOBBUFLEN]; 21059243Sobrien register char *dc = buf; 21159243Sobrien 21259243Sobrien while ((*dc++ = *fn++) != '\0') 21359243Sobrien continue; 21459243Sobrien# ifdef NAMEI_BUG 21559243Sobrien { 21659243Sobrien int st; 21759243Sobrien 21859243Sobrien st = lstat(buf, sb); 21959243Sobrien if (*buf) 22059243Sobrien dc--; 22159243Sobrien return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); 22259243Sobrien } 22359243Sobrien# else 22459243Sobrien return (lstat(buf, sb)); 22559243Sobrien# endif /* NAMEI_BUG */ 22659243Sobrien} 22759243Sobrien#else 22859243Sobrien#define Lstat Stat 22959243Sobrien#endif /* S_IFLNK */ 23059243Sobrien 23159243Sobrienstatic int 23259243SobrienStat(fn, sb) 23359243Sobrien register Char *fn; 23459243Sobrien struct stat *sb; 23559243Sobrien{ 23659243Sobrien char buf[GLOBBUFLEN]; 23759243Sobrien register char *dc = buf; 23859243Sobrien 23959243Sobrien while ((*dc++ = *fn++) != '\0') 24059243Sobrien continue; 24159243Sobrien#ifdef NAMEI_BUG 24259243Sobrien { 24359243Sobrien int st; 24459243Sobrien 24559243Sobrien st = stat(buf, sb); 24659243Sobrien if (*buf) 24759243Sobrien dc--; 24859243Sobrien return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); 24959243Sobrien } 25059243Sobrien#else 25159243Sobrien return (stat(buf, sb)); 25259243Sobrien#endif /* NAMEI_BUG */ 25359243Sobrien} 25459243Sobrien 25559243Sobrienstatic Char * 25659243SobrienStrchr(str, ch) 25759243Sobrien Char *str; 25859243Sobrien int ch; 25959243Sobrien{ 26059243Sobrien do 26159243Sobrien if (*str == ch) 26259243Sobrien return (str); 26359243Sobrien while (*str++); 26459243Sobrien return (NULL); 26559243Sobrien} 26659243Sobrien 26759243Sobrien#ifdef DEBUG 26859243Sobrienstatic void 26959243Sobrienqprintf(s) 27059243SobrienChar *s; 27159243Sobrien{ 27259243Sobrien Char *p; 27359243Sobrien 27459243Sobrien for (p = s; *p; p++) 27559243Sobrien printf("%c", *p & 0xff); 27659243Sobrien printf("\n"); 27759243Sobrien for (p = s; *p; p++) 27859243Sobrien printf("%c", *p & M_PROTECT ? '"' : ' '); 27959243Sobrien printf("\n"); 28059243Sobrien for (p = s; *p; p++) 28159243Sobrien printf("%c", *p & M_META ? '_' : ' '); 28259243Sobrien printf("\n"); 28359243Sobrien} 28459243Sobrien#endif /* DEBUG */ 28559243Sobrien 28659243Sobrienstatic int 28759243Sobriencompare(p, q) 28859243Sobrien const ptr_t p, q; 28959243Sobrien{ 29059243Sobrien#if defined(NLS) && !defined(NOSTRCOLL) 29159243Sobrien errno = 0; /* strcoll sets errno, another brain-damage */ 29259243Sobrien 29359243Sobrien return (strcoll(*(char **) p, *(char **) q)); 29459243Sobrien#else 29559243Sobrien return (strcmp(*(char **) p, *(char **) q)); 29659243Sobrien#endif /* NLS && !NOSTRCOLL */ 29759243Sobrien} 29859243Sobrien 29959243Sobrien/* 30059243Sobrien * The main glob() routine: compiles the pattern (optionally processing 30159243Sobrien * quotes), calls glob1() to do the real pattern matching, and finally 30259243Sobrien * sorts the list (unless unsorted operation is requested). Returns 0 30359243Sobrien * if things went well, nonzero if errors occurred. It is not an error 30459243Sobrien * to find no matches. 30559243Sobrien */ 30659243Sobrienint 30759243Sobrienglob(pattern, flags, errfunc, pglob) 30859243Sobrien const char *pattern; 30959243Sobrien int flags; 31059243Sobrien int (*errfunc) __P((const char *, int)); 31159243Sobrien glob_t *pglob; 31259243Sobrien{ 31359243Sobrien int err, oldpathc; 31459243Sobrien Char *bufnext, *bufend, *compilebuf, m_not; 31559243Sobrien const unsigned char *compilepat, *patnext; 31659243Sobrien int c, not; 31759243Sobrien Char patbuf[GLOBBUFLEN + 1], *qpatnext; 31859243Sobrien int no_match; 31959243Sobrien 32059243Sobrien patnext = (unsigned char *) pattern; 32159243Sobrien if (!(flags & GLOB_APPEND)) { 32259243Sobrien pglob->gl_pathc = 0; 32359243Sobrien pglob->gl_pathv = NULL; 32459243Sobrien if (!(flags & GLOB_DOOFFS)) 32559243Sobrien pglob->gl_offs = 0; 32659243Sobrien } 32759243Sobrien pglob->gl_flags = flags & ~GLOB_MAGCHAR; 32859243Sobrien pglob->gl_errfunc = errfunc; 32959243Sobrien oldpathc = pglob->gl_pathc; 33059243Sobrien pglob->gl_matchc = 0; 33159243Sobrien 33259243Sobrien if (pglob->gl_flags & GLOB_ALTNOT) { 33359243Sobrien not = ALTNOT; 33459243Sobrien m_not = M_ALTNOT; 33559243Sobrien } 33659243Sobrien else { 33759243Sobrien not = NOT; 33859243Sobrien m_not = M_NOT; 33959243Sobrien } 34059243Sobrien 34159243Sobrien bufnext = patbuf; 34259243Sobrien bufend = bufnext + GLOBBUFLEN; 34359243Sobrien compilebuf = bufnext; 34459243Sobrien compilepat = patnext; 34559243Sobrien 34659243Sobrien no_match = *patnext == not; 34759243Sobrien if (no_match) 34859243Sobrien patnext++; 34959243Sobrien 35059243Sobrien if (flags & GLOB_QUOTE) { 35159243Sobrien /* Protect the quoted characters */ 35259243Sobrien while (bufnext < bufend && (c = *patnext++) != EOS) 35359415Sobrien#ifdef DSPMBYTE 35459415Sobrien if (Ismbyte1(c) && *patnext != EOS) 35559415Sobrien { 35659415Sobrien *bufnext++ = (Char) c; 35759415Sobrien *bufnext++ = (Char) *patnext++; 35859415Sobrien } 35959415Sobrien else 36059415Sobrien#endif /* DSPMBYTE */ 36159243Sobrien if (c == QUOTE) { 36259243Sobrien if ((c = *patnext++) == EOS) { 36359243Sobrien c = QUOTE; 36459243Sobrien --patnext; 36559243Sobrien } 36659243Sobrien *bufnext++ = (Char) (c | M_PROTECT); 36759243Sobrien } 36859243Sobrien else 36959243Sobrien *bufnext++ = (Char) c; 37059243Sobrien } 37159243Sobrien else 37259243Sobrien while (bufnext < bufend && (c = *patnext++) != EOS) 37359243Sobrien *bufnext++ = (Char) c; 37459243Sobrien *bufnext = EOS; 37559243Sobrien 37659243Sobrien bufnext = patbuf; 37759243Sobrien qpatnext = patbuf; 37859243Sobrien /* we don't need to check for buffer overflow any more */ 37959243Sobrien while ((c = *qpatnext++) != EOS) { 38059415Sobrien#ifdef DSPMBYTE 38159415Sobrien if (Ismbyte1(c) && *qpatnext != EOS) 38259415Sobrien { 38359415Sobrien *bufnext++ = CHAR(c); 38459415Sobrien *bufnext++ = CHAR(*qpatnext++); 38559415Sobrien } 38659415Sobrien else 38759415Sobrien#endif /* DSPMBYTE */ 38859243Sobrien switch (c) { 38959243Sobrien case LBRACKET: 39059243Sobrien c = *qpatnext; 39159243Sobrien if (c == not) 39259243Sobrien ++qpatnext; 39359243Sobrien if (*qpatnext == EOS || 39459243Sobrien Strchr(qpatnext + 1, RBRACKET) == NULL) { 39559243Sobrien *bufnext++ = LBRACKET; 39659243Sobrien if (c == not) 39759243Sobrien --qpatnext; 39859243Sobrien break; 39959243Sobrien } 40059243Sobrien pglob->gl_flags |= GLOB_MAGCHAR; 40159243Sobrien *bufnext++ = M_SET; 40259243Sobrien if (c == not) 40359243Sobrien *bufnext++ = m_not; 40459243Sobrien c = *qpatnext++; 40559243Sobrien do { 40659243Sobrien *bufnext++ = CHAR(c); 40759243Sobrien if (*qpatnext == RANGE && 40859243Sobrien (c = qpatnext[1]) != RBRACKET) { 40959243Sobrien *bufnext++ = M_RNG; 41059243Sobrien *bufnext++ = CHAR(c); 41159243Sobrien qpatnext += 2; 41259243Sobrien } 41359243Sobrien } while ((c = *qpatnext++) != RBRACKET); 41459243Sobrien *bufnext++ = M_END; 41559243Sobrien break; 41659243Sobrien case QUESTION: 41759243Sobrien pglob->gl_flags |= GLOB_MAGCHAR; 41859243Sobrien *bufnext++ = M_ONE; 41959243Sobrien break; 42059243Sobrien case STAR: 42159243Sobrien pglob->gl_flags |= GLOB_MAGCHAR; 42259243Sobrien /* collapse adjacent stars to one, to avoid 42359243Sobrien * exponential behavior 42459243Sobrien */ 42559243Sobrien if (bufnext == patbuf || bufnext[-1] != M_ALL) 42659243Sobrien *bufnext++ = M_ALL; 42759243Sobrien break; 42859243Sobrien default: 42959243Sobrien *bufnext++ = CHAR(c); 43059243Sobrien break; 43159243Sobrien } 43259243Sobrien } 43359243Sobrien *bufnext = EOS; 43459243Sobrien#ifdef DEBUG 43559243Sobrien qprintf(patbuf); 43659243Sobrien#endif 43759243Sobrien 43859243Sobrien if ((err = glob1(patbuf, pglob, no_match)) != 0) 43959243Sobrien return (err); 44059243Sobrien 44159243Sobrien /* 44259243Sobrien * If there was no match we are going to append the pattern 44359243Sobrien * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 44459243Sobrien * and the pattern did not contain any magic characters 44559243Sobrien * GLOB_NOMAGIC is there just for compatibility with csh. 44659243Sobrien */ 44759243Sobrien if (pglob->gl_pathc == oldpathc && 44859243Sobrien ((flags & GLOB_NOCHECK) || 44959243Sobrien ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { 45059243Sobrien if (!(flags & GLOB_QUOTE)) { 45159243Sobrien Char *dp = compilebuf; 45259243Sobrien const unsigned char *sp = compilepat; 45359243Sobrien 45459243Sobrien while ((*dp++ = *sp++) != '\0') 45559243Sobrien continue; 45659243Sobrien } 45759243Sobrien else { 45859243Sobrien /* 45959243Sobrien * copy pattern, interpreting quotes; this is slightly different 46059243Sobrien * than the interpretation of quotes above -- which should prevail? 46159243Sobrien */ 46259243Sobrien while (*compilepat != EOS) { 46359243Sobrien if (*compilepat == QUOTE) { 46459243Sobrien if (*++compilepat == EOS) 46559243Sobrien --compilepat; 46659243Sobrien } 46759243Sobrien *compilebuf++ = (unsigned char) *compilepat++; 46859243Sobrien } 46959243Sobrien *compilebuf = EOS; 47059243Sobrien } 47159243Sobrien return (globextend(patbuf, pglob)); 47259243Sobrien } 47359415Sobrien else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc)) 47459243Sobrien qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc), 47559243Sobrien pglob->gl_pathc - oldpathc, sizeof(char *), 47659243Sobrien (int (*) __P((const void *, const void *))) compare); 47759243Sobrien return (0); 47859243Sobrien} 47959243Sobrien 48059243Sobrienstatic int 48159243Sobrienglob1(pattern, pglob, no_match) 48259243Sobrien Char *pattern; 48359243Sobrien glob_t *pglob; 48459243Sobrien int no_match; 48559243Sobrien{ 48659243Sobrien Char pathbuf[GLOBBUFLEN + 1]; 48759243Sobrien 48859243Sobrien /* 48959243Sobrien * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. 49059243Sobrien */ 49159243Sobrien if (*pattern == EOS) 49259243Sobrien return (0); 49359243Sobrien return (glob2(pathbuf, pathbuf, pattern, pglob, no_match)); 49459243Sobrien} 49559243Sobrien 49659243Sobrien/* 49759243Sobrien * functions glob2 and glob3 are mutually recursive; there is one level 49859243Sobrien * of recursion for each segment in the pattern that contains one or 49959243Sobrien * more meta characters. 50059243Sobrien */ 50159243Sobrienstatic int 50259243Sobrienglob2(pathbuf, pathend, pattern, pglob, no_match) 50359243Sobrien Char *pathbuf, *pathend, *pattern; 50459243Sobrien glob_t *pglob; 50559243Sobrien int no_match; 50659243Sobrien{ 50759243Sobrien struct stat sbuf; 50859243Sobrien int anymeta; 50959243Sobrien Char *p, *q; 51059243Sobrien 51159243Sobrien /* 51259243Sobrien * loop over pattern segments until end of pattern or until segment with 51359243Sobrien * meta character found. 51459243Sobrien */ 51559243Sobrien anymeta = 0; 51659243Sobrien for (;;) { 51759243Sobrien if (*pattern == EOS) { /* end of pattern? */ 51859243Sobrien *pathend = EOS; 51959243Sobrien 52059243Sobrien if (Lstat(pathbuf, &sbuf)) 52159243Sobrien return (0); 52259243Sobrien 52359243Sobrien if (((pglob->gl_flags & GLOB_MARK) && 52459243Sobrien pathend[-1] != SEP) && 52559243Sobrien (S_ISDIR(sbuf.st_mode) 52659243Sobrien#ifdef S_IFLNK 52759243Sobrien || (S_ISLNK(sbuf.st_mode) && 52859243Sobrien (Stat(pathbuf, &sbuf) == 0) && 52959243Sobrien S_ISDIR(sbuf.st_mode)) 53059243Sobrien#endif 53159243Sobrien )) { 53259243Sobrien *pathend++ = SEP; 53359243Sobrien *pathend = EOS; 53459243Sobrien } 53559243Sobrien ++pglob->gl_matchc; 53659243Sobrien return (globextend(pathbuf, pglob)); 53759243Sobrien } 53859243Sobrien 53959243Sobrien /* find end of next segment, copy tentatively to pathend */ 54059243Sobrien q = pathend; 54159243Sobrien p = pattern; 54259243Sobrien while (*p != EOS && *p != SEP) { 54359243Sobrien if (ismeta(*p)) 54459243Sobrien anymeta = 1; 54559243Sobrien *q++ = *p++; 54659243Sobrien } 54759243Sobrien 54859243Sobrien if (!anymeta) { /* no expansion, do next segment */ 54959243Sobrien pathend = q; 55059243Sobrien pattern = p; 55159243Sobrien while (*pattern == SEP) 55259243Sobrien *pathend++ = *pattern++; 55359243Sobrien } 55459243Sobrien else /* need expansion, recurse */ 55559243Sobrien return (glob3(pathbuf, pathend, pattern, p, pglob, no_match)); 55659243Sobrien } 55759243Sobrien /* NOTREACHED */ 55859243Sobrien} 55959243Sobrien 56059243Sobrien 56159243Sobrienstatic int 56259243Sobrienglob3(pathbuf, pathend, pattern, restpattern, pglob, no_match) 56359243Sobrien Char *pathbuf, *pathend, *pattern, *restpattern; 56459243Sobrien glob_t *pglob; 56559243Sobrien int no_match; 56659243Sobrien{ 56759243Sobrien DIR *dirp; 56859243Sobrien struct dirent *dp; 56959243Sobrien int err; 57059243Sobrien Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; 57159243Sobrien char cpathbuf[GLOBBUFLEN], *ptr;; 57259243Sobrien 57359243Sobrien *pathend = EOS; 57459243Sobrien errno = 0; 57559243Sobrien 57659243Sobrien if (!(dirp = Opendir(pathbuf))) { 57759243Sobrien /* todo: don't call for ENOENT or ENOTDIR? */ 57859243Sobrien for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;) 57959243Sobrien continue; 58059243Sobrien if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) || 58159243Sobrien (pglob->gl_flags & GLOB_ERR)) 58259243Sobrien return (GLOB_ABEND); 58359243Sobrien else 58459243Sobrien return (0); 58559243Sobrien } 58659243Sobrien 58759243Sobrien err = 0; 58859243Sobrien 58959243Sobrien /* search directory for matching names */ 59059243Sobrien while ((dp = readdir(dirp)) != NULL) { 59159243Sobrien register unsigned char *sc; 59259243Sobrien register Char *dc; 59359243Sobrien 59459243Sobrien /* initial DOT must be matched literally */ 59559243Sobrien if (dp->d_name[0] == DOT && *pattern != DOT) 59659243Sobrien continue; 59759243Sobrien for (sc = (unsigned char *) dp->d_name, dc = pathend; 59859243Sobrien (*dc++ = *sc++) != '\0';) 59959243Sobrien continue; 60059243Sobrien if (match(pathend, pattern, restpattern, (int) m_not) == no_match) { 60159243Sobrien *pathend = EOS; 60259243Sobrien continue; 60359243Sobrien } 60459243Sobrien err = glob2(pathbuf, --dc, restpattern, pglob, no_match); 60559243Sobrien if (err) 60659243Sobrien break; 60759243Sobrien } 60859243Sobrien /* todo: check error from readdir? */ 60959243Sobrien (void) closedir(dirp); 61059243Sobrien return (err); 61159243Sobrien} 61259243Sobrien 61359243Sobrien 61459243Sobrien/* 61559243Sobrien * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 61659243Sobrien * add the new item, and update gl_pathc. 61759243Sobrien * 61859243Sobrien * This assumes the BSD realloc, which only copies the block when its size 61959243Sobrien * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 62059243Sobrien * behavior. 62159243Sobrien * 62259243Sobrien * Return 0 if new item added, error code if memory couldn't be allocated. 62359243Sobrien * 62459243Sobrien * Invariant of the glob_t structure: 62559243Sobrien * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 62659243Sobrien * gl_pathv points to (gl_offs + gl_pathc + 1) items. 62759243Sobrien */ 62859243Sobrienstatic int 62959243Sobrienglobextend(path, pglob) 63059243Sobrien Char *path; 63159243Sobrien glob_t *pglob; 63259243Sobrien{ 63359243Sobrien register char **pathv; 63459243Sobrien register int i; 63559243Sobrien unsigned int newsize; 63659243Sobrien char *copy; 63759243Sobrien Char *p; 63859243Sobrien 63959243Sobrien newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 64059243Sobrien pathv = (char **) (pglob->gl_pathv ? 64159243Sobrien xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) : 64259243Sobrien xmalloc((size_t) newsize)); 64359243Sobrien if (pathv == NULL) 64459243Sobrien return (GLOB_NOSPACE); 64559243Sobrien 64659243Sobrien if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 64759243Sobrien /* first time around -- clear initial gl_offs items */ 64859243Sobrien pathv += pglob->gl_offs; 64959243Sobrien for (i = pglob->gl_offs; --i >= 0;) 65059243Sobrien *--pathv = NULL; 65159243Sobrien } 65259243Sobrien pglob->gl_pathv = pathv; 65359243Sobrien 65459243Sobrien for (p = path; *p++;) 65559243Sobrien continue; 65659243Sobrien if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) { 65759243Sobrien register char *dc = copy; 65859243Sobrien register Char *sc = path; 65959243Sobrien 66059243Sobrien while ((*dc++ = *sc++) != '\0') 66159243Sobrien continue; 66259243Sobrien pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 66359243Sobrien } 66459243Sobrien pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 66559243Sobrien return ((copy == NULL) ? GLOB_NOSPACE : 0); 66659243Sobrien} 66759243Sobrien 66859243Sobrien 66959243Sobrien/* 67059243Sobrien * pattern matching function for filenames. Each occurrence of the * 67159243Sobrien * pattern causes a recursion level. 67259243Sobrien */ 67359243Sobrienstatic int 67459243Sobrienmatch(name, pat, patend, m_not) 67559243Sobrien register Char *name, *pat, *patend; 67659243Sobrien int m_not; 67759243Sobrien{ 67859243Sobrien int ok, negate_range; 67959243Sobrien Char c, k; 68059243Sobrien 68159243Sobrien while (pat < patend) { 68259243Sobrien c = *pat++; 68359243Sobrien switch (c & M_MASK) { 68459243Sobrien case M_ALL: 68559243Sobrien if (pat == patend) 68659243Sobrien return (1); 68759243Sobrien do 68859243Sobrien if (match(name, pat, patend, m_not)) 68959243Sobrien return (1); 69059243Sobrien while (*name++ != EOS); 69159243Sobrien return (0); 69259243Sobrien case M_ONE: 69359243Sobrien if (*name++ == EOS) 69459243Sobrien return (0); 69559243Sobrien break; 69659243Sobrien case M_SET: 69759243Sobrien ok = 0; 69859243Sobrien if ((k = *name++) == EOS) 69959243Sobrien return (0); 70059243Sobrien if ((negate_range = ((*pat & M_MASK) == m_not)) != 0) 70159243Sobrien ++pat; 70259243Sobrien while (((c = *pat++) & M_MASK) != M_END) { 70359243Sobrien if ((*pat & M_MASK) == M_RNG) { 70459243Sobrien if (globcharcoll(CHAR(c), CHAR(k)) <= 0 && 70559243Sobrien globcharcoll(CHAR(k), CHAR(pat[1])) <= 0) 70659243Sobrien ok = 1; 70759243Sobrien pat += 2; 70859243Sobrien } 70959243Sobrien else if (c == k) 71059243Sobrien ok = 1; 71159243Sobrien } 71259243Sobrien if (ok == negate_range) 71359243Sobrien return (0); 71459243Sobrien break; 71559243Sobrien default: 71659243Sobrien k = *name++; 71759243Sobrien if (samecase(k) != samecase(c)) 71859243Sobrien return (0); 71959243Sobrien break; 72059243Sobrien } 72159243Sobrien } 72259243Sobrien return (*name == EOS); 72359243Sobrien} 72459243Sobrien 72559243Sobrien/* free allocated data belonging to a glob_t structure */ 72659243Sobrienvoid 72759243Sobrienglobfree(pglob) 72859243Sobrien glob_t *pglob; 72959243Sobrien{ 73059243Sobrien register int i; 73159243Sobrien register char **pp; 73259243Sobrien 73359243Sobrien if (pglob->gl_pathv != NULL) { 73459243Sobrien pp = pglob->gl_pathv + pglob->gl_offs; 73559243Sobrien for (i = pglob->gl_pathc; i--; ++pp) 73659243Sobrien if (*pp) 73759243Sobrien xfree((ptr_t) *pp), *pp = NULL; 73859243Sobrien xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL; 73959243Sobrien } 74059243Sobrien} 741