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