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