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