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