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