1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1989, 1993 3*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 6*0Sstevel@tonic-gate * Guido van Rossum. 7*0Sstevel@tonic-gate * 8*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 9*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 10*0Sstevel@tonic-gate * are met: 11*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 12*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 13*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 14*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 15*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 16*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 17*0Sstevel@tonic-gate * must display the following acknowledgement: 18*0Sstevel@tonic-gate * This product includes software developed by the University of 19*0Sstevel@tonic-gate * California, Berkeley and its contributors. 20*0Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 21*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 22*0Sstevel@tonic-gate * without specific prior written permission. 23*0Sstevel@tonic-gate * 24*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*0Sstevel@tonic-gate * SUCH DAMAGE. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include "includes.h" 38*0Sstevel@tonic-gate #include <ctype.h> 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate static long 41*0Sstevel@tonic-gate get_arg_max(void) 42*0Sstevel@tonic-gate { 43*0Sstevel@tonic-gate #ifdef ARG_MAX 44*0Sstevel@tonic-gate return(ARG_MAX); 45*0Sstevel@tonic-gate #elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX) 46*0Sstevel@tonic-gate return(sysconf(_SC_ARG_MAX)); 47*0Sstevel@tonic-gate #else 48*0Sstevel@tonic-gate return(256); /* XXX: arbitrary */ 49*0Sstevel@tonic-gate #endif 50*0Sstevel@tonic-gate } 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \ 53*0Sstevel@tonic-gate !defined(GLOB_HAS_GL_MATCHC) 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint) 56*0Sstevel@tonic-gate #if 0 57*0Sstevel@tonic-gate static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; 58*0Sstevel@tonic-gate #else 59*0Sstevel@tonic-gate static char rcsid[] = "$OpenBSD: glob.c,v 1.20 2002/06/14 21:34:58 todd Exp $"; 60*0Sstevel@tonic-gate #endif 61*0Sstevel@tonic-gate #endif /* LIBC_SCCS and not lint */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * glob(3) -- a superset of the one defined in POSIX 1003.2. 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 67*0Sstevel@tonic-gate * 68*0Sstevel@tonic-gate * Optional extra services, controlled by flags not defined by POSIX: 69*0Sstevel@tonic-gate * 70*0Sstevel@tonic-gate * GLOB_QUOTE: 71*0Sstevel@tonic-gate * Escaping convention: \ inhibits any special meaning the following 72*0Sstevel@tonic-gate * character might have (except \ at end of string is retained). 73*0Sstevel@tonic-gate * GLOB_MAGCHAR: 74*0Sstevel@tonic-gate * Set in gl_flags if pattern contained a globbing character. 75*0Sstevel@tonic-gate * GLOB_NOMAGIC: 76*0Sstevel@tonic-gate * Same as GLOB_NOCHECK, but it will only append pattern if it did 77*0Sstevel@tonic-gate * not contain any magic characters. [Used in csh style globbing] 78*0Sstevel@tonic-gate * GLOB_ALTDIRFUNC: 79*0Sstevel@tonic-gate * Use alternately specified directory access functions. 80*0Sstevel@tonic-gate * GLOB_TILDE: 81*0Sstevel@tonic-gate * expand ~user/foo to the /home/dir/of/user/foo 82*0Sstevel@tonic-gate * GLOB_BRACE: 83*0Sstevel@tonic-gate * expand {1,2}{a,b} to 1a 1b 2a 2b 84*0Sstevel@tonic-gate * gl_matchc: 85*0Sstevel@tonic-gate * Number of matches in the current invocation of glob. 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate #define DOLLAR '$' 90*0Sstevel@tonic-gate #define DOT '.' 91*0Sstevel@tonic-gate #define EOS '\0' 92*0Sstevel@tonic-gate #define LBRACKET '[' 93*0Sstevel@tonic-gate #define NOT '!' 94*0Sstevel@tonic-gate #define QUESTION '?' 95*0Sstevel@tonic-gate #define QUOTE '\\' 96*0Sstevel@tonic-gate #define RANGE '-' 97*0Sstevel@tonic-gate #define RBRACKET ']' 98*0Sstevel@tonic-gate #define SEP '/' 99*0Sstevel@tonic-gate #define STAR '*' 100*0Sstevel@tonic-gate #undef TILDE /* Some platforms may already define it */ 101*0Sstevel@tonic-gate #define TILDE '~' 102*0Sstevel@tonic-gate #define UNDERSCORE '_' 103*0Sstevel@tonic-gate #define LBRACE '{' 104*0Sstevel@tonic-gate #define RBRACE '}' 105*0Sstevel@tonic-gate #define SLASH '/' 106*0Sstevel@tonic-gate #define COMMA ',' 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate #ifndef DEBUG 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate #define M_QUOTE 0x8000 111*0Sstevel@tonic-gate #define M_PROTECT 0x4000 112*0Sstevel@tonic-gate #define M_MASK 0xffff 113*0Sstevel@tonic-gate #define M_ASCII 0x00ff 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate typedef u_short Char; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate #else 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate #define M_QUOTE 0x80 120*0Sstevel@tonic-gate #define M_PROTECT 0x40 121*0Sstevel@tonic-gate #define M_MASK 0xff 122*0Sstevel@tonic-gate #define M_ASCII 0x7f 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate typedef char Char; 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate #endif 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate #define CHAR(c) ((Char)((c)&M_ASCII)) 130*0Sstevel@tonic-gate #define META(c) ((Char)((c)|M_QUOTE)) 131*0Sstevel@tonic-gate #define M_ALL META('*') 132*0Sstevel@tonic-gate #define M_END META(']') 133*0Sstevel@tonic-gate #define M_NOT META('!') 134*0Sstevel@tonic-gate #define M_ONE META('?') 135*0Sstevel@tonic-gate #define M_RNG META('-') 136*0Sstevel@tonic-gate #define M_SET META('[') 137*0Sstevel@tonic-gate #define ismeta(c) (((c)&M_QUOTE) != 0) 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate static int compare(const void *, const void *); 141*0Sstevel@tonic-gate static int g_Ctoc(const Char *, char *, u_int); 142*0Sstevel@tonic-gate static int g_lstat(Char *, struct stat *, glob_t *); 143*0Sstevel@tonic-gate static DIR *g_opendir(Char *, glob_t *); 144*0Sstevel@tonic-gate static Char *g_strchr(Char *, int); 145*0Sstevel@tonic-gate static int g_stat(Char *, struct stat *, glob_t *); 146*0Sstevel@tonic-gate static int glob0(const Char *, glob_t *); 147*0Sstevel@tonic-gate static int glob1(Char *, Char *, glob_t *, size_t *); 148*0Sstevel@tonic-gate static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, 149*0Sstevel@tonic-gate glob_t *, size_t *); 150*0Sstevel@tonic-gate static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, 151*0Sstevel@tonic-gate Char *, Char *, glob_t *, size_t *); 152*0Sstevel@tonic-gate static int globextend(const Char *, glob_t *, size_t *); 153*0Sstevel@tonic-gate static const Char * 154*0Sstevel@tonic-gate globtilde(const Char *, Char *, size_t, glob_t *); 155*0Sstevel@tonic-gate static int globexp1(const Char *, glob_t *); 156*0Sstevel@tonic-gate static int globexp2(const Char *, const Char *, glob_t *, int *); 157*0Sstevel@tonic-gate static int match(Char *, Char *, Char *); 158*0Sstevel@tonic-gate #ifdef DEBUG 159*0Sstevel@tonic-gate static void qprintf(const char *, Char *); 160*0Sstevel@tonic-gate #endif 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate int 163*0Sstevel@tonic-gate glob(pattern, flags, errfunc, pglob) 164*0Sstevel@tonic-gate const char *pattern; 165*0Sstevel@tonic-gate int flags, (*errfunc)(const char *, int); 166*0Sstevel@tonic-gate glob_t *pglob; 167*0Sstevel@tonic-gate { 168*0Sstevel@tonic-gate const u_char *patnext; 169*0Sstevel@tonic-gate int c; 170*0Sstevel@tonic-gate Char *bufnext, *bufend, patbuf[MAXPATHLEN]; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate patnext = (u_char *) pattern; 173*0Sstevel@tonic-gate if (!(flags & GLOB_APPEND)) { 174*0Sstevel@tonic-gate pglob->gl_pathc = 0; 175*0Sstevel@tonic-gate pglob->gl_pathv = NULL; 176*0Sstevel@tonic-gate if (!(flags & GLOB_DOOFFS)) 177*0Sstevel@tonic-gate pglob->gl_offs = 0; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate pglob->gl_flags = flags & ~GLOB_MAGCHAR; 180*0Sstevel@tonic-gate pglob->gl_errfunc = errfunc; 181*0Sstevel@tonic-gate pglob->gl_matchc = 0; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate bufnext = patbuf; 184*0Sstevel@tonic-gate bufend = bufnext + MAXPATHLEN - 1; 185*0Sstevel@tonic-gate if (flags & GLOB_NOESCAPE) 186*0Sstevel@tonic-gate while (bufnext < bufend && (c = *patnext++) != EOS) 187*0Sstevel@tonic-gate *bufnext++ = c; 188*0Sstevel@tonic-gate else { 189*0Sstevel@tonic-gate /* Protect the quoted characters. */ 190*0Sstevel@tonic-gate while (bufnext < bufend && (c = *patnext++) != EOS) 191*0Sstevel@tonic-gate if (c == QUOTE) { 192*0Sstevel@tonic-gate if ((c = *patnext++) == EOS) { 193*0Sstevel@tonic-gate c = QUOTE; 194*0Sstevel@tonic-gate --patnext; 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate *bufnext++ = c | M_PROTECT; 197*0Sstevel@tonic-gate } else 198*0Sstevel@tonic-gate *bufnext++ = c; 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate *bufnext = EOS; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (flags & GLOB_BRACE) 203*0Sstevel@tonic-gate return globexp1(patbuf, pglob); 204*0Sstevel@tonic-gate else 205*0Sstevel@tonic-gate return glob0(patbuf, pglob); 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * Expand recursively a glob {} pattern. When there is no more expansion 210*0Sstevel@tonic-gate * invoke the standard globbing routine to glob the rest of the magic 211*0Sstevel@tonic-gate * characters 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate static int 214*0Sstevel@tonic-gate globexp1(pattern, pglob) 215*0Sstevel@tonic-gate const Char *pattern; 216*0Sstevel@tonic-gate glob_t *pglob; 217*0Sstevel@tonic-gate { 218*0Sstevel@tonic-gate const Char* ptr = pattern; 219*0Sstevel@tonic-gate int rv; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* Protect a single {}, for find(1), like csh */ 222*0Sstevel@tonic-gate if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) 223*0Sstevel@tonic-gate return glob0(pattern, pglob); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) 226*0Sstevel@tonic-gate if (!globexp2(ptr, pattern, pglob, &rv)) 227*0Sstevel@tonic-gate return rv; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate return glob0(pattern, pglob); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * Recursive brace globbing helper. Tries to expand a single brace. 235*0Sstevel@tonic-gate * If it succeeds then it invokes globexp1 with the new pattern. 236*0Sstevel@tonic-gate * If it fails then it tries to glob the rest of the pattern and returns. 237*0Sstevel@tonic-gate */ 238*0Sstevel@tonic-gate static int 239*0Sstevel@tonic-gate globexp2(ptr, pattern, pglob, rv) 240*0Sstevel@tonic-gate const Char *ptr, *pattern; 241*0Sstevel@tonic-gate glob_t *pglob; 242*0Sstevel@tonic-gate int *rv; 243*0Sstevel@tonic-gate { 244*0Sstevel@tonic-gate int i; 245*0Sstevel@tonic-gate Char *lm, *ls; 246*0Sstevel@tonic-gate const Char *pe, *pm, *pl; 247*0Sstevel@tonic-gate Char patbuf[MAXPATHLEN]; 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* copy part up to the brace */ 250*0Sstevel@tonic-gate for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 251*0Sstevel@tonic-gate ; 252*0Sstevel@tonic-gate *lm = EOS; 253*0Sstevel@tonic-gate ls = lm; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate /* Find the balanced brace */ 256*0Sstevel@tonic-gate for (i = 0, pe = ++ptr; *pe; pe++) 257*0Sstevel@tonic-gate if (*pe == LBRACKET) { 258*0Sstevel@tonic-gate /* Ignore everything between [] */ 259*0Sstevel@tonic-gate for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) 260*0Sstevel@tonic-gate ; 261*0Sstevel@tonic-gate if (*pe == EOS) { 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * We could not find a matching RBRACKET. 264*0Sstevel@tonic-gate * Ignore and just look for RBRACE 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate pe = pm; 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate } else if (*pe == LBRACE) 269*0Sstevel@tonic-gate i++; 270*0Sstevel@tonic-gate else if (*pe == RBRACE) { 271*0Sstevel@tonic-gate if (i == 0) 272*0Sstevel@tonic-gate break; 273*0Sstevel@tonic-gate i--; 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* Non matching braces; just glob the pattern */ 277*0Sstevel@tonic-gate if (i != 0 || *pe == EOS) { 278*0Sstevel@tonic-gate *rv = glob0(patbuf, pglob); 279*0Sstevel@tonic-gate return 0; 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 283*0Sstevel@tonic-gate switch (*pm) { 284*0Sstevel@tonic-gate case LBRACKET: 285*0Sstevel@tonic-gate /* Ignore everything between [] */ 286*0Sstevel@tonic-gate for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) 287*0Sstevel@tonic-gate ; 288*0Sstevel@tonic-gate if (*pm == EOS) { 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * We could not find a matching RBRACKET. 291*0Sstevel@tonic-gate * Ignore and just look for RBRACE 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate pm = pl; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate break; 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate case LBRACE: 298*0Sstevel@tonic-gate i++; 299*0Sstevel@tonic-gate break; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate case RBRACE: 302*0Sstevel@tonic-gate if (i) { 303*0Sstevel@tonic-gate i--; 304*0Sstevel@tonic-gate break; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate /* FALLTHROUGH */ 307*0Sstevel@tonic-gate case COMMA: 308*0Sstevel@tonic-gate if (i && *pm == COMMA) 309*0Sstevel@tonic-gate break; 310*0Sstevel@tonic-gate else { 311*0Sstevel@tonic-gate /* Append the current string */ 312*0Sstevel@tonic-gate for (lm = ls; (pl < pm); *lm++ = *pl++) 313*0Sstevel@tonic-gate ; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * Append the rest of the pattern after the 317*0Sstevel@tonic-gate * closing brace 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate for (pl = pe + 1; (*lm++ = *pl++) != EOS; ) 320*0Sstevel@tonic-gate ; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* Expand the current pattern */ 323*0Sstevel@tonic-gate #ifdef DEBUG 324*0Sstevel@tonic-gate qprintf("globexp2:", patbuf); 325*0Sstevel@tonic-gate #endif 326*0Sstevel@tonic-gate *rv = globexp1(patbuf, pglob); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* move after the comma, to the next string */ 329*0Sstevel@tonic-gate pl = pm + 1; 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate break; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate default: 334*0Sstevel@tonic-gate break; 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate *rv = 0; 338*0Sstevel@tonic-gate return 0; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * expand tilde from the passwd file. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate static const Char * 347*0Sstevel@tonic-gate globtilde(pattern, patbuf, patbuf_len, pglob) 348*0Sstevel@tonic-gate const Char *pattern; 349*0Sstevel@tonic-gate Char *patbuf; 350*0Sstevel@tonic-gate size_t patbuf_len; 351*0Sstevel@tonic-gate glob_t *pglob; 352*0Sstevel@tonic-gate { 353*0Sstevel@tonic-gate struct passwd *pwd; 354*0Sstevel@tonic-gate char *h; 355*0Sstevel@tonic-gate const Char *p; 356*0Sstevel@tonic-gate Char *b, *eb; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) 359*0Sstevel@tonic-gate return pattern; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* Copy up to the end of the string or / */ 362*0Sstevel@tonic-gate eb = &patbuf[patbuf_len - 1]; 363*0Sstevel@tonic-gate for (p = pattern + 1, h = (char *) patbuf; 364*0Sstevel@tonic-gate h < (char *)eb && *p && *p != SLASH; *h++ = *p++) 365*0Sstevel@tonic-gate ; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate *h = EOS; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate #if 0 370*0Sstevel@tonic-gate if (h == (char *)eb) 371*0Sstevel@tonic-gate return what; 372*0Sstevel@tonic-gate #endif 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate if (((char *) patbuf)[0] == EOS) { 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * handle a plain ~ or ~/ by expanding $HOME 377*0Sstevel@tonic-gate * first and then trying the password file 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate #if 0 380*0Sstevel@tonic-gate if (issetugid() != 0 || (h = getenv("HOME")) == NULL) { 381*0Sstevel@tonic-gate #endif 382*0Sstevel@tonic-gate if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) { 383*0Sstevel@tonic-gate if ((pwd = getpwuid(getuid())) == NULL) 384*0Sstevel@tonic-gate return pattern; 385*0Sstevel@tonic-gate else 386*0Sstevel@tonic-gate h = pwd->pw_dir; 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate } else { 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Expand a ~user 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate if ((pwd = getpwnam((char*) patbuf)) == NULL) 393*0Sstevel@tonic-gate return pattern; 394*0Sstevel@tonic-gate else 395*0Sstevel@tonic-gate h = pwd->pw_dir; 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* Copy the home directory */ 399*0Sstevel@tonic-gate for (b = patbuf; b < eb && *h; *b++ = *h++) 400*0Sstevel@tonic-gate ; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate /* Append the rest of the pattern */ 403*0Sstevel@tonic-gate while (b < eb && (*b++ = *p++) != EOS) 404*0Sstevel@tonic-gate ; 405*0Sstevel@tonic-gate *b = EOS; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate return patbuf; 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * The main glob() routine: compiles the pattern (optionally processing 413*0Sstevel@tonic-gate * quotes), calls glob1() to do the real pattern matching, and finally 414*0Sstevel@tonic-gate * sorts the list (unless unsorted operation is requested). Returns 0 415*0Sstevel@tonic-gate * if things went well, nonzero if errors occurred. It is not an error 416*0Sstevel@tonic-gate * to find no matches. 417*0Sstevel@tonic-gate */ 418*0Sstevel@tonic-gate static int 419*0Sstevel@tonic-gate glob0(pattern, pglob) 420*0Sstevel@tonic-gate const Char *pattern; 421*0Sstevel@tonic-gate glob_t *pglob; 422*0Sstevel@tonic-gate { 423*0Sstevel@tonic-gate const Char *qpatnext; 424*0Sstevel@tonic-gate int c, err, oldpathc; 425*0Sstevel@tonic-gate Char *bufnext, patbuf[MAXPATHLEN]; 426*0Sstevel@tonic-gate size_t limit = 0; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); 429*0Sstevel@tonic-gate oldpathc = pglob->gl_pathc; 430*0Sstevel@tonic-gate bufnext = patbuf; 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* We don't need to check for buffer overflow any more. */ 433*0Sstevel@tonic-gate while ((c = *qpatnext++) != EOS) { 434*0Sstevel@tonic-gate switch (c) { 435*0Sstevel@tonic-gate case LBRACKET: 436*0Sstevel@tonic-gate c = *qpatnext; 437*0Sstevel@tonic-gate if (c == NOT) 438*0Sstevel@tonic-gate ++qpatnext; 439*0Sstevel@tonic-gate if (*qpatnext == EOS || 440*0Sstevel@tonic-gate g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { 441*0Sstevel@tonic-gate *bufnext++ = LBRACKET; 442*0Sstevel@tonic-gate if (c == NOT) 443*0Sstevel@tonic-gate --qpatnext; 444*0Sstevel@tonic-gate break; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate *bufnext++ = M_SET; 447*0Sstevel@tonic-gate if (c == NOT) 448*0Sstevel@tonic-gate *bufnext++ = M_NOT; 449*0Sstevel@tonic-gate c = *qpatnext++; 450*0Sstevel@tonic-gate do { 451*0Sstevel@tonic-gate *bufnext++ = CHAR(c); 452*0Sstevel@tonic-gate if (*qpatnext == RANGE && 453*0Sstevel@tonic-gate (c = qpatnext[1]) != RBRACKET) { 454*0Sstevel@tonic-gate *bufnext++ = M_RNG; 455*0Sstevel@tonic-gate *bufnext++ = CHAR(c); 456*0Sstevel@tonic-gate qpatnext += 2; 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate } while ((c = *qpatnext++) != RBRACKET); 459*0Sstevel@tonic-gate pglob->gl_flags |= GLOB_MAGCHAR; 460*0Sstevel@tonic-gate *bufnext++ = M_END; 461*0Sstevel@tonic-gate break; 462*0Sstevel@tonic-gate case QUESTION: 463*0Sstevel@tonic-gate pglob->gl_flags |= GLOB_MAGCHAR; 464*0Sstevel@tonic-gate *bufnext++ = M_ONE; 465*0Sstevel@tonic-gate break; 466*0Sstevel@tonic-gate case STAR: 467*0Sstevel@tonic-gate pglob->gl_flags |= GLOB_MAGCHAR; 468*0Sstevel@tonic-gate /* collapse adjacent stars to one, 469*0Sstevel@tonic-gate * to avoid exponential behavior 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate if (bufnext == patbuf || bufnext[-1] != M_ALL) 472*0Sstevel@tonic-gate *bufnext++ = M_ALL; 473*0Sstevel@tonic-gate break; 474*0Sstevel@tonic-gate default: 475*0Sstevel@tonic-gate *bufnext++ = CHAR(c); 476*0Sstevel@tonic-gate break; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate *bufnext = EOS; 480*0Sstevel@tonic-gate #ifdef DEBUG 481*0Sstevel@tonic-gate qprintf("glob0:", patbuf); 482*0Sstevel@tonic-gate #endif 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0) 485*0Sstevel@tonic-gate return(err); 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * If there was no match we are going to append the pattern 489*0Sstevel@tonic-gate * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 490*0Sstevel@tonic-gate * and the pattern did not contain any magic characters 491*0Sstevel@tonic-gate * GLOB_NOMAGIC is there just for compatibility with csh. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate if (pglob->gl_pathc == oldpathc) { 494*0Sstevel@tonic-gate if ((pglob->gl_flags & GLOB_NOCHECK) || 495*0Sstevel@tonic-gate ((pglob->gl_flags & GLOB_NOMAGIC) && 496*0Sstevel@tonic-gate !(pglob->gl_flags & GLOB_MAGCHAR))) 497*0Sstevel@tonic-gate return(globextend(pattern, pglob, &limit)); 498*0Sstevel@tonic-gate else 499*0Sstevel@tonic-gate return(GLOB_NOMATCH); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate if (!(pglob->gl_flags & GLOB_NOSORT)) 502*0Sstevel@tonic-gate qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 503*0Sstevel@tonic-gate pglob->gl_pathc - oldpathc, sizeof(char *), compare); 504*0Sstevel@tonic-gate return(0); 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate static int 508*0Sstevel@tonic-gate compare(p, q) 509*0Sstevel@tonic-gate const void *p, *q; 510*0Sstevel@tonic-gate { 511*0Sstevel@tonic-gate return(strcmp(*(char **)p, *(char **)q)); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate static int 515*0Sstevel@tonic-gate glob1(pattern, pattern_last, pglob, limitp) 516*0Sstevel@tonic-gate Char *pattern, *pattern_last; 517*0Sstevel@tonic-gate glob_t *pglob; 518*0Sstevel@tonic-gate size_t *limitp; 519*0Sstevel@tonic-gate { 520*0Sstevel@tonic-gate Char pathbuf[MAXPATHLEN]; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 523*0Sstevel@tonic-gate if (*pattern == EOS) 524*0Sstevel@tonic-gate return(0); 525*0Sstevel@tonic-gate return(glob2(pathbuf, pathbuf+MAXPATHLEN-1, 526*0Sstevel@tonic-gate pathbuf, pathbuf+MAXPATHLEN-1, 527*0Sstevel@tonic-gate pattern, pattern_last, pglob, limitp)); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * The functions glob2 and glob3 are mutually recursive; there is one level 532*0Sstevel@tonic-gate * of recursion for each segment in the pattern that contains one or more 533*0Sstevel@tonic-gate * meta characters. 534*0Sstevel@tonic-gate */ 535*0Sstevel@tonic-gate static int 536*0Sstevel@tonic-gate glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, 537*0Sstevel@tonic-gate pattern_last, pglob, limitp) 538*0Sstevel@tonic-gate Char *pathbuf, *pathbuf_last, *pathend, *pathend_last; 539*0Sstevel@tonic-gate Char *pattern, *pattern_last; 540*0Sstevel@tonic-gate glob_t *pglob; 541*0Sstevel@tonic-gate size_t *limitp; 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate struct stat sb; 544*0Sstevel@tonic-gate Char *p, *q; 545*0Sstevel@tonic-gate int anymeta; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate /* 548*0Sstevel@tonic-gate * Loop over pattern segments until end of pattern or until 549*0Sstevel@tonic-gate * segment with meta character found. 550*0Sstevel@tonic-gate */ 551*0Sstevel@tonic-gate for (anymeta = 0;;) { 552*0Sstevel@tonic-gate if (*pattern == EOS) { /* End of pattern? */ 553*0Sstevel@tonic-gate *pathend = EOS; 554*0Sstevel@tonic-gate if (g_lstat(pathbuf, &sb, pglob)) 555*0Sstevel@tonic-gate return(0); 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate if (((pglob->gl_flags & GLOB_MARK) && 558*0Sstevel@tonic-gate pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || 559*0Sstevel@tonic-gate (S_ISLNK(sb.st_mode) && 560*0Sstevel@tonic-gate (g_stat(pathbuf, &sb, pglob) == 0) && 561*0Sstevel@tonic-gate S_ISDIR(sb.st_mode)))) { 562*0Sstevel@tonic-gate if (pathend+1 > pathend_last) 563*0Sstevel@tonic-gate return (1); 564*0Sstevel@tonic-gate *pathend++ = SEP; 565*0Sstevel@tonic-gate *pathend = EOS; 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate ++pglob->gl_matchc; 568*0Sstevel@tonic-gate return(globextend(pathbuf, pglob, limitp)); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate /* Find end of next segment, copy tentatively to pathend. */ 572*0Sstevel@tonic-gate q = pathend; 573*0Sstevel@tonic-gate p = pattern; 574*0Sstevel@tonic-gate while (*p != EOS && *p != SEP) { 575*0Sstevel@tonic-gate if (ismeta(*p)) 576*0Sstevel@tonic-gate anymeta = 1; 577*0Sstevel@tonic-gate if (q+1 > pathend_last) 578*0Sstevel@tonic-gate return (1); 579*0Sstevel@tonic-gate *q++ = *p++; 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if (!anymeta) { /* No expansion, do next segment. */ 583*0Sstevel@tonic-gate pathend = q; 584*0Sstevel@tonic-gate pattern = p; 585*0Sstevel@tonic-gate while (*pattern == SEP) { 586*0Sstevel@tonic-gate if (pathend+1 > pathend_last) 587*0Sstevel@tonic-gate return (1); 588*0Sstevel@tonic-gate *pathend++ = *pattern++; 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate } else 591*0Sstevel@tonic-gate /* Need expansion, recurse. */ 592*0Sstevel@tonic-gate return(glob3(pathbuf, pathbuf_last, pathend, 593*0Sstevel@tonic-gate pathend_last, pattern, pattern_last, 594*0Sstevel@tonic-gate p, pattern_last, pglob, limitp)); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate /* NOTREACHED */ 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate static int 600*0Sstevel@tonic-gate glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, 601*0Sstevel@tonic-gate restpattern, restpattern_last, pglob, limitp) 602*0Sstevel@tonic-gate Char *pathbuf, *pathbuf_last, *pathend, *pathend_last; 603*0Sstevel@tonic-gate Char *pattern, *pattern_last, *restpattern, *restpattern_last; 604*0Sstevel@tonic-gate glob_t *pglob; 605*0Sstevel@tonic-gate size_t *limitp; 606*0Sstevel@tonic-gate { 607*0Sstevel@tonic-gate register struct dirent *dp; 608*0Sstevel@tonic-gate DIR *dirp; 609*0Sstevel@tonic-gate int err; 610*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate /* 613*0Sstevel@tonic-gate * The readdirfunc declaration can't be prototyped, because it is 614*0Sstevel@tonic-gate * assigned, below, to two functions which are prototyped in glob.h 615*0Sstevel@tonic-gate * and dirent.h as taking pointers to differently typed opaque 616*0Sstevel@tonic-gate * structures. 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate struct dirent *(*readdirfunc)(); 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate if (pathend > pathend_last) 621*0Sstevel@tonic-gate return (1); 622*0Sstevel@tonic-gate *pathend = EOS; 623*0Sstevel@tonic-gate errno = 0; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 626*0Sstevel@tonic-gate /* TODO: don't call for ENOENT or ENOTDIR? */ 627*0Sstevel@tonic-gate if (pglob->gl_errfunc) { 628*0Sstevel@tonic-gate if (g_Ctoc(pathbuf, buf, sizeof(buf))) 629*0Sstevel@tonic-gate return(GLOB_ABORTED); 630*0Sstevel@tonic-gate if (pglob->gl_errfunc(buf, errno) || 631*0Sstevel@tonic-gate pglob->gl_flags & GLOB_ERR) 632*0Sstevel@tonic-gate return(GLOB_ABORTED); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate return(0); 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate err = 0; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* Search directory for matching names. */ 640*0Sstevel@tonic-gate if (pglob->gl_flags & GLOB_ALTDIRFUNC) 641*0Sstevel@tonic-gate readdirfunc = pglob->gl_readdir; 642*0Sstevel@tonic-gate else 643*0Sstevel@tonic-gate readdirfunc = readdir; 644*0Sstevel@tonic-gate while ((dp = (*readdirfunc)(dirp))) { 645*0Sstevel@tonic-gate register u_char *sc; 646*0Sstevel@tonic-gate register Char *dc; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* Initial DOT must be matched literally. */ 649*0Sstevel@tonic-gate if (dp->d_name[0] == DOT && *pattern != DOT) 650*0Sstevel@tonic-gate continue; 651*0Sstevel@tonic-gate dc = pathend; 652*0Sstevel@tonic-gate sc = (u_char *) dp->d_name; 653*0Sstevel@tonic-gate while (dc < pathend_last && (*dc++ = *sc++) != EOS) 654*0Sstevel@tonic-gate ; 655*0Sstevel@tonic-gate if (dc >= pathend_last) { 656*0Sstevel@tonic-gate *dc = EOS; 657*0Sstevel@tonic-gate err = 1; 658*0Sstevel@tonic-gate break; 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate if (!match(pathend, pattern, restpattern)) { 662*0Sstevel@tonic-gate *pathend = EOS; 663*0Sstevel@tonic-gate continue; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, 666*0Sstevel@tonic-gate restpattern, restpattern_last, pglob, limitp); 667*0Sstevel@tonic-gate if (err) 668*0Sstevel@tonic-gate break; 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate if (pglob->gl_flags & GLOB_ALTDIRFUNC) 672*0Sstevel@tonic-gate (*pglob->gl_closedir)(dirp); 673*0Sstevel@tonic-gate else 674*0Sstevel@tonic-gate closedir(dirp); 675*0Sstevel@tonic-gate return(err); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate /* 680*0Sstevel@tonic-gate * Extend the gl_pathv member of a glob_t structure to accommodate a new item, 681*0Sstevel@tonic-gate * add the new item, and update gl_pathc. 682*0Sstevel@tonic-gate * 683*0Sstevel@tonic-gate * This assumes the BSD realloc, which only copies the block when its size 684*0Sstevel@tonic-gate * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 685*0Sstevel@tonic-gate * behavior. 686*0Sstevel@tonic-gate * 687*0Sstevel@tonic-gate * Return 0 if new item added, error code if memory couldn't be allocated. 688*0Sstevel@tonic-gate * 689*0Sstevel@tonic-gate * Invariant of the glob_t structure: 690*0Sstevel@tonic-gate * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 691*0Sstevel@tonic-gate * gl_pathv points to (gl_offs + gl_pathc + 1) items. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate static int 694*0Sstevel@tonic-gate globextend(path, pglob, limitp) 695*0Sstevel@tonic-gate const Char *path; 696*0Sstevel@tonic-gate glob_t *pglob; 697*0Sstevel@tonic-gate size_t *limitp; 698*0Sstevel@tonic-gate { 699*0Sstevel@tonic-gate register char **pathv; 700*0Sstevel@tonic-gate register int i; 701*0Sstevel@tonic-gate u_int newsize, len; 702*0Sstevel@tonic-gate char *copy; 703*0Sstevel@tonic-gate const Char *p; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 706*0Sstevel@tonic-gate pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) : 707*0Sstevel@tonic-gate malloc(newsize); 708*0Sstevel@tonic-gate if (pathv == NULL) { 709*0Sstevel@tonic-gate if (pglob->gl_pathv) { 710*0Sstevel@tonic-gate free(pglob->gl_pathv); 711*0Sstevel@tonic-gate pglob->gl_pathv = NULL; 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate return(GLOB_NOSPACE); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 717*0Sstevel@tonic-gate /* first time around -- clear initial gl_offs items */ 718*0Sstevel@tonic-gate pathv += pglob->gl_offs; 719*0Sstevel@tonic-gate for (i = pglob->gl_offs; --i >= 0; ) 720*0Sstevel@tonic-gate *--pathv = NULL; 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate pglob->gl_pathv = pathv; 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate for (p = path; *p++;) 725*0Sstevel@tonic-gate ; 726*0Sstevel@tonic-gate len = (size_t)(p - path); 727*0Sstevel@tonic-gate *limitp += len; 728*0Sstevel@tonic-gate if ((copy = malloc(len)) != NULL) { 729*0Sstevel@tonic-gate if (g_Ctoc(path, copy, len)) { 730*0Sstevel@tonic-gate free(copy); 731*0Sstevel@tonic-gate return(GLOB_NOSPACE); 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate if ((pglob->gl_flags & GLOB_LIMIT) && 738*0Sstevel@tonic-gate newsize + *limitp >= (u_int) get_arg_max()) { 739*0Sstevel@tonic-gate errno = 0; 740*0Sstevel@tonic-gate return(GLOB_NOSPACE); 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate return(copy == NULL ? GLOB_NOSPACE : 0); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate /* 748*0Sstevel@tonic-gate * pattern matching function for filenames. Each occurrence of the * 749*0Sstevel@tonic-gate * pattern causes a recursion level. 750*0Sstevel@tonic-gate */ 751*0Sstevel@tonic-gate static int 752*0Sstevel@tonic-gate match(name, pat, patend) 753*0Sstevel@tonic-gate register Char *name, *pat, *patend; 754*0Sstevel@tonic-gate { 755*0Sstevel@tonic-gate int ok, negate_range; 756*0Sstevel@tonic-gate Char c, k; 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate while (pat < patend) { 759*0Sstevel@tonic-gate c = *pat++; 760*0Sstevel@tonic-gate switch (c & M_MASK) { 761*0Sstevel@tonic-gate case M_ALL: 762*0Sstevel@tonic-gate if (pat == patend) 763*0Sstevel@tonic-gate return(1); 764*0Sstevel@tonic-gate do 765*0Sstevel@tonic-gate if (match(name, pat, patend)) 766*0Sstevel@tonic-gate return(1); 767*0Sstevel@tonic-gate while (*name++ != EOS) 768*0Sstevel@tonic-gate ; 769*0Sstevel@tonic-gate return(0); 770*0Sstevel@tonic-gate case M_ONE: 771*0Sstevel@tonic-gate if (*name++ == EOS) 772*0Sstevel@tonic-gate return(0); 773*0Sstevel@tonic-gate break; 774*0Sstevel@tonic-gate case M_SET: 775*0Sstevel@tonic-gate ok = 0; 776*0Sstevel@tonic-gate if ((k = *name++) == EOS) 777*0Sstevel@tonic-gate return(0); 778*0Sstevel@tonic-gate if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) 779*0Sstevel@tonic-gate ++pat; 780*0Sstevel@tonic-gate while (((c = *pat++) & M_MASK) != M_END) 781*0Sstevel@tonic-gate if ((*pat & M_MASK) == M_RNG) { 782*0Sstevel@tonic-gate if (c <= k && k <= pat[1]) 783*0Sstevel@tonic-gate ok = 1; 784*0Sstevel@tonic-gate pat += 2; 785*0Sstevel@tonic-gate } else if (c == k) 786*0Sstevel@tonic-gate ok = 1; 787*0Sstevel@tonic-gate if (ok == negate_range) 788*0Sstevel@tonic-gate return(0); 789*0Sstevel@tonic-gate break; 790*0Sstevel@tonic-gate default: 791*0Sstevel@tonic-gate if (*name++ != c) 792*0Sstevel@tonic-gate return(0); 793*0Sstevel@tonic-gate break; 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate } 796*0Sstevel@tonic-gate return(*name == EOS); 797*0Sstevel@tonic-gate } 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate /* Free allocated data belonging to a glob_t structure. */ 800*0Sstevel@tonic-gate void 801*0Sstevel@tonic-gate globfree(pglob) 802*0Sstevel@tonic-gate glob_t *pglob; 803*0Sstevel@tonic-gate { 804*0Sstevel@tonic-gate register int i; 805*0Sstevel@tonic-gate register char **pp; 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate if (pglob->gl_pathv != NULL) { 808*0Sstevel@tonic-gate pp = pglob->gl_pathv + pglob->gl_offs; 809*0Sstevel@tonic-gate for (i = pglob->gl_pathc; i--; ++pp) 810*0Sstevel@tonic-gate if (*pp) 811*0Sstevel@tonic-gate free(*pp); 812*0Sstevel@tonic-gate free(pglob->gl_pathv); 813*0Sstevel@tonic-gate pglob->gl_pathv = NULL; 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate static DIR * 818*0Sstevel@tonic-gate g_opendir(str, pglob) 819*0Sstevel@tonic-gate register Char *str; 820*0Sstevel@tonic-gate glob_t *pglob; 821*0Sstevel@tonic-gate { 822*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate if (!*str) 825*0Sstevel@tonic-gate strlcpy(buf, ".", sizeof buf); 826*0Sstevel@tonic-gate else { 827*0Sstevel@tonic-gate if (g_Ctoc(str, buf, sizeof(buf))) 828*0Sstevel@tonic-gate return(NULL); 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gate if (pglob->gl_flags & GLOB_ALTDIRFUNC) 832*0Sstevel@tonic-gate return((*pglob->gl_opendir)(buf)); 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate return(opendir(buf)); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate static int 838*0Sstevel@tonic-gate g_lstat(fn, sb, pglob) 839*0Sstevel@tonic-gate register Char *fn; 840*0Sstevel@tonic-gate struct stat *sb; 841*0Sstevel@tonic-gate glob_t *pglob; 842*0Sstevel@tonic-gate { 843*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate if (g_Ctoc(fn, buf, sizeof(buf))) 846*0Sstevel@tonic-gate return(-1); 847*0Sstevel@tonic-gate if (pglob->gl_flags & GLOB_ALTDIRFUNC) 848*0Sstevel@tonic-gate return((*pglob->gl_lstat)(buf, sb)); 849*0Sstevel@tonic-gate return(lstat(buf, sb)); 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate static int 853*0Sstevel@tonic-gate g_stat(fn, sb, pglob) 854*0Sstevel@tonic-gate register Char *fn; 855*0Sstevel@tonic-gate struct stat *sb; 856*0Sstevel@tonic-gate glob_t *pglob; 857*0Sstevel@tonic-gate { 858*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate if (g_Ctoc(fn, buf, sizeof(buf))) 861*0Sstevel@tonic-gate return(-1); 862*0Sstevel@tonic-gate if (pglob->gl_flags & GLOB_ALTDIRFUNC) 863*0Sstevel@tonic-gate return((*pglob->gl_stat)(buf, sb)); 864*0Sstevel@tonic-gate return(stat(buf, sb)); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate static Char * 868*0Sstevel@tonic-gate g_strchr(str, ch) 869*0Sstevel@tonic-gate Char *str; 870*0Sstevel@tonic-gate int ch; 871*0Sstevel@tonic-gate { 872*0Sstevel@tonic-gate do { 873*0Sstevel@tonic-gate if (*str == ch) 874*0Sstevel@tonic-gate return (str); 875*0Sstevel@tonic-gate } while (*str++); 876*0Sstevel@tonic-gate return (NULL); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate static int 880*0Sstevel@tonic-gate g_Ctoc(str, buf, len) 881*0Sstevel@tonic-gate register const Char *str; 882*0Sstevel@tonic-gate char *buf; 883*0Sstevel@tonic-gate u_int len; 884*0Sstevel@tonic-gate { 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate while (len--) { 887*0Sstevel@tonic-gate if ((*buf++ = *str++) == EOS) 888*0Sstevel@tonic-gate return (0); 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate return (1); 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate #ifdef DEBUG 894*0Sstevel@tonic-gate static void 895*0Sstevel@tonic-gate qprintf(str, s) 896*0Sstevel@tonic-gate const char *str; 897*0Sstevel@tonic-gate register Char *s; 898*0Sstevel@tonic-gate { 899*0Sstevel@tonic-gate register Char *p; 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate (void)printf("%s:\n", str); 902*0Sstevel@tonic-gate for (p = s; *p; p++) 903*0Sstevel@tonic-gate (void)printf("%c", CHAR(*p)); 904*0Sstevel@tonic-gate (void)printf("\n"); 905*0Sstevel@tonic-gate for (p = s; *p; p++) 906*0Sstevel@tonic-gate (void)printf("%c", *p & M_PROTECT ? '"' : ' '); 907*0Sstevel@tonic-gate (void)printf("\n"); 908*0Sstevel@tonic-gate for (p = s; *p; p++) 909*0Sstevel@tonic-gate (void)printf("%c", ismeta(*p) ? '_' : ' '); 910*0Sstevel@tonic-gate (void)printf("\n"); 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate #endif 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || 915*0Sstevel@tonic-gate !defined(GLOB_HAS_GL_MATCHC) */ 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 919