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 6219d2e3deSDmitry Chagin #ifndef HAVE_MBLEN 6319d2e3deSDmitry Chagin #undef mblen 6419d2e3deSDmitry Chagin #define mblen(_s,_n) mbrlen((_s),(_n),NULL) 6519d2e3deSDmitry Chagin #endif 6619d2e3deSDmitry 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 103*d803a9d0SBrooks Davis static void qprintf (const char *, 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 259*d803a9d0SBrooks Davis qprintf(const char *pre, const Char *s) 260c80476e4SDavid E. O'Brien { 26145e5710bSMark Peek const Char *p; 262c80476e4SDavid E. O'Brien 263*d803a9d0SBrooks Davis xprintf("%s", pre); 264c80476e4SDavid E. O'Brien for (p = s; *p; p++) 265*d803a9d0SBrooks Davis xprintf("%c", *p & 0xff); 266*d803a9d0SBrooks Davis xprintf("\n%s", pre); 267c80476e4SDavid E. O'Brien for (p = s; *p; p++) 268*d803a9d0SBrooks Davis xprintf("%c", *p & M_PROTECT ? '"' : ' '); 269*d803a9d0SBrooks Davis xprintf("\n%s", pre); 270c80476e4SDavid E. O'Brien for (p = s; *p; p++) 271*d803a9d0SBrooks Davis xprintf("%c", *p & M_META ? '_' : ' '); 272*d803a9d0SBrooks Davis xprintf("\n"); 273c80476e4SDavid E. O'Brien } 274c80476e4SDavid E. O'Brien #endif /* DEBUG */ 275c80476e4SDavid E. O'Brien 276c80476e4SDavid E. O'Brien static int 27745e5710bSMark Peek compare(const void *p, const void *q) 278c80476e4SDavid E. O'Brien { 27945e5710bSMark Peek #if defined(NLS) && defined(HAVE_STRCOLL) 28045e5710bSMark Peek return (strcoll(*(char *const *) p, *(char *const *) q)); 281c80476e4SDavid E. O'Brien #else 28245e5710bSMark Peek return (strcmp(*(char *const *) p, *(char *const *) q)); 28345e5710bSMark Peek #endif /* NLS && HAVE_STRCOLL */ 284c80476e4SDavid E. O'Brien } 285c80476e4SDavid E. O'Brien 286c80476e4SDavid E. O'Brien /* 287c80476e4SDavid E. O'Brien * The main glob() routine: compiles the pattern (optionally processing 288c80476e4SDavid E. O'Brien * quotes), calls glob1() to do the real pattern matching, and finally 289c80476e4SDavid E. O'Brien * sorts the list (unless unsorted operation is requested). Returns 0 290c80476e4SDavid E. O'Brien * if things went well, nonzero if errors occurred. It is not an error 291c80476e4SDavid E. O'Brien * to find no matches. 292c80476e4SDavid E. O'Brien */ 293c80476e4SDavid E. O'Brien int 29445e5710bSMark Peek glob(const char *pattern, int flags, int (*errfunc) (const char *, int), 29545e5710bSMark Peek glob_t *pglob) 296c80476e4SDavid E. O'Brien { 297c80476e4SDavid E. O'Brien int err, oldpathc; 29845e5710bSMark Peek Char *bufnext, m_not; 29945e5710bSMark Peek const unsigned char *patnext; 300c80476e4SDavid E. O'Brien int c, not; 30145e5710bSMark Peek Char *qpatnext, *patbuf; 302c80476e4SDavid E. O'Brien int no_match; 303c80476e4SDavid E. O'Brien 30423338178SMark Peek patnext = (const unsigned char *) pattern; 305c80476e4SDavid E. O'Brien if (!(flags & GLOB_APPEND)) { 306c80476e4SDavid E. O'Brien pglob->gl_pathc = 0; 307c80476e4SDavid E. O'Brien pglob->gl_pathv = NULL; 308c80476e4SDavid E. O'Brien if (!(flags & GLOB_DOOFFS)) 309c80476e4SDavid E. O'Brien pglob->gl_offs = 0; 310c80476e4SDavid E. O'Brien } 311c80476e4SDavid E. O'Brien pglob->gl_flags = flags & ~GLOB_MAGCHAR; 312c80476e4SDavid E. O'Brien pglob->gl_errfunc = errfunc; 313c80476e4SDavid E. O'Brien oldpathc = pglob->gl_pathc; 314c80476e4SDavid E. O'Brien pglob->gl_matchc = 0; 315c80476e4SDavid E. O'Brien 316c80476e4SDavid E. O'Brien if (pglob->gl_flags & GLOB_ALTNOT) { 317c80476e4SDavid E. O'Brien not = ALTNOT; 318c80476e4SDavid E. O'Brien m_not = M_ALTNOT; 319c80476e4SDavid E. O'Brien } 320c80476e4SDavid E. O'Brien else { 321c80476e4SDavid E. O'Brien not = NOT; 322c80476e4SDavid E. O'Brien m_not = M_NOT; 323c80476e4SDavid E. O'Brien } 324c80476e4SDavid E. O'Brien 32545e5710bSMark Peek patbuf = xmalloc((strlen(pattern) + 1) * sizeof(*patbuf)); 326c80476e4SDavid E. O'Brien bufnext = patbuf; 327c80476e4SDavid E. O'Brien 328c80476e4SDavid E. O'Brien no_match = *patnext == not; 329c80476e4SDavid E. O'Brien if (no_match) 330c80476e4SDavid E. O'Brien patnext++; 331c80476e4SDavid E. O'Brien 332c80476e4SDavid E. O'Brien if (flags & GLOB_QUOTE) { 333c80476e4SDavid E. O'Brien /* Protect the quoted characters */ 33445e5710bSMark Peek while ((c = *patnext++) != EOS) { 33523338178SMark Peek #ifdef WIDE_STRINGS 33623338178SMark Peek int len; 33723338178SMark Peek 33823338178SMark Peek len = mblen((const char *)(patnext - 1), MB_LEN_MAX); 33923338178SMark Peek if (len == -1) 3409ccc37e3SMark Peek TCSH_IGNORE(mblen(NULL, 0)); 341a15e6f9aSMark Peek else if (len > 1) { 3428e66bd9eSDavid E. O'Brien *bufnext++ = (Char) c; 34323338178SMark Peek while (--len != 0) 34423338178SMark Peek *bufnext++ = (Char) (*patnext++ | M_PROTECT); 34523338178SMark Peek } else 34623338178SMark Peek #endif /* WIDE_STRINGS */ 347c80476e4SDavid E. O'Brien if (c == QUOTE) { 348c80476e4SDavid E. O'Brien if ((c = *patnext++) == EOS) { 349c80476e4SDavid E. O'Brien c = QUOTE; 350c80476e4SDavid E. O'Brien --patnext; 351c80476e4SDavid E. O'Brien } 352c80476e4SDavid E. O'Brien *bufnext++ = (Char) (c | M_PROTECT); 353c80476e4SDavid E. O'Brien } 354c80476e4SDavid E. O'Brien else 355c80476e4SDavid E. O'Brien *bufnext++ = (Char) c; 356c80476e4SDavid E. O'Brien } 35723338178SMark Peek } 358c80476e4SDavid E. O'Brien else 35945e5710bSMark Peek while ((c = *patnext++) != EOS) 360c80476e4SDavid E. O'Brien *bufnext++ = (Char) c; 361c80476e4SDavid E. O'Brien *bufnext = EOS; 362c80476e4SDavid E. O'Brien 363c80476e4SDavid E. O'Brien bufnext = patbuf; 364c80476e4SDavid E. O'Brien qpatnext = patbuf; 365c80476e4SDavid E. O'Brien while ((c = *qpatnext++) != EOS) { 366c80476e4SDavid E. O'Brien switch (c) { 367c80476e4SDavid E. O'Brien case LBRACKET: 368c80476e4SDavid E. O'Brien c = *qpatnext; 369c80476e4SDavid E. O'Brien if (c == not) 370c80476e4SDavid E. O'Brien ++qpatnext; 371c80476e4SDavid E. O'Brien if (*qpatnext == EOS || 372c80476e4SDavid E. O'Brien Strchr(qpatnext + 1, RBRACKET) == NULL) { 373c80476e4SDavid E. O'Brien *bufnext++ = LBRACKET; 374c80476e4SDavid E. O'Brien if (c == not) 375c80476e4SDavid E. O'Brien --qpatnext; 376c80476e4SDavid E. O'Brien break; 377c80476e4SDavid E. O'Brien } 378c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 379c80476e4SDavid E. O'Brien *bufnext++ = M_SET; 380c80476e4SDavid E. O'Brien if (c == not) 381c80476e4SDavid E. O'Brien *bufnext++ = m_not; 382c80476e4SDavid E. O'Brien c = *qpatnext++; 383c80476e4SDavid E. O'Brien do { 38445e5710bSMark Peek *bufnext++ = LCHAR(c); 385c80476e4SDavid E. O'Brien if (*qpatnext == RANGE && 386c80476e4SDavid E. O'Brien (c = qpatnext[1]) != RBRACKET) { 387c80476e4SDavid E. O'Brien *bufnext++ = M_RNG; 38845e5710bSMark Peek *bufnext++ = LCHAR(c); 389c80476e4SDavid E. O'Brien qpatnext += 2; 390c80476e4SDavid E. O'Brien } 391c80476e4SDavid E. O'Brien } while ((c = *qpatnext++) != RBRACKET); 392c80476e4SDavid E. O'Brien *bufnext++ = M_END; 393c80476e4SDavid E. O'Brien break; 394c80476e4SDavid E. O'Brien case QUESTION: 395c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 396c80476e4SDavid E. O'Brien *bufnext++ = M_ONE; 397c80476e4SDavid E. O'Brien break; 398c80476e4SDavid E. O'Brien case STAR: 399c80476e4SDavid E. O'Brien pglob->gl_flags |= GLOB_MAGCHAR; 4009ccc37e3SMark Peek /* collapse adjacent stars to one [or three if globstar], 4019ccc37e3SMark Peek * to avoid exponential behavior 402c80476e4SDavid E. O'Brien */ 4039ccc37e3SMark Peek if (bufnext == patbuf || bufnext[-1] != M_ALL || 4049ccc37e3SMark Peek ((flags & GLOB_STAR) != 0 && 4059ccc37e3SMark Peek (bufnext - 1 == patbuf || bufnext[-2] != M_ALL || 4069ccc37e3SMark Peek bufnext - 2 == patbuf || bufnext[-3] != M_ALL))) 407c80476e4SDavid E. O'Brien *bufnext++ = M_ALL; 408c80476e4SDavid E. O'Brien break; 409c80476e4SDavid E. O'Brien default: 41045e5710bSMark Peek *bufnext++ = LCHAR(c); 411c80476e4SDavid E. O'Brien break; 412c80476e4SDavid E. O'Brien } 413c80476e4SDavid E. O'Brien } 414c80476e4SDavid E. O'Brien *bufnext = EOS; 415c80476e4SDavid E. O'Brien #ifdef DEBUG 416*d803a9d0SBrooks Davis qprintf("patbuf=", patbuf); 417c80476e4SDavid E. O'Brien #endif 418c80476e4SDavid E. O'Brien 41945e5710bSMark Peek if ((err = glob1(patbuf, pglob, no_match)) != 0) { 42045e5710bSMark Peek xfree(patbuf); 421c80476e4SDavid E. O'Brien return (err); 42245e5710bSMark Peek } 423c80476e4SDavid E. O'Brien 424c80476e4SDavid E. O'Brien /* 425c80476e4SDavid E. O'Brien * If there was no match we are going to append the pattern 426c80476e4SDavid E. O'Brien * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 427c80476e4SDavid E. O'Brien * and the pattern did not contain any magic characters 428c80476e4SDavid E. O'Brien * GLOB_NOMAGIC is there just for compatibility with csh. 429c80476e4SDavid E. O'Brien */ 430c80476e4SDavid E. O'Brien if (pglob->gl_pathc == oldpathc && 431c80476e4SDavid E. O'Brien ((flags & GLOB_NOCHECK) || 432c80476e4SDavid E. O'Brien ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { 43345e5710bSMark Peek if (!(flags & GLOB_QUOTE)) 43445e5710bSMark Peek globextend(pattern, pglob); 435c80476e4SDavid E. O'Brien else { 43645e5710bSMark Peek char *copy, *dest; 43745e5710bSMark Peek const char *src; 43845e5710bSMark Peek 43945e5710bSMark Peek /* copy pattern, interpreting quotes */ 44045e5710bSMark Peek copy = xmalloc(strlen(pattern) + 1); 44145e5710bSMark Peek dest = copy; 44245e5710bSMark Peek src = pattern; 44345e5710bSMark Peek while (*src != EOS) { 44419d2e3deSDmitry Chagin /* Don't interpret quotes. The spec does not say we should do */ 44545e5710bSMark Peek if (*src == QUOTE) { 44645e5710bSMark Peek if (*++src == EOS) 44745e5710bSMark Peek --src; 448c80476e4SDavid E. O'Brien } 44945e5710bSMark Peek *dest++ = *src++; 450c80476e4SDavid E. O'Brien } 45145e5710bSMark Peek *dest = EOS; 45245e5710bSMark Peek globextend(copy, pglob); 45345e5710bSMark Peek xfree(copy); 454c80476e4SDavid E. O'Brien } 45545e5710bSMark Peek xfree(patbuf); 45645e5710bSMark Peek return 0; 457c80476e4SDavid E. O'Brien } 4588e66bd9eSDavid E. O'Brien else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc)) 45945e5710bSMark Peek qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 46045e5710bSMark Peek pglob->gl_pathc - oldpathc, sizeof(char *), compare); 46145e5710bSMark Peek xfree(patbuf); 462c80476e4SDavid E. O'Brien return (0); 463c80476e4SDavid E. O'Brien } 464c80476e4SDavid E. O'Brien 465c80476e4SDavid E. O'Brien static int 46645e5710bSMark Peek glob1(Char *pattern, glob_t *pglob, int no_match) 467c80476e4SDavid E. O'Brien { 46845e5710bSMark Peek struct strbuf pathbuf = strbuf_INIT; 46945e5710bSMark Peek int err; 470c80476e4SDavid E. O'Brien 471c80476e4SDavid E. O'Brien /* 472c80476e4SDavid E. O'Brien * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. 473c80476e4SDavid E. O'Brien */ 474c80476e4SDavid E. O'Brien if (*pattern == EOS) 475c80476e4SDavid E. O'Brien return (0); 47645e5710bSMark Peek err = glob2(&pathbuf, pattern, pglob, no_match); 47745e5710bSMark Peek xfree(pathbuf.s); 47845e5710bSMark Peek return err; 479c80476e4SDavid E. O'Brien } 480c80476e4SDavid E. O'Brien 481c80476e4SDavid E. O'Brien /* 482c80476e4SDavid E. O'Brien * functions glob2 and glob3 are mutually recursive; there is one level 483c80476e4SDavid E. O'Brien * of recursion for each segment in the pattern that contains one or 484c80476e4SDavid E. O'Brien * more meta characters. 485c80476e4SDavid E. O'Brien */ 486c80476e4SDavid E. O'Brien static int 48745e5710bSMark Peek glob2(struct strbuf *pathbuf, const Char *pattern, glob_t *pglob, int no_match) 488c80476e4SDavid E. O'Brien { 489c80476e4SDavid E. O'Brien struct stat sbuf; 490c80476e4SDavid E. O'Brien int anymeta; 49145e5710bSMark Peek const Char *p; 49245e5710bSMark Peek size_t orig_len; 493c80476e4SDavid E. O'Brien 494c80476e4SDavid E. O'Brien /* 495c80476e4SDavid E. O'Brien * loop over pattern segments until end of pattern or until segment with 496c80476e4SDavid E. O'Brien * meta character found. 497c80476e4SDavid E. O'Brien */ 498c80476e4SDavid E. O'Brien anymeta = 0; 499c80476e4SDavid E. O'Brien for (;;) { 500c80476e4SDavid E. O'Brien if (*pattern == EOS) { /* end of pattern? */ 50145e5710bSMark Peek strbuf_terminate(pathbuf); 502c80476e4SDavid E. O'Brien 50345e5710bSMark Peek if (Lstat(pathbuf->s, &sbuf)) 504c80476e4SDavid E. O'Brien return (0); 505c80476e4SDavid E. O'Brien 506c80476e4SDavid E. O'Brien if (((pglob->gl_flags & GLOB_MARK) && 50745e5710bSMark Peek pathbuf->s[pathbuf->len - 1] != SEP) && 508c80476e4SDavid E. O'Brien (S_ISDIR(sbuf.st_mode) 509c80476e4SDavid E. O'Brien #ifdef S_IFLNK 510c80476e4SDavid E. O'Brien || (S_ISLNK(sbuf.st_mode) && 51145e5710bSMark Peek (Stat(pathbuf->s, &sbuf) == 0) && 512c80476e4SDavid E. O'Brien S_ISDIR(sbuf.st_mode)) 513c80476e4SDavid E. O'Brien #endif 514c80476e4SDavid E. O'Brien )) { 51545e5710bSMark Peek strbuf_append1(pathbuf, SEP); 51645e5710bSMark Peek strbuf_terminate(pathbuf); 517c80476e4SDavid E. O'Brien } 518c80476e4SDavid E. O'Brien ++pglob->gl_matchc; 51945e5710bSMark Peek globextend(pathbuf->s, pglob); 52045e5710bSMark Peek return 0; 521c80476e4SDavid E. O'Brien } 522c80476e4SDavid E. O'Brien 52345e5710bSMark Peek /* find end of next segment, tentatively copy to pathbuf */ 524c80476e4SDavid E. O'Brien p = pattern; 52545e5710bSMark Peek orig_len = pathbuf->len; 526c80476e4SDavid E. O'Brien while (*p != EOS && *p != SEP) { 527c80476e4SDavid E. O'Brien if (ismeta(*p)) 528c80476e4SDavid E. O'Brien anymeta = 1; 52945e5710bSMark Peek strbuf_append1(pathbuf, *p++); 530c80476e4SDavid E. O'Brien } 531c80476e4SDavid E. O'Brien 532c80476e4SDavid E. O'Brien if (!anymeta) { /* no expansion, do next segment */ 533c80476e4SDavid E. O'Brien pattern = p; 534c80476e4SDavid E. O'Brien while (*pattern == SEP) 53545e5710bSMark Peek strbuf_append1(pathbuf, *pattern++); 536c80476e4SDavid E. O'Brien } 53745e5710bSMark Peek else { /* need expansion, recurse */ 53845e5710bSMark Peek pathbuf->len = orig_len; 5399ccc37e3SMark Peek return (glob3(pathbuf, pattern, p, pattern, pglob, no_match)); 54045e5710bSMark Peek } 541c80476e4SDavid E. O'Brien } 542c80476e4SDavid E. O'Brien /* NOTREACHED */ 543c80476e4SDavid E. O'Brien } 544c80476e4SDavid E. O'Brien 5459ccc37e3SMark Peek static size_t 5469ccc37e3SMark Peek One_Char_mbtowc(__Char *pwc, const Char *s, size_t n) 5479ccc37e3SMark Peek { 5489ccc37e3SMark Peek #ifdef WIDE_STRINGS 5499ccc37e3SMark Peek char buf[MB_LEN_MAX], *p; 5509ccc37e3SMark Peek 5519ccc37e3SMark Peek if (n > MB_LEN_MAX) 5529ccc37e3SMark Peek n = MB_LEN_MAX; 5539ccc37e3SMark Peek p = buf; 5549ccc37e3SMark Peek while (p < buf + n && (*p++ = LCHAR(*s++)) != 0) 5559ccc37e3SMark Peek ; 5569ccc37e3SMark Peek return one_mbtowc(pwc, buf, n); 5579ccc37e3SMark Peek #else 5589ccc37e3SMark Peek *pwc = *s & CHAR; 5599ccc37e3SMark Peek return 1; 5609ccc37e3SMark Peek #endif 5619ccc37e3SMark Peek } 562c80476e4SDavid E. O'Brien 563c80476e4SDavid E. O'Brien static int 56445e5710bSMark Peek glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern, 5659ccc37e3SMark Peek const Char *pglobstar, glob_t *pglob, int no_match) 566c80476e4SDavid E. O'Brien { 567c80476e4SDavid E. O'Brien DIR *dirp; 568c80476e4SDavid E. O'Brien struct dirent *dp; 5699ccc37e3SMark Peek struct stat sbuf; 570c80476e4SDavid E. O'Brien int err; 571c80476e4SDavid E. O'Brien Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; 57245e5710bSMark Peek size_t orig_len; 5739ccc37e3SMark Peek int globstar = 0; 5749ccc37e3SMark Peek int chase_symlinks = 0; 5759ccc37e3SMark Peek const Char *termstar = NULL; 576c80476e4SDavid E. O'Brien 57745e5710bSMark Peek strbuf_terminate(pathbuf); 5789ccc37e3SMark Peek orig_len = pathbuf->len; 5799ccc37e3SMark Peek errno = err = 0; 5809ccc37e3SMark Peek 5819ccc37e3SMark Peek while (pglobstar < restpattern) { 5829ccc37e3SMark Peek __Char wc; 5839ccc37e3SMark Peek size_t width = One_Char_mbtowc(&wc, pglobstar, MB_LEN_MAX); 5849ccc37e3SMark Peek if ((pglobstar[0] & M_MASK) == M_ALL && 5859ccc37e3SMark Peek (pglobstar[width] & M_MASK) == M_ALL) { 5869ccc37e3SMark Peek globstar = 1; 5879ccc37e3SMark Peek chase_symlinks = (pglobstar[2 * width] & M_MASK) == M_ALL; 5889ccc37e3SMark Peek termstar = pglobstar + (2 + chase_symlinks) * width; 5899ccc37e3SMark Peek break; 5909ccc37e3SMark Peek } 5919ccc37e3SMark Peek pglobstar += width; 5929ccc37e3SMark Peek } 5939ccc37e3SMark Peek 5949ccc37e3SMark Peek if (globstar) { 5959ccc37e3SMark Peek err = pglobstar==pattern && termstar==restpattern ? 5969ccc37e3SMark Peek *restpattern == EOS ? 5979ccc37e3SMark Peek glob2(pathbuf, restpattern - 1, pglob, no_match) : 5989ccc37e3SMark Peek glob2(pathbuf, restpattern + 1, pglob, no_match) : 5999ccc37e3SMark Peek glob3(pathbuf, pattern, restpattern, termstar, pglob, no_match); 6009ccc37e3SMark Peek if (err) 6019ccc37e3SMark Peek return err; 6029ccc37e3SMark Peek pathbuf->len = orig_len; 6039ccc37e3SMark Peek strbuf_terminate(pathbuf); 6049ccc37e3SMark Peek } 6059ccc37e3SMark Peek 6069ccc37e3SMark Peek if (*pathbuf->s && (Lstat(pathbuf->s, &sbuf) || !S_ISDIR(sbuf.st_mode) 6079ccc37e3SMark Peek #ifdef S_IFLINK 6089ccc37e3SMark Peek && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode)) 6099ccc37e3SMark Peek #endif 6109ccc37e3SMark Peek )) 6119ccc37e3SMark Peek return 0; 612c80476e4SDavid E. O'Brien 61345e5710bSMark Peek if (!(dirp = Opendir(pathbuf->s))) { 614c80476e4SDavid E. O'Brien /* todo: don't call for ENOENT or ENOTDIR? */ 61545e5710bSMark Peek if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf->s, errno)) || 616c80476e4SDavid E. O'Brien (pglob->gl_flags & GLOB_ERR)) 617c80476e4SDavid E. O'Brien return (GLOB_ABEND); 618c80476e4SDavid E. O'Brien else 619c80476e4SDavid E. O'Brien return (0); 620c80476e4SDavid E. O'Brien } 621c80476e4SDavid E. O'Brien 622c80476e4SDavid E. O'Brien /* search directory for matching names */ 623c80476e4SDavid E. O'Brien while ((dp = readdir(dirp)) != NULL) { 624c80476e4SDavid E. O'Brien /* initial DOT must be matched literally */ 625c80476e4SDavid E. O'Brien if (dp->d_name[0] == DOT && *pattern != DOT) 6269ccc37e3SMark Peek if (!(pglob->gl_flags & GLOB_DOT) || !dp->d_name[1] || 6279ccc37e3SMark Peek (dp->d_name[1] == DOT && !dp->d_name[2])) 6289ccc37e3SMark Peek continue; /*unless globdot and not . or .. */ 62945e5710bSMark Peek pathbuf->len = orig_len; 63045e5710bSMark Peek strbuf_append(pathbuf, dp->d_name); 63145e5710bSMark Peek strbuf_terminate(pathbuf); 6329ccc37e3SMark Peek 6339ccc37e3SMark Peek if (globstar) { 6349ccc37e3SMark Peek #ifdef S_IFLNK 6359ccc37e3SMark Peek if (!chase_symlinks && 6369ccc37e3SMark Peek (Lstat(pathbuf->s, &sbuf) || S_ISLNK(sbuf.st_mode))) 637c80476e4SDavid E. O'Brien continue; 6389ccc37e3SMark Peek #endif 6399ccc37e3SMark Peek if (match(pathbuf->s + orig_len, pattern, termstar, 6409ccc37e3SMark Peek (int)m_not) == no_match) 6419ccc37e3SMark Peek continue; 6429ccc37e3SMark Peek strbuf_append1(pathbuf, SEP); 6439ccc37e3SMark Peek strbuf_terminate(pathbuf); 6449ccc37e3SMark Peek if ((err = glob2(pathbuf, pglobstar, pglob, no_match)) != 0) 645c80476e4SDavid E. O'Brien break; 6469ccc37e3SMark Peek } else { 6479ccc37e3SMark Peek if (match(pathbuf->s + orig_len, pattern, restpattern, 6489ccc37e3SMark Peek (int) m_not) == no_match) 6499ccc37e3SMark Peek continue; 6509ccc37e3SMark Peek if ((err = glob2(pathbuf, restpattern, pglob, no_match)) != 0) 6519ccc37e3SMark Peek break; 6529ccc37e3SMark Peek } 653c80476e4SDavid E. O'Brien } 654c80476e4SDavid E. O'Brien /* todo: check error from readdir? */ 65545e5710bSMark Peek closedir(dirp); 656c80476e4SDavid E. O'Brien return (err); 657c80476e4SDavid E. O'Brien } 658c80476e4SDavid E. O'Brien 659c80476e4SDavid E. O'Brien 660c80476e4SDavid E. O'Brien /* 661c80476e4SDavid E. O'Brien * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 662c80476e4SDavid E. O'Brien * add the new item, and update gl_pathc. 663c80476e4SDavid E. O'Brien * 664c80476e4SDavid E. O'Brien * This assumes the BSD realloc, which only copies the block when its size 665c80476e4SDavid E. O'Brien * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 666c80476e4SDavid E. O'Brien * behavior. 667c80476e4SDavid E. O'Brien * 668c80476e4SDavid E. O'Brien * Return 0 if new item added, error code if memory couldn't be allocated. 669c80476e4SDavid E. O'Brien * 670c80476e4SDavid E. O'Brien * Invariant of the glob_t structure: 671c80476e4SDavid E. O'Brien * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 672c80476e4SDavid E. O'Brien * gl_pathv points to (gl_offs + gl_pathc + 1) items. 673c80476e4SDavid E. O'Brien */ 67445e5710bSMark Peek static void 67545e5710bSMark Peek globextend(const char *path, glob_t *pglob) 676c80476e4SDavid E. O'Brien { 67723338178SMark Peek char **pathv; 67823338178SMark Peek int i; 67945e5710bSMark Peek size_t newsize; 680c80476e4SDavid E. O'Brien 681c80476e4SDavid E. O'Brien newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 68245e5710bSMark Peek pathv = xrealloc(pglob->gl_pathv, newsize); 683c80476e4SDavid E. O'Brien 684c80476e4SDavid E. O'Brien if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 685c80476e4SDavid E. O'Brien /* first time around -- clear initial gl_offs items */ 686c80476e4SDavid E. O'Brien pathv += pglob->gl_offs; 687c80476e4SDavid E. O'Brien for (i = pglob->gl_offs; --i >= 0;) 688c80476e4SDavid E. O'Brien *--pathv = NULL; 689c80476e4SDavid E. O'Brien } 690c80476e4SDavid E. O'Brien pglob->gl_pathv = pathv; 691c80476e4SDavid E. O'Brien 69245e5710bSMark Peek pathv[pglob->gl_offs + pglob->gl_pathc++] = strsave(path); 693c80476e4SDavid E. O'Brien pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 694c80476e4SDavid E. O'Brien } 695c80476e4SDavid E. O'Brien 696c80476e4SDavid E. O'Brien /* 697cc698b49SBrooks Davis * pattern matching function for filenames. 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; 703cc698b49SBrooks Davis const Char *patNext; 704cc698b49SBrooks Davis const char *nameNext, *nameStart, *nameEnd; 70545e5710bSMark Peek Char c; 706c80476e4SDavid E. O'Brien 707cc698b49SBrooks Davis patNext = pat; 708cc698b49SBrooks Davis nameStart = nameNext = name; 709cc698b49SBrooks Davis nameEnd = NULL; 710cc698b49SBrooks Davis 711cc698b49SBrooks Davis while (pat < patend || *name) { 712cc698b49SBrooks Davis size_t lwk, pwk; 713*d803a9d0SBrooks Davis __Char wc, wk, wc1; 71423338178SMark Peek 71523338178SMark Peek c = *pat; /* Only for M_MASK bits */ 716cc698b49SBrooks Davis if (*name == EOS) 717cc698b49SBrooks Davis nameEnd = name; 718cc698b49SBrooks Davis 719cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 72045e5710bSMark Peek lwk = one_mbtowc(&wk, name, MB_LEN_MAX); 721c80476e4SDavid E. O'Brien switch (c & M_MASK) { 722c80476e4SDavid E. O'Brien case M_ALL: 723cc698b49SBrooks Davis while ((*(pat + pwk) & M_MASK) == M_ALL) { 724cc698b49SBrooks Davis pat += pwk; 725cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 72623338178SMark Peek } 727cc698b49SBrooks Davis patNext = pat; 728cc698b49SBrooks Davis nameNext = name + lwk; 729cc698b49SBrooks Davis pat += pwk; 730cc698b49SBrooks Davis continue; 731c80476e4SDavid E. O'Brien case M_ONE: 73223338178SMark Peek if (*name == EOS) 733c80476e4SDavid E. O'Brien break; 734cc698b49SBrooks Davis name += lwk; 735cc698b49SBrooks Davis pat += pwk; 736cc698b49SBrooks Davis continue; 737c80476e4SDavid E. O'Brien case M_SET: 738c80476e4SDavid E. O'Brien ok = 0; 73923338178SMark Peek if (*name == EOS) 740cc698b49SBrooks Davis break; 741cc698b49SBrooks Davis pat += pwk; 742cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 74323338178SMark Peek name += lwk; 744cc698b49SBrooks Davis if ((negate_range = ((*pat & M_MASK) == m_not)) != 0) { 745cc698b49SBrooks Davis pat += pwk; 746cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 747cc698b49SBrooks Davis } 748*d803a9d0SBrooks Davis wc1 = wc; 74923338178SMark Peek while ((*pat & M_MASK) != M_END) { 750c80476e4SDavid E. O'Brien if ((*pat & M_MASK) == M_RNG) { 75145e5710bSMark Peek __Char wc2; 75223338178SMark Peek 753cc698b49SBrooks Davis pat += pwk; 754cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc2, pat, MB_LEN_MAX); 755*d803a9d0SBrooks Davis if (globcharcoll(wc1, wk, 0) <= 0 && 75623338178SMark Peek globcharcoll(wk, wc2, 0) <= 0) 757c80476e4SDavid E. O'Brien ok = 1; 75823338178SMark Peek } else if (wc == wk) 759c80476e4SDavid E. O'Brien ok = 1; 760cc698b49SBrooks Davis pat += pwk; 761*d803a9d0SBrooks Davis wc1 = wc; 762cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 763c80476e4SDavid E. O'Brien } 764cc698b49SBrooks Davis pat += pwk; 765cc698b49SBrooks Davis pwk = One_Char_mbtowc(&wc, pat, MB_LEN_MAX); 766c80476e4SDavid E. O'Brien if (ok == negate_range) 767c80476e4SDavid E. O'Brien break; 768cc698b49SBrooks Davis continue; 769c80476e4SDavid E. O'Brien default: 7709ccc37e3SMark Peek if (*name == EOS || samecase(wk) != samecase(wc)) 771c80476e4SDavid E. O'Brien break; 772cc698b49SBrooks Davis name += lwk; 773cc698b49SBrooks Davis pat += pwk; 774cc698b49SBrooks Davis continue; 775c80476e4SDavid E. O'Brien } 776cc698b49SBrooks Davis if (nameNext != nameStart 777cc698b49SBrooks Davis && (nameEnd == NULL || nameNext <= nameEnd)) { 778cc698b49SBrooks Davis pat = patNext; 779cc698b49SBrooks Davis name = nameNext; 780cc698b49SBrooks Davis continue; 781c80476e4SDavid E. O'Brien } 782cc698b49SBrooks Davis return 0; 783cc698b49SBrooks Davis } 784cc698b49SBrooks Davis return 1; 785c80476e4SDavid E. O'Brien } 786c80476e4SDavid E. O'Brien 787c80476e4SDavid E. O'Brien /* free allocated data belonging to a glob_t structure */ 788c80476e4SDavid E. O'Brien void 78945e5710bSMark Peek globfree(glob_t *pglob) 790c80476e4SDavid E. O'Brien { 79123338178SMark Peek int i; 79223338178SMark Peek char **pp; 793c80476e4SDavid E. O'Brien 794c80476e4SDavid E. O'Brien if (pglob->gl_pathv != NULL) { 795c80476e4SDavid E. O'Brien pp = pglob->gl_pathv + pglob->gl_offs; 796c80476e4SDavid E. O'Brien for (i = pglob->gl_pathc; i--; ++pp) 797c80476e4SDavid E. O'Brien if (*pp) 79845e5710bSMark Peek xfree(*pp), *pp = NULL; 79945e5710bSMark Peek xfree(pglob->gl_pathv), pglob->gl_pathv = NULL; 800c80476e4SDavid E. O'Brien } 801c80476e4SDavid E. O'Brien } 802