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