1 /* $OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 5 * 2011, 2012, 2013, 2014, 2015, 2016 6 * mirabilos <m (at) mirbsd.org> 7 * 8 * Provided that these terms and disclaimer and all copyright notices 9 * are retained or reproduced in an accompanying document, permission 10 * is granted to deal in this work without restriction, including un- 11 * limited rights to use, publicly perform, distribute, sell, modify, 12 * merge, give away, or sublicence. 13 * 14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 15 * the utmost extent permitted by applicable law, neither express nor 16 * implied; without malicious intent or gross negligence. In no event 17 * may a licensor, author or contributor be held liable for indirect, 18 * direct, other damage, loss, or other issues arising in any way out 19 * of dealing in the work, even if advised of the possibility of such 20 * damage or existence of a defect, except proven that it results out 21 * of said person's immediate fault when using the work as intended. 22 */ 23 24 #include "sh.h" 25 26 __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.180 2016/01/19 23:12:12 tg Exp $"); 27 28 /* 29 * string expansion 30 * 31 * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution. 32 * second pass: alternation ({,}), filename expansion (*?[]). 33 */ 34 35 /* expansion generator state */ 36 typedef struct { 37 /* not including an "int type;" member, see expand() */ 38 /* string */ 39 const char *str; 40 /* source */ 41 union { 42 /* string[] */ 43 const char **strv; 44 /* file */ 45 struct shf *shf; 46 } u; 47 /* variable in ${var...} */ 48 struct tbl *var; 49 /* split "$@" / call waitlast in $() */ 50 bool split; 51 } Expand; 52 53 #define XBASE 0 /* scanning original */ 54 #define XSUB 1 /* expanding ${} string */ 55 #define XARGSEP 2 /* ifs0 between "$*" */ 56 #define XARG 3 /* expanding $*, $@ */ 57 #define XCOM 4 /* expanding $() */ 58 #define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */ 59 #define XSUBMID 6 /* middle of expanding ${} */ 60 61 /* States used for field splitting */ 62 #define IFS_WORD 0 /* word has chars (or quotes except "$@") */ 63 #define IFS_WS 1 /* have seen IFS white-space */ 64 #define IFS_NWS 2 /* have seen IFS non-white-space */ 65 #define IFS_IWS 3 /* begin of word, ignore IFS WS */ 66 #define IFS_QUOTE 4 /* beg.w/quote, become IFS_WORD unless "$@" */ 67 68 static int varsub(Expand *, const char *, const char *, int *, int *); 69 static int comsub(Expand *, const char *, int); 70 static char *valsub(struct op *, Area *); 71 static char *trimsub(char *, char *, int); 72 static void glob(char *, XPtrV *, bool); 73 static void globit(XString *, char **, char *, XPtrV *, int); 74 static const char *maybe_expand_tilde(const char *, XString *, char **, bool); 75 #ifndef MKSH_NOPWNAM 76 static char *homedir(char *); 77 #endif 78 static void alt_expand(XPtrV *, char *, char *, char *, int); 79 static int utflen(const char *) MKSH_A_PURE; 80 static void utfincptr(const char *, mksh_ari_t *); 81 82 /* UTFMODE functions */ 83 static int 84 utflen(const char *s) 85 { 86 size_t n; 87 88 if (UTFMODE) { 89 n = 0; 90 while (*s) { 91 s += utf_ptradj(s); 92 ++n; 93 } 94 } else 95 n = strlen(s); 96 97 if (n > 2147483647) 98 n = 2147483647; 99 return ((int)n); 100 } 101 102 static void 103 utfincptr(const char *s, mksh_ari_t *lp) 104 { 105 const char *cp = s; 106 107 while ((*lp)--) 108 cp += utf_ptradj(cp); 109 *lp = cp - s; 110 } 111 112 /* compile and expand word */ 113 char * 114 substitute(const char *cp, int f) 115 { 116 struct source *s, *sold; 117 118 sold = source; 119 s = pushs(SWSTR, ATEMP); 120 s->start = s->str = cp; 121 source = s; 122 if (yylex(ONEWORD) != LWORD) 123 internal_errorf("bad substitution"); 124 source = sold; 125 afree(s, ATEMP); 126 return (evalstr(yylval.cp, f)); 127 } 128 129 /* 130 * expand arg-list 131 */ 132 char ** 133 eval(const char **ap, int f) 134 { 135 XPtrV w; 136 137 if (*ap == NULL) { 138 union mksh_ccphack vap; 139 140 vap.ro = ap; 141 return (vap.rw); 142 } 143 XPinit(w, 32); 144 /* space for shell name */ 145 XPput(w, NULL); 146 while (*ap != NULL) 147 expand(*ap++, &w, f); 148 XPput(w, NULL); 149 return ((char **)XPclose(w) + 1); 150 } 151 152 /* 153 * expand string 154 */ 155 char * 156 evalstr(const char *cp, int f) 157 { 158 XPtrV w; 159 char *dp = null; 160 161 XPinit(w, 1); 162 expand(cp, &w, f); 163 if (XPsize(w)) 164 dp = *XPptrv(w); 165 XPfree(w); 166 return (dp); 167 } 168 169 /* 170 * expand string - return only one component 171 * used from iosetup to expand redirection files 172 */ 173 char * 174 evalonestr(const char *cp, int f) 175 { 176 XPtrV w; 177 char *rv; 178 179 XPinit(w, 1); 180 expand(cp, &w, f); 181 switch (XPsize(w)) { 182 case 0: 183 rv = null; 184 break; 185 case 1: 186 rv = (char *) *XPptrv(w); 187 break; 188 default: 189 rv = evalstr(cp, f&~DOGLOB); 190 break; 191 } 192 XPfree(w); 193 return (rv); 194 } 195 196 /* for nested substitution: ${var:=$var2} */ 197 typedef struct SubType { 198 struct tbl *var; /* variable for ${var..} */ 199 struct SubType *prev; /* old type */ 200 struct SubType *next; /* poped type (to avoid re-allocating) */ 201 size_t base; /* begin position of expanded word */ 202 short stype; /* [=+-?%#] action after expanded word */ 203 short f; /* saved value of f (DOPAT, etc) */ 204 uint8_t quotep; /* saved value of quote (for ${..[%#]..}) */ 205 uint8_t quotew; /* saved value of quote (for ${..[+-=]..}) */ 206 } SubType; 207 208 void 209 expand( 210 /* input word */ 211 const char *ccp, 212 /* output words */ 213 XPtrV *wp, 214 /* DO* flags */ 215 int f) 216 { 217 int c = 0; 218 /* expansion type */ 219 int type; 220 /* quoted */ 221 int quote = 0; 222 /* destination string and live pointer */ 223 XString ds; 224 char *dp; 225 /* source */ 226 const char *sp; 227 /* second pass flags */ 228 int fdo; 229 /* have word */ 230 int word; 231 /* field splitting of parameter/command substitution */ 232 int doblank; 233 /* expansion variables */ 234 Expand x = { 235 NULL, { NULL }, NULL, 0 236 }; 237 SubType st_head, *st; 238 /* record number of trailing newlines in COMSUB */ 239 int newlines = 0; 240 bool saw_eq, make_magic; 241 unsigned int tilde_ok; 242 size_t len; 243 char *cp; 244 245 if (ccp == NULL) 246 internal_errorf("expand(NULL)"); 247 /* for alias, readonly, set, typeset commands */ 248 if ((f & DOVACHECK) && is_wdvarassign(ccp)) { 249 f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE); 250 f |= DOASNTILDE | DOSCALAR; 251 } 252 if (Flag(FNOGLOB)) 253 f &= ~DOGLOB; 254 if (Flag(FMARKDIRS)) 255 f |= DOMARKDIRS; 256 if (Flag(FBRACEEXPAND) && (f & DOGLOB)) 257 f |= DOBRACE; 258 259 /* init destination string */ 260 Xinit(ds, dp, 128, ATEMP); 261 type = XBASE; 262 sp = ccp; 263 fdo = 0; 264 saw_eq = false; 265 /* must be 1/0 */ 266 tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0; 267 doblank = 0; 268 make_magic = false; 269 word = (f&DOBLANK) ? IFS_WS : IFS_WORD; 270 /* clang doesn't know OSUBST comes before CSUBST */ 271 memset(&st_head, 0, sizeof(st_head)); 272 st = &st_head; 273 274 while (/* CONSTCOND */ 1) { 275 Xcheck(ds, dp); 276 277 switch (type) { 278 case XBASE: 279 /* original prefixed string */ 280 c = *sp++; 281 switch (c) { 282 case EOS: 283 c = 0; 284 break; 285 case CHAR: 286 c = *sp++; 287 break; 288 case QCHAR: 289 /* temporary quote */ 290 quote |= 2; 291 c = *sp++; 292 break; 293 case OQUOTE: 294 if (word != IFS_WORD) 295 word = IFS_QUOTE; 296 tilde_ok = 0; 297 quote = 1; 298 continue; 299 case CQUOTE: 300 if (word == IFS_QUOTE) 301 word = IFS_WORD; 302 quote = st->quotew; 303 continue; 304 case COMSUB: 305 case FUNSUB: 306 case VALSUB: 307 tilde_ok = 0; 308 if (f & DONTRUNCOMMAND) { 309 word = IFS_WORD; 310 *dp++ = '$'; 311 *dp++ = c == COMSUB ? '(' : '{'; 312 if (c != COMSUB) 313 *dp++ = c == FUNSUB ? ' ' : '|'; 314 while (*sp != '\0') { 315 Xcheck(ds, dp); 316 *dp++ = *sp++; 317 } 318 if (c != COMSUB) { 319 *dp++ = ';'; 320 *dp++ = '}'; 321 } else 322 *dp++ = ')'; 323 } else { 324 type = comsub(&x, sp, c); 325 if (type != XBASE && (f & DOBLANK)) 326 doblank++; 327 sp = strnul(sp) + 1; 328 newlines = 0; 329 } 330 continue; 331 case EXPRSUB: 332 tilde_ok = 0; 333 if (f & DONTRUNCOMMAND) { 334 word = IFS_WORD; 335 *dp++ = '$'; *dp++ = '('; *dp++ = '('; 336 while (*sp != '\0') { 337 Xcheck(ds, dp); 338 *dp++ = *sp++; 339 } 340 *dp++ = ')'; *dp++ = ')'; 341 } else { 342 struct tbl v; 343 344 v.flag = DEFINED|ISSET|INTEGER; 345 /* not default */ 346 v.type = 10; 347 v.name[0] = '\0'; 348 v_evaluate(&v, substitute(sp, 0), 349 KSH_UNWIND_ERROR, true); 350 sp = strnul(sp) + 1; 351 x.str = str_val(&v); 352 type = XSUB; 353 if (f & DOBLANK) 354 doblank++; 355 } 356 continue; 357 case OSUBST: { 358 /* ${{#}var{:}[=+-?#%]word} */ 359 /*- 360 * format is: 361 * OSUBST [{x] plain-variable-part \0 362 * compiled-word-part CSUBST [}x] 363 * This is where all syntax checking gets done... 364 */ 365 /* skip the { or x (}) */ 366 const char *varname = ++sp; 367 int stype; 368 int slen = 0; 369 370 /* skip variable */ 371 sp = cstrchr(sp, '\0') + 1; 372 type = varsub(&x, varname, sp, &stype, &slen); 373 if (type < 0) { 374 char *beg, *end, *str; 375 unwind_substsyn: 376 /* restore sp */ 377 sp = varname - 2; 378 end = (beg = wdcopy(sp, ATEMP)) + 379 (wdscan(sp, CSUBST) - sp); 380 /* ({) the } or x is already skipped */ 381 if (end < wdscan(beg, EOS)) 382 *end = EOS; 383 str = snptreef(NULL, 64, "%S", beg); 384 afree(beg, ATEMP); 385 errorf("%s: %s", str, "bad substitution"); 386 } 387 if (f & DOBLANK) 388 doblank++; 389 tilde_ok = 0; 390 if (word == IFS_QUOTE && type != XNULLSUB) 391 word = IFS_WORD; 392 if (type == XBASE) { 393 /* expand? */ 394 if (!st->next) { 395 SubType *newst; 396 397 newst = alloc(sizeof(SubType), ATEMP); 398 newst->next = NULL; 399 newst->prev = st; 400 st->next = newst; 401 } 402 st = st->next; 403 st->stype = stype; 404 st->base = Xsavepos(ds, dp); 405 st->f = f; 406 if (x.var == &vtemp) { 407 st->var = tempvar(); 408 st->var->flag &= ~INTEGER; 409 /* can't fail here */ 410 setstr(st->var, 411 str_val(x.var), 412 KSH_RETURN_ERROR | 0x4); 413 } else 414 st->var = x.var; 415 416 st->quotew = st->quotep = quote; 417 /* skip qualifier(s) */ 418 if (stype) 419 sp += slen; 420 switch (stype & 0x17F) { 421 case 0x100 | '#': 422 x.str = shf_smprintf("%08X", 423 (unsigned int)hash(str_val(st->var))); 424 break; 425 case 0x100 | 'Q': { 426 struct shf shf; 427 428 shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); 429 print_value_quoted(&shf, str_val(st->var)); 430 x.str = shf_sclose(&shf); 431 break; 432 } 433 case '0': { 434 char *beg, *mid, *end, *stg; 435 mksh_ari_t from = 0, num = -1, flen, finc = 0; 436 437 beg = wdcopy(sp, ATEMP); 438 mid = beg + (wdscan(sp, ADELIM) - sp); 439 stg = beg + (wdscan(sp, CSUBST) - sp); 440 mid[-2] = EOS; 441 if (mid[-1] == /*{*/'}') { 442 sp += mid - beg - 1; 443 end = NULL; 444 } else { 445 end = mid + 446 (wdscan(mid, ADELIM) - mid); 447 if (end[-1] != /*{*/ '}') 448 /* more than max delimiters */ 449 goto unwind_substsyn; 450 end[-2] = EOS; 451 sp += end - beg - 1; 452 } 453 evaluate(substitute(stg = wdstrip(beg, 0), 0), 454 &from, KSH_UNWIND_ERROR, true); 455 afree(stg, ATEMP); 456 if (end) { 457 evaluate(substitute(stg = wdstrip(mid, 0), 0), 458 &num, KSH_UNWIND_ERROR, true); 459 afree(stg, ATEMP); 460 } 461 afree(beg, ATEMP); 462 beg = str_val(st->var); 463 flen = utflen(beg); 464 if (from < 0) { 465 if (-from < flen) 466 finc = flen + from; 467 } else 468 finc = from < flen ? from : flen; 469 if (UTFMODE) 470 utfincptr(beg, &finc); 471 beg += finc; 472 flen = utflen(beg); 473 if (num < 0 || num > flen) 474 num = flen; 475 if (UTFMODE) 476 utfincptr(beg, &num); 477 strndupx(x.str, beg, num, ATEMP); 478 goto do_CSUBST; 479 } 480 case '/': { 481 char *s, *p, *d, *sbeg, *end; 482 char *pat, *rrep; 483 char fpat = 0, *tpat1, *tpat2; 484 485 s = wdcopy(sp, ATEMP); 486 p = s + (wdscan(sp, ADELIM) - sp); 487 d = s + (wdscan(sp, CSUBST) - sp); 488 p[-2] = EOS; 489 if (p[-1] == /*{*/'}') 490 d = NULL; 491 else 492 d[-2] = EOS; 493 sp += (d ? d : p) - s - 1; 494 if (!(stype & 0x80) && 495 s[0] == CHAR && 496 (s[1] == '#' || s[1] == '%')) 497 fpat = s[1]; 498 pat = evalstr(s + (fpat ? 2 : 0), 499 DOTILDE | DOSCALAR | DOPAT); 500 rrep = d ? evalstr(p, 501 DOTILDE | DOSCALAR) : null; 502 afree(s, ATEMP); 503 504 /* check for special cases */ 505 if (!*pat && !fpat) { 506 /* 507 * empty unanchored 508 * pattern => reject 509 */ 510 goto no_repl; 511 } 512 if ((stype & 0x80) && 513 gmatchx(null, pat, false)) { 514 /* 515 * pattern matches empty 516 * string => don't loop 517 */ 518 stype &= ~0x80; 519 } 520 521 /* prepare string on which to work */ 522 strdupx(s, str_val(st->var), ATEMP); 523 sbeg = s; 524 525 /* first see if we have any match at all */ 526 if (fpat == '#') { 527 /* anchor at the beginning */ 528 tpat1 = shf_smprintf("%s%c*", pat, MAGIC); 529 tpat2 = tpat1; 530 } else if (fpat == '%') { 531 /* anchor at the end */ 532 tpat1 = shf_smprintf("%c*%s", MAGIC, pat); 533 tpat2 = pat; 534 } else { 535 /* float */ 536 tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC); 537 tpat2 = tpat1 + 2; 538 } 539 again_repl: 540 /* 541 * this would not be necessary if gmatchx would return 542 * the start and end values of a match found, like re* 543 */ 544 if (!gmatchx(sbeg, tpat1, false)) 545 goto end_repl; 546 end = strnul(s); 547 /* now anchor the beginning of the match */ 548 if (fpat != '#') 549 while (sbeg <= end) { 550 if (gmatchx(sbeg, tpat2, false)) 551 break; 552 else 553 sbeg++; 554 } 555 /* now anchor the end of the match */ 556 p = end; 557 if (fpat != '%') 558 while (p >= sbeg) { 559 bool gotmatch; 560 561 c = *p; 562 *p = '\0'; 563 gotmatch = tobool(gmatchx(sbeg, pat, false)); 564 *p = c; 565 if (gotmatch) 566 break; 567 p--; 568 } 569 strndupx(end, s, sbeg - s, ATEMP); 570 d = shf_smprintf("%s%s%s", end, rrep, p); 571 afree(end, ATEMP); 572 sbeg = d + (sbeg - s) + strlen(rrep); 573 afree(s, ATEMP); 574 s = d; 575 if (stype & 0x80) 576 goto again_repl; 577 end_repl: 578 afree(tpat1, ATEMP); 579 x.str = s; 580 no_repl: 581 afree(pat, ATEMP); 582 if (rrep != null) 583 afree(rrep, ATEMP); 584 goto do_CSUBST; 585 } 586 case '#': 587 case '%': 588 /* ! DOBLANK,DOBRACE */ 589 f = (f & DONTRUNCOMMAND) | 590 DOPAT | DOTILDE | 591 DOTEMP | DOSCALAR; 592 tilde_ok = 1; 593 st->quotew = quote = 0; 594 /* 595 * Prepend open pattern (so | 596 * in a trim will work as 597 * expected) 598 */ 599 if (!Flag(FSH)) { 600 *dp++ = MAGIC; 601 *dp++ = 0x80 | '@'; 602 } 603 break; 604 case '=': 605 /* 606 * Enabling tilde expansion 607 * after :s here is 608 * non-standard ksh, but is 609 * consistent with rules for 610 * other assignments. Not 611 * sure what POSIX thinks of 612 * this. 613 * Not doing tilde expansion 614 * for integer variables is a 615 * non-POSIX thing - makes 616 * sense though, since ~ is 617 * a arithmetic operator. 618 */ 619 if (!(x.var->flag & INTEGER)) 620 f |= DOASNTILDE | DOTILDE; 621 f |= DOTEMP; 622 /* 623 * These will be done after the 624 * value has been assigned. 625 */ 626 f &= ~(DOBLANK|DOGLOB|DOBRACE); 627 tilde_ok = 1; 628 break; 629 case '?': 630 if (*sp == CSUBST) 631 errorf("%s: parameter null or not set", 632 st->var->name); 633 f &= ~DOBLANK; 634 f |= DOTEMP; 635 /* FALLTHROUGH */ 636 default: 637 /* '-' '+' '?' */ 638 if (quote) 639 word = IFS_WORD; 640 else if (dp == Xstring(ds, dp)) 641 word = IFS_IWS; 642 /* Enable tilde expansion */ 643 tilde_ok = 1; 644 f |= DOTILDE; 645 } 646 } else 647 /* skip word */ 648 sp += wdscan(sp, CSUBST) - sp; 649 continue; 650 } 651 case CSUBST: 652 /* only get here if expanding word */ 653 do_CSUBST: 654 /* ({) skip the } or x */ 655 sp++; 656 /* in case of ${unset:-} */ 657 tilde_ok = 0; 658 *dp = '\0'; 659 quote = st->quotep; 660 f = st->f; 661 if (f & DOBLANK) 662 doblank--; 663 switch (st->stype & 0x17F) { 664 case '#': 665 case '%': 666 if (!Flag(FSH)) { 667 /* Append end-pattern */ 668 *dp++ = MAGIC; 669 *dp++ = ')'; 670 } 671 *dp = '\0'; 672 dp = Xrestpos(ds, dp, st->base); 673 /* 674 * Must use st->var since calling 675 * global would break things 676 * like x[i+=1]. 677 */ 678 x.str = trimsub(str_val(st->var), 679 dp, st->stype); 680 if (x.str[0] != '\0') { 681 word = IFS_IWS; 682 type = XSUB; 683 } else if (quote) { 684 word = IFS_WORD; 685 type = XSUB; 686 } else { 687 if (dp == Xstring(ds, dp)) 688 word = IFS_IWS; 689 type = XNULLSUB; 690 } 691 if (f & DOBLANK) 692 doblank++; 693 st = st->prev; 694 continue; 695 case '=': 696 /* 697 * Restore our position and substitute 698 * the value of st->var (may not be 699 * the assigned value in the presence 700 * of integer/right-adj/etc attributes). 701 */ 702 dp = Xrestpos(ds, dp, st->base); 703 /* 704 * Must use st->var since calling 705 * global would cause with things 706 * like x[i+=1] to be evaluated twice. 707 */ 708 /* 709 * Note: not exported by FEXPORT 710 * in AT&T ksh. 711 */ 712 /* 713 * XXX POSIX says readonly is only 714 * fatal for special builtins (setstr 715 * does readonly check). 716 */ 717 len = strlen(dp) + 1; 718 setstr(st->var, 719 debunk(alloc(len, ATEMP), 720 dp, len), KSH_UNWIND_ERROR); 721 x.str = str_val(st->var); 722 type = XSUB; 723 if (f & DOBLANK) 724 doblank++; 725 st = st->prev; 726 word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; 727 continue; 728 case '?': 729 dp = Xrestpos(ds, dp, st->base); 730 731 errorf("%s: %s", st->var->name, 732 debunk(dp, dp, strlen(dp) + 1)); 733 break; 734 case '0': 735 case '/': 736 case 0x100 | '#': 737 case 0x100 | 'Q': 738 dp = Xrestpos(ds, dp, st->base); 739 type = XSUB; 740 word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; 741 if (f & DOBLANK) 742 doblank++; 743 st = st->prev; 744 continue; 745 /* default: '-' '+' */ 746 } 747 st = st->prev; 748 type = XBASE; 749 continue; 750 751 case OPAT: 752 /* open pattern: *(foo|bar) */ 753 /* Next char is the type of pattern */ 754 make_magic = true; 755 c = *sp++ | 0x80; 756 break; 757 758 case SPAT: 759 /* pattern separator (|) */ 760 make_magic = true; 761 c = '|'; 762 break; 763 764 case CPAT: 765 /* close pattern */ 766 make_magic = true; 767 c = /*(*/ ')'; 768 break; 769 } 770 break; 771 772 case XNULLSUB: 773 /* 774 * Special case for "$@" (and "${foo[@]}") - no 775 * word is generated if $# is 0 (unless there is 776 * other stuff inside the quotes). 777 */ 778 type = XBASE; 779 if (f & DOBLANK) { 780 doblank--; 781 if (dp == Xstring(ds, dp) && word != IFS_WORD) 782 word = IFS_IWS; 783 } 784 continue; 785 786 case XSUB: 787 case XSUBMID: 788 if ((c = *x.str++) == 0) { 789 type = XBASE; 790 if (f & DOBLANK) 791 doblank--; 792 continue; 793 } 794 break; 795 796 case XARGSEP: 797 type = XARG; 798 quote = 1; 799 /* FALLTHROUGH */ 800 case XARG: 801 if ((c = *x.str++) == '\0') { 802 /* 803 * force null words to be created so 804 * set -- "" 2 ""; echo "$@" will do 805 * the right thing 806 */ 807 if (quote && x.split) 808 word = IFS_WORD; 809 if ((x.str = *x.u.strv++) == NULL) { 810 type = XBASE; 811 if (f & DOBLANK) 812 doblank--; 813 continue; 814 } 815 c = ifs0; 816 if ((f & DOHEREDOC)) { 817 /* pseudo-field-split reliably */ 818 if (c == 0) 819 c = ' '; 820 break; 821 } 822 if ((f & DOSCALAR)) { 823 /* do not field-split */ 824 if (x.split) { 825 c = ' '; 826 break; 827 } 828 if (c == 0) 829 continue; 830 } 831 if (c == 0) { 832 if (quote && !x.split) 833 continue; 834 if (!quote && word == IFS_WS) 835 continue; 836 /* this is so we don't terminate */ 837 c = ' '; 838 /* now force-emit a word */ 839 goto emit_word; 840 } 841 if (quote && x.split) { 842 /* terminate word for "$@" */ 843 type = XARGSEP; 844 quote = 0; 845 } 846 } 847 break; 848 849 case XCOM: 850 if (x.u.shf == NULL) { 851 /* $(<...) failed */ 852 subst_exstat = 1; 853 /* fake EOF */ 854 c = -1; 855 } else if (newlines) { 856 /* spit out saved NLs */ 857 c = '\n'; 858 --newlines; 859 } else { 860 while ((c = shf_getc(x.u.shf)) == 0 || c == '\n') 861 if (c == '\n') 862 /* save newlines */ 863 newlines++; 864 if (newlines && c != -1) { 865 shf_ungetc(c, x.u.shf); 866 c = '\n'; 867 --newlines; 868 } 869 } 870 if (c == -1) { 871 newlines = 0; 872 if (x.u.shf) 873 shf_close(x.u.shf); 874 if (x.split) 875 subst_exstat = waitlast(); 876 type = XBASE; 877 if (f & DOBLANK) 878 doblank--; 879 continue; 880 } 881 break; 882 } 883 884 /* check for end of word or IFS separation */ 885 if (c == 0 || (!quote && (f & DOBLANK) && doblank && 886 !make_magic && ctype(c, C_IFS))) { 887 /*- 888 * How words are broken up: 889 * | value of c 890 * word | ws nws 0 891 * ----------------------------------- 892 * IFS_WORD w/WS w/NWS w 893 * IFS_WS -/WS -/NWS - 894 * IFS_NWS -/NWS w/NWS - 895 * IFS_IWS -/WS w/NWS - 896 * (w means generate a word) 897 */ 898 if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c && 899 (word == IFS_IWS || word == IFS_NWS) && 900 !ctype(c, C_IFSWS))) { 901 emit_word: 902 if (f & DOHERESTR) 903 *dp++ = '\n'; 904 *dp++ = '\0'; 905 cp = Xclose(ds, dp); 906 if (fdo & DOBRACE) 907 /* also does globbing */ 908 alt_expand(wp, cp, cp, 909 cp + Xlength(ds, (dp - 1)), 910 fdo | (f & DOMARKDIRS)); 911 else if (fdo & DOGLOB) 912 glob(cp, wp, tobool(f & DOMARKDIRS)); 913 else if ((f & DOPAT) || !(fdo & DOMAGIC)) 914 XPput(*wp, cp); 915 else 916 XPput(*wp, debunk(cp, cp, 917 strlen(cp) + 1)); 918 fdo = 0; 919 saw_eq = false; 920 /* must be 1/0 */ 921 tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0; 922 if (c == 0) 923 return; 924 Xinit(ds, dp, 128, ATEMP); 925 } else if (c == 0) { 926 return; 927 } else if (type == XSUB && ctype(c, C_IFS) && 928 !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) { 929 *(cp = alloc(1, ATEMP)) = '\0'; 930 XPput(*wp, cp); 931 type = XSUBMID; 932 } 933 if (word != IFS_NWS) 934 word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS; 935 } else { 936 if (type == XSUB) { 937 if (word == IFS_NWS && 938 Xlength(ds, dp) == 0) { 939 *(cp = alloc(1, ATEMP)) = '\0'; 940 XPput(*wp, cp); 941 } 942 type = XSUBMID; 943 } 944 945 /* age tilde_ok info - ~ code tests second bit */ 946 tilde_ok <<= 1; 947 /* mark any special second pass chars */ 948 if (!quote) 949 switch (c) { 950 case '[': 951 case '!': 952 case '-': 953 case ']': 954 /* 955 * For character classes - doesn't hurt 956 * to have magic !,-,]s outside of 957 * [...] expressions. 958 */ 959 if (f & (DOPAT | DOGLOB)) { 960 fdo |= DOMAGIC; 961 if (c == '[') 962 fdo |= f & DOGLOB; 963 *dp++ = MAGIC; 964 } 965 break; 966 case '*': 967 case '?': 968 if (f & (DOPAT | DOGLOB)) { 969 fdo |= DOMAGIC | (f & DOGLOB); 970 *dp++ = MAGIC; 971 } 972 break; 973 case '{': 974 case '}': 975 case ',': 976 if ((f & DOBRACE) && (c == '{' /*}*/ || 977 (fdo & DOBRACE))) { 978 fdo |= DOBRACE|DOMAGIC; 979 *dp++ = MAGIC; 980 } 981 break; 982 case '=': 983 /* Note first unquoted = for ~ */ 984 if (!(f & DOTEMP) && (!Flag(FPOSIX) || 985 (f & DOASNTILDE)) && !saw_eq) { 986 saw_eq = true; 987 tilde_ok = 1; 988 } 989 break; 990 case ':': 991 /* : */ 992 /* Note unquoted : for ~ */ 993 if (!(f & DOTEMP) && (f & DOASNTILDE)) 994 tilde_ok = 1; 995 break; 996 case '~': 997 /* 998 * tilde_ok is reset whenever 999 * any of ' " $( $(( ${ } are seen. 1000 * Note that tilde_ok must be preserved 1001 * through the sequence ${A=a=}~ 1002 */ 1003 if (type == XBASE && 1004 (f & (DOTILDE | DOASNTILDE)) && 1005 (tilde_ok & 2)) { 1006 const char *tcp; 1007 char *tdp = dp; 1008 1009 tcp = maybe_expand_tilde(sp, 1010 &ds, &tdp, 1011 tobool(f & DOASNTILDE)); 1012 if (tcp) { 1013 if (dp != tdp) 1014 word = IFS_WORD; 1015 dp = tdp; 1016 sp = tcp; 1017 continue; 1018 } 1019 } 1020 break; 1021 } 1022 else 1023 /* undo temporary */ 1024 quote &= ~2; 1025 1026 if (make_magic) { 1027 make_magic = false; 1028 fdo |= DOMAGIC | (f & DOGLOB); 1029 *dp++ = MAGIC; 1030 } else if (ISMAGIC(c)) { 1031 fdo |= DOMAGIC; 1032 *dp++ = MAGIC; 1033 } 1034 /* save output char */ 1035 *dp++ = c; 1036 word = IFS_WORD; 1037 } 1038 } 1039 } 1040 1041 static bool 1042 hasnonempty(const char **strv) 1043 { 1044 size_t i = 0; 1045 1046 while (strv[i]) 1047 if (*strv[i++]) 1048 return (true); 1049 return (false); 1050 } 1051 1052 /* 1053 * Prepare to generate the string returned by ${} substitution. 1054 */ 1055 static int 1056 varsub(Expand *xp, const char *sp, const char *word, 1057 int *stypep, /* becomes qualifier type */ 1058 int *slenp) /* " " len (=, :=, etc.) valid iff *stypep != 0 */ 1059 { 1060 int c; 1061 int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */ 1062 int stype; /* substitution type */ 1063 int slen; 1064 const char *p; 1065 struct tbl *vp; 1066 bool zero_ok = false; 1067 1068 if ((stype = sp[0]) == '\0') 1069 /* Bad variable name */ 1070 return (-1); 1071 1072 xp->var = NULL; 1073 1074 /*- 1075 * ${#var}, string length (-U: characters, +U: octets) or array size 1076 * ${%var}, string width (-U: screen columns, +U: octets) 1077 */ 1078 c = sp[1]; 1079 if (stype == '%' && c == '\0') 1080 return (-1); 1081 if ((stype == '#' || stype == '%') && c != '\0') { 1082 /* Can't have any modifiers for ${#...} or ${%...} */ 1083 if (*word != CSUBST) 1084 return (-1); 1085 sp++; 1086 /* Check for size of array */ 1087 if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') && 1088 p[2] == ']') { 1089 int n = 0; 1090 1091 if (stype != '#') 1092 return (-1); 1093 vp = global(arrayname(sp)); 1094 if (vp->flag & (ISSET|ARRAY)) 1095 zero_ok = true; 1096 for (; vp; vp = vp->u.array) 1097 if (vp->flag & ISSET) 1098 n++; 1099 c = n; 1100 } else if (c == '*' || c == '@') { 1101 if (stype != '#') 1102 return (-1); 1103 c = e->loc->argc; 1104 } else { 1105 p = str_val(global(sp)); 1106 zero_ok = p != null; 1107 if (stype == '#') 1108 c = utflen(p); 1109 else { 1110 /* partial utf_mbswidth reimplementation */ 1111 const char *s = p; 1112 unsigned int wc; 1113 size_t len; 1114 int cw; 1115 1116 c = 0; 1117 while (*s) { 1118 if (!UTFMODE || (len = utf_mbtowc(&wc, 1119 s)) == (size_t)-1) 1120 /* not UTFMODE or not UTF-8 */ 1121 wc = (unsigned char)(*s++); 1122 else 1123 /* UTFMODE and UTF-8 */ 1124 s += len; 1125 /* wc == char or wchar at s++ */ 1126 if ((cw = utf_wcwidth(wc)) == -1) { 1127 /* 646, 8859-1, 10646 C0/C1 */ 1128 c = -1; 1129 break; 1130 } 1131 c += cw; 1132 } 1133 } 1134 } 1135 if (Flag(FNOUNSET) && c == 0 && !zero_ok) 1136 errorf("%s: %s", sp, "parameter not set"); 1137 /* unqualified variable/string substitution */ 1138 *stypep = 0; 1139 xp->str = shf_smprintf("%d", c); 1140 return (XSUB); 1141 } 1142 1143 /* Check for qualifiers in word part */ 1144 stype = 0; 1145 c = word[slen = 0] == CHAR ? word[1] : 0; 1146 if (c == ':') { 1147 slen += 2; 1148 stype = 0x80; 1149 c = word[slen + 0] == CHAR ? word[slen + 1] : 0; 1150 } 1151 if (!stype && c == '/') { 1152 slen += 2; 1153 stype = c; 1154 if (word[slen] == ADELIM) { 1155 slen += 2; 1156 stype |= 0x80; 1157 } 1158 } else if (stype == 0x80 && (c == ' ' || c == '0')) { 1159 stype |= '0'; 1160 } else if (ctype(c, C_SUBOP1)) { 1161 slen += 2; 1162 stype |= c; 1163 } else if (ctype(c, C_SUBOP2)) { 1164 /* Note: ksh88 allows :%, :%%, etc */ 1165 slen += 2; 1166 stype = c; 1167 if (word[slen + 0] == CHAR && c == word[slen + 1]) { 1168 stype |= 0x80; 1169 slen += 2; 1170 } 1171 } else if (c == '@') { 1172 /* @x where x is command char */ 1173 slen += 2; 1174 stype |= 0x100; 1175 if (word[slen] == CHAR) { 1176 stype |= word[slen + 1]; 1177 slen += 2; 1178 } 1179 } else if (stype) 1180 /* : is not ok */ 1181 return (-1); 1182 if (!stype && *word != CSUBST) 1183 return (-1); 1184 *stypep = stype; 1185 *slenp = slen; 1186 1187 c = sp[0]; 1188 if (c == '*' || c == '@') { 1189 switch (stype & 0x17F) { 1190 /* can't assign to a vector */ 1191 case '=': 1192 /* can't trim a vector (yet) */ 1193 case '%': 1194 case '#': 1195 case '0': 1196 case '/': 1197 case 0x100 | '#': 1198 case 0x100 | 'Q': 1199 return (-1); 1200 } 1201 if (e->loc->argc == 0) { 1202 xp->str = null; 1203 xp->var = global(sp); 1204 state = c == '@' ? XNULLSUB : XSUB; 1205 } else { 1206 xp->u.strv = (const char **)e->loc->argv + 1; 1207 xp->str = *xp->u.strv++; 1208 /* $@ */ 1209 xp->split = tobool(c == '@'); 1210 state = XARG; 1211 } 1212 /* POSIX 2009? */ 1213 zero_ok = true; 1214 } else { 1215 if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') && 1216 p[2] == ']') { 1217 XPtrV wv; 1218 1219 switch (stype & 0x17F) { 1220 /* can't assign to a vector */ 1221 case '=': 1222 /* can't trim a vector (yet) */ 1223 case '%': 1224 case '#': 1225 case '?': 1226 case '0': 1227 case '/': 1228 case 0x100 | '#': 1229 case 0x100 | 'Q': 1230 return (-1); 1231 } 1232 XPinit(wv, 32); 1233 if ((c = sp[0]) == '!') 1234 ++sp; 1235 vp = global(arrayname(sp)); 1236 for (; vp; vp = vp->u.array) { 1237 if (!(vp->flag&ISSET)) 1238 continue; 1239 XPput(wv, c == '!' ? shf_smprintf("%lu", 1240 arrayindex(vp)) : 1241 str_val(vp)); 1242 } 1243 if (XPsize(wv) == 0) { 1244 xp->str = null; 1245 state = p[1] == '@' ? XNULLSUB : XSUB; 1246 XPfree(wv); 1247 } else { 1248 XPput(wv, 0); 1249 xp->u.strv = (const char **)XPptrv(wv); 1250 xp->str = *xp->u.strv++; 1251 /* ${foo[@]} */ 1252 xp->split = tobool(p[1] == '@'); 1253 state = XARG; 1254 } 1255 } else { 1256 /* Can't assign things like $! or $1 */ 1257 if ((stype & 0x17F) == '=' && 1258 ctype(*sp, C_VAR1 | C_DIGIT)) 1259 return (-1); 1260 if (*sp == '!' && sp[1]) { 1261 ++sp; 1262 xp->var = global(sp); 1263 if (vstrchr(sp, '[')) 1264 xp->str = shf_smprintf("%s[%lu]", 1265 xp->var->name, 1266 arrayindex(xp->var)); 1267 else 1268 xp->str = xp->var->name; 1269 } else { 1270 xp->var = global(sp); 1271 xp->str = str_val(xp->var); 1272 } 1273 state = XSUB; 1274 } 1275 } 1276 1277 c = stype & 0x7F; 1278 /* test the compiler's code generator */ 1279 if (((stype < 0x100) && (ctype(c, C_SUBOP2) || c == '/' || 1280 (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) && 1281 (state != XARG || (ifs0 || xp->split ? 1282 (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ? 1283 c == '=' || c == '-' || c == '?' : c == '+'))) || 1284 stype == (0x80 | '0') || stype == (0x100 | '#') || 1285 stype == (0x100 | 'Q')) 1286 /* expand word instead of variable value */ 1287 state = XBASE; 1288 if (Flag(FNOUNSET) && xp->str == null && !zero_ok && 1289 (ctype(c, C_SUBOP2) || (state != XBASE && c != '+'))) 1290 errorf("%s: %s", sp, "parameter not set"); 1291 return (state); 1292 } 1293 1294 /* 1295 * Run the command in $(...) and read its output. 1296 */ 1297 static int 1298 comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED) 1299 { 1300 Source *s, *sold; 1301 struct op *t; 1302 struct shf *shf; 1303 uint8_t old_utfmode = UTFMODE; 1304 1305 s = pushs(SSTRING, ATEMP); 1306 s->start = s->str = cp; 1307 sold = source; 1308 t = compile(s, true); 1309 afree(s, ATEMP); 1310 source = sold; 1311 1312 UTFMODE = old_utfmode; 1313 1314 if (t == NULL) 1315 return (XBASE); 1316 1317 /* no waitlast() unless specifically enabled later */ 1318 xp->split = false; 1319 1320 if (t->type == TCOM && 1321 *t->args == NULL && *t->vars == NULL && t->ioact != NULL) { 1322 /* $(<file) */ 1323 struct ioword *io = *t->ioact; 1324 char *name; 1325 1326 if ((io->ioflag & IOTYPE) != IOREAD) 1327 errorf("%s: %s", T_funny_command, 1328 snptreef(NULL, 32, "%R", io)); 1329 shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY, 1330 0, SHF_MAPHI | SHF_CLEXEC); 1331 if (shf == NULL) 1332 warningf(!Flag(FTALKING), "%s: %s %s: %s", name, 1333 "can't open", "$(<...) input", cstrerror(errno)); 1334 } else if (fn == FUNSUB) { 1335 int ofd1; 1336 struct temp *tf = NULL; 1337 1338 /* 1339 * create a temporary file, open for reading and writing, 1340 * with an shf open for reading (buffered) but yet unused 1341 */ 1342 maketemp(ATEMP, TT_FUNSUB, &tf); 1343 if (!tf->shf) { 1344 errorf("can't %s temporary file %s: %s", 1345 "create", tf->tffn, cstrerror(errno)); 1346 } 1347 /* extract shf from temporary file, unlink and free it */ 1348 shf = tf->shf; 1349 unlink(tf->tffn); 1350 afree(tf, ATEMP); 1351 /* save stdout and let it point to the tempfile */ 1352 ofd1 = savefd(1); 1353 ksh_dup2(shf_fileno(shf), 1, false); 1354 /* 1355 * run tree, with output thrown into the tempfile, 1356 * in a new function block 1357 */ 1358 valsub(t, NULL); 1359 subst_exstat = exstat & 0xFF; 1360 /* rewind the tempfile and restore regular stdout */ 1361 lseek(shf_fileno(shf), (off_t)0, SEEK_SET); 1362 restfd(1, ofd1); 1363 } else if (fn == VALSUB) { 1364 xp->str = valsub(t, ATEMP); 1365 subst_exstat = exstat & 0xFF; 1366 return (XSUB); 1367 } else { 1368 int ofd1, pv[2]; 1369 1370 openpipe(pv); 1371 shf = shf_fdopen(pv[0], SHF_RD, NULL); 1372 ofd1 = savefd(1); 1373 if (pv[1] != 1) { 1374 ksh_dup2(pv[1], 1, false); 1375 close(pv[1]); 1376 } 1377 execute(t, XXCOM | XPIPEO | XFORK, NULL); 1378 restfd(1, ofd1); 1379 startlast(); 1380 /* waitlast() */ 1381 xp->split = true; 1382 } 1383 1384 xp->u.shf = shf; 1385 return (XCOM); 1386 } 1387 1388 /* 1389 * perform #pattern and %pattern substitution in ${} 1390 */ 1391 static char * 1392 trimsub(char *str, char *pat, int how) 1393 { 1394 char *end = strnul(str); 1395 char *p, c; 1396 1397 switch (how & 0xFF) { 1398 case '#': 1399 /* shortest match at beginning */ 1400 for (p = str; p <= end; p += utf_ptradj(p)) { 1401 c = *p; *p = '\0'; 1402 if (gmatchx(str, pat, false)) { 1403 *p = c; 1404 return (p); 1405 } 1406 *p = c; 1407 } 1408 break; 1409 case '#'|0x80: 1410 /* longest match at beginning */ 1411 for (p = end; p >= str; p--) { 1412 c = *p; *p = '\0'; 1413 if (gmatchx(str, pat, false)) { 1414 *p = c; 1415 return (p); 1416 } 1417 *p = c; 1418 } 1419 break; 1420 case '%': 1421 /* shortest match at end */ 1422 p = end; 1423 while (p >= str) { 1424 if (gmatchx(p, pat, false)) 1425 goto trimsub_match; 1426 if (UTFMODE) { 1427 char *op = p; 1428 while ((p-- > str) && ((*p & 0xC0) == 0x80)) 1429 ; 1430 if ((p < str) || (p + utf_ptradj(p) != op)) 1431 p = op - 1; 1432 } else 1433 --p; 1434 } 1435 break; 1436 case '%'|0x80: 1437 /* longest match at end */ 1438 for (p = str; p <= end; p++) 1439 if (gmatchx(p, pat, false)) { 1440 trimsub_match: 1441 strndupx(end, str, p - str, ATEMP); 1442 return (end); 1443 } 1444 break; 1445 } 1446 1447 /* no match, return string */ 1448 return (str); 1449 } 1450 1451 /* 1452 * glob 1453 * Name derived from V6's /etc/glob, the program that expanded filenames. 1454 */ 1455 1456 /* XXX cp not const 'cause slashes are temporarily replaced with NULs... */ 1457 static void 1458 glob(char *cp, XPtrV *wp, bool markdirs) 1459 { 1460 int oldsize = XPsize(*wp); 1461 1462 if (glob_str(cp, wp, markdirs) == 0) 1463 XPput(*wp, debunk(cp, cp, strlen(cp) + 1)); 1464 else 1465 qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize, 1466 sizeof(void *), xstrcmp); 1467 } 1468 1469 #define GF_NONE 0 1470 #define GF_EXCHECK BIT(0) /* do existence check on file */ 1471 #define GF_GLOBBED BIT(1) /* some globbing has been done */ 1472 #define GF_MARKDIR BIT(2) /* add trailing / to directories */ 1473 1474 /* 1475 * Apply file globbing to cp and store the matching files in wp. Returns 1476 * the number of matches found. 1477 */ 1478 int 1479 glob_str(char *cp, XPtrV *wp, bool markdirs) 1480 { 1481 int oldsize = XPsize(*wp); 1482 XString xs; 1483 char *xp; 1484 1485 Xinit(xs, xp, 256, ATEMP); 1486 globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE); 1487 Xfree(xs, xp); 1488 1489 return (XPsize(*wp) - oldsize); 1490 } 1491 1492 static void 1493 globit(XString *xs, /* dest string */ 1494 char **xpp, /* ptr to dest end */ 1495 char *sp, /* source path */ 1496 XPtrV *wp, /* output list */ 1497 int check) /* GF_* flags */ 1498 { 1499 char *np; /* next source component */ 1500 char *xp = *xpp; 1501 char *se; 1502 char odirsep; 1503 1504 /* This to allow long expansions to be interrupted */ 1505 intrcheck(); 1506 1507 if (sp == NULL) { 1508 /* end of source path */ 1509 /* 1510 * We only need to check if the file exists if a pattern 1511 * is followed by a non-pattern (eg, foo*x/bar; no check 1512 * is needed for foo* since the match must exist) or if 1513 * any patterns were expanded and the markdirs option is set. 1514 * Symlinks make things a bit tricky... 1515 */ 1516 if ((check & GF_EXCHECK) || 1517 ((check & GF_MARKDIR) && (check & GF_GLOBBED))) { 1518 #define stat_check() (stat_done ? stat_done : (stat_done = \ 1519 stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1)) 1520 struct stat lstatb, statb; 1521 /* -1: failed, 1 ok, 0 not yet done */ 1522 int stat_done = 0; 1523 1524 if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0) 1525 return; 1526 /* 1527 * special case for systems which strip trailing 1528 * slashes from regular files (eg, /etc/passwd/). 1529 * SunOS 4.1.3 does this... 1530 */ 1531 if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) && 1532 xp[-1] == '/' && !S_ISDIR(lstatb.st_mode) && 1533 (!S_ISLNK(lstatb.st_mode) || 1534 stat_check() < 0 || !S_ISDIR(statb.st_mode))) 1535 return; 1536 /* 1537 * Possibly tack on a trailing / if there isn't already 1538 * one and if the file is a directory or a symlink to a 1539 * directory 1540 */ 1541 if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) && 1542 xp > Xstring(*xs, xp) && xp[-1] != '/' && 1543 (S_ISDIR(lstatb.st_mode) || 1544 (S_ISLNK(lstatb.st_mode) && stat_check() > 0 && 1545 S_ISDIR(statb.st_mode)))) { 1546 *xp++ = '/'; 1547 *xp = '\0'; 1548 } 1549 } 1550 strndupx(np, Xstring(*xs, xp), Xlength(*xs, xp), ATEMP); 1551 XPput(*wp, np); 1552 return; 1553 } 1554 1555 if (xp > Xstring(*xs, xp)) 1556 *xp++ = '/'; 1557 while (*sp == '/') { 1558 Xcheck(*xs, xp); 1559 *xp++ = *sp++; 1560 } 1561 np = strchr(sp, '/'); 1562 if (np != NULL) { 1563 se = np; 1564 /* don't assume '/', can be multiple kinds */ 1565 odirsep = *np; 1566 *np++ = '\0'; 1567 } else { 1568 odirsep = '\0'; /* keep gcc quiet */ 1569 se = sp + strlen(sp); 1570 } 1571 1572 1573 /* 1574 * Check if sp needs globbing - done to avoid pattern checks for strings 1575 * containing MAGIC characters, open [s without the matching close ], 1576 * etc. (otherwise opendir() will be called which may fail because the 1577 * directory isn't readable - if no globbing is needed, only execute 1578 * permission should be required (as per POSIX)). 1579 */ 1580 if (!has_globbing(sp, se)) { 1581 XcheckN(*xs, xp, se - sp + 1); 1582 debunk(xp, sp, Xnleft(*xs, xp)); 1583 xp += strlen(xp); 1584 *xpp = xp; 1585 globit(xs, xpp, np, wp, check); 1586 } else { 1587 DIR *dirp; 1588 struct dirent *d; 1589 char *name; 1590 size_t len, prefix_len; 1591 1592 /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ 1593 *xp = '\0'; 1594 prefix_len = Xlength(*xs, xp); 1595 dirp = opendir(prefix_len ? Xstring(*xs, xp) : "."); 1596 if (dirp == NULL) 1597 goto Nodir; 1598 while ((d = readdir(dirp)) != NULL) { 1599 name = d->d_name; 1600 if (name[0] == '.' && 1601 (name[1] == 0 || (name[1] == '.' && name[2] == 0))) 1602 /* always ignore . and .. */ 1603 continue; 1604 if ((*name == '.' && *sp != '.') || 1605 !gmatchx(name, sp, true)) 1606 continue; 1607 1608 len = strlen(d->d_name) + 1; 1609 XcheckN(*xs, xp, len); 1610 memcpy(xp, name, len); 1611 *xpp = xp + len - 1; 1612 globit(xs, xpp, np, wp, 1613 (check & GF_MARKDIR) | GF_GLOBBED 1614 | (np ? GF_EXCHECK : GF_NONE)); 1615 xp = Xstring(*xs, xp) + prefix_len; 1616 } 1617 closedir(dirp); 1618 Nodir: 1619 ; 1620 } 1621 1622 if (np != NULL) 1623 *--np = odirsep; 1624 } 1625 1626 /* remove MAGIC from string */ 1627 char * 1628 debunk(char *dp, const char *sp, size_t dlen) 1629 { 1630 char *d; 1631 const char *s; 1632 1633 if ((s = cstrchr(sp, MAGIC))) { 1634 if (s - sp >= (ssize_t)dlen) 1635 return (dp); 1636 memmove(dp, sp, s - sp); 1637 for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++) 1638 if (!ISMAGIC(*s) || !(*++s & 0x80) || 1639 !vstrchr("*+?@! ", *s & 0x7f)) 1640 *d++ = *s; 1641 else { 1642 /* extended pattern operators: *+?@! */ 1643 if ((*s & 0x7f) != ' ') 1644 *d++ = *s & 0x7f; 1645 if (d - dp < (ssize_t)dlen) 1646 *d++ = '('; 1647 } 1648 *d = '\0'; 1649 } else if (dp != sp) 1650 strlcpy(dp, sp, dlen); 1651 return (dp); 1652 } 1653 1654 /* 1655 * Check if p is an unquoted name, possibly followed by a / or :. If so 1656 * puts the expanded version in *dcp,dp and returns a pointer in p just 1657 * past the name, otherwise returns 0. 1658 */ 1659 static const char * 1660 maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign) 1661 { 1662 XString ts; 1663 char *dp = *dpp; 1664 char *tp; 1665 const char *r; 1666 1667 Xinit(ts, tp, 16, ATEMP); 1668 /* : only for DOASNTILDE form */ 1669 while (p[0] == CHAR && p[1] != '/' && (!isassign || p[1] != ':')) 1670 { 1671 Xcheck(ts, tp); 1672 *tp++ = p[1]; 1673 p += 2; 1674 } 1675 *tp = '\0'; 1676 r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? 1677 do_tilde(Xstring(ts, tp)) : NULL; 1678 Xfree(ts, tp); 1679 if (r) { 1680 while (*r) { 1681 Xcheck(*dsp, dp); 1682 if (ISMAGIC(*r)) 1683 *dp++ = MAGIC; 1684 *dp++ = *r++; 1685 } 1686 *dpp = dp; 1687 r = p; 1688 } 1689 return (r); 1690 } 1691 1692 /* 1693 * tilde expansion 1694 * 1695 * based on a version by Arnold Robbins 1696 */ 1697 1698 char * 1699 do_tilde(char *cp) 1700 { 1701 char *dp = null; 1702 1703 if (cp[0] == '\0') 1704 dp = str_val(global("HOME")); 1705 else if (cp[0] == '+' && cp[1] == '\0') 1706 dp = str_val(global("PWD")); 1707 else if (ksh_isdash(cp)) 1708 dp = str_val(global("OLDPWD")); 1709 #ifndef MKSH_NOPWNAM 1710 else 1711 dp = homedir(cp); 1712 #endif 1713 /* If HOME, PWD or OLDPWD are not set, don't expand ~ */ 1714 return (dp == null ? NULL : dp); 1715 } 1716 1717 #ifndef MKSH_NOPWNAM 1718 /* 1719 * map userid to user's home directory. 1720 * note that 4.3's getpw adds more than 6K to the shell, 1721 * and the YP version probably adds much more. 1722 * we might consider our own version of getpwnam() to keep the size down. 1723 */ 1724 static char * 1725 homedir(char *name) 1726 { 1727 struct tbl *ap; 1728 1729 ap = ktenter(&homedirs, name, hash(name)); 1730 if (!(ap->flag & ISSET)) { 1731 struct passwd *pw; 1732 1733 pw = getpwnam(name); 1734 if (pw == NULL) 1735 return (NULL); 1736 strdupx(ap->val.s, pw->pw_dir, APERM); 1737 ap->flag |= DEFINED|ISSET|ALLOC; 1738 } 1739 return (ap->val.s); 1740 } 1741 #endif 1742 1743 static void 1744 alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo) 1745 { 1746 unsigned int count = 0; 1747 char *brace_start, *brace_end, *comma = NULL; 1748 char *field_start; 1749 char *p = exp_start; 1750 1751 /* search for open brace */ 1752 while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/) 1753 p += 2; 1754 brace_start = p; 1755 1756 /* find matching close brace, if any */ 1757 if (p) { 1758 comma = NULL; 1759 count = 1; 1760 p += 2; 1761 while (*p && count) { 1762 if (ISMAGIC(*p++)) { 1763 if (*p == '{' /*}*/) 1764 ++count; 1765 else if (*p == /*{*/ '}') 1766 --count; 1767 else if (*p == ',' && count == 1) 1768 comma = p; 1769 ++p; 1770 } 1771 } 1772 } 1773 /* no valid expansions... */ 1774 if (!p || count != 0) { 1775 /* 1776 * Note that given a{{b,c} we do not expand anything (this is 1777 * what AT&T ksh does. This may be changed to do the {b,c} 1778 * expansion. } 1779 */ 1780 if (fdo & DOGLOB) 1781 glob(start, wp, tobool(fdo & DOMARKDIRS)); 1782 else 1783 XPput(*wp, debunk(start, start, end - start)); 1784 return; 1785 } 1786 brace_end = p; 1787 if (!comma) { 1788 alt_expand(wp, start, brace_end, end, fdo); 1789 return; 1790 } 1791 1792 /* expand expression */ 1793 field_start = brace_start + 2; 1794 count = 1; 1795 for (p = brace_start + 2; p != brace_end; p++) { 1796 if (ISMAGIC(*p)) { 1797 if (*++p == '{' /*}*/) 1798 ++count; 1799 else if ((*p == /*{*/ '}' && --count == 0) || 1800 (*p == ',' && count == 1)) { 1801 char *news; 1802 int l1, l2, l3; 1803 1804 /* 1805 * addition safe since these operate on 1806 * one string (separate substrings) 1807 */ 1808 l1 = brace_start - start; 1809 l2 = (p - 1) - field_start; 1810 l3 = end - brace_end; 1811 news = alloc(l1 + l2 + l3 + 1, ATEMP); 1812 memcpy(news, start, l1); 1813 memcpy(news + l1, field_start, l2); 1814 memcpy(news + l1 + l2, brace_end, l3); 1815 news[l1 + l2 + l3] = '\0'; 1816 alt_expand(wp, news, news + l1, 1817 news + l1 + l2 + l3, fdo); 1818 field_start = p + 1; 1819 } 1820 } 1821 } 1822 return; 1823 } 1824 1825 /* helper function due to setjmp/longjmp woes */ 1826 static char * 1827 valsub(struct op *t, Area *ap) 1828 { 1829 char * volatile cp = NULL; 1830 struct tbl * volatile vp = NULL; 1831 1832 newenv(E_FUNC); 1833 newblock(); 1834 if (ap) 1835 vp = local("REPLY", false); 1836 if (!kshsetjmp(e->jbuf)) 1837 execute(t, XXCOM | XERROK, NULL); 1838 if (vp) 1839 strdupx(cp, str_val(vp), ap); 1840 quitenv(NULL); 1841 1842 return (cp); 1843 } 1844