1 /* $NetBSD: eval.c,v 1.22 2017/06/30 04:41:19 kamil Exp $ */ 2 3 /* 4 * Expansion - quoting, separation, substitution, globbing 5 */ 6 #include <sys/cdefs.h> 7 8 #ifndef lint 9 __RCSID("$NetBSD: eval.c,v 1.22 2017/06/30 04:41:19 kamil Exp $"); 10 #endif 11 12 #include <sys/stat.h> 13 #include <stdint.h> 14 #include <pwd.h> 15 16 #include "sh.h" 17 #include "ksh_dir.h" 18 19 /* 20 * string expansion 21 * 22 * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution. 23 * second pass: alternation ({,}), filename expansion (*?[]). 24 */ 25 26 /* expansion generator state */ 27 typedef struct Expand { 28 /* int type; */ /* see expand() */ 29 const char *str; /* string */ 30 union { 31 const char **strv;/* string[] */ 32 struct shf *shf;/* file */ 33 } u; /* source */ 34 struct tbl *var; /* variable in ${var..} */ 35 short split; /* split "$@" / call waitlast $() */ 36 } Expand; 37 38 #define XBASE 0 /* scanning original */ 39 #define XSUB 1 /* expanding ${} string */ 40 #define XARGSEP 2 /* ifs0 between "$*" */ 41 #define XARG 3 /* expanding $*, $@ */ 42 #define XCOM 4 /* expanding $() */ 43 #define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */ 44 45 /* States used for field splitting */ 46 #define IFS_WORD 0 /* word has chars (or quotes) */ 47 #define IFS_WS 1 /* have seen IFS white-space */ 48 #define IFS_NWS 2 /* have seen IFS non-white-space */ 49 50 static int varsub ARGS((Expand *xp, char *sp, char *word, int *stypep, int *slenp)); 51 static int comsub ARGS((Expand *xp, char *cp)); 52 static char *trimsub ARGS((char *str, char *pat, int how)); 53 static void glob ARGS((char *cp, XPtrV *wp, int markdirs)); 54 static void globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp, 55 int check)); 56 static char *maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp, 57 int isassign)); 58 static char *tilde ARGS((char *acp)); 59 static char *homedir ARGS((char *name)); 60 #ifdef BRACE_EXPAND 61 static void alt_expand ARGS((XPtrV *wp, char *start, char *exp_start, 62 char *end, int fdo)); 63 #endif 64 65 /* compile and expand word */ 66 char * 67 substitute(cp, f) 68 const char *cp; 69 int f; 70 { 71 struct source *s, *sold; 72 73 sold = source; 74 s = pushs(SWSTR, ATEMP); 75 s->start = s->str = cp; 76 source = s; 77 if (yylex(ONEWORD) != LWORD) 78 internal_errorf(1, "substitute"); 79 source = sold; 80 afree(s, ATEMP); 81 return evalstr(yylval.cp, f); 82 } 83 84 /* 85 * expand arg-list 86 */ 87 char ** 88 eval(ap, f) 89 register char **ap; 90 int f; 91 { 92 XPtrV w; 93 94 if (*ap == NULL) 95 return ap; 96 XPinit(w, 32); 97 XPput(w, NULL); /* space for shell name */ 98 while (*ap != NULL) 99 expand(*ap++, &w, f); 100 XPput(w, NULL); 101 return (char **) XPclose(w) + 1; 102 } 103 104 /* 105 * expand string 106 */ 107 char * 108 evalstr(cp, f) 109 char *cp; 110 int f; 111 { 112 XPtrV w; 113 114 XPinit(w, 1); 115 expand(cp, &w, f); 116 cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w); 117 XPfree(w); 118 return cp; 119 } 120 121 /* 122 * expand string - return only one component 123 * used from iosetup to expand redirection files 124 */ 125 char * 126 evalonestr(cp, f) 127 register char *cp; 128 int f; 129 { 130 XPtrV w; 131 132 XPinit(w, 1); 133 expand(cp, &w, f); 134 switch (XPsize(w)) { 135 case 0: 136 cp = null; 137 break; 138 case 1: 139 cp = (char*) *XPptrv(w); 140 break; 141 default: 142 cp = evalstr(cp, f&~DOGLOB); 143 break; 144 } 145 XPfree(w); 146 return cp; 147 } 148 149 /* for nested substitution: ${var:=$var2} */ 150 typedef struct SubType { 151 short stype; /* [=+-?%#] action after expanded word */ 152 short base; /* begin position of expanded word */ 153 short f; /* saved value of f (DOPAT, etc) */ 154 struct tbl *var; /* variable for ${var..} */ 155 short quote; /* saved value of quote (for ${..[%#]..}) */ 156 struct SubType *prev; /* old type */ 157 struct SubType *next; /* poped type (to avoid re-allocating) */ 158 } SubType; 159 160 void 161 expand(cp, wp, f) 162 char *cp; /* input word */ 163 register XPtrV *wp; /* output words */ 164 int f; /* DO* flags */ 165 { 166 register int UNINITIALIZED(c); 167 register int type; /* expansion type */ 168 register int quote = 0; /* quoted */ 169 XString ds; /* destination string */ 170 register char *dp, *sp; /* dest., source */ 171 int fdo, word; /* second pass flags; have word */ 172 int doblank; /* field splitting of parameter/command subst */ 173 Expand x; /* expansion variables */ 174 SubType st_head, *st; 175 int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */ 176 int saw_eq, tilde_ok; 177 int make_magic; 178 size_t len; 179 180 x.split = 0; /* XXX gcc */ 181 x.str = NULL; /* XXX gcc */ 182 x.u.strv = NULL;/* XXX gcc */ 183 if (cp == NULL) 184 internal_errorf(1, "expand(NULL)"); 185 /* for alias, readonly, set, typeset commands */ 186 if ((f & DOVACHECK) && is_wdvarassign(cp)) { 187 f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE); 188 f |= DOASNTILDE; 189 } 190 if (Flag(FNOGLOB)) 191 f &= ~DOGLOB; 192 if (Flag(FMARKDIRS)) 193 f |= DOMARKDIRS; 194 #ifdef BRACE_EXPAND 195 if (Flag(FBRACEEXPAND) && (f & DOGLOB)) 196 f |= DOBRACE_; 197 #endif /* BRACE_EXPAND */ 198 199 Xinit(ds, dp, 128, ATEMP); /* init dest. string */ 200 type = XBASE; 201 sp = cp; 202 fdo = 0; 203 saw_eq = 0; 204 tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */ 205 doblank = 0; 206 make_magic = 0; 207 word = (f&DOBLANK) ? IFS_WS : IFS_WORD; 208 st_head.next = (SubType *) 0; 209 st = &st_head; 210 211 while (1) { 212 Xcheck(ds, dp); 213 214 switch (type) { 215 case XBASE: /* original prefixed string */ 216 c = *sp++; 217 switch (c) { 218 case EOS: 219 c = 0; 220 break; 221 case CHAR: 222 c = *sp++; 223 break; 224 case QCHAR: 225 quote |= 2; /* temporary quote */ 226 c = *sp++; 227 break; 228 case OQUOTE: 229 word = IFS_WORD; 230 tilde_ok = 0; 231 quote = 1; 232 continue; 233 case CQUOTE: 234 quote = 0; 235 continue; 236 case COMSUB: 237 tilde_ok = 0; 238 if (f & DONTRUNCOMMAND) { 239 word = IFS_WORD; 240 *dp++ = '$'; *dp++ = '('; 241 while (*sp != '\0') { 242 Xcheck(ds, dp); 243 *dp++ = *sp++; 244 } 245 *dp++ = ')'; 246 } else { 247 type = comsub(&x, sp); 248 if (type == XCOM && (f&DOBLANK)) 249 doblank++; 250 sp = strchr(sp, 0) + 1; 251 newlines = 0; 252 } 253 continue; 254 case EXPRSUB: 255 word = IFS_WORD; 256 tilde_ok = 0; 257 if (f & DONTRUNCOMMAND) { 258 *dp++ = '$'; *dp++ = '('; *dp++ = '('; 259 while (*sp != '\0') { 260 Xcheck(ds, dp); 261 *dp++ = *sp++; 262 } 263 *dp++ = ')'; *dp++ = ')'; 264 } else { 265 struct tbl v; 266 char *p; 267 268 v.flag = DEFINED|ISSET|INTEGER; 269 v.type = 10; /* not default */ 270 v.name[0] = '\0'; 271 v_evaluate(&v, substitute(sp, 0), 272 KSH_UNWIND_ERROR); 273 sp = strchr(sp, 0) + 1; 274 for (p = str_val(&v); *p; ) { 275 Xcheck(ds, dp); 276 *dp++ = *p++; 277 } 278 } 279 continue; 280 case OSUBST: /* ${{#}var{:}[=+-?#%]word} */ 281 /* format is: 282 * OSUBST [{x] plain-variable-part \0 283 * compiled-word-part CSUBST [}x] 284 * This is were all syntax checking gets done... 285 */ 286 { 287 char *varname = ++sp; /* skip the { or x (}) */ 288 int stype; 289 int slen; 290 291 slen = -1; /* XXX gcc */ 292 sp = strchr(sp, '\0') + 1; /* skip variable */ 293 type = varsub(&x, varname, sp, &stype, &slen); 294 if (type < 0) { 295 char endc; 296 char *str, *end; 297 298 end = (char *) wdscan(sp, CSUBST); 299 /* ({) the } or x is already skipped */ 300 endc = *end; 301 *end = EOS; 302 str = snptreef((char *) 0, 64, "%S", 303 varname - 1); 304 *end = endc; 305 errorf("%s: bad substitution", str); 306 } 307 if (f&DOBLANK) 308 doblank++; 309 tilde_ok = 0; 310 if (type == XBASE) { /* expand? */ 311 if (!st->next) { 312 SubType *newst; 313 314 newst = (SubType *) alloc( 315 sizeof(SubType), ATEMP); 316 newst->next = (SubType *) 0; 317 newst->prev = st; 318 st->next = newst; 319 } 320 st = st->next; 321 st->stype = stype; 322 st->base = Xsavepos(ds, dp); 323 st->f = f; 324 st->var = x.var; 325 st->quote = quote; 326 /* skip qualifier(s) */ 327 if (stype) 328 sp += slen; 329 switch (stype & 0x7f) { 330 case '#': 331 case '%': 332 /* ! DOBLANK,DOBRACE_,DOTILDE */ 333 f = DOPAT | (f&DONTRUNCOMMAND) 334 | DOTEMP_; 335 quote = 0; 336 /* Prepend open pattern (so | 337 * in a trim will work as 338 * expected) 339 */ 340 *dp++ = MAGIC; 341 *dp++ = (char)('@' + 0x80); 342 break; 343 case '=': 344 /* Enabling tilde expansion 345 * after :'s here is 346 * non-standard ksh, but is 347 * consistent with rules for 348 * other assignments. Not 349 * sure what POSIX thinks of 350 * this. 351 * Not doing tilde expansion 352 * for integer variables is a 353 * non-POSIX thing - makes 354 * sense though, since ~ is 355 * a arithmetic operator. 356 */ 357 if (!(x.var->flag & INTEGER)) 358 f |= DOASNTILDE|DOTILDE; 359 f |= DOTEMP_; 360 /* These will be done after the 361 * value has been assigned. 362 */ 363 f &= ~(DOBLANK|DOGLOB|DOBRACE_); 364 tilde_ok = 1; 365 break; 366 case '?': 367 f &= ~DOBLANK; 368 f |= DOTEMP_; 369 /* fall through */ 370 default: 371 /* Enable tilde expansion */ 372 tilde_ok = 1; 373 f |= DOTILDE; 374 } 375 } else 376 /* skip word */ 377 sp = (char *) wdscan(sp, CSUBST); 378 continue; 379 } 380 case CSUBST: /* only get here if expanding word */ 381 sp++; /* ({) skip the } or x */ 382 tilde_ok = 0; /* in case of ${unset:-} */ 383 *dp = '\0'; 384 quote = st->quote; 385 f = st->f; 386 if (f&DOBLANK) 387 doblank--; 388 switch (st->stype&0x7f) { 389 case '#': 390 case '%': 391 /* Append end-pattern */ 392 *dp++ = MAGIC; *dp++ = ')'; *dp = '\0'; 393 dp = Xrestpos(ds, dp, st->base); 394 /* Must use st->var since calling 395 * global would break things 396 * like x[i+=1]. 397 */ 398 x.str = trimsub(str_val(st->var), 399 dp, st->stype); 400 type = XSUB; 401 if (f&DOBLANK) 402 doblank++; 403 st = st->prev; 404 continue; 405 case '=': 406 /* Restore our position and substitute 407 * the value of st->var (may not be 408 * the assigned value in the presence 409 * of integer/right-adj/etc attributes). 410 */ 411 dp = Xrestpos(ds, dp, st->base); 412 /* Must use st->var since calling 413 * global would cause with things 414 * like x[i+=1] to be evaluated twice. 415 */ 416 /* Note: not exported by FEXPORT 417 * in at&t ksh. 418 */ 419 /* XXX POSIX says readonly is only 420 * fatal for special builtins (setstr 421 * does readonly check). 422 */ 423 len = strlen(dp) + 1; 424 setstr(st->var, 425 debunk((char *) alloc(len, ATEMP), 426 dp, len), 427 KSH_UNWIND_ERROR); 428 x.str = str_val(st->var); 429 type = XSUB; 430 if (f&DOBLANK) 431 doblank++; 432 st = st->prev; 433 continue; 434 case '?': 435 { 436 char *s = Xrestpos(ds, dp, st->base); 437 438 errorf("%s: %s", st->var->name, 439 dp == s ? 440 "parameter null or not set" 441 : (debunk(s, s, strlen(s) + 1), s)); 442 } 443 } 444 st = st->prev; 445 type = XBASE; 446 continue; 447 448 case OPAT: /* open pattern: *(foo|bar) */ 449 /* Next char is the type of pattern */ 450 make_magic = 1; 451 c = *sp++ + 0x80; 452 break; 453 454 case SPAT: /* pattern separator (|) */ 455 make_magic = 1; 456 c = '|'; 457 break; 458 459 case CPAT: /* close pattern */ 460 make_magic = 1; 461 c = /*(*/ ')'; 462 break; 463 } 464 break; 465 466 case XNULLSUB: 467 /* Special case for "$@" (and "${foo[@]}") - no 468 * word is generated if $# is 0 (unless there is 469 * other stuff inside the quotes). 470 */ 471 type = XBASE; 472 if (f&DOBLANK) { 473 doblank--; 474 /* not really correct: x=; "$x$@" should 475 * generate a null argument and 476 * set A; "${@:+}" shouldn't. 477 */ 478 if (dp == Xstring(ds, dp)) 479 word = IFS_WS; 480 } 481 continue; 482 483 case XSUB: 484 if ((c = *x.str++) == 0) { 485 type = XBASE; 486 if (f&DOBLANK) 487 doblank--; 488 continue; 489 } 490 break; 491 492 case XARGSEP: 493 type = XARG; 494 quote = 1; 495 case XARG: 496 if ((c = *x.str++) == '\0') { 497 /* force null words to be created so 498 * set -- '' 2 ''; foo "$@" will do 499 * the right thing 500 */ 501 if (quote && x.split) 502 word = IFS_WORD; 503 if ((x.str = *x.u.strv++) == NULL) { 504 type = XBASE; 505 if (f&DOBLANK) 506 doblank--; 507 continue; 508 } 509 c = ifs0; 510 if (c == 0) { 511 if (quote && !x.split) 512 continue; 513 c = ' '; 514 } 515 if (quote && x.split) { 516 /* terminate word for "$@" */ 517 type = XARGSEP; 518 quote = 0; 519 } 520 } 521 break; 522 523 case XCOM: 524 if (newlines) { /* Spit out saved nl's */ 525 c = '\n'; 526 --newlines; 527 } else { 528 while ((c = shf_getc(x.u.shf)) == 0 || c == '\n') 529 if (c == '\n') 530 newlines++; /* Save newlines */ 531 if (newlines && c != EOF) { 532 shf_ungetc(c, x.u.shf); 533 c = '\n'; 534 --newlines; 535 } 536 } 537 if (c == EOF) { 538 newlines = 0; 539 shf_close(x.u.shf); 540 if (x.split) 541 subst_exstat = waitlast(); 542 type = XBASE; 543 if (f&DOBLANK) 544 doblank--; 545 continue; 546 } 547 break; 548 } 549 550 /* check for end of word or IFS separation */ 551 if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic 552 && ctype(c, C_IFS))) 553 { 554 /* How words are broken up: 555 * | value of c 556 * word | ws nws 0 557 * ----------------------------------- 558 * IFS_WORD w/WS w/NWS w 559 * IFS_WS -/WS w/NWS - 560 * IFS_NWS -/NWS w/NWS w 561 * (w means generate a word) 562 * Note that IFS_NWS/0 generates a word (at&t ksh 563 * doesn't do this, but POSIX does). 564 */ 565 if (word == IFS_WORD 566 || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS))) 567 { 568 char *p; 569 570 *dp++ = '\0'; 571 p = Xclose(ds, dp); 572 #ifdef BRACE_EXPAND 573 if (fdo & DOBRACE_) 574 /* also does globbing */ 575 alt_expand(wp, p, p, 576 p + Xlength(ds, (dp - 1)), 577 fdo | (f & DOMARKDIRS)); 578 else 579 #endif /* BRACE_EXPAND */ 580 if (fdo & DOGLOB) 581 glob(p, wp, f & DOMARKDIRS); 582 else if ((f & DOPAT) || !(fdo & DOMAGIC_)) 583 XPput(*wp, p); 584 else 585 XPput(*wp, debunk(p, p, strlen(p) + 1)); 586 fdo = 0; 587 saw_eq = 0; 588 tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; 589 if (c != 0) 590 Xinit(ds, dp, 128, ATEMP); 591 } 592 if (c == 0) 593 return; 594 if (word != IFS_NWS) 595 word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS; 596 } else { 597 /* age tilde_ok info - ~ code tests second bit */ 598 tilde_ok <<= 1; 599 /* mark any special second pass chars */ 600 if (!quote) 601 switch (c) { 602 case '[': 603 case NOT: 604 case '-': 605 case ']': 606 /* For character classes - doesn't hurt 607 * to have magic !,-,]'s outside of 608 * [...] expressions. 609 */ 610 if (f & (DOPAT | DOGLOB)) { 611 fdo |= DOMAGIC_; 612 if (c == '[') 613 fdo |= f & DOGLOB; 614 *dp++ = MAGIC; 615 } 616 break; 617 case '*': 618 case '?': 619 if (f & (DOPAT | DOGLOB)) { 620 fdo |= DOMAGIC_ | (f & DOGLOB); 621 *dp++ = MAGIC; 622 } 623 break; 624 #ifdef BRACE_EXPAND 625 case OBRACE: 626 case ',': 627 case CBRACE: 628 if ((f & DOBRACE_) && (c == OBRACE 629 || (fdo & DOBRACE_))) 630 { 631 fdo |= DOBRACE_|DOMAGIC_; 632 *dp++ = MAGIC; 633 } 634 break; 635 #endif /* BRACE_EXPAND */ 636 case '=': 637 /* Note first unquoted = for ~ */ 638 if (!(f & DOTEMP_) && !saw_eq) { 639 saw_eq = 1; 640 tilde_ok = 1; 641 } 642 break; 643 case PATHSEP: /* : */ 644 /* Note unquoted : for ~ */ 645 if (!(f & DOTEMP_) && (f & DOASNTILDE)) 646 tilde_ok = 1; 647 break; 648 case '~': 649 /* tilde_ok is reset whenever 650 * any of ' " $( $(( ${ } are seen. 651 * Note that tilde_ok must be preserved 652 * through the sequence ${A=a=}~ 653 */ 654 if (type == XBASE 655 && (f & (DOTILDE|DOASNTILDE)) 656 && (tilde_ok & 2)) 657 { 658 char *p, *dp_x; 659 660 dp_x = dp; 661 p = maybe_expand_tilde(sp, 662 &ds, &dp_x, 663 f & DOASNTILDE); 664 if (p) { 665 if (dp != dp_x) 666 word = IFS_WORD; 667 dp = dp_x; 668 sp = p; 669 continue; 670 } 671 } 672 break; 673 } 674 else 675 quote &= ~2; /* undo temporary */ 676 677 if (make_magic) { 678 make_magic = 0; 679 fdo |= DOMAGIC_ | (f & DOGLOB); 680 *dp++ = MAGIC; 681 } else if (ISMAGIC(c)) { 682 fdo |= DOMAGIC_; 683 *dp++ = MAGIC; 684 } 685 *dp++ = c; /* save output char */ 686 word = IFS_WORD; 687 } 688 } 689 } 690 691 /* 692 * Prepare to generate the string returned by ${} substitution. 693 */ 694 static int 695 varsub(xp, sp, word, stypep, slenp) 696 Expand *xp; 697 char *sp; 698 char *word; 699 int *stypep; /* becomes qualifier type */ 700 int *slenp; /* " " len (=, :=, etc.) valid iff *stypep != 0 */ 701 { 702 int c; 703 int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */ 704 int stype; /* substitution type */ 705 int slen; 706 char *p; 707 struct tbl *vp; 708 709 if (sp[0] == '\0') /* Bad variable name */ 710 return -1; 711 712 xp->var = NULL; 713 714 /* ${#var}, string length or array size */ 715 if (sp[0] == '#' && (c = sp[1]) != '\0') { 716 int zero_ok = 0; 717 718 /* Can't have any modifiers for ${#...} */ 719 if (*word != CSUBST) 720 return -1; 721 sp++; 722 /* Check for size of array */ 723 if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { 724 int n = 0; 725 vp = global(arrayname(sp)); 726 if (vp->flag & (ISSET|ARRAY)) 727 zero_ok = 1; 728 for (; vp; vp = vp->u.array) 729 if (vp->flag & ISSET) { 730 n++; 731 } 732 c = n; /* ksh88/ksh93 go for number, not max index */ 733 } else if (c == '*' || c == '@') 734 c = e->loc->argc; 735 else { 736 p = str_val(global(sp)); 737 zero_ok = p != null; 738 c = strlen(p); 739 } 740 if (Flag(FNOUNSET) && c == 0 && !zero_ok) 741 errorf("%s: parameter not set", sp); 742 *stypep = 0; /* unqualified variable/string substitution */ 743 xp->str = str_save(ulton((unsigned long)c, 10), ATEMP); 744 return XSUB; 745 } 746 747 /* Check for qualifiers in word part */ 748 stype = 0; 749 c = word[slen = 0] == CHAR ? word[1] : 0; 750 if (c == ':') { 751 slen += 2; 752 stype = 0x80; 753 c = word[slen + 0] == CHAR ? word[slen + 1] : 0; 754 } 755 if (ctype(c, C_SUBOP1)) { 756 slen += 2; 757 stype |= c; 758 } else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */ 759 slen += 2; 760 stype = c; 761 if (word[slen + 0] == CHAR && c == word[slen + 1]) { 762 stype |= 0x80; 763 slen += 2; 764 } 765 } else if (stype) /* : is not ok */ 766 return -1; 767 if (!stype && *word != CSUBST) 768 return -1; 769 *stypep = stype; 770 *slenp = slen; 771 772 c = sp[0]; 773 if (c == '*' || c == '@') { 774 switch (stype & 0x7f) { 775 case '=': /* can't assign to a vector */ 776 case '%': /* can't trim a vector (yet) */ 777 case '#': 778 return -1; 779 } 780 if (e->loc->argc == 0) { 781 xp->u.strv = NULL; 782 xp->str = null; 783 state = c == '@' ? XNULLSUB : XSUB; 784 } else { 785 char **t = &e->loc->argv[1]; 786 xp->u.strv = (void *)(uintptr_t)t; 787 xp->str = *xp->u.strv++; 788 xp->split = c == '@'; /* $@ */ 789 state = XARG; 790 } 791 } else { 792 if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { 793 XPtrV wv; 794 795 switch (stype & 0x7f) { 796 case '=': /* can't assign to a vector */ 797 case '%': /* can't trim a vector (yet) */ 798 case '#': 799 return -1; 800 } 801 XPinit(wv, 32); 802 vp = global(arrayname(sp)); 803 for (; vp; vp = vp->u.array) { 804 if (!(vp->flag&ISSET)) 805 continue; 806 XPput(wv, str_val(vp)); 807 } 808 if (XPsize(wv) == 0) { 809 xp->str = null; 810 state = p[1] == '@' ? XNULLSUB : XSUB; 811 XPfree(wv); 812 } else { 813 XPput(wv, 0); 814 xp->u.strv = (const char **) XPptrv(wv); 815 xp->str = *xp->u.strv++; 816 xp->split = p[1] == '@'; /* ${foo[@]} */ 817 state = XARG; 818 } 819 } else { 820 /* Can't assign things like $! or $1 */ 821 if ((stype & 0x7f) == '=' 822 && (ctype(*sp, C_VAR1) || digit(*sp))) 823 return -1; 824 xp->var = global(sp); 825 xp->str = str_val(xp->var); 826 state = XSUB; 827 } 828 } 829 830 c = stype&0x7f; 831 /* test the compiler's code generator */ 832 if (ctype(c, C_SUBOP2) || 833 (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */ 834 c == '=' || c == '-' || c == '?' : c == '+')) 835 state = XBASE; /* expand word instead of variable value */ 836 if (Flag(FNOUNSET) && xp->str == null 837 && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+'))) 838 errorf("%s: parameter not set", sp); 839 return state; 840 } 841 842 /* 843 * Run the command in $(...) and read its output. 844 */ 845 static int 846 comsub(xp, cp) 847 register Expand *xp; 848 char *cp; 849 { 850 Source *s, *sold; 851 register struct op *t; 852 struct shf *shf; 853 854 s = pushs(SSTRING, ATEMP); 855 s->start = s->str = cp; 856 sold = source; 857 t = compile(s); 858 afree(s, ATEMP); 859 source = sold; 860 861 if (t == NULL) 862 return XBASE; 863 864 if (t != NULL && t->type == TCOM && /* $(<file) */ 865 *t->args == NULL && *t->vars == NULL && t->ioact != NULL) { 866 register struct ioword *io = *t->ioact; 867 char *name; 868 869 if ((io->flag&IOTYPE) != IOREAD) 870 errorf("funny $() command: %s", 871 snptreef((char *) 0, 32, "%R", io)); 872 shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0, 873 SHF_MAPHI|SHF_CLEXEC); 874 if (shf == NULL) 875 errorf("%s: cannot open $() input", name); 876 xp->split = 0; /* no waitlast() */ 877 } else { 878 int ofd1, pv[2]; 879 openpipe(pv); 880 shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0); 881 ofd1 = savefd(1, 0); /* fd 1 may be closed... */ 882 if (pv[1] != 1) { 883 ksh_dup2(pv[1], 1, false); 884 close(pv[1]); 885 } 886 execute(t, XFORK|XXCOM|XPIPEO); 887 restfd(1, ofd1); 888 startlast(); 889 xp->split = 1; /* waitlast() */ 890 } 891 892 xp->u.shf = shf; 893 return XCOM; 894 } 895 896 /* 897 * perform #pattern and %pattern substitution in ${} 898 */ 899 900 static char * 901 trimsub(str, pat, how) 902 register char *str; 903 char *pat; 904 int how; 905 { 906 register char *end = strchr(str, 0); 907 register char *p, c; 908 909 switch (how&0xff) { /* UCHAR_MAX maybe? */ 910 case '#': /* shortest at beginning */ 911 for (p = str; p <= end; p++) { 912 c = *p; *p = '\0'; 913 if (gmatch(str, pat, false)) { 914 *p = c; 915 return p; 916 } 917 *p = c; 918 } 919 break; 920 case '#'|0x80: /* longest match at beginning */ 921 for (p = end; p >= str; p--) { 922 c = *p; *p = '\0'; 923 if (gmatch(str, pat, false)) { 924 *p = c; 925 return p; 926 } 927 *p = c; 928 } 929 break; 930 case '%': /* shortest match at end */ 931 for (p = end; p >= str; p--) { 932 if (gmatch(p, pat, false)) 933 return str_nsave(str, p - str, ATEMP); 934 } 935 break; 936 case '%'|0x80: /* longest match at end */ 937 for (p = str; p <= end; p++) { 938 if (gmatch(p, pat, false)) 939 return str_nsave(str, p - str, ATEMP); 940 } 941 break; 942 } 943 944 return str; /* no match, return string */ 945 } 946 947 /* 948 * glob 949 * Name derived from V6's /etc/glob, the program that expanded filenames. 950 */ 951 952 /* XXX cp not const 'cause slashes are temporarily replaced with nulls... */ 953 static void 954 glob(cp, wp, markdirs) 955 char *cp; 956 register XPtrV *wp; 957 int markdirs; 958 { 959 int oldsize = XPsize(*wp); 960 961 if (glob_str(cp, wp, markdirs) == 0) 962 XPput(*wp, debunk(cp, cp, strlen(cp) + 1)); 963 else 964 qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), 965 xstrcmp); 966 } 967 968 #define GF_NONE 0 969 #define GF_EXCHECK BIT(0) /* do existence check on file */ 970 #define GF_GLOBBED BIT(1) /* some globbing has been done */ 971 #define GF_MARKDIR BIT(2) /* add trailing / to directories */ 972 973 /* Apply file globbing to cp and store the matching files in wp. Returns 974 * the number of matches found. 975 */ 976 int 977 glob_str(cp, wp, markdirs) 978 char *cp; 979 XPtrV *wp; 980 int markdirs; 981 { 982 int oldsize = XPsize(*wp); 983 XString xs; 984 char *xp; 985 986 Xinit(xs, xp, 256, ATEMP); 987 globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE); 988 Xfree(xs, xp); 989 990 return XPsize(*wp) - oldsize; 991 } 992 993 static void 994 globit(xs, xpp, sp, wp, check) 995 XString *xs; /* dest string */ 996 char **xpp; /* ptr to dest end */ 997 char *sp; /* source path */ 998 register XPtrV *wp; /* output list */ 999 int check; /* GF_* flags */ 1000 { 1001 register char *np; /* next source component */ 1002 char *xp = *xpp; 1003 char *se; 1004 char odirsep; 1005 1006 /* This to allow long expansions to be interrupted */ 1007 intrcheck(); 1008 1009 if (sp == NULL) { /* end of source path */ 1010 /* We only need to check if the file exists if a pattern 1011 * is followed by a non-pattern (eg, foo*x/bar; no check 1012 * is needed for foo* since the match must exist) or if 1013 * any patterns were expanded and the markdirs option is set. 1014 * Symlinks make things a bit tricky... 1015 */ 1016 if ((check & GF_EXCHECK) 1017 || ((check & GF_MARKDIR) && (check & GF_GLOBBED))) 1018 { 1019 #define stat_check() (stat_done ? stat_done : \ 1020 (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \ 1021 ? -1 : 1)) 1022 struct stat lstatb, statb; 1023 int stat_done = 0; /* -1: failed, 1 ok */ 1024 1025 if (lstat(Xstring(*xs, xp), &lstatb) < 0) 1026 return; 1027 /* special case for systems which strip trailing 1028 * slashes from regular files (eg, /etc/passwd/). 1029 * SunOS 4.1.3 does this... 1030 */ 1031 if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) 1032 && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode) 1033 #ifdef S_ISLNK 1034 && (!S_ISLNK(lstatb.st_mode) 1035 || stat_check() < 0 1036 || !S_ISDIR(statb.st_mode)) 1037 #endif /* S_ISLNK */ 1038 ) 1039 return; 1040 /* Possibly tack on a trailing / if there isn't already 1041 * one and if the file is a directory or a symlink to a 1042 * directory 1043 */ 1044 if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) 1045 && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1]) 1046 && (S_ISDIR(lstatb.st_mode) 1047 #ifdef S_ISLNK 1048 || (S_ISLNK(lstatb.st_mode) 1049 && stat_check() > 0 1050 && S_ISDIR(statb.st_mode)) 1051 #endif /* S_ISLNK */ 1052 )) 1053 { 1054 *xp++ = DIRSEP; 1055 *xp = '\0'; 1056 } 1057 } 1058 # define KLUDGE_VAL 0 1059 XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp) 1060 + KLUDGE_VAL, ATEMP)); 1061 return; 1062 } 1063 1064 if (xp > Xstring(*xs, xp)) 1065 *xp++ = DIRSEP; 1066 while (ISDIRSEP(*sp)) { 1067 Xcheck(*xs, xp); 1068 *xp++ = *sp++; 1069 } 1070 np = ksh_strchr_dirsep(sp); 1071 if (np != NULL) { 1072 se = np; 1073 odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */ 1074 *np++ = '\0'; 1075 } else { 1076 odirsep = '\0'; /* keep gcc quiet */ 1077 se = sp + strlen(sp); 1078 } 1079 1080 1081 /* Check if sp needs globbing - done to avoid pattern checks for strings 1082 * containing MAGIC characters, open ['s without the matching close ], 1083 * etc. (otherwise opendir() will be called which may fail because the 1084 * directory isn't readable - if no globbing is needed, only execute 1085 * permission should be required (as per POSIX)). 1086 */ 1087 if (!has_globbing(sp, se)) { 1088 XcheckN(*xs, xp, se - sp + 1); 1089 debunk(xp, sp, Xnleft(*xs, xp)); 1090 xp += strlen(xp); 1091 *xpp = xp; 1092 globit(xs, xpp, np, wp, check); 1093 } else { 1094 DIR *dirp; 1095 struct dirent *d; 1096 char *name; 1097 int len; 1098 int prefix_len; 1099 1100 /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ 1101 *xp = '\0'; 1102 prefix_len = Xlength(*xs, xp); 1103 dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : "."); 1104 if (dirp == NULL) 1105 goto Nodir; 1106 while ((d = readdir(dirp)) != NULL) { 1107 name = d->d_name; 1108 if ((*name == '.' && *sp != '.') 1109 || !gmatch(name, sp, true)) 1110 continue; 1111 1112 len = NLENGTH(d) + 1; 1113 XcheckN(*xs, xp, len); 1114 memcpy(xp, name, len); 1115 *xpp = xp + len - 1; 1116 globit(xs, xpp, np, wp, 1117 (check & GF_MARKDIR) | GF_GLOBBED 1118 | (np ? GF_EXCHECK : GF_NONE)); 1119 xp = Xstring(*xs, xp) + prefix_len; 1120 } 1121 closedir(dirp); 1122 Nodir:; 1123 } 1124 1125 if (np != NULL) 1126 *--np = odirsep; 1127 } 1128 1129 #if 0 1130 /* Check if p contains something that needs globbing; if it does, 0 is 1131 * returned; if not, p is copied into xs/xp after stripping any MAGICs 1132 */ 1133 static int copy_non_glob ARGS((XString *xs, char **xpp, char *p)); 1134 static int 1135 copy_non_glob(xs, xpp, p) 1136 XString *xs; 1137 char **xpp; 1138 char *p; 1139 { 1140 char *xp; 1141 int len = strlen(p); 1142 1143 XcheckN(*xs, *xpp, len); 1144 xp = *xpp; 1145 for (; *p; p++) { 1146 if (ISMAGIC(*p)) { 1147 int c = *++p; 1148 1149 if (c == '*' || c == '?') 1150 return 0; 1151 if (*p == '[') { 1152 char *q = p + 1; 1153 1154 if (ISMAGIC(*q) && q[1] == NOT) 1155 q += 2; 1156 if (ISMAGIC(*q) && q[1] == ']') 1157 q += 2; 1158 for (; *q; q++) 1159 if (ISMAGIC(*q) && *++q == ']') 1160 return 0; 1161 /* pass a literal [ through */ 1162 } 1163 /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */ 1164 } 1165 *xp++ = *p; 1166 } 1167 *xp = '\0'; 1168 *xpp = xp; 1169 return 1; 1170 } 1171 #endif /* 0 */ 1172 1173 /* remove MAGIC from string */ 1174 char * 1175 debunk(dp, sp, dlen) 1176 char *dp; 1177 const char *sp; 1178 size_t dlen; 1179 { 1180 char *d, *s; 1181 1182 if ((s = strchr(sp, MAGIC))) { 1183 if (s - sp >= (ptrdiff_t)dlen) 1184 return dp; 1185 memcpy(dp, sp, s - sp); 1186 for (d = dp + (s - sp); *s && (d - dp < (ptrdiff_t)dlen); s++) 1187 if (!ISMAGIC(*s) || !(*++s & 0x80) 1188 || !strchr("*+?@! ", *s & 0x7f)) 1189 *d++ = *s; 1190 else { 1191 /* extended pattern operators: *+?@! */ 1192 if ((*s & 0x7f) != ' ') 1193 *d++ = *s & 0x7f; 1194 if (d - dp < (ptrdiff_t)dlen) 1195 *d++ = '('; 1196 } 1197 *d = '\0'; 1198 } else if (dp != sp) 1199 strlcpy(dp, sp, dlen); 1200 return dp; 1201 } 1202 1203 /* Check if p is an unquoted name, possibly followed by a / or :. If so 1204 * puts the expanded version in *dcp,dp and returns a pointer in p just 1205 * past the name, otherwise returns 0. 1206 */ 1207 static char * 1208 maybe_expand_tilde(p, dsp, dpp, isassign) 1209 char *p; 1210 XString *dsp; 1211 char **dpp; 1212 int isassign; 1213 { 1214 XString ts; 1215 char *dp = *dpp; 1216 char *tp, *r; 1217 1218 Xinit(ts, tp, 16, ATEMP); 1219 /* : only for DOASNTILDE form */ 1220 while (p[0] == CHAR && !ISDIRSEP(p[1]) 1221 && (!isassign || p[1] != PATHSEP)) 1222 { 1223 Xcheck(ts, tp); 1224 *tp++ = p[1]; 1225 p += 2; 1226 } 1227 *tp = '\0'; 1228 r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0; 1229 Xfree(ts, tp); 1230 if (r) { 1231 while (*r) { 1232 Xcheck(*dsp, dp); 1233 if (ISMAGIC(*r)) 1234 *dp++ = MAGIC; 1235 *dp++ = *r++; 1236 } 1237 *dpp = dp; 1238 r = p; 1239 } 1240 return r; 1241 } 1242 1243 /* 1244 * tilde expansion 1245 * 1246 * based on a version by Arnold Robbins 1247 */ 1248 1249 static char * 1250 tilde(cp) 1251 char *cp; 1252 { 1253 char *dp; 1254 1255 if (cp[0] == '\0') 1256 dp = str_val(global("HOME")); 1257 else if (cp[0] == '+' && cp[1] == '\0') 1258 dp = str_val(global("PWD")); 1259 else if (cp[0] == '-' && cp[1] == '\0') 1260 dp = str_val(global("OLDPWD")); 1261 else 1262 dp = homedir(cp); 1263 /* If HOME, PWD or OLDPWD are not set, don't expand ~ */ 1264 if (dp == null) 1265 dp = (char *) 0; 1266 return dp; 1267 } 1268 1269 /* 1270 * map userid to user's home directory. 1271 * note that 4.3's getpw adds more than 6K to the shell, 1272 * and the YP version probably adds much more. 1273 * we might consider our own version of getpwnam() to keep the size down. 1274 */ 1275 1276 static char * 1277 homedir(name) 1278 char *name; 1279 { 1280 register struct tbl *ap; 1281 1282 ap = tenter(&homedirs, name, hash(name)); 1283 if (!(ap->flag & ISSET)) { 1284 struct passwd *pw; 1285 size_t n; 1286 1287 pw = getpwnam(name); 1288 if (pw == NULL) 1289 return NULL; 1290 n = strlen(pw->pw_dir); 1291 if (n > 0 && '/' != pw->pw_dir[n - 1]) { 1292 ap->val.s = str_nsave(pw->pw_dir, n + 1, APERM); 1293 ap->val.s[n] = '/'; 1294 ap->val.s[n + 1] = '\0'; 1295 } else { 1296 ap->val.s = str_save(pw->pw_dir, APERM); 1297 } 1298 ap->flag |= DEFINED|ISSET|ALLOC; 1299 } 1300 return ap->val.s; 1301 } 1302 1303 #ifdef BRACE_EXPAND 1304 static void 1305 alt_expand(wp, start, exp_start, end, fdo) 1306 XPtrV *wp; 1307 char *start, *exp_start; 1308 char *end; 1309 int fdo; 1310 { 1311 int UNINITIALIZED(count); 1312 char *brace_start, *brace_end, *UNINITIALIZED(comma); 1313 char *field_start; 1314 char *p; 1315 1316 /* search for open brace */ 1317 for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2) 1318 ; 1319 brace_start = p; 1320 1321 /* find matching close brace, if any */ 1322 if (p) { 1323 comma = (char *) 0; 1324 count = 1; 1325 for (p += 2; *p && count; p++) { 1326 if (ISMAGIC(*p)) { 1327 if (*++p == OBRACE) 1328 count++; 1329 else if (*p == CBRACE) 1330 --count; 1331 else if (*p == ',' && count == 1) 1332 comma = p; 1333 } 1334 } 1335 } 1336 /* no valid expansions... */ 1337 if (!p || count != 0) { 1338 /* Note that given a{{b,c} we do not expand anything (this is 1339 * what at&t ksh does. This may be changed to do the {b,c} 1340 * expansion. } 1341 */ 1342 if (fdo & DOGLOB) 1343 glob(start, wp, fdo & DOMARKDIRS); 1344 else 1345 XPput(*wp, debunk(start, start, end - start)); 1346 return; 1347 } 1348 brace_end = p; 1349 if (!comma) { 1350 alt_expand(wp, start, brace_end, end, fdo); 1351 return; 1352 } 1353 1354 /* expand expression */ 1355 field_start = brace_start + 2; 1356 count = 1; 1357 for (p = brace_start + 2; p != brace_end; p++) { 1358 if (ISMAGIC(*p)) { 1359 if (*++p == OBRACE) 1360 count++; 1361 else if ((*p == CBRACE && --count == 0) 1362 || (*p == ',' && count == 1)) 1363 { 1364 char *new; 1365 int l1, l2, l3; 1366 1367 l1 = brace_start - start; 1368 l2 = (p - 1) - field_start; 1369 l3 = end - brace_end; 1370 new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP); 1371 memcpy(new, start, l1); 1372 memcpy(new + l1, field_start, l2); 1373 memcpy(new + l1 + l2, brace_end, l3); 1374 new[l1 + l2 + l3] = '\0'; 1375 alt_expand(wp, new, new + l1, 1376 new + l1 + l2 + l3, fdo); 1377 field_start = p + 1; 1378 } 1379 } 1380 } 1381 return; 1382 } 1383 #endif /* BRACE_EXPAND */ 1384