1c80476e4SDavid E. O'Brien /* 2c80476e4SDavid E. O'Brien * Copyright (c) 1989 The Regents of the University of California. 3c80476e4SDavid E. O'Brien * All rights reserved. 4c80476e4SDavid E. O'Brien * 5c80476e4SDavid E. O'Brien * This code is derived from software contributed to Berkeley by 6c80476e4SDavid E. O'Brien * Guido van Rossum. 7c80476e4SDavid E. O'Brien * 8c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 9c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions 10c80476e4SDavid E. O'Brien * are met: 11c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 12c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 13c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 14c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 15c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution. 1629301572SMark Peek * 3. Neither the name of the University nor the names of its contributors 17c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software 18c80476e4SDavid E. O'Brien * without specific prior written permission. 19c80476e4SDavid E. O'Brien * 20c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30c80476e4SDavid E. O'Brien * SUCH DAMAGE. 31c80476e4SDavid E. O'Brien */ 32c80476e4SDavid E. O'Brien #if defined(LIBC_SCCS) && !defined(lint) 33c80476e4SDavid E. O'Brien static char sccsid[] = "@(#)glob.c 5.12 (Berkeley) 6/24/91"; 34c80476e4SDavid E. O'Brien #endif /* LIBC_SCCS and not lint */ 35c80476e4SDavid E. O'Brien /* 36c80476e4SDavid E. O'Brien * Glob: the interface is a superset of the one defined in POSIX 1003.2, 37c80476e4SDavid E. O'Brien * draft 9. 38c80476e4SDavid E. O'Brien * 39c80476e4SDavid E. O'Brien * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 40c80476e4SDavid E. O'Brien * 41c80476e4SDavid E. O'Brien * Optional extra services, controlled by flags not defined by POSIX: 42c80476e4SDavid E. O'Brien * 43c80476e4SDavid E. O'Brien * GLOB_QUOTE: 44c80476e4SDavid E. O'Brien * Escaping convention: \ inhibits any special meaning the following 45c80476e4SDavid E. O'Brien * character might have (except \ at end of string is retained). 46c80476e4SDavid E. O'Brien * GLOB_MAGCHAR: 47c80476e4SDavid E. O'Brien * Set in gl_flags if pattern contained a globbing character. 48c80476e4SDavid E. O'Brien * GLOB_ALTNOT: 49c80476e4SDavid E. O'Brien * Use ^ instead of ! for "not". 50c80476e4SDavid E. O'Brien * gl_matchc: 51c80476e4SDavid E. O'Brien * Number of matches in the current invocation of glob. 52c80476e4SDavid E. O'Brien */ 53c80476e4SDavid E. O'Brien 543b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 55c80476e4SDavid E. O'Brien #pragma warning(disable:4244) 563b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */ 57c80476e4SDavid E. O'Brien 58c80476e4SDavid E. O'Brien #define Char __Char 59c80476e4SDavid E. O'Brien #include "sh.h" 6023338178SMark Peek #include "glob.h" 6123338178SMark Peek 62*19d2e3deSDmitry Chagin #ifndef HAVE_MBLEN 63*19d2e3deSDmitry Chagin #undef mblen 64*19d2e3deSDmitry Chagin #define mblen(_s,_n) mbrlen((_s),(_n),NULL) 65*19d2e3deSDmitry Chagin #endif 66*19d2e3deSDmitry Chagin 67c80476e4SDavid E. O'Brien #undef Char 68c80476e4SDavid E. O'Brien #undef QUOTE 69c80476e4SDavid E. O'Brien #undef TILDE 70c80476e4SDavid E. O'Brien #undef META 71c80476e4SDavid E. O'Brien #undef ismeta 72c80476e4SDavid E. O'Brien #undef Strchr 73c80476e4SDavid E. O'Brien 74c80476e4SDavid E. O'Brien #ifndef S_ISDIR 75c80476e4SDavid E. O'Brien #define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) 76c80476e4SDavid E. O'Brien #endif 77c80476e4SDavid E. O'Brien 78c80476e4SDavid E. O'Brien #if !defined(S_ISLNK) && defined(S_IFLNK) 79c80476e4SDavid E. O'Brien #define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) 80c80476e4SDavid E. O'Brien #endif 81c80476e4SDavid E. O'Brien 82c80476e4SDavid E. O'Brien #if !defined(S_ISLNK) && !defined(lstat) 83c80476e4SDavid E. O'Brien #define lstat stat 84c80476e4SDavid E. O'Brien #endif 85c80476e4SDavid E. O'Brien 86c80476e4SDavid E. O'Brien typedef unsigned short Char; 87c80476e4SDavid E. O'Brien 8845e5710bSMark Peek static int glob1 (Char *, glob_t *, int); 8945e5710bSMark Peek static int glob2 (struct strbuf *, const Char *, glob_t *, int); 9045e5710bSMark Peek static int glob3 (struct strbuf *, const Char *, const Char *, 919ccc37e3SMark Peek const Char *, glob_t *, int); 9245e5710bSMark Peek static void globextend (const char *, glob_t *); 9345e5710bSMark Peek static int match (const char *, const Char *, const Char *, 9445e5710bSMark Peek int); 9545e5710bSMark Peek static int compare (const void *, const void *); 9645e5710bSMark Peek static DIR *Opendir (const char *); 97c80476e4SDavid E. O'Brien #ifdef S_IFLNK 9845e5710bSMark Peek static int Lstat (const char *, struct stat *); 99c80476e4SDavid E. O'Brien #endif 10045e5710bSMark Peek static int Stat (const char *, struct stat *sb); 10145e5710bSMark Peek static Char *Strchr (Char *, int); 102c80476e4SDavid E. O'Brien #ifdef DEBUG 10345e5710bSMark Peek static void qprintf (const Char *); 104c80476e4SDavid E. O'Brien #endif 105c80476e4SDavid E. O'Brien 106c80476e4SDavid E. O'Brien #define DOLLAR '$' 107c80476e4SDavid E. O'Brien #define DOT '.' 108c80476e4SDavid E. O'Brien #define EOS '\0' 109c80476e4SDavid E. O'Brien #define LBRACKET '[' 110c80476e4SDavid E. O'Brien #define NOT '!' 111c80476e4SDavid E. O'Brien #define ALTNOT '^' 112c80476e4SDavid E. O'Brien #define QUESTION '?' 113c80476e4SDavid E. O'Brien #define QUOTE '\\' 114c80476e4SDavid E. O'Brien #define RANGE '-' 115c80476e4SDavid E. O'Brien #define RBRACKET ']' 116c80476e4SDavid E. O'Brien #define SEP '/' 117c80476e4SDavid E. O'Brien #define STAR '*' 118c80476e4SDavid E. O'Brien #define TILDE '~' 119c80476e4SDavid E. O'Brien #define UNDERSCORE '_' 120c80476e4SDavid E. O'Brien 121c80476e4SDavid E. O'Brien #define M_META 0x8000 122c80476e4SDavid E. O'Brien #define M_PROTECT 0x4000 123c80476e4SDavid E. O'Brien #define M_MASK 0xffff 124c80476e4SDavid E. O'Brien #define M_ASCII 0x00ff 125c80476e4SDavid E. O'Brien 12645e5710bSMark Peek #define LCHAR(c) ((c)&M_ASCII) 127c80476e4SDavid E. O'Brien #define META(c) ((c)|M_META) 128c80476e4SDavid E. O'Brien #define M_ALL META('*') 129c80476e4SDavid E. O'Brien #define M_END META(']') 130c80476e4SDavid E. O'Brien #define M_NOT META('!') 131c80476e4SDavid E. O'Brien #define M_ALTNOT META('^') 132c80476e4SDavid E. O'Brien #define M_ONE META('?') 133c80476e4SDavid E. O'Brien #define M_RNG META('-') 134c80476e4SDavid E. O'Brien #define M_SET META('[') 135c80476e4SDavid E. O'Brien #define ismeta(c) (((c)&M_META) != 0) 136c80476e4SDavid E. O'Brien 137c80476e4SDavid E. O'Brien int 13845e5710bSMark Peek globcharcoll(__Char c1, __Char c2, int cs) 139c80476e4SDavid E. O'Brien { 14045e5710bSMark Peek #if defined(NLS) && defined(LC_COLLATE) && defined(HAVE_STRCOLL) 14145e5710bSMark Peek # if defined(WIDE_STRINGS) 14223338178SMark Peek wchar_t s1[2], s2[2]; 14323338178SMark Peek 14423338178SMark Peek if (c1 == c2) 14523338178SMark Peek return (0); 14623338178SMark Peek if (cs) { 14723338178SMark Peek c1 = towlower(c1); 14823338178SMark Peek c2 = towlower(c2); 14923338178SMark Peek } else { 1502219fc0fSAndrey A. Chernov #ifndef __FreeBSD__ 15123338178SMark Peek /* This should not be here, but I'll rather leave it in than engage in 15223338178SMark Peek a LC_COLLATE flamewar about a shell I don't use... */ 15323338178SMark Peek if (iswlower(c1) && iswupper(c2)) 15423338178SMark Peek return (1); 15523338178SMark Peek if (iswupper(c1) && iswlower(c2)) 15623338178SMark Peek return (-1); 1572219fc0fSAndrey A. Chernov #endif 15823338178SMark Peek } 15923338178SMark Peek s1[0] = c1; 16023338178SMark Peek s2[0] = c2; 16123338178SMark Peek s1[1] = s2[1] = '\0'; 16223338178SMark Peek return wcscoll(s1, s2); 16345e5710bSMark Peek # else /* not WIDE_STRINGS */ 164c80476e4SDavid E. O'Brien char s1[2], s2[2]; 165c80476e4SDavid E. O'Brien 166c80476e4SDavid E. O'Brien if (c1 == c2) 167c80476e4SDavid E. O'Brien return (0); 1688e66bd9eSDavid E. O'Brien /* 1698e66bd9eSDavid E. O'Brien * From kevin lyda <kevin@suberic.net>: 1708e66bd9eSDavid E. O'Brien * strcoll does not guarantee case sorting, so we pre-process now: 1718e66bd9eSDavid E. O'Brien */ 172b2d5d167SMark Peek if (cs) { 173b2d5d167SMark Peek c1 = islower(c1) ? c1 : tolower(c1); 174b2d5d167SMark Peek c2 = islower(c2) ? c2 : tolower(c2); 175b2d5d167SMark Peek } else { 1768e66bd9eSDavid E. O'Brien if (islower(c1) && isupper(c2)) 1778e66bd9eSDavid E. O'Brien return (1); 17823338178SMark Peek if (isupper(c1) && islower(c2)) 17923338178SMark Peek return (-1); 180b2d5d167SMark Peek } 181c80476e4SDavid E. O'Brien s1[0] = c1; 182c80476e4SDavid E. O'Brien s2[0] = c2; 183c80476e4SDavid E. O'Brien s1[1] = s2[1] = '\0'; 184c80476e4SDavid E. O'Brien return strcoll(s1, s2); 18523338178SMark Peek # endif 186c80476e4SDavid E. O'Brien #else 187c80476e4SDavid E. O'Brien return (c1 - c2); 188c80476e4SDavid E. O'Brien #endif 189c80476e4SDavid E. O'Brien } 190c80476e4SDavid E. O'Brien 191c80476e4SDavid E. O'Brien /* 192c80476e4SDavid E. O'Brien * Need to dodge two kernel bugs: 193c80476e4SDavid E. O'Brien * opendir("") != opendir(".") 194c80476e4SDavid E. O'Brien * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels. 195c80476e4SDavid E. O'Brien * POSIX specifies that they should be ignored in directories. 196c80476e4SDavid E. O'Brien */ 197c80476e4SDavid E. O'Brien 198c80476e4SDavid E. O'Brien static DIR * 19945e5710bSMark Peek Opendir(const char *str) 200c80476e4SDavid E. O'Brien { 201c80476e4SDavid E. O'Brien #if defined(hpux) || defined(__hpux) 202c80476e4SDavid E. O'Brien struct stat st; 203c80476e4SDavid E. O'Brien #endif 204c80476e4SDavid E. O'Brien 205c80476e4SDavid E. O'Brien if (!*str) 206c80476e4SDavid E. O'Brien return (opendir(".")); 207c80476e4SDavid E. O'Brien #if defined(hpux) || defined(__hpux) 208c80476e4SDavid E. O'Brien /* 209c80476e4SDavid E. O'Brien * Opendir on some device files hangs, so avoid it 210c80476e4SDavid E. O'Brien */ 21145e5710bSMark Peek if (stat(str, &st) == -1 || !S_ISDIR(st.st_mode)) 212c80476e4SDavid E. O'Brien return NULL; 213c80476e4SDavid E. O'Brien #endif 21445e5710bSMark Peek return opendir(str); 215c80476e4SDavid E. O'Brien } 216c80476e4SDavid E. O'Brien 217c80476e4SDavid E. O'Brien #ifdef S_IFLNK 218c80476e4SDavid E. O'Brien static int 21945e5710bSMark Peek Lstat(const char *fn, struct stat *sb) 220c80476e4SDavid E. O'Brien { 221c80476e4SDavid E. O'Brien int st; 222c80476e4SDavid E. O'Brien 22345e5710bSMark Peek st = lstat(fn, sb); 22445e5710bSMark Peek # ifdef NAMEI_BUG 22545e5710bSMark Peek if (*fn != 0 && strend(fn)[-1] == '/' && !S_ISDIR(sb->st_mode)) 22645e5710bSMark Peek st = -1; 227c80476e4SDavid E. O'Brien # endif /* NAMEI_BUG */ 22845e5710bSMark Peek return st; 229c80476e4SDavid E. O'Brien } 230c80476e4SDavid E. O'Brien #else 231c80476e4SDavid E. O'Brien #define Lstat Stat 232c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 233c80476e4SDavid E. O'Brien 234c80476e4SDavid E. O'Brien static int 23545e5710bSMark Peek Stat(const char *fn, struct stat *sb) 236c80476e4SDavid E. O'Brien { 237c80476e4SDavid E. O'Brien int st; 238c80476e4SDavid E. O'Brien 23945e5710bSMark Peek st = stat(fn, sb); 24045e5710bSMark Peek #ifdef NAMEI_BUG 24145e5710bSMark Peek if (*fn != 0 && strend(fn)[-1] == '/' && !S_ISDIR(sb->st_mode)) 24245e5710bSMark Peek st = -1; 243c80476e4SDavid E. O'Brien #endif /* NAMEI_BUG */ 24445e5710bSMark Peek return st; 245c80476e4SDavid E. O'Brien } 246c80476e4SDavid E. O'Brien 247c80476e4SDavid E. O'Brien static Char * 24845e5710bSMark Peek Strchr(Char *str, int ch) 249c80476e4SDavid E. O'Brien { 250c80476e4SDavid E. O'Brien do 251c80476e4SDavid E. O'Brien if (*str == ch) 252c80476e4SDavid E. O'Brien return (str); 253c80476e4SDavid E. O'Brien while (*str++); 254c80476e4SDavid E. O'Brien return (NULL); 255c80476e4SDavid E. O'Brien } 256c80476e4SDavid E. O'Brien 257c80476e4SDavid E. O'Brien #ifdef DEBUG 258c80476e4SDavid E. O'Brien static void 25945e5710bSMark Peek qprintf(const Char *s) 260c80476e4SDavid E. O'Brien { 26145e5710bSMark Peek const Char *p; 262c80476e4SDavid E. O'Brien 263c80476e4SDavid E. O'Brien for (p = s; *p; p++) 264c80476e4SDavid E. O'Brien printf("%c", *p & 0xff); 265c80476e4SDavid E. O'Brien printf("\n"); 266c80476e4SDavid E. O'Brien for (p = s; *p; p++) 267c80476e4SDavid E. O'Brien printf("%c", *p & M_PROTECT ? '"' : ' '); 268c80476e4SDavid E. O'Brien printf("\n"); 269c80476e4SDavid E. O'Brien for (p = s; *p; p++) 270c80476e4SDavid E. O'Brien printf("%c", *p & M_META ? '_' : ' '); 271c80476e4SDavid E. O'Brien printf("\n"); 272c80476e4SDavid E. O'Brien } 273c80476e4SDavid E. O'Brien #endif /* DEBUG */ 274c80476e4SDavid E. O'Brien 275c80476e4SDavid E. O'Brien static int 27645e5710bSMark Peek compare(const void *p, const void *q) 277c80476e4SDavid E. O'Brien { 27845e5710bSMark Peek #if defined(NLS) && defined(HAVE_STRCOLL) 27945e5710bSMark Peek return (strcoll(*(char *const *) p, *(char *const *) q)); 280c80476e4SDavid E. O'Brien #else 28145e5710bSMark Peek return (strcmp(*(char *const *) p, *(char *const *) q)); 28245e5710bSMark Peek #endif /* NLS && HAVE_STRCOLL */ 283c80476e4SDavid E. O'Brien } 284c80476e4SDavid E. O'Brien 285c80476e4SDavid E. O'Brien /* 286c80476e4SDavid E. O'Brien * The main glob() routine: compiles the pattern (optionally processing 287c80476e4SDavid E. O'Brien * quotes), calls glob1() to do the real pattern matching, and finally 288c80476e4SDavid E. O'Brien * sorts the list (unless unsorted operation is requested). Returns 0 289c80476e4SDavid E. O'Brien * if things went well, nonzero if errors occurred. It is not an error 290c80476e4SDavid E. O'Brien * to find no matches. 291c80476e4SDavid E. O'Brien */ 292c80476e4SDavid E. O'Brien int 29345e5710bSMark Peek glob(const char *pattern, int flags, int (*errfunc) (const char *, int), 29445e5710bSMark Peek glob_t *pglob) 295c80476e4SDavid E. O'Brien { 296c80476e4SDavid E. O'Brien int err, oldpathc; 29745e5710bSMark Peek Char *bufnext, m_not; 29845e5710bSMark Peek const unsigned char *patnext; 299c80476e4SDavid E. O'Brien int c, not; 30045e5710bSMark Peek Char *qpatnext, *patbuf; 301c80476e4SDavid E. O'Brien int no_match; 302c80476e4SDavid E. O'Brien 30323338178SMark Peek patnext = (const unsigned char *) pattern; 304c80476e4SDavid E. O'Brien if (!(flags & GLOB_APPEND)) { 305c80476e4SDavid E. O'Brien pglob->gl_pathc = 0; 306c80476e4SDavid E. O'Brien pglob->gl_pathv = NULL; 307c80476e4SDavid E. O'Brien if (!(flags & GLOB_DOOFFS)) 308c80476e4SDavid E. O'Brien pglob->gl_offs = 0; 309c80476e4SDavid E. O'Brien } 310c80476e4SDavid E. O'Brien pglob->gl_flags = flags & ~GLOB_MAGCHAR; 311c80476e4SDavid E. O'Brien pglob->gl_errfunc = errfunc; 312c80476e4SDavid E. O'Brien oldpathc = pglob->gl_pathc; 313c80476e4SDavid E. O'Brien pglob->gl_matchc = 0; 314c80476e4SDavid E. O'Brien 315c80476e4SDavid E. O'Brien if (pglob->gl_flags & GLOB_ALTNOT) { 316c80476e4SDavid E. O'Brien not = ALTNOT; 317c80476e4SDavid E. O'Brien m_not = M_ALTNOT; 318c80476e4SDavid E. O'Brien } 319c80476e4SDavid E. O'Brien else { 320c80476e4SDavid E. O'Brien not = NOT; 321c80476e4SDavid E. O'Brien m_not = M_NOT; 322c80476e4SDavid E. O'Brien } 323c80476e4SDavid E. O'Brien 32445e5710bSMark Peek patbuf = xmalloc((strlen(pattern) + 1) * sizeof(*patbuf)); 325c80476e4SDavid E. O'Brien bufnext = patbuf; 326c80476e4SDavid E. O'Brien 327c80476e4SDavid E. O'Brien no_match = *patnext == not; 328c80476e4SDavid E. O'Brien if (no_match) 329c80476e4SDavid E. O'Brien patnext++; 330c80476e4SDavid E. O'Brien 331c80476e4SDavid E. O'Brien if (flags & GLOB_QUOTE) { 332c80476e4SDavid E. O'Brien /* Protect the quoted characters */ 33345e5710bSMark Peek while ((c = *patnext++) != EOS) { 33423338178SMark Peek #ifdef WIDE_STRINGS 33523338178SMark Peek int len; 33623338178SMark Peek 33723338178SMark Peek len = mblen((const char *)(patnext - 1), MB_LEN_MAX); 33823338178SMark Peek if (len == -1) 3399ccc37e3SMark Peek TCSH_IGNORE(mblen(NULL, 0)); 340a15e6f9aSMark Peek else if (len > 1) { 3418e66bd9eSDavid E. O'Brien *bufnext++ = (Char) c; 34223338178SMark Peek while (--len != 0) 34323338178SMark Peek *bufnext++ = (Char) (*patnext++ | M_PROTECT); 34423338178SMark Peek } else 34523338178SMark Peek #endif /* WIDE_STRINGS */ 346c80476e4SDavid E. O'Brien if (c == QUOTE) { 347c80476e4SDavid E. O'Brien if ((c = *patnext++) == EOS) { 348c80476e4SDavid E. O'Brien c = QUOTE; 349c80476e4SDavid E. O'Brien --patnext; 350c80476e4SDavid E. O'Brien } 351c80476e4SDavid E. O'Brien *bufnext++ = (Char) (c | M_PROTECT); 352c80476e4SDavid E. O'Brien } 353c80476e4SDavid E. O'Brien else 354c80476e4SDavid E. O'Brien *bufnext++ = (Char) c; 355c80476e4SDavid E. O'Brien } 35623338178SMark Peek } 357c80476e4SDavid E. O'Brien else 35845e5710bSMark Peek while ((c = *patnext++) != EOS) 359c80476e4SDavid E. O'Brien *bufnext++ = (Char) c; 360c80476e4SDavid E. O'Brien *bufnext = EOS; 361c80476e4SDavid E. O'Brien 362c80476e4SDavid E. O'Brien bufnext = patbuf; 363c80476e4SDavid E. O'Brien qpatnext = patbuf; 364c80476e4SDavid E. O'Brien while ((c = *qpatnext++) != EOS) { 365c80476e4SDavid E. O'Brien switch (c) { 366c80476e4SDavid E. O'Brien case LBRACKET: 367c80476e4SDavid E. O'Brien c = *qpatnext; 368c80476e4SDavid E. O'Brien if (c == not) 369c80476e4SDavid E. O'Brien ++qpatnext; 370c80476e4SDavid E. O'Brien if (*qpatnext == EOS || 371c80476e4SDavid E. O'Brien Strchr(qpatnext + 1, RBRACKET) == NULL) { 372c80476e4SDavid E. O'Brien *bufnext++ = LBRACKET; 373c80476e4SDavid E. O'Brien if (c == not) 374c80476e4SDavid E. O'Brien --qpatnext; 375c80476e4SDavid E. O'Brien break; 376c80476e4SDavid E. O'Brien } 377c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 378c80476e4SDavid E. O'Brien *bufnext++ = M_SET; 379c80476e4SDavid E. O'Brien if (c == not) 380c80476e4SDavid E. O'Brien *bufnext++ = m_not; 381c80476e4SDavid E. O'Brien c = *qpatnext++; 382c80476e4SDavid E. O'Brien do { 38345e5710bSMark Peek *bufnext++ = LCHAR(c); 384c80476e4SDavid E. O'Brien if (*qpatnext == RANGE && 385c80476e4SDavid E. O'Brien (c = qpatnext[1]) != RBRACKET) { 386c80476e4SDavid E. O'Brien *bufnext++ = M_RNG; 38745e5710bSMark Peek *bufnext++ = LCHAR(c); 388c80476e4SDavid E. O'Brien qpatnext += 2; 389c80476e4SDavid E. O'Brien } 390c80476e4SDavid E. O'Brien } while ((c = *qpatnext++) != RBRACKET); 391c80476e4SDavid E. O'Brien *bufnext++ = M_END; 392c80476e4SDavid E. O'Brien break; 393c80476e4SDavid E. O'Brien case QUESTION: 394c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 395c80476e4SDavid E. O'Brien *bufnext++ = M_ONE; 396c80476e4SDavid E. O'Brien break; 397c80476e4SDavid E. O'Brien case STAR: 398c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 3999ccc37e3SMark Peek /* collapse adjacent stars to one [or three if globstar], 4009ccc37e3SMark Peek * to avoid exponential behavior 401c80476e4SDavid E. O'Brien */ 4029ccc37e3SMark Peek if (bufnext == patbuf || bufnext[-1] != M_ALL || 4039ccc37e3SMark Peek ((flags & GLOB_STAR) != 0 && 4049ccc37e3SMark Peek (bufnext - 1 == patbuf || bufnext[-2] != M_ALL || 4059ccc37e3SMark Peek bufnext - 2 == patbuf || bufnext[-3] != M_ALL))) 406c80476e4SDavid E. O'Brien *bufnext++ = M_ALL; 407c80476e4SDavid E. O'Brien break; 408c80476e4SDavid E. O'Brien default: 40945e5710bSMark Peek *bufnext++ = LCHAR(c); 410c80476e4SDavid E. O'Brien break; 411c80476e4SDavid E. O'Brien } 412c80476e4SDavid E. O'Brien } 413c80476e4SDavid E. O'Brien *bufnext = EOS; 414c80476e4SDavid E. O'Brien #ifdef DEBUG 415c80476e4SDavid E. O'Brien qprintf(patbuf); 416c80476e4SDavid E. O'Brien #endif 417c80476e4SDavid E. O'Brien 41845e5710bSMark Peek if ((err = glob1(patbuf, pglob, no_match)) != 0) { 41945e5710bSMark Peek xfree(patbuf); 420c80476e4SDavid E. O'Brien return (err); 42145e5710bSMark Peek } 422c80476e4SDavid E. O'Brien 423c80476e4SDavid E. O'Brien /* 424c80476e4SDavid E. O'Brien * If there was no match we are going to append the pattern 425c80476e4SDavid E. O'Brien * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 426c80476e4SDavid E. O'Brien * and the pattern did not contain any magic characters 427c80476e4SDavid E. O'Brien * GLOB_NOMAGIC is there just for compatibility with csh. 428c80476e4SDavid E. O'Brien */ 429c80476e4SDavid E. O'Brien if (pglob->gl_pathc == oldpathc && 430c80476e4SDavid E. O'Brien ((flags & GLOB_NOCHECK) || 431c80476e4SDavid E. O'Brien ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { 43245e5710bSMark Peek if (!(flags & GLOB_QUOTE)) 43345e5710bSMark Peek globextend(pattern, pglob); 434c80476e4SDavid E. O'Brien else { 43545e5710bSMark Peek char *copy, *dest; 43645e5710bSMark Peek const char *src; 43745e5710bSMark Peek 43845e5710bSMark Peek /* copy pattern, interpreting quotes */ 43945e5710bSMark Peek copy = xmalloc(strlen(pattern) + 1); 44045e5710bSMark Peek dest = copy; 44145e5710bSMark Peek src = pattern; 44245e5710bSMark Peek while (*src != EOS) { 443*19d2e3deSDmitry Chagin /* Don't interpret quotes. The spec does not say we should do */ 44445e5710bSMark Peek if (*src == QUOTE) { 44545e5710bSMark Peek if (*++src == EOS) 44645e5710bSMark Peek --src; 447c80476e4SDavid E. O'Brien } 44845e5710bSMark Peek *dest++ = *src++; 449c80476e4SDavid E. O'Brien } 45045e5710bSMark Peek *dest = EOS; 45145e5710bSMark Peek globextend(copy, pglob); 45245e5710bSMark Peek xfree(copy); 453c80476e4SDavid E. O'Brien } 45445e5710bSMark Peek xfree(patbuf); 45545e5710bSMark Peek return 0; 456c80476e4SDavid E. O'Brien } 4578e66bd9eSDavid E. O'Brien else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc)) 45845e5710bSMark Peek qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 45945e5710bSMark Peek pglob->gl_pathc - oldpathc, sizeof(char *), compare); 46045e5710bSMark Peek xfree(patbuf); 461c80476e4SDavid E. O'Brien return (0); 462c80476e4SDavid E. O'Brien } 463c80476e4SDavid E. O'Brien 464c80476e4SDavid E. O'Brien static int 46545e5710bSMark Peek glob1(Char *pattern, glob_t *pglob, int no_match) 466c80476e4SDavid E. O'Brien { 46745e5710bSMark Peek struct strbuf pathbuf = strbuf_INIT; 46845e5710bSMark Peek int err; 469c80476e4SDavid E. O'Brien 470c80476e4SDavid E. O'Brien /* 471c80476e4SDavid E. O'Brien * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. 472c80476e4SDavid E. O'Brien */ 473c80476e4SDavid E. O'Brien if (*pattern == EOS) 474c80476e4SDavid E. O'Brien return (0); 47545e5710bSMark Peek err = glob2(&pathbuf, pattern, pglob, no_match); 47645e5710bSMark Peek xfree(pathbuf.s); 47745e5710bSMark Peek return err; 478c80476e4SDavid E. O'Brien } 479c80476e4SDavid E. O'Brien 480c80476e4SDavid E. O'Brien /* 481c80476e4SDavid E. O'Brien * functions glob2 and glob3 are mutually recursive; there is one level 482c80476e4SDavid E. O'Brien * of recursion for each segment in the pattern that contains one or 483c80476e4SDavid E. O'Brien * more meta characters. 484c80476e4SDavid E. O'Brien */ 485c80476e4SDavid E. O'Brien static int 48645e5710bSMark Peek glob2(struct strbuf *pathbuf, const Char *pattern, glob_t *pglob, int no_match) 487c80476e4SDavid E. O'Brien { 488c80476e4SDavid E. O'Brien struct stat sbuf; 489c80476e4SDavid E. O'Brien int anymeta; 49045e5710bSMark Peek const Char *p; 49145e5710bSMark Peek size_t orig_len; 492c80476e4SDavid E. O'Brien 493c80476e4SDavid E. O'Brien /* 494c80476e4SDavid E. O'Brien * loop over pattern segments until end of pattern or until segment with 495c80476e4SDavid E. O'Brien * meta character found. 496c80476e4SDavid E. O'Brien */ 497c80476e4SDavid E. O'Brien anymeta = 0; 498c80476e4SDavid E. O'Brien for (;;) { 499c80476e4SDavid E. O'Brien if (*pattern == EOS) { /* end of pattern? */ 50045e5710bSMark Peek strbuf_terminate(pathbuf); 501c80476e4SDavid E. O'Brien 50245e5710bSMark Peek if (Lstat(pathbuf->s, &sbuf)) 503c80476e4SDavid E. O'Brien return (0); 504c80476e4SDavid E. O'Brien 505c80476e4SDavid E. O'Brien if (((pglob->gl_flags & GLOB_MARK) && 50645e5710bSMark Peek pathbuf->s[pathbuf->len - 1] != SEP) && 507c80476e4SDavid E. O'Brien (S_ISDIR(sbuf.st_mode) 508c80476e4SDavid E. O'Brien #ifdef S_IFLNK 509c80476e4SDavid E. O'Brien || (S_ISLNK(sbuf.st_mode) && 51045e5710bSMark Peek (Stat(pathbuf->s, &sbuf) == 0) && 511c80476e4SDavid E. O'Brien S_ISDIR(sbuf.st_mode)) 512c80476e4SDavid E. O'Brien #endif 513c80476e4SDavid E. O'Brien )) { 51445e5710bSMark Peek strbuf_append1(pathbuf, SEP); 51545e5710bSMark Peek strbuf_terminate(pathbuf); 516c80476e4SDavid E. O'Brien } 517c80476e4SDavid E. O'Brien ++pglob->gl_matchc; 51845e5710bSMark Peek globextend(pathbuf->s, pglob); 51945e5710bSMark Peek return 0; 520c80476e4SDavid E. O'Brien } 521c80476e4SDavid E. O'Brien 52245e5710bSMark Peek /* find end of next segment, tentatively copy to pathbuf */ 523c80476e4SDavid E. O'Brien p = pattern; 52445e5710bSMark Peek orig_len = pathbuf->len; 525c80476e4SDavid E. O'Brien while (*p != EOS && *p != SEP) { 526c80476e4SDavid E. O'Brien if (ismeta(*p)) 527c80476e4SDavid E. O'Brien anymeta = 1; 52845e5710bSMark Peek strbuf_append1(pathbuf, *p++); 529c80476e4SDavid E. O'Brien } 530c80476e4SDavid E. O'Brien 531c80476e4SDavid E. O'Brien if (!anymeta) { /* no expansion, do next segment */ 532c80476e4SDavid E. O'Brien pattern = p; 533c80476e4SDavid E. O'Brien while (*pattern == SEP) 53445e5710bSMark Peek strbuf_append1(pathbuf, *pattern++); 535c80476e4SDavid E. O'Brien } 53645e5710bSMark Peek else { /* need expansion, recurse */ 53745e5710bSMark Peek pathbuf->len = orig_len; 5389ccc37e3SMark Peek return (glob3(pathbuf, pattern, p, pattern, pglob, no_match)); 53945e5710bSMark Peek } 540c80476e4SDavid E. O'Brien } 541c80476e4SDavid E. O'Brien /* NOTREACHED */ 542c80476e4SDavid E. O'Brien } 543c80476e4SDavid E. O'Brien 5449ccc37e3SMark Peek static size_t 5459ccc37e3SMark Peek One_Char_mbtowc(__Char *pwc, const Char *s, size_t n) 5469ccc37e3SMark Peek { 5479ccc37e3SMark Peek #ifdef WIDE_STRINGS 5489ccc37e3SMark Peek char buf[MB_LEN_MAX], *p; 5499ccc37e3SMark Peek 5509ccc37e3SMark Peek if (n > MB_LEN_MAX) 5519ccc37e3SMark Peek n = MB_LEN_MAX; 5529ccc37e3SMark Peek p = buf; 5539ccc37e3SMark Peek while (p < buf + n && (*p++ = LCHAR(*s++)) != 0) 5549ccc37e3SMark Peek ; 5559ccc37e3SMark Peek return one_mbtowc(pwc, buf, n); 5569ccc37e3SMark Peek #else 5579ccc37e3SMark Peek *pwc = *s & CHAR; 5589ccc37e3SMark Peek return 1; 5599ccc37e3SMark Peek #endif 5609ccc37e3SMark Peek } 561c80476e4SDavid E. O'Brien 562c80476e4SDavid E. O'Brien static int 56345e5710bSMark Peek glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern, 5649ccc37e3SMark Peek const Char *pglobstar, glob_t *pglob, int no_match) 565c80476e4SDavid E. O'Brien { 566c80476e4SDavid E. O'Brien DIR *dirp; 567c80476e4SDavid E. O'Brien struct dirent *dp; 5689ccc37e3SMark Peek struct stat sbuf; 569c80476e4SDavid E. O'Brien int err; 570c80476e4SDavid E. O'Brien Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; 57145e5710bSMark Peek size_t orig_len; 5729ccc37e3SMark Peek int globstar = 0; 5739ccc37e3SMark Peek int chase_symlinks = 0; 5749ccc37e3SMark Peek const Char *termstar = NULL; 575c80476e4SDavid E. O'Brien 57645e5710bSMark Peek strbuf_terminate(pathbuf); 5779ccc37e3SMark Peek orig_len = pathbuf->len; 5789ccc37e3SMark Peek errno = err = 0; 5799ccc37e3SMark Peek 5809ccc37e3SMark Peek while (pglobstar < restpattern) { 5819ccc37e3SMark Peek __Char wc; 5829ccc37e3SMark Peek size_t width = One_Char_mbtowc(&wc, pglobstar, MB_LEN_MAX); 5839ccc37e3SMark Peek if ((pglobstar[0] & M_MASK) == M_ALL && 5849ccc37e3SMark Peek (pglobstar[width] & M_MASK) == M_ALL) { 5859ccc37e3SMark Peek globstar = 1; 5869ccc37e3SMark Peek chase_symlinks = (pglobstar[2 * width] & M_MASK) == M_ALL; 5879ccc37e3SMark Peek termstar = pglobstar + (2 + chase_symlinks) * width; 5889ccc37e3SMark Peek break; 5899ccc37e3SMark Peek } 5909ccc37e3SMark Peek pglobstar += width; 5919ccc37e3SMark Peek } 5929ccc37e3SMark Peek 5939ccc37e3SMark Peek if (globstar) { 5949ccc37e3SMark Peek err = pglobstar==pattern && termstar==restpattern ? 5959ccc37e3SMark Peek *restpattern == EOS ? 5969ccc37e3SMark Peek glob2(pathbuf, restpattern - 1, pglob, no_match) : 5979ccc37e3SMark Peek glob2(pathbuf, restpattern + 1, pglob, no_match) : 5989ccc37e3SMark Peek glob3(pathbuf, pattern, restpattern, termstar, pglob, no_match); 5999ccc37e3SMark Peek if (err) 6009ccc37e3SMark Peek return err; 6019ccc37e3SMark Peek pathbuf->len = orig_len; 6029ccc37e3SMark Peek strbuf_terminate(pathbuf); 6039ccc37e3SMark Peek } 6049ccc37e3SMark Peek 6059ccc37e3SMark Peek if (*pathbuf->s && (Lstat(pathbuf->s, &sbuf) || !S_ISDIR(sbuf.st_mode) 6069ccc37e3SMark Peek #ifdef S_IFLINK 6079ccc37e3SMark Peek && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode)) 6089ccc37e3SMark Peek #endif 6099ccc37e3SMark Peek )) 6109ccc37e3SMark Peek return 0; 611c80476e4SDavid E. O'Brien 61245e5710bSMark Peek if (!(dirp = Opendir(pathbuf->s))) { 613c80476e4SDavid E. O'Brien /* todo: don't call for ENOENT or ENOTDIR? */ 61445e5710bSMark Peek if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf->s, errno)) || 615c80476e4SDavid E. O'Brien (pglob->gl_flags & GLOB_ERR)) 616c80476e4SDavid E. O'Brien return (GLOB_ABEND); 617c80476e4SDavid E. O'Brien else 618c80476e4SDavid E. O'Brien return (0); 619c80476e4SDavid E. O'Brien } 620c80476e4SDavid E. O'Brien 621c80476e4SDavid E. O'Brien /* search directory for matching names */ 622c80476e4SDavid E. O'Brien while ((dp = readdir(dirp)) != NULL) { 623c80476e4SDavid E. O'Brien /* initial DOT must be matched literally */ 624c80476e4SDavid E. O'Brien if (dp->d_name[0] == DOT && *pattern != DOT) 6259ccc37e3SMark Peek if (!(pglob->gl_flags & GLOB_DOT) || !dp->d_name[1] || 6269ccc37e3SMark Peek (dp->d_name[1] == DOT && !dp->d_name[2])) 6279ccc37e3SMark Peek continue; /*unless globdot and not . or .. */ 62845e5710bSMark Peek pathbuf->len = orig_len; 62945e5710bSMark Peek strbuf_append(pathbuf, dp->d_name); 63045e5710bSMark Peek strbuf_terminate(pathbuf); 6319ccc37e3SMark Peek 6329ccc37e3SMark Peek if (globstar) { 6339ccc37e3SMark Peek #ifdef S_IFLNK 6349ccc37e3SMark Peek if (!chase_symlinks && 6359ccc37e3SMark Peek (Lstat(pathbuf->s, &sbuf) || S_ISLNK(sbuf.st_mode))) 636c80476e4SDavid E. O'Brien continue; 6379ccc37e3SMark Peek #endif 6389ccc37e3SMark Peek if (match(pathbuf->s + orig_len, pattern, termstar, 6399ccc37e3SMark Peek (int)m_not) == no_match) 6409ccc37e3SMark Peek continue; 6419ccc37e3SMark Peek strbuf_append1(pathbuf, SEP); 6429ccc37e3SMark Peek strbuf_terminate(pathbuf); 6439ccc37e3SMark Peek if ((err = glob2(pathbuf, pglobstar, pglob, no_match)) != 0) 644c80476e4SDavid E. O'Brien break; 6459ccc37e3SMark Peek } else { 6469ccc37e3SMark Peek if (match(pathbuf->s + orig_len, pattern, restpattern, 6479ccc37e3SMark Peek (int) m_not) == no_match) 6489ccc37e3SMark Peek continue; 6499ccc37e3SMark Peek if ((err = glob2(pathbuf, restpattern, pglob, no_match)) != 0) 6509ccc37e3SMark Peek break; 6519ccc37e3SMark Peek } 652c80476e4SDavid E. O'Brien } 653c80476e4SDavid E. O'Brien /* todo: check error from readdir? */ 65445e5710bSMark Peek closedir(dirp); 655c80476e4SDavid E. O'Brien return (err); 656c80476e4SDavid E. O'Brien } 657c80476e4SDavid E. O'Brien 658c80476e4SDavid E. O'Brien 659c80476e4SDavid E. O'Brien /* 660c80476e4SDavid E. O'Brien * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 661c80476e4SDavid E. O'Brien * add the new item, and update gl_pathc. 662c80476e4SDavid E. O'Brien * 663c80476e4SDavid E. O'Brien * This assumes the BSD realloc, which only copies the block when its size 664c80476e4SDavid E. O'Brien * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 665c80476e4SDavid E. O'Brien * behavior. 666c80476e4SDavid E. O'Brien * 667c80476e4SDavid E. O'Brien * Return 0 if new item added, error code if memory couldn't be allocated. 668c80476e4SDavid E. O'Brien * 669c80476e4SDavid E. O'Brien * Invariant of the glob_t structure: 670c80476e4SDavid E. O'Brien * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 671c80476e4SDavid E. O'Brien * gl_pathv points to (gl_offs + gl_pathc + 1) items. 672c80476e4SDavid E. O'Brien */ 67345e5710bSMark Peek static void 67445e5710bSMark Peek globextend(const char *path, glob_t *pglob) 675c80476e4SDavid E. O'Brien { 67623338178SMark Peek char **pathv; 67723338178SMark Peek int i; 67845e5710bSMark Peek size_t newsize; 679c80476e4SDavid E. O'Brien 680c80476e4SDavid E. O'Brien newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 68145e5710bSMark Peek pathv = xrealloc(pglob->gl_pathv, newsize); 682c80476e4SDavid E. O'Brien 683c80476e4SDavid E. O'Brien if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 684c80476e4SDavid E. O'Brien /* first time around -- clear initial gl_offs items */ 685c80476e4SDavid E. O'Brien pathv += pglob->gl_offs; 686c80476e4SDavid E. O'Brien for (i = pglob->gl_offs; --i >= 0;) 687c80476e4SDavid E. O'Brien *--pathv = NULL; 688c80476e4SDavid E. O'Brien } 689c80476e4SDavid E. O'Brien pglob->gl_pathv = pathv; 690c80476e4SDavid E. O'Brien 69145e5710bSMark Peek pathv[pglob->gl_offs + pglob->gl_pathc++] = strsave(path); 692c80476e4SDavid E. O'Brien pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 693c80476e4SDavid E. O'Brien } 694c80476e4SDavid E. O'Brien 695c80476e4SDavid E. O'Brien /* 696c80476e4SDavid E. O'Brien * pattern matching function for filenames. Each occurrence of the * 697c80476e4SDavid E. O'Brien * pattern causes a recursion level. 698c80476e4SDavid E. O'Brien */ 699c80476e4SDavid E. O'Brien static int 70045e5710bSMark Peek match(const char *name, const Char *pat, const Char *patend, int m_not) 701c80476e4SDavid E. O'Brien { 702c80476e4SDavid E. O'Brien int ok, negate_range; 70345e5710bSMark Peek Char c; 704c80476e4SDavid E. O'Brien 705c80476e4SDavid E. O'Brien while (pat < patend) { 70623338178SMark Peek size_t lwk; 70745e5710bSMark Peek __Char wc, wk; 70823338178SMark Peek 70923338178SMark Peek c = *pat; /* Only for M_MASK bits */ 71045e5710bSMark Peek pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 71145e5710bSMark Peek lwk = one_mbtowc(&wk, name, MB_LEN_MAX); 712c80476e4SDavid E. O'Brien switch (c & M_MASK) { 713c80476e4SDavid E. O'Brien case M_ALL: 7149ccc37e3SMark Peek while (pat < patend && (*pat & M_MASK) == M_ALL) /* eat consecutive '*' */ 7159ccc37e3SMark Peek pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 716c80476e4SDavid E. O'Brien if (pat == patend) 717c80476e4SDavid E. O'Brien return (1); 7189ccc37e3SMark Peek while (!match(name, pat, patend, m_not)) { 71923338178SMark Peek if (*name == EOS) 7209ccc37e3SMark Peek return (0); 72123338178SMark Peek name += lwk; 72245e5710bSMark Peek lwk = one_mbtowc(&wk, name, MB_LEN_MAX); 72323338178SMark Peek } 7249ccc37e3SMark Peek return (1); 725c80476e4SDavid E. O'Brien case M_ONE: 72623338178SMark Peek if (*name == EOS) 727c80476e4SDavid E. O'Brien return (0); 72823338178SMark Peek name += lwk; 729c80476e4SDavid E. O'Brien break; 730c80476e4SDavid E. O'Brien case M_SET: 731c80476e4SDavid E. O'Brien ok = 0; 73223338178SMark Peek if (*name == EOS) 733c80476e4SDavid E. O'Brien return (0); 73423338178SMark Peek name += lwk; 735c80476e4SDavid E. O'Brien if ((negate_range = ((*pat & M_MASK) == m_not)) != 0) 736c80476e4SDavid E. O'Brien ++pat; 73723338178SMark Peek while ((*pat & M_MASK) != M_END) { 73845e5710bSMark Peek pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 739c80476e4SDavid E. O'Brien if ((*pat & M_MASK) == M_RNG) { 74045e5710bSMark Peek __Char wc2; 74123338178SMark Peek 74223338178SMark Peek pat++; 74345e5710bSMark Peek pat += One_Char_mbtowc(&wc2, pat, MB_LEN_MAX); 74423338178SMark Peek if (globcharcoll(wc, wk, 0) <= 0 && 74523338178SMark Peek globcharcoll(wk, wc2, 0) <= 0) 746c80476e4SDavid E. O'Brien ok = 1; 74723338178SMark Peek } else if (wc == wk) 748c80476e4SDavid E. O'Brien ok = 1; 749c80476e4SDavid E. O'Brien } 75045e5710bSMark Peek pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 751c80476e4SDavid E. O'Brien if (ok == negate_range) 752c80476e4SDavid E. O'Brien return (0); 753c80476e4SDavid E. O'Brien break; 754c80476e4SDavid E. O'Brien default: 7559ccc37e3SMark Peek if (*name == EOS || samecase(wk) != samecase(wc)) 756c80476e4SDavid E. O'Brien return (0); 7579ccc37e3SMark Peek name += lwk; 758c80476e4SDavid E. O'Brien break; 759c80476e4SDavid E. O'Brien } 760c80476e4SDavid E. O'Brien } 761c80476e4SDavid E. O'Brien return (*name == EOS); 762c80476e4SDavid E. O'Brien } 763c80476e4SDavid E. O'Brien 764c80476e4SDavid E. O'Brien /* free allocated data belonging to a glob_t structure */ 765c80476e4SDavid E. O'Brien void 76645e5710bSMark Peek globfree(glob_t *pglob) 767c80476e4SDavid E. O'Brien { 76823338178SMark Peek int i; 76923338178SMark Peek char **pp; 770c80476e4SDavid E. O'Brien 771c80476e4SDavid E. O'Brien if (pglob->gl_pathv != NULL) { 772c80476e4SDavid E. O'Brien pp = pglob->gl_pathv + pglob->gl_offs; 773c80476e4SDavid E. O'Brien for (i = pglob->gl_pathc; i--; ++pp) 774c80476e4SDavid E. O'Brien if (*pp) 77545e5710bSMark Peek xfree(*pp), *pp = NULL; 77645e5710bSMark Peek xfree(pglob->gl_pathv), pglob->gl_pathv = NULL; 777c80476e4SDavid E. O'Brien } 778c80476e4SDavid E. O'Brien } 779