1 /* $NetBSD: glob.c,v 1.27 2013/07/16 17:47:43 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 __RCSID("$NetBSD: glob.c,v 1.27 2013/07/16 17:47:43 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 43 #include <errno.h> 44 #include <glob.h> 45 #include <stdarg.h> 46 #include <stddef.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "csh.h" 52 #include "extern.h" 53 54 static int noglob; 55 static int gargsiz, pargsiz; 56 57 /* 58 * Values for gflag 59 */ 60 #define G_NONE 0 /* No globbing needed */ 61 #define G_GLOB 1 /* string contains *?[] characters */ 62 #define G_CSH 2 /* string contains ~`{ characters */ 63 64 #define GLOBSPACE 100 /* Alloc increment */ 65 66 #define LBRC '{' 67 #define RBRC '}' 68 #define LBRK '[' 69 #define RBRK ']' 70 #define EOS '\0' 71 72 Char **gargv = NULL; 73 Char **pargv = NULL; 74 long gargc = 0; 75 long pargc = 0; 76 77 /* 78 * globbing is now done in two stages. In the first pass we expand 79 * csh globbing idioms ~`{ and then we proceed doing the normal 80 * globbing if needed ?*[ 81 * 82 * Csh type globbing is handled in globexpand() and the rest is 83 * handled in glob() which is part of the 4.4BSD libc. 84 * 85 */ 86 static Char *globtilde(Char **, Char *); 87 static Char *handleone(Char *, Char **, int); 88 static Char **libglob(Char **); 89 static Char **globexpand(Char **); 90 static int globbrace(Char *, Char *, Char ***); 91 static void expbrace(Char ***, Char ***, size_t); 92 static int pmatch(Char *, Char *); 93 static void pword(void); 94 static void psave(int); 95 static void backeval(Char *, int); 96 97 static Char * 98 globtilde(Char **nv, Char *s) 99 { 100 Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u; 101 102 gstart = gbuf; 103 *gstart++ = *s++; 104 u = s; 105 for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; 106 *s && *s != '/' && *s != ':' && b < e; 107 *b++ = *s++) 108 continue; 109 *b = EOS; 110 if (gethdir(gstart)) { 111 blkfree(nv); 112 if (*gstart) 113 stderror(ERR_UNKUSER, vis_str(gstart)); 114 else 115 stderror(ERR_NOHOME); 116 } 117 b = &gstart[Strlen(gstart)]; 118 while (*s) 119 *b++ = *s++; 120 *b = EOS; 121 --u; 122 xfree((ptr_t) u); 123 return (Strsave(gstart)); 124 } 125 126 static int 127 globbrace(Char *s, Char *p, Char ***bl) 128 { 129 Char gbuf[MAXPATHLEN]; 130 Char *lm, *pe, *pl, *pm, **nv, **vl; 131 int i, len, size; 132 133 size = GLOBSPACE; 134 nv = vl = xmalloc(sizeof(Char *) * (size_t)size); 135 *vl = NULL; 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)Strcpy(lm, pl); 193 (void)Strcat(gbuf, pe + 1); 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, 201 (size_t)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 static void 215 expbrace(Char ***nvp, Char ***elp, size_t size) 216 { 217 Char **ex, **nv, *s, **vl; 218 219 vl = nv = *nvp; 220 if (elp != NULL) 221 ex = *elp; 222 else 223 for (ex = vl; *ex; ex++) 224 continue; 225 226 for (s = *vl; s; s = *++vl) { 227 Char *b, **bp, **vp; 228 229 /* leave {} untouched for find */ 230 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 231 continue; 232 if ((b = Strchr(s, '{')) != NULL) { 233 Char **bl; 234 int len; 235 236 if ((len = globbrace(s, b, &bl)) < 0) { 237 xfree((ptr_t)nv); 238 stderror(ERR_MISSING, -len); 239 } 240 xfree((ptr_t) s); 241 if (len == 1) { 242 *vl-- = *bl; 243 xfree((ptr_t) bl); 244 continue; 245 } 246 len = blklen(bl); 247 if (&ex[len] >= &nv[size]) { 248 ptrdiff_t l, e; 249 250 l = &ex[len] - &nv[size]; 251 size += (size_t)(GLOBSPACE > l ? GLOBSPACE : l); 252 l = vl - nv; 253 e = ex - nv; 254 nv = (Char **)xrealloc((ptr_t)nv, 255 (size_t)size * sizeof(Char *)); 256 vl = nv + l; 257 ex = nv + e; 258 } 259 vp = vl--; 260 *vp = *bl; 261 len--; 262 for (bp = ex; bp != vp; bp--) 263 bp[len] = *bp; 264 ex += len; 265 vp++; 266 for (bp = bl + 1; *bp; *vp++ = *bp++) 267 continue; 268 xfree((ptr_t)bl); 269 } 270 271 } 272 if (elp != NULL) 273 *elp = ex; 274 *nvp = nv; 275 } 276 277 static Char ** 278 globexpand(Char **v) 279 { 280 Char **ex, **nv, *s, **vl; 281 size_t size; 282 283 size = GLOBSPACE; 284 nv = vl = xmalloc(sizeof(Char *) * size); 285 *vl = NULL; 286 287 /* 288 * Step 1: expand backquotes. 289 */ 290 while ((s = *v++) != NULL) { 291 if (Strchr(s, '`')) { 292 int i; 293 294 (void) dobackp(s, 0); 295 for (i = 0; i < pargc; i++) { 296 *vl++ = pargv[i]; 297 if (vl == &nv[size]) { 298 size += GLOBSPACE; 299 nv = (Char **)xrealloc((ptr_t) nv, 300 (size_t)size * sizeof(Char *)); 301 vl = &nv[size - GLOBSPACE]; 302 } 303 } 304 xfree((ptr_t)pargv); 305 pargv = NULL; 306 } 307 else { 308 *vl++ = Strsave(s); 309 if (vl == &nv[size]) { 310 size += GLOBSPACE; 311 nv = (Char **)xrealloc((ptr_t)nv, 312 size * sizeof(Char *)); 313 vl = &nv[size - GLOBSPACE]; 314 } 315 } 316 } 317 *vl = NULL; 318 319 if (noglob) 320 return (nv); 321 322 /* 323 * Step 2: expand braces 324 */ 325 ex = vl; 326 expbrace(&nv, &ex, size); 327 328 /* 329 * Step 3: expand ~ 330 */ 331 vl = nv; 332 for (s = *vl; s; s = *++vl) 333 if (*s == '~') 334 *vl = globtilde(nv, s); 335 vl = nv; 336 return (vl); 337 } 338 339 static Char * 340 handleone(Char *str, Char **vl, int action) 341 { 342 Char *cp, **vlp; 343 344 vlp = vl; 345 switch (action) { 346 case G_ERROR: 347 setname(vis_str(str)); 348 blkfree(vl); 349 stderror(ERR_NAME | ERR_AMBIG); 350 /* NOTREACHED */ 351 case G_APPEND: 352 trim(vlp); 353 str = Strsave(*vlp++); 354 do { 355 cp = Strspl(str, STRspace); 356 xfree((ptr_t)str); 357 str = Strspl(cp, *vlp); 358 xfree((ptr_t)cp); 359 } 360 while (*++vlp); 361 blkfree(vl); 362 break; 363 case G_IGNORE: 364 str = Strsave(strip(*vlp)); 365 blkfree(vl); 366 break; 367 default: 368 break; 369 } 370 return (str); 371 } 372 373 static Char ** 374 libglob(Char **vl) 375 { 376 glob_t globv; 377 char *ptr; 378 int gflgs, magic, match, nonomatch; 379 380 gflgs = GLOB_NOMAGIC; 381 magic = 0; 382 match = 0; 383 nonomatch = adrof(STRnonomatch) != 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 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 416 NULL : blk2short(globv.gl_pathv); 417 globfree(&globv); 418 return (vl); 419 } 420 421 Char * 422 globone(Char *str, int action) 423 { 424 Char *v[2], **vl, **vo; 425 int gflg; 426 427 noglob = adrof(STRnoglob) != 0; 428 gflag = 0; 429 v[0] = str; 430 v[1] = 0; 431 tglob(v); 432 gflg = gflag; 433 if (gflg == G_NONE) 434 return (strip(Strsave(str))); 435 436 if (gflg & G_CSH) { 437 /* 438 * Expand back-quote, tilde and brace 439 */ 440 vo = globexpand(v); 441 if (noglob || (gflg & G_GLOB) == 0) { 442 if (vo[0] == NULL) { 443 xfree((ptr_t)vo); 444 return (Strsave(STRNULL)); 445 } 446 if (vo[1] != NULL) 447 return (handleone(str, vo, action)); 448 else { 449 str = strip(vo[0]); 450 xfree((ptr_t) vo); 451 return (str); 452 } 453 } 454 } 455 else if (noglob || (gflg & G_GLOB) == 0) 456 return (strip(Strsave(str))); 457 else 458 vo = v; 459 460 vl = libglob(vo); 461 if ((gflg & G_CSH) && vl != vo) 462 blkfree(vo); 463 if (vl == NULL) { 464 setname(vis_str(str)); 465 stderror(ERR_NAME | ERR_NOMATCH); 466 } 467 if (vl[0] == NULL) { 468 xfree((ptr_t)vl); 469 return (Strsave(STRNULL)); 470 } 471 if (vl[1] != NULL) 472 return (handleone(str, vl, action)); 473 else { 474 str = strip(*vl); 475 xfree((ptr_t)vl); 476 return (str); 477 } 478 } 479 480 Char ** 481 globall(Char **v) 482 { 483 Char **vl, **vo; 484 int gflg; 485 486 gflg = gflag; 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 = xmalloc(sizeof(Char *) * (size_t)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, int literal) 588 { 589 Char word[MAXPATHLEN], *ep, *lp, *rp; 590 591 if (pargv) { 592 #ifdef notdef 593 abort(); 594 #endif 595 blkfree(pargv); 596 } 597 pargsiz = GLOBSPACE; 598 pargv = xmalloc(sizeof(Char *) * (size_t)pargsiz); 599 pargv[0] = NULL; 600 pargcp = pargs = word; 601 pargc = 0; 602 pnleft = MAXPATHLEN - 4; 603 for (;;) { 604 for (lp = cp; *lp != '`'; lp++) { 605 if (*lp == 0) { 606 if (pargcp != pargs) 607 pword(); 608 return (pargv); 609 } 610 psave(*lp); 611 } 612 lp++; 613 for (rp = lp; *rp && *rp != '`'; rp++) 614 if (*rp == '\\') { 615 rp++; 616 if (!*rp) 617 goto oops; 618 } 619 if (!*rp) { 620 oops: 621 stderror(ERR_UNMATCHED, '`'); 622 } 623 ep = Strsave(lp); 624 ep[rp - lp] = 0; 625 backeval(ep, literal); 626 cp = rp + 1; 627 } 628 } 629 630 static void 631 backeval(Char *cp, int literal) 632 { 633 struct command faket; 634 char tibuf[BUFSIZE]; 635 Char ibuf[BUFSIZE], *fakecom[2], *ip; 636 int pvec[2], c, quoted; 637 ssize_t icnt; 638 int hadnl; 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 fparaml; 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 for (arginp = cp; *cp; cp++) { 684 *cp &= TRIM; 685 if (*cp == '\n' || *cp == '\r') 686 *cp = ';'; 687 } 688 689 /* 690 * In the child ``forget'' everything about current aliases or 691 * eval vectors. 692 */ 693 alvec = NULL; 694 evalvec = NULL; 695 alvecp = NULL; 696 evalp = NULL; 697 (void) lex(&fparaml); 698 if (seterr) 699 stderror(ERR_OLD); 700 alias(&fparaml); 701 t = syntax(fparaml.next, &fparaml, 0); 702 if (seterr) 703 stderror(ERR_OLD); 704 if (t) 705 t->t_dflg |= F_NOFORK; 706 (void)signal(SIGTSTP, SIG_IGN); 707 (void)signal(SIGTTIN, SIG_IGN); 708 (void)signal(SIGTTOU, SIG_IGN); 709 execute(t, -1, NULL, NULL); 710 exitstat(); 711 } 712 xfree((ptr_t)cp); 713 (void)close(pvec[1]); 714 c = 0; 715 ip = NULL; 716 do { 717 int cnt; 718 719 cnt = 0; 720 721 for (;;) { 722 if (icnt == 0) { 723 int i; 724 725 ip = ibuf; 726 do 727 icnt = read(pvec[0], tibuf, BUFSIZE); 728 while (icnt == -1 && errno == EINTR); 729 if (icnt <= 0) { 730 c = -1; 731 break; 732 } 733 for (i = 0; i < icnt; i++) 734 ip[i] = (unsigned char) tibuf[i]; 735 } 736 if (hadnl) 737 break; 738 --icnt; 739 c = (*ip++ & TRIM); 740 if (c == 0) 741 break; 742 if (c == '\n') { 743 /* 744 * Continue around the loop one more time, so that we can eat 745 * the last newline without terminating this word. 746 */ 747 hadnl = 1; 748 continue; 749 } 750 if (!quoted && (c == ' ' || c == '\t')) 751 break; 752 cnt++; 753 psave(c | quoted); 754 } 755 /* 756 * Unless at end-of-file, we will form a new word here if there were 757 * characters in the word, or in any case when we take text literally. 758 * If we didn't make empty words here when literal was set then we 759 * would lose blank lines. 760 */ 761 if (c != -1 && (cnt || literal)) 762 pword(); 763 hadnl = 0; 764 } while (c >= 0); 765 (void)close(pvec[0]); 766 pwait(); 767 prestjob(); 768 } 769 770 static void 771 psave(int c) 772 { 773 if (--pnleft <= 0) 774 stderror(ERR_WTOOLONG); 775 *pargcp++ = (Char)c; 776 } 777 778 static void 779 pword(void) 780 { 781 psave(0); 782 if (pargc == pargsiz - 1) { 783 pargsiz += GLOBSPACE; 784 pargv = (Char **)xrealloc((ptr_t)pargv, 785 (size_t)pargsiz * sizeof(Char *)); 786 } 787 pargv[pargc++] = Strsave(pargs); 788 pargv[pargc] = NULL; 789 pargcp = pargs; 790 pnleft = MAXPATHLEN - 4; 791 } 792 793 int 794 Gmatch(Char *string, Char *pattern) 795 { 796 Char **blk, **p; 797 int gpol, gres; 798 799 gpol = 1; 800 gres = 0; 801 802 if (*pattern == '^') { 803 gpol = 0; 804 pattern++; 805 } 806 807 blk = xmalloc(GLOBSPACE * sizeof(Char *)); 808 blk[0] = Strsave(pattern); 809 blk[1] = NULL; 810 811 expbrace(&blk, NULL, GLOBSPACE); 812 813 for (p = blk; *p; p++) 814 gres |= pmatch(string, *p); 815 816 blkfree(blk); 817 return(gres == gpol); 818 } 819 820 static int 821 pmatch(Char *string, Char *pattern) 822 { 823 int match, negate_range; 824 Char patternc, rangec, stringc; 825 826 for (;; ++string) { 827 stringc = *string & TRIM; 828 patternc = *pattern++; 829 switch (patternc) { 830 case 0: 831 return (stringc == 0); 832 case '?': 833 if (stringc == 0) 834 return (0); 835 break; 836 case '*': 837 if (!*pattern) 838 return (1); 839 while (*string) 840 if (Gmatch(string++, pattern)) 841 return (1); 842 return (0); 843 case '[': 844 match = 0; 845 if ((negate_range = (*pattern == '^')) != 0) 846 pattern++; 847 while ((rangec = *pattern++) != '\0') { 848 if (rangec == ']') 849 break; 850 if (match) 851 continue; 852 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 853 match = (stringc <= (*pattern & TRIM) && 854 (*(pattern-2) & TRIM) <= stringc); 855 pattern++; 856 } 857 else 858 match = (stringc == (rangec & TRIM)); 859 } 860 if (rangec == 0) 861 stderror(ERR_NAME | ERR_MISSING, ']'); 862 if (match == negate_range) 863 return (0); 864 break; 865 default: 866 if ((patternc & TRIM) != stringc) 867 return (0); 868 break; 869 870 } 871 } 872 } 873 874 void 875 Gcat(Char *s1, Char *s2) 876 { 877 Char *p, *q; 878 ptrdiff_t n; 879 880 for (p = s1; *p++;) 881 continue; 882 for (q = s2; *q++;) 883 continue; 884 n = (p - s1) + (q - s2) - 1; 885 if (++gargc >= gargsiz) { 886 gargsiz += GLOBSPACE; 887 gargv = (Char **)xrealloc((ptr_t)gargv, 888 (size_t)gargsiz * sizeof(Char *)); 889 } 890 gargv[gargc] = 0; 891 p = gargv[gargc - 1] = xmalloc((size_t)n * sizeof(Char)); 892 for (q = s1; (*p++ = *q++) != '\0';) 893 continue; 894 for (p--, q = s2; (*p++ = *q++) != '\0';) 895 continue; 896 } 897 898 #ifdef FILEC 899 int 900 sortscmp(const ptr_t a, const ptr_t b) 901 { 902 #if defined(NLS) && !defined(NOSTRCOLL) 903 char buf[2048]; 904 #endif 905 906 if (!a) /* check for NULL */ 907 return (b ? 1 : 0); 908 if (!b) 909 return (-1); 910 911 if (!*(Char **)a) /* check for NULL */ 912 return (*(Char **)b ? 1 : 0); 913 if (!*(Char **)b) 914 return (-1); 915 916 #if defined(NLS) && !defined(NOSTRCOLL) 917 (void)strcpy(buf, short2str(*(Char **)a)); 918 return ((int)strcoll(buf, short2str(*(Char **)b))); 919 #else 920 return ((int)Strcmp(*(Char **)a, *(Char **)b)); 921 #endif 922 } 923 #endif /* FILEC */ 924