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