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