1 /* $Header: /src/pub/tcsh/sh.glob.c,v 3.55 2004/03/21 16:48:14 christos Exp $ */ 2 /* 3 * sh.glob.c: Regular expression expansion 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$Id: sh.glob.c,v 3.55 2004/03/21 16:48:14 christos Exp $") 36 37 #include "tc.h" 38 #include "tw.h" 39 40 #include "glob.h" 41 42 static int noglob; 43 static int pargsiz, gargsiz; 44 45 /* 46 * Values for gflag 47 */ 48 #define G_NONE 0 /* No globbing needed */ 49 #define G_GLOB 1 /* string contains *?[] characters */ 50 #define G_CSH 2 /* string contains ~`{ characters */ 51 52 #define GLOBSPACE 100 /* Alloc increment */ 53 #define LONGBSIZE 10240 /* Backquote expansion buffer size */ 54 55 56 #define LBRC '{' 57 #define RBRC '}' 58 #define LBRK '[' 59 #define RBRK ']' 60 #define EOS '\0' 61 62 Char **gargv = NULL; 63 int gargc = 0; 64 Char **pargv = NULL; 65 static int pargc = 0; 66 67 /* 68 * globbing is now done in two stages. In the first pass we expand 69 * csh globbing idioms ~`{ and then we proceed doing the normal 70 * globbing if needed ?*[ 71 * 72 * Csh type globbing is handled in globexpand() and the rest is 73 * handled in glob() which is part of the 4.4BSD libc. 74 * 75 */ 76 static Char *globtilde __P((Char **, Char *)); 77 static Char *handleone __P((Char *, Char **, int)); 78 static Char **libglob __P((Char **)); 79 static Char **globexpand __P((Char **)); 80 static int globbrace __P((Char *, Char *, Char ***)); 81 static void expbrace __P((Char ***, Char ***, int)); 82 static void pword __P((int)); 83 static void psave __P((int)); 84 static void backeval __P((Char *, bool)); 85 86 static Char * 87 globtilde(nv, s) 88 Char **nv, *s; 89 { 90 Char gbuf[BUFSIZE], *gstart, *b, *u, *e; 91 #ifdef apollo 92 int slash; 93 #endif 94 95 gstart = gbuf; 96 *gstart++ = *s++; 97 u = s; 98 for (b = gstart, e = &gbuf[BUFSIZE - 1]; 99 *s && *s != '/' && *s != ':' && b < e; 100 *b++ = *s++) 101 continue; 102 *b = EOS; 103 if (gethdir(gstart)) { 104 if (adrof(STRnonomatch)) 105 return (--u); 106 blkfree(nv); 107 if (*gstart) 108 stderror(ERR_UNKUSER, short2str(gstart)); 109 else 110 stderror(ERR_NOHOME); 111 } 112 b = &gstart[Strlen(gstart)]; 113 #ifdef apollo 114 slash = gstart[0] == '/' && gstart[1] == '\0'; 115 #endif 116 while (*s) 117 *b++ = *s++; 118 *b = EOS; 119 --u; 120 xfree((ptr_t) u); 121 #ifdef apollo 122 if (slash && gstart[1] == '/') 123 gstart++; 124 #endif 125 return (Strsave(gstart)); 126 } 127 128 Char * 129 globequal(new, old) 130 Char *new, *old; 131 { 132 int dig; 133 Char *b, *d; 134 135 /* 136 * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names 137 * in stack. PWP: let =foobar pass through (for X windows) 138 */ 139 if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { 140 /* =- */ 141 dig = -1; 142 b = &old[2]; 143 } 144 else if (Isdigit(old[1])) { 145 /* =<number> */ 146 dig = old[1] - '0'; 147 for (b = &old[2]; Isdigit(*b); b++) 148 dig = dig * 10 + (*b - '0'); 149 if (*b != '\0' && *b != '/') 150 /* =<number>foobar */ 151 return old; 152 } 153 else 154 /* =foobar */ 155 return old; 156 157 if (!getstakd(new, dig)) 158 return NULL; 159 160 /* Copy the rest of the string */ 161 for (d = &new[Strlen(new)]; 162 d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';) 163 continue; 164 *d = '\0'; 165 166 return new; 167 } 168 169 static int 170 globbrace(s, p, bl) 171 Char *s, *p, ***bl; 172 { 173 int i, len; 174 Char *pm, *pe, *lm, *pl; 175 Char **nv, **vl; 176 Char gbuf[BUFSIZE]; 177 int size = GLOBSPACE; 178 179 nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); 180 *vl = NULL; 181 182 len = 0; 183 /* copy part up to the brace */ 184 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 185 continue; 186 187 /* check for balanced braces */ 188 for (i = 0, pe = ++p; *pe; pe++) 189 #ifdef DSPMBYTE 190 if (Ismbyte1(*pe) && *(pe + 1) != EOS) 191 pe ++; 192 else 193 #endif /* DSPMBYTE */ 194 if (*pe == LBRK) { 195 /* Ignore everything between [] */ 196 for (++pe; *pe != RBRK && *pe != EOS; pe++) 197 #ifdef DSPMBYTE 198 if (Ismbyte1(*pe) && *(pe + 1) != EOS) 199 pe ++; 200 else 201 #endif /* DSPMBYTE */ 202 continue; 203 if (*pe == EOS) { 204 blkfree(nv); 205 return (-RBRK); 206 } 207 } 208 else if (*pe == LBRC) 209 i++; 210 else if (*pe == RBRC) { 211 if (i == 0) 212 break; 213 i--; 214 } 215 216 if (i != 0 || *pe == '\0') { 217 blkfree(nv); 218 return (-RBRC); 219 } 220 221 for (i = 0, pl = pm = p; pm <= pe; pm++) 222 #ifdef DSPMBYTE 223 if (Ismbyte1(*pm) && pm + 1 <= pe) 224 pm ++; 225 else 226 #endif /* DSPMBYTE */ 227 switch (*pm) { 228 case LBRK: 229 for (++pm; *pm != RBRK && *pm != EOS; pm++) 230 #ifdef DSPMBYTE 231 if (Ismbyte1(*pm) && *(pm + 1) != EOS) 232 pm ++; 233 else 234 #endif /* DSPMBYTE */ 235 continue; 236 if (*pm == EOS) { 237 *vl = NULL; 238 blkfree(nv); 239 return (-RBRK); 240 } 241 break; 242 case LBRC: 243 i++; 244 break; 245 case RBRC: 246 if (i) { 247 i--; 248 break; 249 } 250 /* FALLTHROUGH */ 251 case ',': 252 if (i && *pm == ',') 253 break; 254 else { 255 Char savec = *pm; 256 257 *pm = EOS; 258 (void) Strcpy(lm, pl); 259 (void) Strcat(gbuf, pe + 1); 260 *pm = savec; 261 *vl++ = Strsave(gbuf); 262 len++; 263 pl = pm + 1; 264 if (vl == &nv[size]) { 265 size += GLOBSPACE; 266 nv = (Char **) xrealloc((ptr_t) nv, 267 (size_t) (size * sizeof(Char *))); 268 vl = &nv[size - GLOBSPACE]; 269 } 270 } 271 break; 272 default: 273 break; 274 } 275 *vl = NULL; 276 *bl = nv; 277 return (len); 278 } 279 280 281 static void 282 expbrace(nvp, elp, size) 283 Char ***nvp, ***elp; 284 int size; 285 { 286 Char **vl, **el, **nv, *s; 287 288 vl = nv = *nvp; 289 if (elp != NULL) 290 el = *elp; 291 else 292 for (el = vl; *el; el++) 293 continue; 294 295 for (s = *vl; s; s = *++vl) { 296 Char *b; 297 Char **vp, **bp; 298 299 /* leave {} untouched for find */ 300 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 301 continue; 302 if ((b = Strchr(s, '{')) != NULL) { 303 Char **bl; 304 int len; 305 306 #if defined (DSPMBYTE) 307 if (b != s && Ismbyte2(*b) && Ismbyte1(*(b-1))) { 308 /* The "{" is the 2nd byte of a MB character */ 309 continue; 310 } 311 #endif /* DSPMBYTE */ 312 if ((len = globbrace(s, b, &bl)) < 0) { 313 xfree((ptr_t) nv); 314 stderror(ERR_MISSING, -len); 315 } 316 xfree((ptr_t) s); 317 if (len == 1) { 318 *vl-- = *bl; 319 xfree((ptr_t) bl); 320 continue; 321 } 322 if (&el[len] >= &nv[size]) { 323 int l, e; 324 l = (int) (&el[len] - &nv[size]); 325 size += GLOBSPACE > l ? GLOBSPACE : l; 326 l = (int) (vl - nv); 327 e = (int) (el - nv); 328 nv = (Char **) xrealloc((ptr_t) nv, 329 (size_t) (size * sizeof(Char *))); 330 vl = nv + l; 331 el = nv + e; 332 } 333 /* nv vl el bl 334 * | | | | 335 * -.--..-- x-- 336 * | len 337 * vp 338 */ 339 vp = vl--; 340 *vp = *bl; 341 len--; 342 for (bp = el; bp != vp; bp--) 343 bp[len] = *bp; 344 el += len; 345 /* nv vl el bl 346 * | | | | 347 * -.-x --- -- 348 * |len 349 * vp 350 */ 351 vp++; 352 for (bp = bl + 1; *bp; *vp++ = *bp++) 353 continue; 354 xfree((ptr_t) bl); 355 } 356 357 } 358 if (elp != NULL) 359 *elp = el; 360 *nvp = nv; 361 } 362 363 static Char ** 364 globexpand(v) 365 Char **v; 366 { 367 Char *s; 368 Char **nv, **vl, **el; 369 int size = GLOBSPACE; 370 371 372 nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); 373 *vl = NULL; 374 375 /* 376 * Step 1: expand backquotes. 377 */ 378 while ((s = *v++) != '\0') { 379 if (Strchr(s, '`')) { 380 int i; 381 382 (void) dobackp(s, 0); 383 for (i = 0; i < pargc; i++) { 384 *vl++ = pargv[i]; 385 if (vl == &nv[size]) { 386 size += GLOBSPACE; 387 nv = (Char **) xrealloc((ptr_t) nv, 388 (size_t) (size * sizeof(Char *))); 389 vl = &nv[size - GLOBSPACE]; 390 } 391 } 392 xfree((ptr_t) pargv); 393 pargv = NULL; 394 } 395 else { 396 *vl++ = Strsave(s); 397 if (vl == &nv[size]) { 398 size += GLOBSPACE; 399 nv = (Char **) xrealloc((ptr_t) nv, 400 (size_t) (size * sizeof(Char *))); 401 vl = &nv[size - GLOBSPACE]; 402 } 403 } 404 } 405 *vl = NULL; 406 407 if (noglob) 408 return (nv); 409 410 /* 411 * Step 2: expand braces 412 */ 413 el = vl; 414 expbrace(&nv, &el, size); 415 416 417 /* 418 * Step 3: expand ~ = 419 */ 420 vl = nv; 421 for (s = *vl; s; s = *++vl) 422 switch (*s) { 423 Char gp[BUFSIZE], *ns; 424 case '~': 425 *vl = globtilde(nv, s); 426 break; 427 case '=': 428 if ((ns = globequal(gp, s)) == NULL) { 429 if (!adrof(STRnonomatch)) { 430 /* Error */ 431 blkfree(nv); 432 stderror(ERR_DEEP); 433 } 434 } 435 if (ns && ns != s) { 436 /* Expansion succeeded */ 437 xfree((ptr_t) s); 438 *vl = Strsave(gp); 439 } 440 break; 441 default: 442 break; 443 } 444 vl = nv; 445 446 /* 447 * Step 4: expand .. if the variable symlinks==expand is set 448 */ 449 if (symlinks == SYM_EXPAND) { 450 for (s = *vl; s; s = *++vl) { 451 *vl = dnormalize(s, 1); 452 xfree((ptr_t) s); 453 } 454 } 455 vl = nv; 456 457 return (vl); 458 } 459 460 static Char * 461 handleone(str, vl, action) 462 Char *str, **vl; 463 int action; 464 { 465 466 Char **vlp = vl; 467 int chars; 468 Char **t, *p, *strp; 469 470 switch (action) { 471 case G_ERROR: 472 setname(short2str(str)); 473 blkfree(vl); 474 stderror(ERR_NAME | ERR_AMBIG); 475 break; 476 case G_APPEND: 477 chars = 0; 478 for (t = vlp; (p = *t++) != '\0'; chars++) 479 while (*p++) 480 chars++; 481 str = (Char *)xmalloc((size_t)(chars * sizeof(Char))); 482 for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) { 483 while (*p) 484 *strp++ = *p++ & TRIM; 485 *strp++ = ' '; 486 } 487 *--strp = '\0'; 488 blkfree(vl); 489 break; 490 case G_IGNORE: 491 str = Strsave(strip(*vlp)); 492 blkfree(vl); 493 break; 494 default: 495 break; 496 } 497 return (str); 498 } 499 500 static Char ** 501 libglob(vl) 502 Char **vl; 503 { 504 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 505 glob_t globv; 506 char *ptr; 507 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 508 509 if (!vl || !vl[0]) 510 return(vl); 511 512 globv.gl_offs = 0; 513 globv.gl_pathv = 0; 514 globv.gl_pathc = 0; 515 516 if (nonomatch) 517 gflgs |= GLOB_NOCHECK; 518 519 do { 520 ptr = short2qstr(*vl); 521 switch (glob(ptr, gflgs, 0, &globv)) { 522 case GLOB_ABEND: 523 globfree(&globv); 524 setname(ptr); 525 stderror(ERR_NAME | ERR_GLOB); 526 /* NOTREACHED */ 527 case GLOB_NOSPACE: 528 globfree(&globv); 529 stderror(ERR_NOMEM); 530 /* NOTREACHED */ 531 default: 532 break; 533 } 534 if (globv.gl_flags & GLOB_MAGCHAR) { 535 match |= (globv.gl_matchc != 0); 536 magic = 1; 537 } 538 gflgs |= GLOB_APPEND; 539 } 540 while (*++vl); 541 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 542 NULL : blk2short(globv.gl_pathv); 543 globfree(&globv); 544 return (vl); 545 } 546 547 Char * 548 globone(str, action) 549 Char *str; 550 int action; 551 { 552 553 Char *v[2], **vl, **vo; 554 int gflg; 555 556 noglob = adrof(STRnoglob) != 0; 557 gflag = 0; 558 v[0] = str; 559 v[1] = 0; 560 tglob(v); 561 gflg = gflag; 562 if (gflg == G_NONE) 563 return (strip(Strsave(str))); 564 565 if (gflg & G_CSH) { 566 /* 567 * Expand back-quote, tilde and brace 568 */ 569 vo = globexpand(v); 570 if (noglob || (gflg & G_GLOB) == 0) { 571 if (vo[0] == NULL) { 572 xfree((ptr_t) vo); 573 return (Strsave(STRNULL)); 574 } 575 if (vo[1] != NULL) 576 return (handleone(str, vo, action)); 577 else { 578 str = strip(vo[0]); 579 xfree((ptr_t) vo); 580 return (str); 581 } 582 } 583 } 584 else if (noglob || (gflg & G_GLOB) == 0) 585 return (strip(Strsave(str))); 586 else 587 vo = v; 588 589 vl = libglob(vo); 590 if ((gflg & G_CSH) && vl != vo) 591 blkfree(vo); 592 if (vl == NULL) { 593 setname(short2str(str)); 594 stderror(ERR_NAME | ERR_NOMATCH); 595 } 596 if (vl[0] == NULL) { 597 xfree((ptr_t) vl); 598 return (Strsave(STRNULL)); 599 } 600 if (vl[1]) 601 return (handleone(str, vl, action)); 602 else { 603 str = strip(*vl); 604 xfree((ptr_t) vl); 605 return (str); 606 } 607 } 608 609 Char ** 610 globall(v) 611 Char **v; 612 { 613 Char **vl, **vo; 614 int gflg = gflag; 615 616 if (!v || !v[0]) { 617 gargv = saveblk(v); 618 gargc = blklen(gargv); 619 return (gargv); 620 } 621 622 noglob = adrof(STRnoglob) != 0; 623 624 if (gflg & G_CSH) 625 /* 626 * Expand back-quote, tilde and brace 627 */ 628 vl = vo = globexpand(v); 629 else 630 vl = vo = saveblk(v); 631 632 if (!noglob && (gflg & G_GLOB)) { 633 vl = libglob(vo); 634 if (vl != vo) 635 blkfree(vo); 636 } 637 else 638 trim(vl); 639 640 gargc = vl ? blklen(vl) : 0; 641 return (gargv = vl); 642 } 643 644 void 645 ginit() 646 { 647 gargsiz = GLOBSPACE; 648 gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz)); 649 gargv[0] = 0; 650 gargc = 0; 651 } 652 653 void 654 rscan(t, f) 655 register Char **t; 656 void (*f) __P((int)); 657 { 658 register Char *p; 659 660 while ((p = *t++) != '\0') 661 while (*p) 662 (*f) (*p++); 663 } 664 665 void 666 trim(t) 667 register Char **t; 668 { 669 register Char *p; 670 671 while ((p = *t++) != '\0') 672 while (*p) 673 *p++ &= TRIM; 674 } 675 676 void 677 tglob(t) 678 register Char **t; 679 { 680 register Char *p, *c; 681 682 while ((p = *t++) != '\0') { 683 if (*p == '~' || *p == '=') 684 gflag |= G_CSH; 685 else if (*p == '{' && 686 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 687 continue; 688 /* 689 * The following line used to be *(c = p++), but hp broke their 690 * optimizer in 9.01, so we break the assignment into two pieces 691 * The careful reader here will note that *most* compiler workarounds 692 * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence? 693 */ 694 while ( *(c = p) != '\0') { 695 p++; 696 if (*c == '`') { 697 gflag |= G_CSH; 698 #ifdef notdef 699 /* 700 * We do want to expand echo `echo '*'`, so we don't\ 701 * use this piece of code anymore. 702 */ 703 while (*p && *p != '`') 704 if (*p++ == '\\') { 705 if (*p) /* Quoted chars */ 706 p++; 707 else 708 break; 709 } 710 if (*p) /* The matching ` */ 711 p++; 712 else 713 break; 714 #endif 715 } 716 else if (*c == '{') 717 gflag |= G_CSH; 718 else if (isglob(*c)) 719 gflag |= G_GLOB; 720 else if (symlinks == SYM_EXPAND && 721 *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') ) 722 gflag |= G_CSH; 723 } 724 } 725 } 726 727 /* 728 * Command substitute cp. If literal, then this is a substitution from a 729 * << redirection, and so we should not crunch blanks and tabs, separating 730 * words only at newlines. 731 */ 732 Char ** 733 dobackp(cp, literal) 734 Char *cp; 735 bool literal; 736 { 737 register Char *lp, *rp; 738 Char *ep, word[LONGBSIZE]; 739 740 if (pargv) { 741 #ifdef notdef 742 abort(); 743 #endif 744 blkfree(pargv); 745 } 746 pargsiz = GLOBSPACE; 747 pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz)); 748 pargv[0] = NULL; 749 pargcp = pargs = word; 750 pargc = 0; 751 pnleft = LONGBSIZE - 4; 752 for (;;) { 753 #if defined(DSPMBYTE) 754 for (lp = cp;; lp++) { /* } */ 755 if (*lp == '`' && 756 (lp-1 < cp || !Ismbyte2(*lp) || !Ismbyte1(*(lp-1)))) { 757 break; 758 } 759 #else /* DSPMBYTE */ 760 for (lp = cp; *lp != '`'; lp++) { 761 #endif /* DSPMBYTE */ 762 if (*lp == 0) { 763 if (pargcp != pargs) 764 pword(LONGBSIZE); 765 return (pargv); 766 } 767 psave(*lp); 768 } 769 lp++; 770 for (rp = lp; *rp && *rp != '`'; rp++) 771 if (*rp == '\\') { 772 rp++; 773 if (!*rp) 774 goto oops; 775 } 776 if (!*rp) 777 oops: stderror(ERR_UNMATCHED, '`'); 778 ep = Strsave(lp); 779 ep[rp - lp] = 0; 780 backeval(ep, literal); 781 cp = rp + 1; 782 } 783 } 784 785 786 static void 787 backeval(cp, literal) 788 Char *cp; 789 bool literal; 790 { 791 register int icnt, c; 792 register Char *ip; 793 struct command faket; 794 bool hadnl; 795 int pvec[2], quoted; 796 Char *fakecom[2], ibuf[BUFSIZE]; 797 char tibuf[BUFSIZE]; 798 799 hadnl = 0; 800 icnt = 0; 801 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 802 faket.t_dtyp = NODE_COMMAND; 803 faket.t_dflg = F_BACKQ; 804 faket.t_dlef = 0; 805 faket.t_drit = 0; 806 faket.t_dspr = 0; 807 faket.t_dcom = fakecom; 808 fakecom[0] = STRfakecom1; 809 fakecom[1] = 0; 810 811 /* 812 * We do the psave job to temporarily change the current job so that the 813 * following fork is considered a separate job. This is so that when 814 * backquotes are used in a builtin function that calls glob the "current 815 * job" is not corrupted. We only need one level of pushed jobs as long as 816 * we are sure to fork here. 817 */ 818 psavejob(); 819 820 /* 821 * It would be nicer if we could integrate this redirection more with the 822 * routines in sh.sem.c by doing a fake execute on a builtin function that 823 * was piped out. 824 */ 825 mypipe(pvec); 826 if (pfork(&faket, -1) == 0) { 827 struct command *t; 828 829 (void) close(pvec[0]); 830 (void) dmove(pvec[1], 1); 831 (void) dmove(SHDIAG, 2); 832 initdesc(); 833 closem(); 834 /* 835 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 836 * posted to comp.bugs.4bsd 12 Sep. 1989. 837 */ 838 if (pargv) /* mg, 21.dec.88 */ 839 blkfree(pargv), pargv = 0, pargsiz = 0; 840 /* mg, 21.dec.88 */ 841 arginp = cp; 842 for (arginp = cp; *cp; cp++) { 843 *cp &= TRIM; 844 if (*cp == '\n' || *cp == '\r') 845 *cp = ' '; 846 } 847 848 /* 849 * In the child ``forget'' everything about current aliases or 850 * eval vectors. 851 */ 852 alvec = NULL; 853 evalvec = NULL; 854 alvecp = NULL; 855 evalp = NULL; 856 (void) lex(¶ml); 857 if (seterr) 858 stderror(ERR_OLD); 859 alias(¶ml); 860 t = syntax(paraml.next, ¶ml, 0); 861 if (seterr) 862 stderror(ERR_OLD); 863 if (t) 864 t->t_dflg |= F_NOFORK; 865 #ifdef SIGTSTP 866 (void) sigignore(SIGTSTP); 867 #endif 868 #ifdef SIGTTIN 869 (void) sigignore(SIGTTIN); 870 #endif 871 #ifdef SIGTTOU 872 (void) sigignore(SIGTTOU); 873 #endif 874 execute(t, -1, NULL, NULL, TRUE); 875 exitstat(); 876 } 877 xfree((ptr_t) cp); 878 (void) close(pvec[1]); 879 c = 0; 880 ip = NULL; 881 do { 882 int cnt = 0; 883 884 for (;;) { 885 if (icnt == 0) { 886 int i; 887 888 ip = ibuf; 889 do 890 icnt = read(pvec[0], tibuf, BUFSIZE); 891 while (icnt == -1 && errno == EINTR); 892 if (icnt <= 0) { 893 c = -1; 894 break; 895 } 896 for (i = 0; i < icnt; i++) 897 ip[i] = (unsigned char) tibuf[i]; 898 } 899 if (hadnl) 900 break; 901 --icnt; 902 c = (*ip++ & TRIM); 903 if (c == 0) 904 break; 905 #ifdef WINNT_NATIVE 906 if (c == '\r') 907 c = ' '; 908 #endif /* WINNT_NATIVE */ 909 if (c == '\n') { 910 /* 911 * Continue around the loop one more time, so that we can eat 912 * the last newline without terminating this word. 913 */ 914 hadnl = 1; 915 continue; 916 } 917 if (!quoted && (c == ' ' || c == '\t')) 918 break; 919 cnt++; 920 psave(c | quoted); 921 } 922 /* 923 * Unless at end-of-file, we will form a new word here if there were 924 * characters in the word, or in any case when we take text literally. 925 * If we didn't make empty words here when literal was set then we 926 * would lose blank lines. 927 */ 928 if (c != -1 && (cnt || literal)) 929 pword(BUFSIZE); 930 hadnl = 0; 931 } while (c >= 0); 932 (void) close(pvec[0]); 933 pwait(); 934 prestjob(); 935 } 936 937 static void 938 psave(c) 939 int c; 940 { 941 if (--pnleft <= 0) 942 stderror(ERR_WTOOLONG); 943 *pargcp++ = (Char) c; 944 } 945 946 static void 947 pword(bufsiz) 948 int bufsiz; 949 { 950 psave(0); 951 if (pargc == pargsiz - 1) { 952 pargsiz += GLOBSPACE; 953 pargv = (Char **) xrealloc((ptr_t) pargv, 954 (size_t) (pargsiz * sizeof(Char *))); 955 } 956 pargv[pargc++] = Strsave(pargs); 957 pargv[pargc] = NULL; 958 pargcp = pargs; 959 pnleft = bufsiz - 4; 960 } 961 962 int 963 Gmatch(string, pattern) 964 Char *string, *pattern; 965 { 966 return Gnmatch(string, pattern, NULL); 967 } 968 969 int 970 Gnmatch(string, pattern, endstr) 971 Char *string, *pattern, **endstr; 972 { 973 Char **blk, **p, *tstring = string; 974 int gpol = 1, gres = 0; 975 976 if (*pattern == '^') { 977 gpol = 0; 978 pattern++; 979 } 980 981 blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *))); 982 blk[0] = Strsave(pattern); 983 blk[1] = NULL; 984 985 expbrace(&blk, NULL, GLOBSPACE); 986 987 if (endstr == NULL) 988 /* Exact matches only */ 989 for (p = blk; *p; p++) 990 gres |= t_pmatch(string, *p, &tstring, 0) == 2 ? 1 : 0; 991 else { 992 /* partial matches */ 993 int minc = 0x7fffffff; 994 for (p = blk; *p; p++) 995 if (t_pmatch(string, *p, &tstring, 0) != 0) { 996 int t = (int) (tstring - string); 997 gres |= 1; 998 if (minc == -1 || minc > t) 999 minc = t; 1000 } 1001 *endstr = string + minc; 1002 } 1003 1004 blkfree(blk); 1005 return(gres == gpol); 1006 } 1007 1008 /* t_pmatch(): 1009 * Return 2 on exact match, 1010 * Return 1 on substring match. 1011 * Return 0 on no match. 1012 * *estr will point to the end of the longest exact or substring match. 1013 */ 1014 int 1015 t_pmatch(string, pattern, estr, cs) 1016 Char *string, *pattern, **estr; 1017 int cs; 1018 { 1019 Char stringc, patternc; 1020 int match, negate_range; 1021 Char rangec, *oestr, *pestr; 1022 1023 for (;; ++string) { 1024 stringc = *string & TRIM; 1025 /* 1026 * apollo compiler bug: switch (patternc = *pattern++) dies 1027 */ 1028 patternc = *pattern++; 1029 switch (patternc) { 1030 case 0: 1031 *estr = string; 1032 return (stringc == 0 ? 2 : 1); 1033 case '?': 1034 if (stringc == 0) 1035 return (0); 1036 *estr = string; 1037 break; 1038 case '*': 1039 if (!*pattern) { 1040 while (*string) string++; 1041 *estr = string; 1042 return (2); 1043 } 1044 oestr = *estr; 1045 pestr = NULL; 1046 1047 do { 1048 switch(t_pmatch(string, pattern, estr, cs)) { 1049 case 0: 1050 break; 1051 case 1: 1052 pestr = *estr; 1053 break; 1054 case 2: 1055 return 2; 1056 default: 1057 abort(); /* Cannot happen */ 1058 } 1059 *estr = string; 1060 } 1061 while (*string++); 1062 1063 if (pestr) { 1064 *estr = pestr; 1065 return 1; 1066 } 1067 else { 1068 *estr = oestr; 1069 return 0; 1070 } 1071 1072 case '[': 1073 match = 0; 1074 if ((negate_range = (*pattern == '^')) != 0) 1075 pattern++; 1076 while ((rangec = *pattern++) != '\0') { 1077 if (rangec == ']') 1078 break; 1079 if (match) 1080 continue; 1081 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 1082 match = (globcharcoll(stringc, *pattern & TRIM, cs) <= 0 && 1083 globcharcoll(*(pattern-2) & TRIM, stringc, cs) <= 0); 1084 pattern++; 1085 } 1086 else 1087 match = (stringc == (rangec & TRIM)); 1088 } 1089 if (rangec == 0) 1090 stderror(ERR_NAME | ERR_MISSING, ']'); 1091 if (match == negate_range) 1092 return (0); 1093 *estr = string; 1094 break; 1095 default: 1096 if ((patternc & TRIM) != stringc) 1097 return (0); 1098 *estr = string; 1099 break; 1100 } 1101 } 1102 } 1103 1104 void 1105 Gcat(s1, s2) 1106 Char *s1, *s2; 1107 { 1108 register Char *p, *q; 1109 int n; 1110 1111 for (p = s1; *p++;) 1112 continue; 1113 for (q = s2; *q++;) 1114 continue; 1115 n = (int) ((p - s1) + (q - s2) - 1); 1116 if (++gargc >= gargsiz) { 1117 gargsiz += GLOBSPACE; 1118 gargv = (Char **) xrealloc((ptr_t) gargv, 1119 (size_t) (gargsiz * sizeof(Char *))); 1120 } 1121 gargv[gargc] = 0; 1122 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char))); 1123 for (q = s1; (*p++ = *q++) != '\0';) 1124 continue; 1125 for (p--, q = s2; (*p++ = *q++) != '\0';) 1126 continue; 1127 } 1128 1129 #if defined(FILEC) && defined(TIOCSTI) 1130 int 1131 sortscmp(a, b) 1132 register Char **a, **b; 1133 { 1134 if (!a) /* check for NULL */ 1135 return (b ? 1 : 0); 1136 if (!b) 1137 return (-1); 1138 1139 if (!*a) /* check for NULL */ 1140 return (*b ? 1 : 0); 1141 if (!*b) 1142 return (-1); 1143 1144 return (int) collate(*a, *b); 1145 } 1146 1147 #endif 1148