glob.c revision 131962
1228753Smm/* 2228753Smm * Copyright (c) 1989 The Regents of the University of California. 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * This code is derived from software contributed to Berkeley by 6228753Smm * Guido van Rossum. 7228753Smm * 8228753Smm * Redistribution and use in source and binary forms, with or without 9228753Smm * modification, are permitted provided that the following conditions 10228753Smm * are met: 11228753Smm * 1. Redistributions of source code must retain the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer. 13228753Smm * 2. Redistributions in binary form must reproduce the above copyright 14228753Smm * notice, this list of conditions and the following disclaimer in the 15228753Smm * documentation and/or other materials provided with the distribution. 16228753Smm * 3. Neither the name of the University nor the names of its contributors 17228753Smm * may be used to endorse or promote products derived from this software 18228753Smm * without specific prior written permission. 19228753Smm * 20228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30228753Smm * SUCH DAMAGE. 31228753Smm */ 32228753Smm#if defined(LIBC_SCCS) && !defined(lint) 33228753Smmstatic char sccsid[] = "@(#)glob.c 5.12 (Berkeley) 6/24/91"; 34228753Smm#endif /* LIBC_SCCS and not lint */ 35228753Smm/* 36228753Smm * Glob: the interface is a superset of the one defined in POSIX 1003.2, 37228753Smm * draft 9. 38228753Smm * 39228753Smm * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 40228753Smm * 41228753Smm * Optional extra services, controlled by flags not defined by POSIX: 42228753Smm * 43228753Smm * GLOB_QUOTE: 44228753Smm * Escaping convention: \ inhibits any special meaning the following 45228753Smm * character might have (except \ at end of string is retained). 46228753Smm * GLOB_MAGCHAR: 47228753Smm * Set in gl_flags if pattern contained a globbing character. 48228753Smm * GLOB_ALTNOT: 49228753Smm * Use ^ instead of ! for "not". 50228753Smm * gl_matchc: 51228753Smm * Number of matches in the current invocation of glob. 52228753Smm */ 53228753Smm 54228753Smm#ifdef notdef 55228753Smm#include <sys/types.h> 56228753Smm#include <sys/param.h> 57228753Smm#include <sys/stat.h> 58228753Smm#include <dirent.h> 59228753Smm#include <ctype.h> 60228753Smmtypedef void * ptr_t; 61228753Smm#endif 62228753Smm#ifdef WINNT_NATIVE 63228753Smm #pragma warning(disable:4244) 64228753Smm#endif /* WINNT_NATIVE */ 65228753Smm 66228753Smm#define Char __Char 67228753Smm#include "sh.h" 68228753Smm#undef Char 69228753Smm#undef QUOTE 70228753Smm#undef TILDE 71228753Smm#undef META 72228753Smm#undef CHAR 73228753Smm#undef ismeta 74228753Smm#undef Strchr 75228753Smm 76228753Smm#include "glob.h" 77228753Smm 78228753Smm#ifndef S_ISDIR 79228753Smm#define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) 80228753Smm#endif 81228753Smm 82228753Smm#if !defined(S_ISLNK) && defined(S_IFLNK) 83228753Smm#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) 84228753Smm#endif 85228753Smm 86228753Smm#if !defined(S_ISLNK) && !defined(lstat) 87228753Smm#define lstat stat 88228753Smm#endif 89228753Smm 90228753Smmtypedef unsigned short Char; 91228753Smm 92228753Smmstatic int glob1 __P((Char *, glob_t *, int)); 93228753Smmstatic int glob2 __P((Char *, Char *, Char *, glob_t *, int)); 94228753Smmstatic int glob3 __P((Char *, Char *, Char *, Char *, 95228753Smm glob_t *, int)); 96228753Smmstatic int globextend __P((Char *, glob_t *)); 97228753Smmstatic int match __P((Char *, Char *, Char *, int)); 98228753Smm#ifndef __clipper__ 99228753Smmstatic int compare __P((const ptr_t, const ptr_t)); 100228753Smm#endif 101228753Smmstatic DIR *Opendir __P((Char *)); 102228753Smm#ifdef S_IFLNK 103228753Smmstatic int Lstat __P((Char *, struct stat *)); 104228753Smm#endif 105228753Smmstatic int Stat __P((Char *, struct stat *sb)); 106228753Smmstatic Char *Strchr __P((Char *, int)); 107228753Smm#ifdef DEBUG 108228753Smmstatic void qprintf __P((Char *)); 109228753Smm#endif 110228753Smm 111228753Smm#define DOLLAR '$' 112228753Smm#define DOT '.' 113228753Smm#define EOS '\0' 114228753Smm#define LBRACKET '[' 115228753Smm#define NOT '!' 116228753Smm#define ALTNOT '^' 117228753Smm#define QUESTION '?' 118228753Smm#define QUOTE '\\' 119228753Smm#define RANGE '-' 120228753Smm#define RBRACKET ']' 121228753Smm#define SEP '/' 122228753Smm#define STAR '*' 123228753Smm#define TILDE '~' 124228753Smm#define UNDERSCORE '_' 125228753Smm 126228753Smm#define M_META 0x8000 127228753Smm#define M_PROTECT 0x4000 128228753Smm#define M_MASK 0xffff 129228753Smm#define M_ASCII 0x00ff 130228753Smm 131228753Smm#define CHAR(c) ((c)&M_ASCII) 132228753Smm#define META(c) ((c)|M_META) 133228753Smm#define M_ALL META('*') 134228753Smm#define M_END META(']') 135228753Smm#define M_NOT META('!') 136228753Smm#define M_ALTNOT META('^') 137228753Smm#define M_ONE META('?') 138228753Smm#define M_RNG META('-') 139228753Smm#define M_SET META('[') 140228753Smm#define ismeta(c) (((c)&M_META) != 0) 141228753Smm 142228753Smm#ifndef BUFSIZE 143228753Smm#define GLOBBUFLEN MAXPATHLEN 144228753Smm#else 145228753Smm#define GLOBBUFLEN BUFSIZE 146228753Smm#endif 147228753Smm 148228753Smmint 149228753Smmglobcharcoll(c1, c2, cs) 150228753Smm int c1, c2, cs; 151228753Smm{ 152228753Smm#if defined(NLS) && defined(LC_COLLATE) && !defined(NOSTRCOLL) 153228753Smm char s1[2], s2[2]; 154228753Smm 155228753Smm if (c1 == c2) 156228753Smm return (0); 157228753Smm /* 158228753Smm * From kevin lyda <kevin@suberic.net>: 159228753Smm * strcoll does not guarantee case sorting, so we pre-process now: 160228753Smm */ 161228753Smm if (cs) { 162228753Smm c1 = islower(c1) ? c1 : tolower(c1); 163228753Smm c2 = islower(c2) ? c2 : tolower(c2); 164228753Smm } else { 165228753Smm if (islower(c1) && isupper(c2)) 166228753Smm return (1); 167228753Smm } 168228753Smm s1[0] = c1; 169228753Smm s2[0] = c2; 170228753Smm s1[1] = s2[1] = '\0'; 171228753Smm return strcoll(s1, s2); 172228753Smm#else 173228753Smm return (c1 - c2); 174228753Smm#endif 175228753Smm} 176228753Smm 177228753Smm/* 178228753Smm * Need to dodge two kernel bugs: 179228753Smm * opendir("") != opendir(".") 180228753Smm * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels. 181228753Smm * POSIX specifies that they should be ignored in directories. 182228753Smm */ 183228753Smm 184228753Smmstatic DIR * 185228753SmmOpendir(str) 186228753Smm register Char *str; 187228753Smm{ 188228753Smm char buf[GLOBBUFLEN]; 189228753Smm register char *dc = buf; 190228753Smm#if defined(hpux) || defined(__hpux) 191228753Smm struct stat st; 192228753Smm#endif 193228753Smm 194228753Smm if (!*str) 195228753Smm return (opendir(".")); 196228753Smm while ((*dc++ = *str++) != '\0') 197228753Smm continue; 198228753Smm#if defined(hpux) || defined(__hpux) 199228753Smm /* 200228753Smm * Opendir on some device files hangs, so avoid it 201228753Smm */ 202228753Smm if (stat(buf, &st) == -1 || !S_ISDIR(st.st_mode)) 203228753Smm return NULL; 204228753Smm#endif 205228753Smm return (opendir(buf)); 206228753Smm} 207228753Smm 208228753Smm#ifdef S_IFLNK 209228753Smmstatic int 210228753SmmLstat(fn, sb) 211228753Smm register Char *fn; 212228753Smm struct stat *sb; 213228753Smm{ 214228753Smm char buf[GLOBBUFLEN]; 215228753Smm register char *dc = buf; 216228753Smm 217228753Smm while ((*dc++ = *fn++) != '\0') 218228753Smm continue; 219228753Smm# ifdef NAMEI_BUG 220228753Smm { 221228753Smm int st; 222228753Smm 223228753Smm st = lstat(buf, sb); 224228753Smm if (*buf) 225228753Smm dc--; 226228753Smm return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); 227228753Smm } 228228753Smm# else 229228753Smm return (lstat(buf, sb)); 230228753Smm# endif /* NAMEI_BUG */ 231228753Smm} 232228753Smm#else 233228753Smm#define Lstat Stat 234228753Smm#endif /* S_IFLNK */ 235228753Smm 236228753Smmstatic int 237228753SmmStat(fn, sb) 238228753Smm register Char *fn; 239228753Smm struct stat *sb; 240228753Smm{ 241228753Smm char buf[GLOBBUFLEN]; 242228753Smm register char *dc = buf; 243228753Smm 244228753Smm while ((*dc++ = *fn++) != '\0') 245228753Smm continue; 246228753Smm#ifdef NAMEI_BUG 247228753Smm { 248228753Smm int st; 249228753Smm 250228753Smm st = stat(buf, sb); 251228753Smm if (*buf) 252228753Smm dc--; 253228753Smm return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); 254228753Smm } 255228753Smm#else 256228753Smm return (stat(buf, sb)); 257228753Smm#endif /* NAMEI_BUG */ 258228753Smm} 259228753Smm 260228753Smmstatic Char * 261228753SmmStrchr(str, ch) 262228753Smm Char *str; 263228753Smm int ch; 264228753Smm{ 265228753Smm do 266228753Smm if (*str == ch) 267228753Smm return (str); 268228753Smm while (*str++); 269228753Smm return (NULL); 270228753Smm} 271228753Smm 272228753Smm#ifdef DEBUG 273228753Smmstatic void 274228753Smmqprintf(s) 275228753SmmChar *s; 276228753Smm{ 277228753Smm Char *p; 278228753Smm 279228753Smm for (p = s; *p; p++) 280228753Smm printf("%c", *p & 0xff); 281228753Smm printf("\n"); 282228753Smm for (p = s; *p; p++) 283228753Smm printf("%c", *p & M_PROTECT ? '"' : ' '); 284228753Smm printf("\n"); 285228753Smm for (p = s; *p; p++) 286228753Smm printf("%c", *p & M_META ? '_' : ' '); 287228753Smm printf("\n"); 288228753Smm} 289228753Smm#endif /* DEBUG */ 290228753Smm 291228753Smmstatic int 292228753Smmcompare(p, q) 293228753Smm const ptr_t p, q; 294228753Smm{ 295228753Smm#if defined(NLS) && !defined(NOSTRCOLL) 296228753Smm errno = 0; /* strcoll sets errno, another brain-damage */ 297228753Smm 298228753Smm return (strcoll(*(char **) p, *(char **) q)); 299228753Smm#else 300228753Smm return (strcmp(*(char **) p, *(char **) q)); 301228753Smm#endif /* NLS && !NOSTRCOLL */ 302228753Smm} 303228753Smm 304228753Smm/* 305228753Smm * The main glob() routine: compiles the pattern (optionally processing 306228753Smm * quotes), calls glob1() to do the real pattern matching, and finally 307228753Smm * sorts the list (unless unsorted operation is requested). Returns 0 308228753Smm * if things went well, nonzero if errors occurred. It is not an error 309228753Smm * to find no matches. 310228753Smm */ 311228753Smmint 312228753Smmglob(pattern, flags, errfunc, pglob) 313228753Smm const char *pattern; 314228753Smm int flags; 315228753Smm int (*errfunc) __P((const char *, int)); 316228753Smm glob_t *pglob; 317228753Smm{ 318228753Smm int err, oldpathc; 319228753Smm Char *bufnext, *bufend, *compilebuf, m_not; 320228753Smm const unsigned char *compilepat, *patnext; 321228753Smm int c, not; 322228753Smm Char patbuf[GLOBBUFLEN + 1], *qpatnext; 323228753Smm int no_match; 324228753Smm 325228753Smm patnext = (unsigned char *) pattern; 326228753Smm if (!(flags & GLOB_APPEND)) { 327228753Smm pglob->gl_pathc = 0; 328228753Smm pglob->gl_pathv = NULL; 329228753Smm if (!(flags & GLOB_DOOFFS)) 330228753Smm pglob->gl_offs = 0; 331228753Smm } 332228753Smm pglob->gl_flags = flags & ~GLOB_MAGCHAR; 333228753Smm pglob->gl_errfunc = errfunc; 334228753Smm oldpathc = pglob->gl_pathc; 335228753Smm pglob->gl_matchc = 0; 336228753Smm 337228753Smm if (pglob->gl_flags & GLOB_ALTNOT) { 338228753Smm not = ALTNOT; 339228753Smm m_not = M_ALTNOT; 340228753Smm } 341228753Smm else { 342228753Smm not = NOT; 343228753Smm m_not = M_NOT; 344228753Smm } 345228753Smm 346228753Smm bufnext = patbuf; 347228753Smm bufend = bufnext + GLOBBUFLEN; 348228753Smm compilebuf = bufnext; 349228753Smm compilepat = patnext; 350228753Smm 351228753Smm no_match = *patnext == not; 352228753Smm if (no_match) 353228753Smm patnext++; 354228753Smm 355228753Smm if (flags & GLOB_QUOTE) { 356228753Smm /* Protect the quoted characters */ 357228753Smm while (bufnext < bufend && (c = *patnext++) != EOS) 358228753Smm#ifdef DSPMBYTE 359228753Smm if (Ismbyte1(c) && *patnext != EOS) 360228753Smm { 361228753Smm *bufnext++ = (Char) c; 362228753Smm *bufnext++ = (Char) *patnext++; 363228753Smm } 364228753Smm else 365228753Smm#endif /* DSPMBYTE */ 366228753Smm if (c == QUOTE) { 367228753Smm if ((c = *patnext++) == EOS) { 368228753Smm c = QUOTE; 369228753Smm --patnext; 370228753Smm } 371228753Smm *bufnext++ = (Char) (c | M_PROTECT); 372228753Smm } 373228753Smm else 374228753Smm *bufnext++ = (Char) c; 375228753Smm } 376228753Smm else 377228753Smm while (bufnext < bufend && (c = *patnext++) != EOS) 378228753Smm *bufnext++ = (Char) c; 379228753Smm *bufnext = EOS; 380228753Smm 381228753Smm bufnext = patbuf; 382228753Smm qpatnext = patbuf; 383228753Smm /* we don't need to check for buffer overflow any more */ 384228753Smm while ((c = *qpatnext++) != EOS) { 385228753Smm#ifdef DSPMBYTE 386228753Smm if (Ismbyte1(c) && *qpatnext != EOS) 387228753Smm { 388228753Smm *bufnext++ = CHAR(c); 389228753Smm *bufnext++ = CHAR(*qpatnext++); 390228753Smm } 391228753Smm else 392228753Smm#endif /* DSPMBYTE */ 393228753Smm switch (c) { 394228753Smm case LBRACKET: 395228753Smm c = *qpatnext; 396228753Smm if (c == not) 397228753Smm ++qpatnext; 398228753Smm if (*qpatnext == EOS || 399228753Smm Strchr(qpatnext + 1, RBRACKET) == NULL) { 400228753Smm *bufnext++ = LBRACKET; 401228753Smm if (c == not) 402228753Smm --qpatnext; 403228753Smm break; 404228753Smm } 405228753Smm pglob->gl_flags |= GLOB_MAGCHAR; 406228753Smm *bufnext++ = M_SET; 407228753Smm if (c == not) 408228753Smm *bufnext++ = m_not; 409228753Smm c = *qpatnext++; 410228753Smm do { 411228753Smm *bufnext++ = CHAR(c); 412228753Smm if (*qpatnext == RANGE && 413228753Smm (c = qpatnext[1]) != RBRACKET) { 414228753Smm *bufnext++ = M_RNG; 415228753Smm *bufnext++ = CHAR(c); 416228753Smm qpatnext += 2; 417228753Smm } 418228753Smm } while ((c = *qpatnext++) != RBRACKET); 419228753Smm *bufnext++ = M_END; 420228753Smm break; 421228753Smm case QUESTION: 422228753Smm pglob->gl_flags |= GLOB_MAGCHAR; 423228753Smm *bufnext++ = M_ONE; 424228753Smm break; 425228753Smm case STAR: 426228753Smm pglob->gl_flags |= GLOB_MAGCHAR; 427228753Smm /* collapse adjacent stars to one, to avoid 428228753Smm * exponential behavior 429228753Smm */ 430228753Smm if (bufnext == patbuf || bufnext[-1] != M_ALL) 431228753Smm *bufnext++ = M_ALL; 432228753Smm break; 433228753Smm default: 434228753Smm *bufnext++ = CHAR(c); 435228753Smm break; 436228753Smm } 437228753Smm } 438228753Smm *bufnext = EOS; 439228753Smm#ifdef DEBUG 440228753Smm qprintf(patbuf); 441228753Smm#endif 442228753Smm 443228753Smm if ((err = glob1(patbuf, pglob, no_match)) != 0) 444228753Smm return (err); 445228753Smm 446228753Smm /* 447228753Smm * If there was no match we are going to append the pattern 448228753Smm * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 449228753Smm * and the pattern did not contain any magic characters 450228753Smm * GLOB_NOMAGIC is there just for compatibility with csh. 451228753Smm */ 452228753Smm if (pglob->gl_pathc == oldpathc && 453228753Smm ((flags & GLOB_NOCHECK) || 454228753Smm ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { 455228753Smm if (!(flags & GLOB_QUOTE)) { 456228753Smm Char *dp = compilebuf; 457228753Smm const unsigned char *sp = compilepat; 458228753Smm 459228753Smm while ((*dp++ = *sp++) != '\0') 460228753Smm continue; 461228753Smm } 462228753Smm else { 463228753Smm /* 464228753Smm * copy pattern, interpreting quotes; this is slightly different 465228753Smm * than the interpretation of quotes above -- which should prevail? 466228753Smm */ 467228753Smm while (*compilepat != EOS) { 468228753Smm if (*compilepat == QUOTE) { 469228753Smm if (*++compilepat == EOS) 470228753Smm --compilepat; 471228753Smm } 472228753Smm *compilebuf++ = (unsigned char) *compilepat++; 473228753Smm } 474228753Smm *compilebuf = EOS; 475228753Smm } 476228753Smm return (globextend(patbuf, pglob)); 477228753Smm } 478228753Smm else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc)) 479228753Smm qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc), 480228753Smm pglob->gl_pathc - oldpathc, sizeof(char *), 481228753Smm (int (*) __P((const void *, const void *))) compare); 482228753Smm return (0); 483228753Smm} 484228753Smm 485228753Smmstatic int 486228753Smmglob1(pattern, pglob, no_match) 487228753Smm Char *pattern; 488228753Smm glob_t *pglob; 489228753Smm int no_match; 490228753Smm{ 491228753Smm Char pathbuf[GLOBBUFLEN + 1]; 492228753Smm 493228753Smm /* 494228753Smm * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. 495228753Smm */ 496228753Smm if (*pattern == EOS) 497228753Smm return (0); 498228753Smm return (glob2(pathbuf, pathbuf, pattern, pglob, no_match)); 499228753Smm} 500228753Smm 501228753Smm/* 502228753Smm * functions glob2 and glob3 are mutually recursive; there is one level 503228753Smm * of recursion for each segment in the pattern that contains one or 504228753Smm * more meta characters. 505228753Smm */ 506228753Smmstatic int 507228753Smmglob2(pathbuf, pathend, pattern, pglob, no_match) 508228753Smm Char *pathbuf, *pathend, *pattern; 509228753Smm glob_t *pglob; 510228753Smm int no_match; 511228753Smm{ 512228753Smm struct stat sbuf; 513228753Smm int anymeta; 514228753Smm Char *p, *q; 515228753Smm 516228753Smm /* 517228753Smm * loop over pattern segments until end of pattern or until segment with 518228753Smm * meta character found. 519228753Smm */ 520228753Smm anymeta = 0; 521228753Smm for (;;) { 522228753Smm if (*pattern == EOS) { /* end of pattern? */ 523228753Smm *pathend = EOS; 524228753Smm 525228753Smm if (Lstat(pathbuf, &sbuf)) 526228753Smm return (0); 527228753Smm 528228753Smm if (((pglob->gl_flags & GLOB_MARK) && 529228753Smm pathend[-1] != SEP) && 530228753Smm (S_ISDIR(sbuf.st_mode) 531228753Smm#ifdef S_IFLNK 532228753Smm || (S_ISLNK(sbuf.st_mode) && 533228753Smm (Stat(pathbuf, &sbuf) == 0) && 534228753Smm S_ISDIR(sbuf.st_mode)) 535228753Smm#endif 536228753Smm )) { 537228753Smm *pathend++ = SEP; 538228753Smm *pathend = EOS; 539228753Smm } 540228753Smm ++pglob->gl_matchc; 541228753Smm return (globextend(pathbuf, pglob)); 542228753Smm } 543228753Smm 544228753Smm /* find end of next segment, copy tentatively to pathend */ 545228753Smm q = pathend; 546228753Smm p = pattern; 547228753Smm while (*p != EOS && *p != SEP) { 548228753Smm if (ismeta(*p)) 549228753Smm anymeta = 1; 550228753Smm *q++ = *p++; 551228753Smm } 552228753Smm 553228753Smm if (!anymeta) { /* no expansion, do next segment */ 554228753Smm pathend = q; 555228753Smm pattern = p; 556228753Smm while (*pattern == SEP) 557228753Smm *pathend++ = *pattern++; 558228753Smm } 559228753Smm else /* need expansion, recurse */ 560228753Smm return (glob3(pathbuf, pathend, pattern, p, pglob, no_match)); 561228753Smm } 562228753Smm /* NOTREACHED */ 563228753Smm} 564228753Smm 565228753Smm 566228753Smmstatic int 567228753Smmglob3(pathbuf, pathend, pattern, restpattern, pglob, no_match) 568228753Smm Char *pathbuf, *pathend, *pattern, *restpattern; 569228753Smm glob_t *pglob; 570228753Smm int no_match; 571228753Smm{ 572228753Smm DIR *dirp; 573228753Smm struct dirent *dp; 574228753Smm int err; 575228753Smm Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; 576228753Smm char cpathbuf[GLOBBUFLEN], *ptr;; 577228753Smm 578228753Smm *pathend = EOS; 579228753Smm errno = 0; 580228753Smm 581228753Smm if (!(dirp = Opendir(pathbuf))) { 582228753Smm /* todo: don't call for ENOENT or ENOTDIR? */ 583228753Smm for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;) 584228753Smm continue; 585228753Smm if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) || 586228753Smm (pglob->gl_flags & GLOB_ERR)) 587228753Smm return (GLOB_ABEND); 588228753Smm else 589228753Smm return (0); 590228753Smm } 591228753Smm 592228753Smm err = 0; 593228753Smm 594228753Smm /* search directory for matching names */ 595228753Smm while ((dp = readdir(dirp)) != NULL) { 596228753Smm register unsigned char *sc; 597228753Smm register Char *dc; 598228753Smm 599228753Smm /* initial DOT must be matched literally */ 600228753Smm if (dp->d_name[0] == DOT && *pattern != DOT) 601228753Smm continue; 602228753Smm for (sc = (unsigned char *) dp->d_name, dc = pathend; 603228753Smm (*dc++ = *sc++) != '\0';) 604228753Smm continue; 605228753Smm if (match(pathend, pattern, restpattern, (int) m_not) == no_match) { 606228753Smm *pathend = EOS; 607228753Smm continue; 608228753Smm } 609228753Smm err = glob2(pathbuf, --dc, restpattern, pglob, no_match); 610228753Smm if (err) 611228753Smm break; 612228753Smm } 613228753Smm /* todo: check error from readdir? */ 614228753Smm (void) closedir(dirp); 615228753Smm return (err); 616228753Smm} 617228753Smm 618228753Smm 619228753Smm/* 620228753Smm * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 621228753Smm * add the new item, and update gl_pathc. 622228753Smm * 623228753Smm * This assumes the BSD realloc, which only copies the block when its size 624228753Smm * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 625228753Smm * behavior. 626228753Smm * 627228753Smm * Return 0 if new item added, error code if memory couldn't be allocated. 628228753Smm * 629228753Smm * Invariant of the glob_t structure: 630228753Smm * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 631228753Smm * gl_pathv points to (gl_offs + gl_pathc + 1) items. 632228753Smm */ 633228753Smmstatic int 634228753Smmglobextend(path, pglob) 635228753Smm Char *path; 636228753Smm glob_t *pglob; 637228753Smm{ 638228753Smm register char **pathv; 639228753Smm register int i; 640228753Smm unsigned int newsize; 641228753Smm char *copy; 642228753Smm Char *p; 643228753Smm 644228753Smm newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 645228753Smm pathv = (char **) (pglob->gl_pathv ? 646228753Smm xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) : 647228753Smm xmalloc((size_t) newsize)); 648228753Smm if (pathv == NULL) 649228753Smm return (GLOB_NOSPACE); 650228753Smm 651228753Smm if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 652228753Smm /* first time around -- clear initial gl_offs items */ 653228753Smm pathv += pglob->gl_offs; 654228753Smm for (i = pglob->gl_offs; --i >= 0;) 655228753Smm *--pathv = NULL; 656228753Smm } 657228753Smm pglob->gl_pathv = pathv; 658228753Smm 659228753Smm for (p = path; *p++;) 660228753Smm continue; 661228753Smm if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) { 662228753Smm register char *dc = copy; 663228753Smm register Char *sc = path; 664228753Smm 665228753Smm while ((*dc++ = *sc++) != '\0') 666228753Smm continue; 667228753Smm pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 668228753Smm } 669228753Smm pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 670228753Smm return ((copy == NULL) ? GLOB_NOSPACE : 0); 671228753Smm} 672228753Smm 673228753Smm 674228753Smm/* 675228753Smm * pattern matching function for filenames. Each occurrence of the * 676228753Smm * pattern causes a recursion level. 677228753Smm */ 678228753Smmstatic int 679228753Smmmatch(name, pat, patend, m_not) 680228753Smm register Char *name, *pat, *patend; 681228753Smm int m_not; 682228753Smm{ 683228753Smm int ok, negate_range; 684228753Smm Char c, k; 685228753Smm 686228753Smm while (pat < patend) { 687228753Smm c = *pat++; 688228753Smm switch (c & M_MASK) { 689228753Smm case M_ALL: 690228753Smm if (pat == patend) 691228753Smm return (1); 692228753Smm do 693228753Smm if (match(name, pat, patend, m_not)) 694228753Smm return (1); 695228753Smm while (*name++ != EOS); 696228753Smm return (0); 697228753Smm case M_ONE: 698228753Smm if (*name++ == EOS) 699228753Smm return (0); 700228753Smm break; 701228753Smm case M_SET: 702228753Smm ok = 0; 703228753Smm if ((k = *name++) == EOS) 704228753Smm return (0); 705228753Smm if ((negate_range = ((*pat & M_MASK) == m_not)) != 0) 706228753Smm ++pat; 707228753Smm while (((c = *pat++) & M_MASK) != M_END) { 708228753Smm if ((*pat & M_MASK) == M_RNG) { 709228753Smm if (globcharcoll(CHAR(c), CHAR(k), 0) <= 0 && 710228753Smm globcharcoll(CHAR(k), CHAR(pat[1]), 0) <= 0) 711228753Smm ok = 1; 712228753Smm pat += 2; 713228753Smm } 714228753Smm else if (c == k) 715228753Smm ok = 1; 716228753Smm } 717228753Smm if (ok == negate_range) 718228753Smm return (0); 719228753Smm break; 720228753Smm default: 721228753Smm k = *name++; 722228753Smm if (samecase(k) != samecase(c)) 723228753Smm return (0); 724228753Smm break; 725228753Smm } 726228753Smm } 727228753Smm return (*name == EOS); 728228753Smm} 729228753Smm 730228753Smm/* free allocated data belonging to a glob_t structure */ 731228753Smmvoid 732228753Smmglobfree(pglob) 733228753Smm glob_t *pglob; 734228753Smm{ 735228753Smm register int i; 736228753Smm register char **pp; 737228753Smm 738228753Smm if (pglob->gl_pathv != NULL) { 739228753Smm pp = pglob->gl_pathv + pglob->gl_offs; 740228753Smm for (i = pglob->gl_pathc; i--; ++pp) 741228753Smm if (*pp) 742228753Smm xfree((ptr_t) *pp), *pp = NULL; 743228753Smm xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL; 744228753Smm } 745228753Smm} 746228753Smm