1 /* $NetBSD: glob.c,v 1.12 1997/07/04 21:24:02 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.12 1997/07/04 21:24:02 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 break; 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_QUOTE | 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_ABEND: 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: stderror(ERR_UNMATCHED, '`'); 646 ep = Strsave(lp); 647 ep[rp - lp] = 0; 648 backeval(ep, literal); 649 cp = rp + 1; 650 } 651 } 652 653 static void 654 backeval(cp, literal) 655 Char *cp; 656 bool literal; 657 { 658 int icnt, c; 659 Char *ip; 660 struct command faket; 661 bool hadnl; 662 int pvec[2], quoted; 663 Char *fakecom[2], ibuf[BUFSIZ]; 664 char tibuf[BUFSIZ]; 665 666 hadnl = 0; 667 icnt = 0; 668 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 669 faket.t_dtyp = NODE_COMMAND; 670 faket.t_dflg = 0; 671 faket.t_dlef = 0; 672 faket.t_drit = 0; 673 faket.t_dspr = 0; 674 faket.t_dcom = fakecom; 675 fakecom[0] = STRfakecom1; 676 fakecom[1] = 0; 677 678 /* 679 * We do the psave job to temporarily change the current job so that the 680 * following fork is considered a separate job. This is so that when 681 * backquotes are used in a builtin function that calls glob the "current 682 * job" is not corrupted. We only need one level of pushed jobs as long as 683 * we are sure to fork here. 684 */ 685 psavejob(); 686 687 /* 688 * It would be nicer if we could integrate this redirection more with the 689 * routines in sh.sem.c by doing a fake execute on a builtin function that 690 * was piped out. 691 */ 692 mypipe(pvec); 693 if (pfork(&faket, -1) == 0) { 694 struct wordent paraml; 695 struct command *t; 696 697 (void) close(pvec[0]); 698 (void) dmove(pvec[1], 1); 699 (void) dmove(SHERR, 2); 700 initdesc(); 701 /* 702 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 703 * posted to comp.bugs.4bsd 12 Sep. 1989. 704 */ 705 if (pargv) /* mg, 21.dec.88 */ 706 blkfree(pargv), pargv = 0, pargsiz = 0; 707 /* mg, 21.dec.88 */ 708 arginp = cp; 709 while (*cp) 710 *cp++ &= TRIM; 711 712 /* 713 * In the child ``forget'' everything about current aliases or 714 * eval vectors. 715 */ 716 alvec = NULL; 717 evalvec = NULL; 718 alvecp = NULL; 719 evalp = NULL; 720 (void) lex(¶ml); 721 if (seterr) 722 stderror(ERR_OLD); 723 alias(¶ml); 724 t = syntax(paraml.next, ¶ml, 0); 725 if (seterr) 726 stderror(ERR_OLD); 727 if (t) 728 t->t_dflg |= F_NOFORK; 729 (void) signal(SIGTSTP, SIG_IGN); 730 (void) signal(SIGTTIN, SIG_IGN); 731 (void) signal(SIGTTOU, SIG_IGN); 732 execute(t, -1, NULL, NULL); 733 exitstat(); 734 } 735 xfree((ptr_t) cp); 736 (void) close(pvec[1]); 737 c = 0; 738 ip = NULL; 739 do { 740 int cnt = 0; 741 742 for (;;) { 743 if (icnt == 0) { 744 int i; 745 746 ip = ibuf; 747 do 748 icnt = read(pvec[0], tibuf, BUFSIZ); 749 while (icnt == -1 && errno == EINTR); 750 if (icnt <= 0) { 751 c = -1; 752 break; 753 } 754 for (i = 0; i < icnt; i++) 755 ip[i] = (unsigned char) tibuf[i]; 756 } 757 if (hadnl) 758 break; 759 --icnt; 760 c = (*ip++ & TRIM); 761 if (c == 0) 762 break; 763 if (c == '\n') { 764 /* 765 * Continue around the loop one more time, so that we can eat 766 * the last newline without terminating this word. 767 */ 768 hadnl = 1; 769 continue; 770 } 771 if (!quoted && (c == ' ' || c == '\t')) 772 break; 773 cnt++; 774 psave(c | quoted); 775 } 776 /* 777 * Unless at end-of-file, we will form a new word here if there were 778 * characters in the word, or in any case when we take text literally. 779 * If we didn't make empty words here when literal was set then we 780 * would lose blank lines. 781 */ 782 if (c != -1 && (cnt || literal)) 783 pword(); 784 hadnl = 0; 785 } while (c >= 0); 786 (void) close(pvec[0]); 787 pwait(); 788 prestjob(); 789 } 790 791 static void 792 psave(c) 793 int c; 794 { 795 if (--pnleft <= 0) 796 stderror(ERR_WTOOLONG); 797 *pargcp++ = c; 798 } 799 800 static void 801 pword() 802 { 803 psave(0); 804 if (pargc == pargsiz - 1) { 805 pargsiz += GLOBSPACE; 806 pargv = (Char **) xrealloc((ptr_t) pargv, 807 (size_t) pargsiz * sizeof(Char *)); 808 } 809 pargv[pargc++] = Strsave(pargs); 810 pargv[pargc] = NULL; 811 pargcp = pargs; 812 pnleft = MAXPATHLEN - 4; 813 } 814 815 int 816 Gmatch(string, pattern) 817 Char *string, *pattern; 818 { 819 Char **blk, **p; 820 int gpol = 1, gres = 0; 821 822 if (*pattern == '^') { 823 gpol = 0; 824 pattern++; 825 } 826 827 blk = (Char **) xmalloc(GLOBSPACE * sizeof(Char *)); 828 blk[0] = Strsave(pattern); 829 blk[1] = NULL; 830 831 expbrace(&blk, NULL, GLOBSPACE); 832 833 for (p = blk; *p; p++) 834 gres |= pmatch(string, *p); 835 836 blkfree(blk); 837 return(gres == gpol); 838 } 839 840 static int 841 pmatch(string, pattern) 842 Char *string, *pattern; 843 { 844 Char stringc, patternc; 845 int match, negate_range; 846 Char rangec; 847 848 for (;; ++string) { 849 stringc = *string & TRIM; 850 patternc = *pattern++; 851 switch (patternc) { 852 case 0: 853 return (stringc == 0); 854 case '?': 855 if (stringc == 0) 856 return (0); 857 break; 858 case '*': 859 if (!*pattern) 860 return (1); 861 while (*string) 862 if (Gmatch(string++, pattern)) 863 return (1); 864 return (0); 865 case '[': 866 match = 0; 867 if ((negate_range = (*pattern == '^')) != 0) 868 pattern++; 869 while ((rangec = *pattern++) != '\0') { 870 if (rangec == ']') 871 break; 872 if (match) 873 continue; 874 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 875 match = (stringc <= (*pattern & TRIM) && 876 (*(pattern-2) & TRIM) <= stringc); 877 pattern++; 878 } 879 else 880 match = (stringc == (rangec & TRIM)); 881 } 882 if (rangec == 0) 883 stderror(ERR_NAME | ERR_MISSING, ']'); 884 if (match == negate_range) 885 return (0); 886 break; 887 default: 888 if ((patternc & TRIM) != stringc) 889 return (0); 890 break; 891 892 } 893 } 894 } 895 896 void 897 Gcat(s1, s2) 898 Char *s1, *s2; 899 { 900 Char *p, *q; 901 int n; 902 903 for (p = s1; *p++;) 904 continue; 905 for (q = s2; *q++;) 906 continue; 907 n = (p - s1) + (q - s2) - 1; 908 if (++gargc >= gargsiz) { 909 gargsiz += GLOBSPACE; 910 gargv = (Char **) xrealloc((ptr_t) gargv, 911 (size_t) gargsiz * sizeof(Char *)); 912 } 913 gargv[gargc] = 0; 914 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char)); 915 for (q = s1; (*p++ = *q++) != '\0';) 916 continue; 917 for (p--, q = s2; (*p++ = *q++) != '\0';) 918 continue; 919 } 920 921 #ifdef FILEC 922 int 923 sortscmp(a, b) 924 const ptr_t a, b; 925 { 926 #if defined(NLS) && !defined(NOSTRCOLL) 927 char buf[2048]; 928 #endif 929 930 if (!a) /* check for NULL */ 931 return (b ? 1 : 0); 932 if (!b) 933 return (-1); 934 935 if (!*(Char **)a) /* check for NULL */ 936 return (*(Char **)b ? 1 : 0); 937 if (!*(Char **)b) 938 return (-1); 939 940 #if defined(NLS) && !defined(NOSTRCOLL) 941 (void) strcpy(buf, short2str(*(Char **)a)); 942 return ((int) strcoll(buf, short2str(*(Char **)b))); 943 #else 944 return ((int) Strcmp(*(Char **)a, *(Char **)b)); 945 #endif 946 } 947 #endif /* FILEC */ 948