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