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