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