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