1 /* $OpenBSD: glob.c,v 1.12 2003/06/25 21:12:39 deraadt Exp $ */ 2 /* $NetBSD: glob.c,v 1.10 1995/03/21 09:03:01 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 static char rcsid[] = "$OpenBSD: glob.c,v 1.12 2003/06/25 21:12:39 deraadt Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <glob.h> 43 #include <errno.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <stdarg.h> 48 49 #include "csh.h" 50 #include "extern.h" 51 52 static int noglob; 53 static int pargsiz, gargsiz; 54 55 /* 56 * Values for gflag 57 */ 58 #define G_NONE 0 /* No globbing needed */ 59 #define G_GLOB 1 /* string contains *?[] characters */ 60 #define G_CSH 2 /* string contains ~`{ characters */ 61 62 #define GLOBSPACE 100 /* Alloc increment */ 63 64 #define LBRC '{' 65 #define RBRC '}' 66 #define LBRK '[' 67 #define RBRK ']' 68 #define EOS '\0' 69 70 Char **gargv = NULL; 71 long gargc = 0; 72 Char **pargv = NULL; 73 long pargc = 0; 74 75 /* 76 * globbing is now done in two stages. In the first pass we expand 77 * csh globbing idioms ~`{ and then we proceed doing the normal 78 * globbing if needed ?*[ 79 * 80 * Csh type globbing is handled in globexpand() and the rest is 81 * handled in glob() which is part of the 4.4BSD libc. 82 * 83 */ 84 static Char *globtilde(Char **, Char *); 85 static Char **libglob(Char **); 86 static Char **globexpand(Char **); 87 static int globbrace(Char *, Char *, Char ***); 88 static void expbrace(Char ***, Char ***, int); 89 static int pmatch(Char *, Char *); 90 static void pword(void); 91 static void psave(int); 92 static void backeval(Char *, bool); 93 94 95 static Char * 96 globtilde(Char **nv, Char *s) 97 { 98 Char gbuf[MAXPATHLEN], *gstart, *b, *u, *e; 99 100 gstart = gbuf; 101 *gstart++ = *s++; 102 u = s; 103 for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; 104 *s && *s != '/' && *s != ':' && b < e; 105 *b++ = *s++) 106 continue; 107 *b = EOS; 108 if (gethdir(gstart, &gbuf[sizeof(gbuf)/sizeof(Char)] - gstart)) { 109 blkfree(nv); 110 if (*gstart) 111 stderror(ERR_UNKUSER, vis_str(gstart)); 112 else 113 stderror(ERR_NOHOME); 114 } 115 b = &gstart[Strlen(gstart)]; 116 while (*s) 117 *b++ = *s++; 118 *b = EOS; 119 --u; 120 xfree((ptr_t) u); 121 return (Strsave(gstart)); 122 } 123 124 static int 125 globbrace(Char *s, Char *p, Char ***bl) 126 { 127 int i, len; 128 Char *pm, *pe, *lm, *pl; 129 Char **nv, **vl; 130 Char gbuf[MAXPATHLEN]; 131 int size = GLOBSPACE; 132 133 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); 134 *vl = NULL; 135 136 len = 0; 137 /* copy part up to the brace */ 138 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 139 continue; 140 141 /* check for balanced braces */ 142 for (i = 0, pe = ++p; *pe; pe++) 143 if (*pe == LBRK) { 144 /* Ignore everything between [] */ 145 for (++pe; *pe != RBRK && *pe != EOS; pe++) 146 continue; 147 if (*pe == EOS) { 148 blkfree(nv); 149 return (-RBRK); 150 } 151 } 152 else if (*pe == LBRC) 153 i++; 154 else if (*pe == RBRC) { 155 if (i == 0) 156 break; 157 i--; 158 } 159 160 if (i != 0 || *pe == '\0') { 161 blkfree(nv); 162 return (-RBRC); 163 } 164 165 for (i = 0, pl = pm = p; pm <= pe; pm++) 166 switch (*pm) { 167 case LBRK: 168 for (++pm; *pm != RBRK && *pm != EOS; pm++) 169 continue; 170 if (*pm == EOS) { 171 *vl = NULL; 172 blkfree(nv); 173 return (-RBRK); 174 } 175 break; 176 case LBRC: 177 i++; 178 break; 179 case RBRC: 180 if (i) { 181 i--; 182 break; 183 } 184 /* FALLTHROUGH */ 185 case ',': 186 if (i && *pm == ',') 187 break; 188 else { 189 Char savec = *pm; 190 191 *pm = EOS; 192 (void) Strlcpy(lm, pl, &gbuf[sizeof(gbuf)/sizeof(Char)] - lm); 193 (void) Strlcat(gbuf, pe + 1, MAXPATHLEN); 194 *pm = savec; 195 *vl++ = Strsave(gbuf); 196 len++; 197 pl = pm + 1; 198 if (vl == &nv[size]) { 199 size += GLOBSPACE; 200 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 201 size * sizeof(Char *)); 202 vl = &nv[size - GLOBSPACE]; 203 } 204 } 205 break; 206 default: 207 break; 208 } 209 *vl = NULL; 210 *bl = nv; 211 return (len); 212 } 213 214 215 static void 216 expbrace(Char ***nvp, Char ***elp, int size) 217 { 218 Char **vl, **el, **nv, *s; 219 220 vl = nv = *nvp; 221 if (elp != NULL) 222 el = *elp; 223 else 224 for (el = vl; *el; el++) 225 continue; 226 227 for (s = *vl; s; s = *++vl) { 228 Char *b; 229 Char **vp, **bp; 230 231 /* leave {} untouched for find */ 232 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 233 continue; 234 if ((b = Strchr(s, '{')) != NULL) { 235 Char **bl; 236 int len; 237 238 if ((len = globbrace(s, b, &bl)) < 0) { 239 xfree((ptr_t) nv); 240 stderror(ERR_MISSING, -len); 241 } 242 xfree((ptr_t) s); 243 if (len == 1) { 244 *vl-- = *bl; 245 xfree((ptr_t) bl); 246 continue; 247 } 248 len = blklen(bl); 249 if (&el[len] >= &nv[size]) { 250 int l, e; 251 252 l = &el[len] - &nv[size]; 253 size += GLOBSPACE > l ? GLOBSPACE : l; 254 l = vl - nv; 255 e = el - nv; 256 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 257 size * sizeof(Char *)); 258 vl = nv + l; 259 el = nv + e; 260 } 261 vp = vl--; 262 *vp = *bl; 263 len--; 264 for (bp = el; bp != vp; bp--) 265 bp[len] = *bp; 266 el += len; 267 vp++; 268 for (bp = bl + 1; *bp; *vp++ = *bp++) 269 continue; 270 xfree((ptr_t) bl); 271 } 272 273 } 274 if (elp != NULL) 275 *elp = el; 276 *nvp = nv; 277 } 278 279 static Char ** 280 globexpand(Char **v) 281 { 282 Char *s; 283 Char **nv, **vl, **el; 284 int size = GLOBSPACE; 285 286 287 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); 288 *vl = NULL; 289 290 /* 291 * Step 1: expand backquotes. 292 */ 293 while ((s = *v++) != NULL) { 294 if (Strchr(s, '`')) { 295 int i; 296 297 (void) dobackp(s, 0); 298 for (i = 0; i < pargc; i++) { 299 *vl++ = pargv[i]; 300 if (vl == &nv[size]) { 301 size += GLOBSPACE; 302 nv = (Char **) xrealloc((ptr_t) nv, 303 (size_t) size * sizeof(Char *)); 304 vl = &nv[size - GLOBSPACE]; 305 } 306 } 307 xfree((ptr_t) pargv); 308 pargv = NULL; 309 } 310 else { 311 *vl++ = Strsave(s); 312 if (vl == &nv[size]) { 313 size += GLOBSPACE; 314 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 315 size * sizeof(Char *)); 316 vl = &nv[size - GLOBSPACE]; 317 } 318 } 319 } 320 *vl = NULL; 321 322 if (noglob) 323 return (nv); 324 325 /* 326 * Step 2: expand braces 327 */ 328 el = vl; 329 expbrace(&nv, &el, size); 330 331 /* 332 * Step 3: expand ~ 333 */ 334 vl = nv; 335 for (s = *vl; s; s = *++vl) 336 if (*s == '~') 337 *vl = globtilde(nv, s); 338 vl = nv; 339 return (vl); 340 } 341 342 static Char * 343 handleone(Char *str, Char **vl, int action) 344 { 345 346 Char *cp, **vlp = vl; 347 348 switch (action) { 349 case G_ERROR: 350 setname(vis_str(str)); 351 blkfree(vl); 352 stderror(ERR_NAME | ERR_AMBIG); 353 break; 354 case G_APPEND: 355 trim(vlp); 356 str = Strsave(*vlp++); 357 do { 358 cp = Strspl(str, STRspace); 359 xfree((ptr_t) str); 360 str = Strspl(cp, *vlp); 361 xfree((ptr_t) cp); 362 } 363 while (*++vlp) 364 ; 365 blkfree(vl); 366 break; 367 case G_IGNORE: 368 str = Strsave(strip(*vlp)); 369 blkfree(vl); 370 break; 371 default: 372 break; 373 } 374 return (str); 375 } 376 377 static Char ** 378 libglob(Char **vl) 379 { 380 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC; 381 glob_t globv; 382 char *ptr; 383 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 384 385 if (!vl || !vl[0]) 386 return (vl); 387 388 globv.gl_offs = 0; 389 globv.gl_pathv = 0; 390 globv.gl_pathc = 0; 391 392 if (nonomatch) 393 gflgs |= GLOB_NOCHECK; 394 395 do { 396 ptr = short2qstr(*vl); 397 switch (glob(ptr, gflgs, 0, &globv)) { 398 case GLOB_ABORTED: 399 setname(vis_str(*vl)); 400 stderror(ERR_NAME | ERR_GLOB); 401 /* NOTREACHED */ 402 case GLOB_NOSPACE: 403 stderror(ERR_NOMEM); 404 /* NOTREACHED */ 405 default: 406 break; 407 } 408 if (globv.gl_flags & GLOB_MAGCHAR) { 409 match |= (globv.gl_matchc != 0); 410 magic = 1; 411 } 412 gflgs |= GLOB_APPEND; 413 } 414 while (*++vl) 415 ; 416 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 417 NULL : blk2short(globv.gl_pathv); 418 globfree(&globv); 419 return (vl); 420 } 421 422 Char * 423 globone(Char *str, int action) 424 { 425 Char *v[2], **vl, **vo; 426 int gflg; 427 428 noglob = adrof(STRnoglob) != 0; 429 gflag = 0; 430 v[0] = str; 431 v[1] = 0; 432 tglob(v); 433 gflg = gflag; 434 if (gflg == G_NONE) 435 return (strip(Strsave(str))); 436 437 if (gflg & G_CSH) { 438 /* 439 * Expand back-quote, tilde and brace 440 */ 441 vo = globexpand(v); 442 if (noglob || (gflg & G_GLOB) == 0) { 443 if (vo[0] == NULL) { 444 xfree((ptr_t) vo); 445 return (Strsave(STRNULL)); 446 } 447 if (vo[1] != NULL) 448 return (handleone(str, vo, action)); 449 else { 450 str = strip(vo[0]); 451 xfree((ptr_t) vo); 452 return (str); 453 } 454 } 455 } 456 else if (noglob || (gflg & G_GLOB) == 0) 457 return (strip(Strsave(str))); 458 else 459 vo = v; 460 461 vl = libglob(vo); 462 if ((gflg & G_CSH) && vl != vo) 463 blkfree(vo); 464 if (vl == NULL) { 465 setname(vis_str(str)); 466 stderror(ERR_NAME | ERR_NOMATCH); 467 } 468 if (vl[0] == NULL) { 469 xfree((ptr_t) vl); 470 return (Strsave(STRNULL)); 471 } 472 if (vl[1] != NULL) 473 return (handleone(str, vl, action)); 474 else { 475 str = strip(*vl); 476 xfree((ptr_t) vl); 477 return (str); 478 } 479 } 480 481 Char ** 482 globall(Char **v) 483 { 484 Char **vl, **vo; 485 int gflg = gflag; 486 487 if (!v || !v[0]) { 488 gargv = saveblk(v); 489 gargc = blklen(gargv); 490 return (gargv); 491 } 492 493 noglob = adrof(STRnoglob) != 0; 494 495 if (gflg & G_CSH) 496 /* 497 * Expand back-quote, tilde and brace 498 */ 499 vl = vo = globexpand(v); 500 else 501 vl = vo = saveblk(v); 502 503 if (!noglob && (gflg & G_GLOB)) { 504 vl = libglob(vo); 505 if ((gflg & G_CSH) && vl != vo) 506 blkfree(vo); 507 } 508 else 509 trim(vl); 510 511 gargc = vl ? blklen(vl) : 0; 512 return (gargv = vl); 513 } 514 515 void 516 ginit(void) 517 { 518 gargsiz = GLOBSPACE; 519 gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz); 520 gargv[0] = 0; 521 gargc = 0; 522 } 523 524 void 525 rscan(Char **t, void (*f)(int)) 526 { 527 Char *p; 528 529 while ((p = *t++) != NULL) 530 while (*p) 531 (*f) (*p++); 532 } 533 534 void 535 trim(Char **t) 536 { 537 Char *p; 538 539 while ((p = *t++) != NULL) 540 while (*p) 541 *p++ &= TRIM; 542 } 543 544 void 545 tglob(Char **t) 546 { 547 Char *p, c; 548 549 while ((p = *t++) != NULL) { 550 if (*p == '~' || *p == '=') 551 gflag |= G_CSH; 552 else if (*p == '{' && 553 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 554 continue; 555 while ((c = *p++) != '\0') { 556 /* 557 * eat everything inside the matching backquotes 558 */ 559 if (c == '`') { 560 gflag |= G_CSH; 561 while (*p && *p != '`') 562 if (*p++ == '\\') { 563 if (*p) /* Quoted chars */ 564 p++; 565 else 566 break; 567 } 568 if (*p) /* The matching ` */ 569 p++; 570 else 571 break; 572 } 573 else if (c == '{') 574 gflag |= G_CSH; 575 else if (isglob(c)) 576 gflag |= G_GLOB; 577 } 578 } 579 } 580 581 /* 582 * Command substitute cp. If literal, then this is a substitution from a 583 * << redirection, and so we should not crunch blanks and tabs, separating 584 * words only at newlines. 585 */ 586 Char ** 587 dobackp(Char *cp, bool literal) 588 { 589 Char *lp, *rp; 590 Char *ep, word[MAXPATHLEN]; 591 592 if (pargv) { 593 #ifdef notdef 594 abort(); 595 #endif 596 blkfree(pargv); 597 } 598 pargsiz = GLOBSPACE; 599 pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz); 600 pargv[0] = NULL; 601 pargcp = pargs = word; 602 pargc = 0; 603 pnleft = MAXPATHLEN - 4; 604 for (;;) { 605 for (lp = cp; *lp != '`'; lp++) { 606 if (*lp == 0) { 607 if (pargcp != pargs) 608 pword(); 609 return (pargv); 610 } 611 psave(*lp); 612 } 613 lp++; 614 for (rp = lp; *rp && *rp != '`'; rp++) 615 if (*rp == '\\') { 616 rp++; 617 if (!*rp) 618 goto oops; 619 } 620 if (!*rp) 621 oops: stderror(ERR_UNMATCHED, '`'); 622 ep = Strsave(lp); 623 ep[rp - lp] = 0; 624 backeval(ep, literal); 625 cp = rp + 1; 626 } 627 } 628 629 static void 630 backeval(Char *cp, bool literal) 631 { 632 int icnt, c; 633 Char *ip; 634 struct command faket; 635 bool hadnl; 636 int pvec[2], quoted; 637 Char *fakecom[2], ibuf[BUFSIZ]; 638 char tibuf[BUFSIZ]; 639 640 hadnl = 0; 641 icnt = 0; 642 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 643 faket.t_dtyp = NODE_COMMAND; 644 faket.t_dflg = 0; 645 faket.t_dlef = 0; 646 faket.t_drit = 0; 647 faket.t_dspr = 0; 648 faket.t_dcom = fakecom; 649 fakecom[0] = STRfakecom1; 650 fakecom[1] = 0; 651 652 /* 653 * We do the psave job to temporarily change the current job so that the 654 * following fork is considered a separate job. This is so that when 655 * backquotes are used in a builtin function that calls glob the "current 656 * job" is not corrupted. We only need one level of pushed jobs as long as 657 * we are sure to fork here. 658 */ 659 psavejob(); 660 661 /* 662 * It would be nicer if we could integrate this redirection more with the 663 * routines in sh.sem.c by doing a fake execute on a builtin function that 664 * was piped out. 665 */ 666 mypipe(pvec); 667 if (pfork(&faket, -1) == 0) { 668 struct wordent paraml; 669 struct command *t; 670 671 (void) close(pvec[0]); 672 (void) dmove(pvec[1], 1); 673 (void) dmove(SHERR, 2); 674 initdesc(); 675 /* 676 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 677 * posted to comp.bugs.4bsd 12 Sep. 1989. 678 */ 679 if (pargv) /* mg, 21.dec.88 */ 680 blkfree(pargv), pargv = 0, pargsiz = 0; 681 /* mg, 21.dec.88 */ 682 arginp = cp; 683 while (*cp) 684 *cp++ &= TRIM; 685 686 /* 687 * In the child ``forget'' everything about current aliases or 688 * eval vectors. 689 */ 690 alvec = NULL; 691 evalvec = NULL; 692 alvecp = NULL; 693 evalp = NULL; 694 (void) lex(¶ml); 695 if (seterr) 696 stderror(ERR_OLD); 697 alias(¶ml); 698 t = syntax(paraml.next, ¶ml, 0); 699 if (seterr) 700 stderror(ERR_OLD); 701 if (t) 702 t->t_dflg |= F_NOFORK; 703 (void) signal(SIGTSTP, SIG_IGN); 704 (void) signal(SIGTTIN, SIG_IGN); 705 (void) signal(SIGTTOU, SIG_IGN); 706 execute(t, -1, NULL, NULL); 707 exitstat(); 708 } 709 xfree((ptr_t) cp); 710 (void) close(pvec[1]); 711 c = 0; 712 ip = NULL; 713 do { 714 int cnt = 0; 715 716 for (;;) { 717 if (icnt == 0) { 718 int i; 719 720 ip = ibuf; 721 do 722 icnt = read(pvec[0], tibuf, BUFSIZ); 723 while (icnt == -1 && errno == EINTR); 724 if (icnt <= 0) { 725 c = -1; 726 break; 727 } 728 for (i = 0; i < icnt; i++) 729 ip[i] = (unsigned char) tibuf[i]; 730 } 731 if (hadnl) 732 break; 733 --icnt; 734 c = (*ip++ & TRIM); 735 if (c == 0) 736 break; 737 if (c == '\n') { 738 /* 739 * Continue around the loop one more time, so that we can eat 740 * the last newline without terminating this word. 741 */ 742 hadnl = 1; 743 continue; 744 } 745 if (!quoted && (c == ' ' || c == '\t')) 746 break; 747 cnt++; 748 psave(c | quoted); 749 } 750 /* 751 * Unless at end-of-file, we will form a new word here if there were 752 * characters in the word, or in any case when we take text literally. 753 * If we didn't make empty words here when literal was set then we 754 * would lose blank lines. 755 */ 756 if (c != -1 && (cnt || literal)) 757 pword(); 758 hadnl = 0; 759 } while (c >= 0); 760 (void) close(pvec[0]); 761 pwait(); 762 prestjob(); 763 } 764 765 static void 766 psave(int c) 767 { 768 if (--pnleft <= 0) 769 stderror(ERR_WTOOLONG); 770 *pargcp++ = c; 771 } 772 773 static void 774 pword(void) 775 { 776 psave(0); 777 if (pargc == pargsiz - 1) { 778 pargsiz += GLOBSPACE; 779 pargv = (Char **) xrealloc((ptr_t) pargv, 780 (size_t) pargsiz * sizeof(Char *)); 781 } 782 pargv[pargc++] = Strsave(pargs); 783 pargv[pargc] = NULL; 784 pargcp = pargs; 785 pnleft = MAXPATHLEN - 4; 786 } 787 788 int 789 Gmatch(Char *string, Char *pattern) 790 { 791 Char **blk, **p; 792 int gpol = 1, gres = 0; 793 794 if (*pattern == '^') { 795 gpol = 0; 796 pattern++; 797 } 798 799 blk = (Char **) xmalloc(GLOBSPACE * sizeof(Char *)); 800 blk[0] = Strsave(pattern); 801 blk[1] = NULL; 802 803 expbrace(&blk, NULL, GLOBSPACE); 804 805 for (p = blk; *p; p++) 806 gres |= pmatch(string, *p); 807 808 blkfree(blk); 809 return(gres == gpol); 810 } 811 812 static int 813 pmatch(Char *string, Char *pattern) 814 { 815 Char stringc, patternc; 816 int match, negate_range; 817 Char rangec; 818 819 for (;; ++string) { 820 stringc = *string & TRIM; 821 patternc = *pattern++; 822 switch (patternc) { 823 case 0: 824 return (stringc == 0); 825 case '?': 826 if (stringc == 0) 827 return (0); 828 break; 829 case '*': 830 if (!*pattern) 831 return (1); 832 while (*string) 833 if (Gmatch(string++, pattern)) 834 return (1); 835 return (0); 836 case '[': 837 match = 0; 838 if ((negate_range = (*pattern == '^')) != 0) 839 pattern++; 840 while ((rangec = *pattern++) != '\0') { 841 if (rangec == ']') 842 break; 843 if (match) 844 continue; 845 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 846 match = (stringc <= (*pattern & TRIM) && 847 (*(pattern-2) & TRIM) <= stringc); 848 pattern++; 849 } 850 else 851 match = (stringc == (rangec & TRIM)); 852 } 853 if (rangec == 0) 854 stderror(ERR_NAME | ERR_MISSING, ']'); 855 if (match == negate_range) 856 return (0); 857 break; 858 default: 859 if ((patternc & TRIM) != stringc) 860 return (0); 861 break; 862 863 } 864 } 865 } 866 867 void 868 Gcat(Char *s1, Char *s2) 869 { 870 Char *p, *q; 871 int n; 872 873 for (p = s1; *p++;) 874 continue; 875 for (q = s2; *q++;) 876 continue; 877 n = (p - s1) + (q - s2) - 1; 878 if (++gargc >= gargsiz) { 879 gargsiz += GLOBSPACE; 880 gargv = (Char **) xrealloc((ptr_t) gargv, 881 (size_t) gargsiz * sizeof(Char *)); 882 } 883 gargv[gargc] = 0; 884 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char)); 885 for (q = s1; (*p++ = *q++) != '\0';) 886 continue; 887 for (p--, q = s2; (*p++ = *q++) != '\0';) 888 continue; 889 } 890 891 #ifdef FILEC 892 int 893 sortscmp(ptr_t a, ptr_t b) 894 { 895 #if defined(NLS) && !defined(NOSTRCOLL) 896 char buf[2048]; 897 #endif 898 899 if (!a) /* check for NULL */ 900 return (b ? 1 : 0); 901 if (!b) 902 return (-1); 903 904 if (!*(Char **)a) /* check for NULL */ 905 return (*(Char **)b ? 1 : 0); 906 if (!*(Char **)b) 907 return (-1); 908 909 #if defined(NLS) && !defined(NOSTRCOLL) 910 (void) strlcpy(buf, short2str(*(Char **)a), sizeof buf); 911 return ((int) strcoll(buf, short2str(*(Char **)b))); 912 #else 913 return ((int) Strcmp(*(Char **)a, *(Char **)b)); 914 #endif 915 } 916 #endif /* FILEC */ 917