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