1 /* $Header: /src/pub/tcsh/sh.glob.c,v 3.62 2004/12/25 21:15:07 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.62 2004/12/25 21:15:07 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((Char)); 84 static void backeval __P((Char *, int)); 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 if (*pe == LBRK) { 190 /* Ignore everything between [] */ 191 for (++pe; *pe != RBRK && *pe != EOS; pe++) 192 continue; 193 if (*pe == EOS) { 194 blkfree(nv); 195 return (-RBRK); 196 } 197 } 198 else if (*pe == LBRC) 199 i++; 200 else if (*pe == RBRC) { 201 if (i == 0) 202 break; 203 i--; 204 } 205 206 if (i != 0 || *pe == '\0') { 207 blkfree(nv); 208 return (-RBRC); 209 } 210 211 for (i = 0, pl = pm = p; pm <= pe; pm++) 212 switch (*pm) { 213 case LBRK: 214 for (++pm; *pm != RBRK && *pm != EOS; pm++) 215 continue; 216 if (*pm == EOS) { 217 *vl = NULL; 218 blkfree(nv); 219 return (-RBRK); 220 } 221 break; 222 case LBRC: 223 i++; 224 break; 225 case RBRC: 226 if (i) { 227 i--; 228 break; 229 } 230 /* FALLTHROUGH */ 231 case ',': 232 if (i && *pm == ',') 233 break; 234 else { 235 Char savec = *pm; 236 237 *pm = EOS; 238 (void) Strcpy(lm, pl); 239 (void) Strcat(gbuf, pe + 1); 240 *pm = savec; 241 *vl++ = Strsave(gbuf); 242 len++; 243 pl = pm + 1; 244 if (vl == &nv[size]) { 245 size += GLOBSPACE; 246 nv = (Char **) xrealloc((ptr_t) nv, 247 (size_t) (size * sizeof(Char *))); 248 vl = &nv[size - GLOBSPACE]; 249 } 250 } 251 break; 252 default: 253 break; 254 } 255 *vl = NULL; 256 *bl = nv; 257 return (len); 258 } 259 260 261 static void 262 expbrace(nvp, elp, size) 263 Char ***nvp, ***elp; 264 int size; 265 { 266 Char **vl, **el, **nv, *s; 267 268 vl = nv = *nvp; 269 if (elp != NULL) 270 el = *elp; 271 else 272 for (el = vl; *el; el++) 273 continue; 274 275 for (s = *vl; s; s = *++vl) { 276 Char *b; 277 Char **vp, **bp; 278 279 /* leave {} untouched for find */ 280 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 281 continue; 282 if ((b = Strchr(s, '{')) != NULL) { 283 Char **bl; 284 int len; 285 286 if ((len = globbrace(s, b, &bl)) < 0) { 287 xfree((ptr_t) nv); 288 stderror(ERR_MISSING, -len); 289 } 290 xfree((ptr_t) s); 291 if (len == 1) { 292 *vl-- = *bl; 293 xfree((ptr_t) bl); 294 continue; 295 } 296 if (&el[len] >= &nv[size]) { 297 int l, e; 298 l = (int) (&el[len] - &nv[size]); 299 size += GLOBSPACE > l ? GLOBSPACE : l; 300 l = (int) (vl - nv); 301 e = (int) (el - nv); 302 nv = (Char **) xrealloc((ptr_t) nv, 303 (size_t) (size * sizeof(Char *))); 304 vl = nv + l; 305 el = nv + e; 306 } 307 /* nv vl el bl 308 * | | | | 309 * -.--..-- x-- 310 * | len 311 * vp 312 */ 313 vp = vl--; 314 *vp = *bl; 315 len--; 316 for (bp = el; bp != vp; bp--) 317 bp[len] = *bp; 318 el += len; 319 /* nv vl el bl 320 * | | | | 321 * -.-x --- -- 322 * |len 323 * vp 324 */ 325 vp++; 326 for (bp = bl + 1; *bp; *vp++ = *bp++) 327 continue; 328 xfree((ptr_t) bl); 329 } 330 331 } 332 if (elp != NULL) 333 *elp = el; 334 *nvp = nv; 335 } 336 337 static Char ** 338 globexpand(v) 339 Char **v; 340 { 341 Char *s; 342 Char **nv, **vl, **el; 343 int size = GLOBSPACE; 344 345 346 nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); 347 *vl = NULL; 348 349 /* 350 * Step 1: expand backquotes. 351 */ 352 while ((s = *v++) != '\0') { 353 if (Strchr(s, '`')) { 354 int i; 355 356 (void) dobackp(s, 0); 357 for (i = 0; i < pargc; i++) { 358 *vl++ = pargv[i]; 359 if (vl == &nv[size]) { 360 size += GLOBSPACE; 361 nv = (Char **) xrealloc((ptr_t) nv, 362 (size_t) (size * sizeof(Char *))); 363 vl = &nv[size - GLOBSPACE]; 364 } 365 } 366 xfree((ptr_t) pargv); 367 pargv = NULL; 368 } 369 else { 370 *vl++ = Strsave(s); 371 if (vl == &nv[size]) { 372 size += GLOBSPACE; 373 nv = (Char **) xrealloc((ptr_t) nv, 374 (size_t) (size * sizeof(Char *))); 375 vl = &nv[size - GLOBSPACE]; 376 } 377 } 378 } 379 *vl = NULL; 380 381 if (noglob) 382 return (nv); 383 384 /* 385 * Step 2: expand braces 386 */ 387 el = vl; 388 expbrace(&nv, &el, size); 389 390 391 /* 392 * Step 3: expand ~ = 393 */ 394 vl = nv; 395 for (s = *vl; s; s = *++vl) 396 switch (*s) { 397 Char gp[BUFSIZE], *ns; 398 case '~': 399 *vl = globtilde(nv, s); 400 break; 401 case '=': 402 if ((ns = globequal(gp, s)) == NULL) { 403 if (!adrof(STRnonomatch)) { 404 /* Error */ 405 blkfree(nv); 406 stderror(ERR_DEEP); 407 } 408 } 409 if (ns && ns != s) { 410 /* Expansion succeeded */ 411 xfree((ptr_t) s); 412 *vl = Strsave(gp); 413 } 414 break; 415 default: 416 break; 417 } 418 vl = nv; 419 420 /* 421 * Step 4: expand .. if the variable symlinks==expand is set 422 */ 423 if (symlinks == SYM_EXPAND) { 424 for (s = *vl; s; s = *++vl) { 425 *vl = dnormalize(s, 1); 426 xfree((ptr_t) s); 427 } 428 } 429 vl = nv; 430 431 return (vl); 432 } 433 434 static Char * 435 handleone(str, vl, action) 436 Char *str, **vl; 437 int action; 438 { 439 440 Char **vlp = vl; 441 int chars; 442 Char **t, *p, *strp; 443 444 switch (action) { 445 case G_ERROR: 446 setname(short2str(str)); 447 blkfree(vl); 448 stderror(ERR_NAME | ERR_AMBIG); 449 break; 450 case G_APPEND: 451 chars = 0; 452 for (t = vlp; (p = *t++) != '\0'; chars++) 453 while (*p++) 454 chars++; 455 str = (Char *)xmalloc((size_t)(chars * sizeof(Char))); 456 for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) { 457 while (*p) 458 *strp++ = *p++ & TRIM; 459 *strp++ = ' '; 460 } 461 *--strp = '\0'; 462 blkfree(vl); 463 break; 464 case G_IGNORE: 465 str = Strsave(strip(*vlp)); 466 blkfree(vl); 467 break; 468 default: 469 break; 470 } 471 return (str); 472 } 473 474 static Char ** 475 libglob(vl) 476 Char **vl; 477 { 478 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 479 glob_t globv; 480 char *ptr; 481 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 482 483 if (!vl || !vl[0]) 484 return(vl); 485 486 globv.gl_offs = 0; 487 globv.gl_pathv = 0; 488 globv.gl_pathc = 0; 489 490 if (nonomatch) 491 gflgs |= GLOB_NOCHECK; 492 493 do { 494 ptr = short2qstr(*vl); 495 switch (glob(ptr, gflgs, 0, &globv)) { 496 case GLOB_ABEND: 497 globfree(&globv); 498 setname(ptr); 499 stderror(ERR_NAME | ERR_GLOB); 500 /* NOTREACHED */ 501 case GLOB_NOSPACE: 502 globfree(&globv); 503 stderror(ERR_NOMEM); 504 /* NOTREACHED */ 505 default: 506 break; 507 } 508 if (globv.gl_flags & GLOB_MAGCHAR) { 509 match |= (globv.gl_matchc != 0); 510 magic = 1; 511 } 512 gflgs |= GLOB_APPEND; 513 } 514 while (*++vl); 515 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 516 NULL : blk2short(globv.gl_pathv); 517 globfree(&globv); 518 return (vl); 519 } 520 521 Char * 522 globone(str, action) 523 Char *str; 524 int action; 525 { 526 527 Char *v[2], **vl, **vo; 528 int gflg; 529 530 noglob = adrof(STRnoglob) != 0; 531 gflag = 0; 532 v[0] = str; 533 v[1] = 0; 534 tglob(v); 535 gflg = gflag; 536 if (gflg == G_NONE) 537 return (strip(Strsave(str))); 538 539 if (gflg & G_CSH) { 540 /* 541 * Expand back-quote, tilde and brace 542 */ 543 vo = globexpand(v); 544 if (noglob || (gflg & G_GLOB) == 0) { 545 if (vo[0] == NULL) { 546 xfree((ptr_t) vo); 547 return (Strsave(STRNULL)); 548 } 549 if (vo[1] != NULL) 550 return (handleone(str, vo, action)); 551 else { 552 str = strip(vo[0]); 553 xfree((ptr_t) vo); 554 return (str); 555 } 556 } 557 } 558 else if (noglob || (gflg & G_GLOB) == 0) 559 return (strip(Strsave(str))); 560 else 561 vo = v; 562 563 vl = libglob(vo); 564 if ((gflg & G_CSH) && vl != vo) 565 blkfree(vo); 566 if (vl == NULL) { 567 setname(short2str(str)); 568 stderror(ERR_NAME | ERR_NOMATCH); 569 } 570 if (vl[0] == NULL) { 571 xfree((ptr_t) vl); 572 return (Strsave(STRNULL)); 573 } 574 if (vl[1]) 575 return (handleone(str, vl, action)); 576 else { 577 str = strip(*vl); 578 xfree((ptr_t) vl); 579 return (str); 580 } 581 } 582 583 Char ** 584 globall(v) 585 Char **v; 586 { 587 Char **vl, **vo; 588 int gflg = gflag; 589 590 if (!v || !v[0]) { 591 gargv = saveblk(v); 592 gargc = blklen(gargv); 593 return (gargv); 594 } 595 596 noglob = adrof(STRnoglob) != 0; 597 598 if (gflg & G_CSH) 599 /* 600 * Expand back-quote, tilde and brace 601 */ 602 vl = vo = globexpand(v); 603 else 604 vl = vo = saveblk(v); 605 606 if (!noglob && (gflg & G_GLOB)) { 607 vl = libglob(vo); 608 if (vl != vo) 609 blkfree(vo); 610 } 611 else 612 trim(vl); 613 614 gargc = vl ? blklen(vl) : 0; 615 return (gargv = vl); 616 } 617 618 void 619 ginit() 620 { 621 gargsiz = GLOBSPACE; 622 gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz)); 623 gargv[0] = 0; 624 gargc = 0; 625 } 626 627 void 628 rscan(t, f) 629 Char **t; 630 void (*f) __P((Char)); 631 { 632 Char *p; 633 634 while ((p = *t++) != '\0') 635 while (*p) 636 (*f) (*p++); 637 } 638 639 void 640 trim(t) 641 Char **t; 642 { 643 Char *p; 644 645 while ((p = *t++) != '\0') 646 while (*p) 647 *p++ &= TRIM; 648 } 649 650 void 651 tglob(t) 652 Char **t; 653 { 654 Char *p, *c; 655 656 while ((p = *t++) != '\0') { 657 if (*p == '~' || *p == '=') 658 gflag |= G_CSH; 659 else if (*p == '{' && 660 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 661 continue; 662 /* 663 * The following line used to be *(c = p++), but hp broke their 664 * optimizer in 9.01, so we break the assignment into two pieces 665 * The careful reader here will note that *most* compiler workarounds 666 * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence? 667 */ 668 while ( *(c = p) != '\0') { 669 p++; 670 if (*c == '`') { 671 gflag |= G_CSH; 672 #ifdef notdef 673 /* 674 * We do want to expand echo `echo '*'`, so we don't\ 675 * use this piece of code anymore. 676 */ 677 while (*p && *p != '`') 678 if (*p++ == '\\') { 679 if (*p) /* Quoted chars */ 680 p++; 681 else 682 break; 683 } 684 if (*p) /* The matching ` */ 685 p++; 686 else 687 break; 688 #endif 689 } 690 else if (*c == '{') 691 gflag |= G_CSH; 692 else if (isglob(*c)) 693 gflag |= G_GLOB; 694 else if (symlinks == SYM_EXPAND && 695 *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') ) 696 gflag |= G_CSH; 697 } 698 } 699 } 700 701 /* 702 * Command substitute cp. If literal, then this is a substitution from a 703 * << redirection, and so we should not crunch blanks and tabs, separating 704 * words only at newlines. 705 */ 706 Char ** 707 dobackp(cp, literal) 708 Char *cp; 709 int literal; 710 { 711 Char *lp, *rp; 712 Char *ep, word[LONGBSIZE]; 713 714 if (pargv) { 715 #ifdef notdef 716 abort(); 717 #endif 718 blkfree(pargv); 719 } 720 pargsiz = GLOBSPACE; 721 pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz)); 722 pargv[0] = NULL; 723 pargcp = pargs = word; 724 pargc = 0; 725 pnleft = LONGBSIZE - 4; 726 for (;;) { 727 for (lp = cp; *lp != '`'; lp++) { 728 if (*lp == 0) { 729 if (pargcp != pargs) 730 pword(LONGBSIZE); 731 return (pargv); 732 } 733 psave(*lp); 734 } 735 lp++; 736 for (rp = lp; *rp && *rp != '`'; rp++) 737 if (*rp == '\\') { 738 rp++; 739 if (!*rp) 740 goto oops; 741 } 742 if (!*rp) 743 oops: stderror(ERR_UNMATCHED, '`'); 744 ep = Strsave(lp); 745 ep[rp - lp] = 0; 746 backeval(ep, literal); 747 cp = rp + 1; 748 } 749 } 750 751 752 static void 753 backeval(cp, literal) 754 Char *cp; 755 int literal; 756 { 757 int icnt; 758 Char c, *ip; 759 struct command faket; 760 int hadnl; 761 int pvec[2], quoted; 762 Char *fakecom[2], ibuf[BUFSIZE]; 763 char tibuf[BUFSIZE]; 764 765 hadnl = 0; 766 icnt = 0; 767 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 768 faket.t_dtyp = NODE_COMMAND; 769 faket.t_dflg = F_BACKQ; 770 faket.t_dlef = 0; 771 faket.t_drit = 0; 772 faket.t_dspr = 0; 773 faket.t_dcom = fakecom; 774 fakecom[0] = STRfakecom1; 775 fakecom[1] = 0; 776 777 /* 778 * We do the psave job to temporarily change the current job so that the 779 * following fork is considered a separate job. This is so that when 780 * backquotes are used in a builtin function that calls glob the "current 781 * job" is not corrupted. We only need one level of pushed jobs as long as 782 * we are sure to fork here. 783 */ 784 psavejob(); 785 786 /* 787 * It would be nicer if we could integrate this redirection more with the 788 * routines in sh.sem.c by doing a fake execute on a builtin function that 789 * was piped out. 790 */ 791 mypipe(pvec); 792 if (pfork(&faket, -1) == 0) { 793 jmp_buf_t osetexit; 794 struct command *volatile t; 795 796 (void) close(pvec[0]); 797 (void) dmove(pvec[1], 1); 798 (void) dmove(SHDIAG, 2); 799 initdesc(); 800 closem(); 801 /* 802 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 803 * posted to comp.bugs.4bsd 12 Sep. 1989. 804 */ 805 if (pargv) /* mg, 21.dec.88 */ 806 blkfree(pargv), pargv = 0, pargsiz = 0; 807 /* mg, 21.dec.88 */ 808 arginp = cp; 809 for (arginp = cp; *cp; cp++) { 810 *cp &= TRIM; 811 if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 812 *cp = ' '; 813 } 814 815 /* 816 * In the child ``forget'' everything about current aliases or 817 * eval vectors. 818 */ 819 alvec = NULL; 820 evalvec = NULL; 821 alvecp = NULL; 822 evalp = NULL; 823 824 t = NULL; 825 getexit(osetexit); 826 for (;;) { 827 828 if (paraml.next && paraml.next != ¶ml) 829 freelex(¶ml); 830 831 paraml.next = paraml.prev = ¶ml; 832 paraml.word = STRNULL; 833 (void) setexit(); 834 justpr = 0; 835 836 /* 837 * For the sake of reset() 838 */ 839 freelex(¶ml); 840 if (t) 841 freesyn(t), t = NULL; 842 843 if (haderr) { 844 /* unwind */ 845 doneinp = 0; 846 resexit(osetexit); 847 reset(); 848 } 849 if (seterr) { 850 xfree((ptr_t) seterr); 851 seterr = NULL; 852 } 853 854 (void) lex(¶ml); 855 if (seterr) 856 stderror(ERR_OLD); 857 alias(¶ml); 858 t = syntax(paraml.next, ¶ml, 0); 859 if (seterr) 860 stderror(ERR_OLD); 861 #ifdef SIGTSTP 862 (void) sigignore(SIGTSTP); 863 #endif 864 #ifdef SIGTTIN 865 (void) sigignore(SIGTTIN); 866 #endif 867 #ifdef SIGTTOU 868 (void) sigignore(SIGTTOU); 869 #endif 870 execute(t, -1, NULL, NULL, TRUE); 871 872 freelex(¶ml); 873 freesyn(t), t = NULL; 874 } 875 } 876 xfree((ptr_t) cp); 877 (void) close(pvec[1]); 878 c = 0; 879 ip = NULL; 880 do { 881 int cnt = 0; 882 char *tmp; 883 884 tmp = tibuf; 885 for (;;) { 886 while (icnt == 0) { 887 int i, eof; 888 889 ip = ibuf; 890 do 891 icnt = read(pvec[0], tmp, tibuf + BUFSIZE - tmp); 892 while (icnt == -1 && errno == EINTR); 893 eof = 0; 894 if (icnt <= 0) { 895 if (tmp == tibuf) 896 goto eof; 897 icnt = 0; 898 eof = 1; 899 } 900 icnt += tmp - tibuf; 901 i = 0; 902 tmp = tibuf; 903 while (tmp < tibuf + icnt) { 904 int len; 905 906 len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp); 907 if (len == -1) { 908 reset_mbtowc(); 909 if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) { 910 break; /* Maybe a partial character */ 911 } 912 ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */ 913 } 914 if (len <= 0) 915 len = 1; 916 i++; 917 tmp += len; 918 } 919 if (tmp != tibuf) 920 memmove (tibuf, tmp, tibuf + icnt - tmp); 921 tmp = tibuf + (tibuf + icnt - tmp); 922 icnt = i; 923 } 924 if (hadnl) 925 break; 926 --icnt; 927 c = (*ip++ & TRIM); 928 if (c == 0) 929 break; 930 #ifdef WINNT_NATIVE 931 if (c == '\r') 932 c = ' '; 933 #endif /* WINNT_NATIVE */ 934 if (c == '\n') { 935 /* 936 * Continue around the loop one more time, so that we can eat 937 * the last newline without terminating this word. 938 */ 939 hadnl = 1; 940 continue; 941 } 942 if (!quoted && (c == ' ' || c == '\t')) 943 break; 944 cnt++; 945 psave(c | quoted); 946 } 947 /* 948 * Unless at end-of-file, we will form a new word here if there were 949 * characters in the word, or in any case when we take text literally. 950 * If we didn't make empty words here when literal was set then we 951 * would lose blank lines. 952 */ 953 if (c != 0 && (cnt || literal)) 954 pword(BUFSIZE); 955 hadnl = 0; 956 } while (c > 0); 957 eof: 958 (void) close(pvec[0]); 959 pwait(); 960 prestjob(); 961 } 962 963 static void 964 psave(c) 965 Char c; 966 { 967 if (--pnleft <= 0) 968 stderror(ERR_WTOOLONG); 969 *pargcp++ = (Char) c; 970 } 971 972 static void 973 pword(bufsiz) 974 int bufsiz; 975 { 976 psave(0); 977 if (pargc == pargsiz - 1) { 978 pargsiz += GLOBSPACE; 979 pargv = (Char **) xrealloc((ptr_t) pargv, 980 (size_t) (pargsiz * sizeof(Char *))); 981 } 982 NLSQuote(pargs); 983 pargv[pargc++] = Strsave(pargs); 984 pargv[pargc] = NULL; 985 pargcp = pargs; 986 pnleft = bufsiz - 4; 987 } 988 989 int 990 Gmatch(string, pattern) 991 Char *string, *pattern; 992 { 993 return Gnmatch(string, pattern, NULL); 994 } 995 996 int 997 Gnmatch(string, pattern, endstr) 998 Char *string, *pattern, **endstr; 999 { 1000 Char **blk, **p, *tstring = string; 1001 int gpol = 1, gres = 0; 1002 1003 if (*pattern == '^') { 1004 gpol = 0; 1005 pattern++; 1006 } 1007 1008 blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *))); 1009 blk[0] = Strsave(pattern); 1010 blk[1] = NULL; 1011 1012 expbrace(&blk, NULL, GLOBSPACE); 1013 1014 if (endstr == NULL) 1015 /* Exact matches only */ 1016 for (p = blk; *p; p++) 1017 gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 1018 else { 1019 /* partial matches */ 1020 int minc = 0x7fffffff; 1021 for (p = blk; *p; p++) 1022 if (t_pmatch(string, *p, &tstring, 1) != 0) { 1023 int t = (int) (tstring - string); 1024 gres |= 1; 1025 if (minc == -1 || minc > t) 1026 minc = t; 1027 } 1028 *endstr = string + minc; 1029 } 1030 1031 blkfree(blk); 1032 return(gres == gpol); 1033 } 1034 1035 /* t_pmatch(): 1036 * Return 2 on exact match, 1037 * Return 1 on substring match. 1038 * Return 0 on no match. 1039 * *estr will point to the end of the longest exact or substring match. 1040 */ 1041 int 1042 t_pmatch(string, pattern, estr, cs) 1043 Char *string, *pattern, **estr; 1044 int cs; 1045 { 1046 NLSChar stringc, patternc, rangec; 1047 int match, negate_range; 1048 Char *oestr, *pestr, *nstring; 1049 1050 for (nstring = string;; string = nstring) { 1051 stringc = *nstring++; 1052 TRIM_AND_EXTEND(nstring, stringc); 1053 /* 1054 * apollo compiler bug: switch (patternc = *pattern++) dies 1055 */ 1056 patternc = *pattern++; 1057 TRIM_AND_EXTEND(pattern, patternc); 1058 switch (patternc) { 1059 case '\0': 1060 *estr = string; 1061 return (stringc == '\0' ? 2 : 1); 1062 case '?': 1063 if (stringc == 0) 1064 return (0); 1065 *estr = string; 1066 break; 1067 case '*': 1068 if (!*pattern) { 1069 while (*string) string++; 1070 *estr = string; 1071 return (2); 1072 } 1073 oestr = *estr; 1074 pestr = NULL; 1075 1076 for (;;) { 1077 switch(t_pmatch(string, pattern, estr, cs)) { 1078 case 0: 1079 break; 1080 case 1: 1081 pestr = *estr; 1082 break; 1083 case 2: 1084 return 2; 1085 default: 1086 abort(); /* Cannot happen */ 1087 } 1088 *estr = string; 1089 stringc = *string++; 1090 if (!stringc) 1091 break; 1092 TRIM_AND_EXTEND(string, stringc); 1093 } 1094 1095 if (pestr) { 1096 *estr = pestr; 1097 return 1; 1098 } 1099 else { 1100 *estr = oestr; 1101 return 0; 1102 } 1103 1104 case '[': 1105 match = 0; 1106 if ((negate_range = (*pattern == '^')) != 0) 1107 pattern++; 1108 while ((rangec = *pattern++) != '\0') { 1109 if (rangec == ']') 1110 break; 1111 if (match) 1112 continue; 1113 TRIM_AND_EXTEND(pattern, rangec); 1114 if (*pattern == '-' && pattern[1] != ']') { 1115 NLSChar rangec2; 1116 pattern++; 1117 rangec2 = *pattern++; 1118 TRIM_AND_EXTEND(pattern, rangec2); 1119 match = (globcharcoll(stringc, rangec2, 0) <= 0 && 1120 globcharcoll(rangec, stringc, 0) <= 0); 1121 } 1122 else 1123 match = (stringc == rangec); 1124 } 1125 if (rangec == '\0') 1126 stderror(ERR_NAME | ERR_MISSING, ']'); 1127 if ((!match) && (stringc == '\0')) 1128 return (0); 1129 if (match == negate_range) 1130 return (0); 1131 *estr = string; 1132 break; 1133 default: 1134 TRIM_AND_EXTEND(pattern, patternc); 1135 if (cs ? patternc != stringc 1136 #if defined (NLS) && defined (SHORT_STRINGS) 1137 : towlower(patternc) != towlower(stringc)) 1138 #else 1139 : Tolower(patternc) != Tolower(stringc)) 1140 #endif 1141 return (0); 1142 *estr = string; 1143 break; 1144 } 1145 } 1146 } 1147 1148 void 1149 Gcat(s1, s2) 1150 Char *s1, *s2; 1151 { 1152 Char *p, *q; 1153 int n; 1154 1155 for (p = s1; *p++;) 1156 continue; 1157 for (q = s2; *q++;) 1158 continue; 1159 n = (int) ((p - s1) + (q - s2) - 1); 1160 if (++gargc >= gargsiz) { 1161 gargsiz += GLOBSPACE; 1162 gargv = (Char **) xrealloc((ptr_t) gargv, 1163 (size_t) (gargsiz * sizeof(Char *))); 1164 } 1165 gargv[gargc] = 0; 1166 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char))); 1167 for (q = s1; (*p++ = *q++) != '\0';) 1168 continue; 1169 for (p--, q = s2; (*p++ = *q++) != '\0';) 1170 continue; 1171 } 1172 1173 #if defined(FILEC) && defined(TIOCSTI) 1174 int 1175 sortscmp(a, b) 1176 Char **a, **b; 1177 { 1178 if (!a) /* check for NULL */ 1179 return (b ? 1 : 0); 1180 if (!b) 1181 return (-1); 1182 1183 if (!*a) /* check for NULL */ 1184 return (*b ? 1 : 0); 1185 if (!*b) 1186 return (-1); 1187 1188 return (int) collate(*a, *b); 1189 } 1190 1191 #endif 1192