1 #include "sh.h" 2 #include "ksh_time.h" 3 #include "ksh_limval.h" 4 #include "ksh_stat.h" 5 #include <ctype.h> 6 7 /* 8 * Variables 9 * 10 * WARNING: unreadable code, needs a rewrite 11 * 12 * if (flag&INTEGER), val.i contains integer value, and type contains base. 13 * otherwise, (val.s + type) contains string value. 14 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. 15 */ 16 static struct tbl vtemp; 17 static struct table specials; 18 static char *formatstr ARGS((struct tbl *vp, const char *s)); 19 static void export ARGS((struct tbl *vp, const char *val)); 20 static int special ARGS((const char *name)); 21 static void getspec ARGS((struct tbl *vp)); 22 static void setspec ARGS((struct tbl *vp)); 23 static void unsetspec ARGS((struct tbl *vp)); 24 static struct tbl *arraysearch ARGS((struct tbl *, int)); 25 26 /* 27 * create a new block for function calls and simple commands 28 * assume caller has allocated and set up e->loc 29 */ 30 void 31 newblock() 32 { 33 register struct block *l; 34 static char *const empty[] = {null}; 35 36 l = (struct block *) alloc(sizeof(struct block), ATEMP); 37 ainit(&l->area); 38 if (!e->loc) { 39 l->argc = 0; 40 l->argv = (char **) empty; 41 } else { 42 l->argc = e->loc->argc; 43 l->argv = e->loc->argv; 44 } 45 l->exit = l->error = NULL; 46 tinit(&l->vars, &l->area, 0); 47 tinit(&l->funs, &l->area, 0); 48 l->next = e->loc; 49 e->loc = l; 50 } 51 52 /* 53 * pop a block handling special variables 54 */ 55 void 56 popblock() 57 { 58 register struct block *l = e->loc; 59 register struct tbl *vp, **vpp = l->vars.tbls, *vq; 60 register int i; 61 62 e->loc = l->next; /* pop block */ 63 for (i = l->vars.size; --i >= 0; ) 64 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) 65 if ((vq = global(vp->name))->flag & ISSET) 66 setspec(vq); 67 else 68 unsetspec(vq); 69 afreeall(&l->area); 70 afree(l, ATEMP); 71 } 72 73 /* called by main() to initialize variable data structures */ 74 void 75 initvar() 76 { 77 static const struct { 78 const char *name; 79 int v; 80 } names[] = { 81 { "COLUMNS", V_COLUMNS }, 82 { "IFS", V_IFS }, 83 { "OPTIND", V_OPTIND }, 84 { "PATH", V_PATH }, 85 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT }, 86 { "TMPDIR", V_TMPDIR }, 87 #ifdef HISTORY 88 { "HISTFILE", V_HISTFILE }, 89 { "HISTSIZE", V_HISTSIZE }, 90 #endif /* HISTORY */ 91 #ifdef EDIT 92 { "EDITOR", V_EDITOR }, 93 { "VISUAL", V_VISUAL }, 94 #endif /* EDIT */ 95 #ifdef KSH 96 { "MAIL", V_MAIL }, 97 { "MAILCHECK", V_MAILCHECK }, 98 { "MAILPATH", V_MAILPATH }, 99 { "RANDOM", V_RANDOM }, 100 { "SECONDS", V_SECONDS }, 101 { "TMOUT", V_TMOUT }, 102 #endif /* KSH */ 103 { (char *) 0, 0 } 104 }; 105 int i; 106 struct tbl *tp; 107 108 tinit(&specials, APERM, 32); /* must be 2^n (currently 16 speciasl) */ 109 for (i = 0; names[i].name; i++) { 110 tp = tenter(&specials, names[i].name, hash(names[i].name)); 111 tp->flag = DEFINED|ISSET; 112 tp->type = names[i].v; 113 } 114 } 115 116 /* Used to calculate an array index for global()/local(). Sets *arrayp to 117 * non-zero if this is an array, sets *valp to the array index, returns 118 * the basename of the array. 119 */ 120 const char * 121 array_index_calc(n, arrayp, valp) 122 const char *n; 123 bool_t *arrayp; 124 int *valp; 125 { 126 const char *p; 127 int len; 128 129 *arrayp = FALSE; 130 p = skip_varname(n, FALSE); 131 if (p != n && *p == '[' && (len = array_ref_len(p))) { 132 char *sub, *tmp; 133 long rval; 134 135 /* Calculate the value of the subscript */ 136 *arrayp = TRUE; 137 tmp = str_nsave(p+1, len-2, ATEMP); 138 sub = substitute(tmp, 0); 139 afree(tmp, ATEMP); 140 n = str_nsave(n, p - n, ATEMP); 141 evaluate(sub, &rval, FALSE); 142 if (rval < 0 || rval > ARRAYMAX) 143 errorf("%s: subscript out of range", n); 144 *valp = rval; 145 afree(sub, ATEMP); 146 } 147 return n; 148 } 149 150 /* 151 * Search for variable, if not found create globally. 152 */ 153 struct tbl * 154 global(n) 155 register const char *n; 156 { 157 register struct block *l = e->loc; 158 register struct tbl *vp; 159 register int c; 160 unsigned h; 161 bool_t array; 162 int val; 163 164 /* Check to see if this is an array */ 165 n = array_index_calc(n, &array, &val); 166 h = hash(n); 167 c = n[0]; 168 if (!letter(c)) { 169 if (array) 170 errorf("bad substitution"); 171 vp = &vtemp; 172 vp->flag = (DEFINED|RDONLY); 173 vp->type = 0; 174 vp->areap = ATEMP; 175 *vp->name = c; 176 if (digit(c)) { 177 for (c = 0; digit(*n); n++) 178 c = c*10 + *n-'0'; 179 if (c <= l->argc) 180 setstr(vp, l->argv[c]); 181 return vp; 182 } 183 if (n[1] != '\0') 184 return vp; 185 vp->flag |= ISSET|INTEGER; 186 switch (c) { 187 case '$': 188 vp->val.i = kshpid; 189 break; 190 case '!': 191 /* If no job, expand to nothing */ 192 if ((vp->val.i = j_async()) == 0) 193 vp->flag &= ~(ISSET|INTEGER); 194 break; 195 case '?': 196 vp->val.i = exstat; 197 break; 198 case '#': 199 vp->val.i = l->argc; 200 break; 201 case '-': 202 vp->flag &= ~INTEGER; 203 vp->val.s = getoptions(); 204 break; 205 default: 206 vp->flag &= ~(ISSET|INTEGER); 207 } 208 return vp; 209 } 210 for (l = e->loc; ; l = l->next) { 211 vp = tsearch(&l->vars, n, h); 212 if (vp != NULL) 213 if (array) 214 return arraysearch(vp, val); 215 else 216 return vp; 217 if (l->next == NULL) 218 break; 219 } 220 vp = tenter(&l->vars, n, h); 221 if (array) 222 vp = arraysearch(vp, val); 223 vp->flag |= DEFINED; 224 if (special(n)) 225 vp->flag |= SPECIAL; 226 return vp; 227 } 228 229 /* 230 * Search for local variable, if not found create locally. 231 */ 232 struct tbl * 233 local(n, copy) 234 register const char *n; 235 bool_t copy; 236 { 237 register struct block *l = e->loc; 238 register struct tbl *vp; 239 unsigned h; 240 bool_t array; 241 int val; 242 243 /* Check to see if this is an array */ 244 n = array_index_calc(n, &array, &val); 245 h = hash(n); 246 if (!letter(*n)) { 247 vp = &vtemp; 248 vp->flag = DEFINED|RDONLY; 249 vp->type = 0; 250 vp->areap = ATEMP; 251 return vp; 252 } 253 vp = tenter(&l->vars, n, h); 254 if (copy && !(vp->flag & DEFINED)) { 255 struct block *ll = l; 256 struct tbl *vq = (struct tbl *) 0; 257 258 while ((ll = ll->next) && !(vq = tsearch(&ll->vars, n, h))) 259 ; 260 if (vq) { 261 vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY 262 |LJUST|RJUST|ZEROFIL 263 |LCASEV|UCASEV_AL|INT_U|INT_L); 264 if (vq->flag & INTEGER) 265 vp->type = vq->type; 266 vp->u2.field = vq->u2.field; 267 } 268 } 269 if (array) 270 vp = arraysearch(vp, val); 271 vp->flag |= DEFINED; 272 if (special(n)) 273 vp->flag |= SPECIAL; 274 return vp; 275 } 276 277 /* get variable string value */ 278 char * 279 str_val(vp) 280 register struct tbl *vp; 281 { 282 char *s; 283 284 if ((vp->flag&SPECIAL)) 285 getspec(vp); 286 if (!(vp->flag&ISSET)) 287 s = null; /* special to dollar() */ 288 else if (!(vp->flag&INTEGER)) /* string source */ 289 s = vp->val.s + vp->type; 290 else { /* integer source */ 291 /* worst case number length is when base=2, so use BITS(long) */ 292 /* minus base # number null */ 293 static char strbuf[1 + 2 + 1 + BITS(long) + 1]; 294 const char *digits = (vp->flag & UCASEV_AL) ? 295 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 296 : "0123456789abcdefghijklmnopqrstuvwxyz"; 297 register unsigned long n; 298 register int base; 299 300 s = strbuf + sizeof(strbuf); 301 if (vp->flag & INT_U) 302 n = (unsigned long) vp->val.i; 303 else 304 n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; 305 base = (vp->type == 0) ? 10 : vp->type; 306 307 *--s = '\0'; 308 do { 309 *--s = digits[n % base]; 310 n /= base; 311 } while (n != 0); 312 if (base != 10) { 313 *--s = '#'; 314 *--s = digits[base % 10]; 315 if (base >= 10) 316 *--s = digits[base / 10]; 317 } 318 if (!(vp->flag & INT_U) && vp->val.i < 0) 319 *--s = '-'; 320 if (vp->flag & (RJUST|LJUST)) /* case already dealt with */ 321 s = formatstr(vp, s); 322 } 323 return s; 324 } 325 326 /* get variable integer value, with error checking */ 327 long 328 intval(vp) 329 register struct tbl *vp; 330 { 331 long num; 332 int base; 333 334 base = getint(vp, &num); 335 if (base == -1) 336 /* XXX check calls - is error here ok by POSIX? */ 337 errorf("%s: bad number", str_val(vp)); 338 return num; 339 } 340 341 /* set variable to string value */ 342 void 343 setstr(vq, s) 344 register struct tbl *vq; 345 const char *s; 346 { 347 if (!(vq->flag&INTEGER)) { /* string dest */ 348 if ((vq->flag&ALLOC)) { 349 /* debugging */ 350 if (s >= vq->val.s 351 && s <= vq->val.s + strlen(vq->val.s)) 352 internal_errorf(TRUE, 353 "setstr: %s=%s: assigning to self", 354 vq->name, s); 355 afree((void*)vq->val.s, vq->areap); 356 } 357 vq->flag &= ~(ISSET|ALLOC); 358 vq->type = 0; 359 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) 360 s = formatstr(vq, s); 361 if ((vq->flag&EXPORT)) 362 export(vq, s); 363 else { 364 vq->val.s = str_save(s, vq->areap); 365 if (vq->val.s) /* <sjg> don't lie */ 366 vq->flag |= ALLOC; 367 } 368 } else /* integer dest */ 369 /* XXX is this correct? */ 370 v_evaluate(vq, s, FALSE); 371 vq->flag |= ISSET; 372 if ((vq->flag&SPECIAL)) 373 setspec(vq); 374 } 375 376 /* set variable to integer */ 377 void 378 setint(vq, n) 379 register struct tbl *vq; 380 long n; 381 { 382 if (!(vq->flag&INTEGER)) { 383 register struct tbl *vp = &vtemp; 384 vp->flag = (ISSET|INTEGER); 385 vp->type = 0; 386 vp->areap = ATEMP; 387 vp->val.i = n; 388 setstr(vq, str_val(vp)); 389 } else 390 vq->val.i = n; 391 vq->flag |= ISSET; 392 if ((vq->flag&SPECIAL)) 393 setspec(vq); 394 } 395 396 int 397 getint(vp, nump) 398 struct tbl *vp; 399 long *nump; 400 { 401 register char *s; 402 register int c; 403 int base, neg; 404 int have_base = 0; 405 long num; 406 407 if (vp->flag&SPECIAL) 408 getspec(vp); 409 /* XXX is it possible for ISSET to be set and val.s to be 0? */ 410 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 411 return -1; 412 if (vp->flag&INTEGER) { 413 *nump = vp->val.i; 414 return vp->type; 415 } 416 s = vp->val.s + vp->type; 417 if (s == NULL) /* redundent given initial test */ 418 s = null; 419 base = 10; 420 num = 0; 421 neg = 0; 422 for (c = *s++; c ; c = *s++) { 423 if (c == '-') { 424 neg++; 425 } else if (c == '#') { 426 base = (int) num; 427 if (have_base || base < 2 || base > 36) 428 return -1; 429 num = 0; 430 have_base = 1; 431 } else if (letnum(c)) { 432 if (isdigit(c)) 433 c -= '0'; 434 else if (islower(c)) 435 c -= 'a' - 10; /* todo: assumes ascii */ 436 else if (isupper(c)) 437 c -= 'A' - 10; /* todo: assumes ascii */ 438 else 439 c = -1; /* _: force error */ 440 if (c < 0 || c >= base) 441 return -1; 442 num = num * base + c; 443 } else 444 return -1; 445 } 446 if (neg) 447 num = -num; 448 *nump = num; 449 return base; 450 } 451 452 /* convert variable vq to integer variable, setting its value from vp 453 * (vq and vp may be the same) 454 */ 455 struct tbl * 456 setint_v(vq, vp) 457 register struct tbl *vq, *vp; 458 { 459 int base; 460 long num; 461 462 if ((base = getint(vp, &num)) == -1) 463 return NULL; 464 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 465 vq->flag &= ~ALLOC; 466 afree(vq->val.s, vq->areap); 467 } 468 vq->val.i = num; 469 if (vq->type == 0) /* default base */ 470 vq->type = base; 471 vq->flag |= ISSET|INTEGER; 472 if (vq->flag&SPECIAL) 473 setspec(vq); 474 return vq; 475 } 476 477 static char * 478 formatstr(vp, s) 479 struct tbl *vp; 480 const char *s; 481 { 482 int olen, nlen; 483 char *p, *q; 484 485 olen = strlen(s); 486 487 if (vp->flag & (RJUST|LJUST)) { 488 if (!vp->u2.field) /* default field width */ 489 vp->u2.field = olen; 490 nlen = vp->u2.field; 491 } else 492 nlen = olen; 493 494 p = (char *) alloc(nlen + 1, ATEMP); 495 if (vp->flag & (RJUST|LJUST)) { 496 int slen; 497 498 if (vp->flag & RJUST) { 499 const char *q = s + olen; 500 /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */ 501 while (q > s && isspace(q[-1])) 502 --q; 503 slen = q - s; 504 if (slen > vp->u2.field) { 505 s += slen - vp->u2.field; 506 slen = vp->u2.field; 507 } 508 shf_snprintf(p, nlen + 1, 509 ((vp->flag & ZEROFIL) && digit(*s)) ? 510 "%0*s%.*s" : "%*s%.*s", 511 vp->u2.field - slen, null, slen, s); 512 } else { 513 /* strip leading spaces/zeros */ 514 while (isspace(*s)) 515 s++; 516 if (vp->flag & ZEROFIL) 517 while (*s == '0') 518 s++; 519 shf_snprintf(p, nlen + 1, "%-*.*s", 520 vp->u2.field, vp->u2.field, s); 521 } 522 } else 523 memcpy(p, s, olen + 1); 524 525 if (vp->flag & UCASEV_AL) { 526 for (q = p; *q; q++) 527 if (islower(*q)) 528 *q = toupper(*q); 529 } else if (vp->flag & LCASEV) { 530 for (q = p; *q; q++) 531 if (isupper(*q)) 532 *q = tolower(*q); 533 } 534 535 return p; 536 } 537 538 /* 539 * make vp->val.s be "name=value" for quick exporting. 540 */ 541 static void 542 export(vp, val) 543 register struct tbl *vp; 544 const char *val; 545 { 546 register char *xp; 547 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 548 int namelen = strlen(vp->name); 549 int vallen = strlen(val) + 1; 550 551 vp->flag |= ALLOC; 552 xp = (char*)alloc(namelen + 1 + vallen, vp->areap); 553 memcpy(vp->val.s = xp, vp->name, namelen); 554 xp += namelen; 555 *xp++ = '='; 556 vp->type = xp - vp->val.s; /* offset to value */ 557 memcpy(xp, val, vallen); 558 if (op != NULL) 559 afree((void*)op, vp->areap); 560 } 561 562 /* 563 * lookup variable (according to (set&LOCAL)), 564 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, 565 * LCASEV, UCASEV_AL), and optionally set its value if an assignment. 566 */ 567 struct tbl * 568 typeset(var, set, clr, field, base) 569 register const char *var; 570 Tflag clr, set; 571 int field, base; 572 { 573 register struct tbl *vp; 574 struct tbl *vpbase, *t; 575 char *tvar; 576 const char *val; 577 578 /* check for valid variable name, search for value */ 579 val = skip_varname(var, FALSE); 580 if (val == var) 581 return NULL; 582 if (*val == '[') { 583 int len; 584 585 len = array_ref_len(val); 586 if (len == 0) 587 return NULL; 588 /* IMPORT is only used when the shell starts up and is 589 * setting up its environment. Allow only simple array 590 * references at this time since parameter/command substitution 591 * is preformed on the [expression], which would be a major 592 * security hole. 593 */ 594 if (set & IMPORT) { 595 int i; 596 for (i = 1; i < len - 1; i++) 597 if (!digit(val[i])) 598 return NULL; 599 } 600 val += len; 601 } 602 if (*val == '=') 603 tvar = str_nsave(var, val++ - var, ATEMP); 604 else { 605 /* Importing from original envirnment: must have an = */ 606 if (set & IMPORT) 607 return NULL; 608 tvar = (char *) var; 609 val = NULL; 610 } 611 612 /* Prevent typeset from creating a local PATH/ENV/SHELL */ 613 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 614 || strcmp(tvar, "ENV") == 0 615 || strcmp(tvar, "SHELL") == 0)) 616 errorf("%s: restricted", tvar); 617 618 vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE) 619 : global(tvar); 620 set &= ~(LOCAL|LOCAL_COPY); 621 622 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; 623 624 /* only allow export flag to be set. at&t ksh allows any attribute to 625 * be changed, which means it can be truncated or modified 626 * (-L/-R/-Z/-i). 627 */ 628 if ((vpbase->flag&RDONLY) 629 && (val || clr || (set & ~EXPORT))) 630 /* XXX check calls - is error here ok by POSIX? */ 631 errorf("%s: is read only", tvar); 632 if (val) 633 afree(tvar, ATEMP); 634 635 /* most calls are with set/clr == 0 */ 636 if (set | clr) { 637 /* XXX if x[0] isn't set, there will be problems: need to have 638 * one copy of attributes for arrays... 639 */ 640 for (t = vpbase; t; t = t->u.array) { 641 int fake_assign; 642 char UNINITIALIZED(*s); 643 char UNINITIALIZED(*free_me); 644 645 fake_assign = (t->flag & ISSET) && (!val || t != vp) 646 && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) 647 || ((t->flag & INTEGER) && (clr & INTEGER)) 648 || (!(t->flag & INTEGER) && (set & INTEGER))); 649 if (fake_assign) { 650 if (t->flag & INTEGER) { 651 s = str_val(t); 652 free_me = (char *) 0; 653 } else { 654 s = t->val.s + t->type; 655 free_me = (t->flag & ALLOC) ? t->val.s 656 : (char *) 0; 657 } 658 t->flag &= ~ALLOC; 659 } 660 if (!(t->flag & INTEGER) && (set & INTEGER)) { 661 t->type = 0; 662 t->flag &= ~ALLOC; 663 } 664 t->flag = (t->flag | set) & ~clr; 665 /* Don't change base if assignment is to be done, 666 * in case assignment fails. 667 */ 668 if ((set & INTEGER) && base > 0 && (!val || t != vp)) 669 t->type = base; 670 if (set & (LJUST|RJUST|ZEROFIL)) 671 t->u2.field = field; 672 if (fake_assign) { 673 setstr(t, s); 674 if (free_me) 675 afree((void *) free_me, t->areap); 676 } 677 } 678 } 679 680 if (val != NULL) { 681 if (vp->flag&INTEGER) { 682 /* do not zero base before assignment */ 683 setstr(vp, val); 684 /* Done after assignment to override default */ 685 if (base > 0) 686 vp->type = base; 687 } else 688 setstr(vp, val); 689 } 690 691 /* only x[0] is ever exported, so use vpbase */ 692 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) 693 && vpbase->type == 0) 694 export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 695 696 return vp; 697 } 698 699 /* Unset a variable. array_ref is set if there was an array reference in 700 * the name lookup (eg, x[2]). 701 */ 702 void 703 unset(vp, array_ref) 704 register struct tbl *vp; 705 int array_ref; 706 { 707 if (vp->flag & ALLOC) 708 afree((void*)vp->val.s, vp->areap); 709 if ((vp->flag & ARRAY) && !array_ref) { 710 struct tbl *a, *tmp; 711 712 /* Free up entire array */ 713 for (a = vp->u.array; a; ) { 714 tmp = a; 715 a = a->u.array; 716 if (tmp->flag & ALLOC) 717 afree((void *) tmp->val.s, tmp->areap); 718 afree(tmp, tmp->areap); 719 } 720 vp->u.array = (struct tbl *) 0; 721 } 722 /* If foo[0] is being unset, the remainder of the array is kept... */ 723 vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0); 724 if (vp->flag & SPECIAL) 725 unsetspec(vp); /* responsible for `unspecial'ing var */ 726 } 727 728 /* return a pointer to the first char past a legal variable name (returns the 729 * argument if there is no legal name, returns * a pointer to the terminating 730 * null if whole string is legal). 731 */ 732 char * 733 skip_varname(s, aok) 734 const char *s; 735 int aok; 736 { 737 int alen; 738 739 if (s && letter(*s)) { 740 while (*++s && letnum(*s)) 741 ; 742 if (aok && *s == '[' && (alen = array_ref_len(s))) 743 s += alen; 744 } 745 return (char *) s; 746 } 747 748 /* Return a pointer to the first character past any legal variable name. */ 749 char * 750 skip_wdvarname(s, aok) 751 const char *s; 752 int aok; /* skip array de-reference? */ 753 { 754 if (s[0] == CHAR && letter(s[1])) { 755 do 756 s += 2; 757 while (s[0] == CHAR && letnum(s[1])); 758 if (aok && s[0] == CHAR && s[1] == '[') { 759 /* skip possible array de-reference */ 760 const char *p = s; 761 char c; 762 int depth = 0; 763 764 while (1) { 765 if (p[0] != CHAR) 766 break; 767 c = p[1]; 768 p += 2; 769 if (c == '[') 770 depth++; 771 else if (c == ']' && --depth == 0) { 772 s = p; 773 break; 774 } 775 } 776 } 777 } 778 return (char *) s; 779 } 780 781 /* Check if coded string s is a variable name */ 782 int 783 is_wdvarname(s, aok) 784 const char *s; 785 int aok; 786 { 787 char *p = skip_wdvarname(s, aok); 788 789 return p != s && p[0] == EOS; 790 } 791 792 /* Check if coded string s is a variable assignment */ 793 int 794 is_wdvarassign(s) 795 const char *s; 796 { 797 char *p = skip_wdvarname(s, TRUE); 798 799 return p != s && p[0] == CHAR && p[1] == '='; 800 } 801 802 /* 803 * Make the exported environment from the exported names in the dictionary. 804 */ 805 char ** 806 makenv() 807 { 808 struct block *l = e->loc; 809 XPtrV env; 810 register struct tbl *vp, **vpp; 811 register int i; 812 813 XPinit(env, 64); 814 for (l = e->loc; l != NULL; l = l->next) 815 for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) 816 if ((vp = *vpp++) != NULL 817 && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 818 register struct block *l2; 819 register struct tbl *vp2; 820 unsigned h = hash(vp->name); 821 822 /* unexport any redefined instances */ 823 for (l2 = l->next; l2 != NULL; l2 = l2->next) { 824 vp2 = tsearch(&l2->vars, vp->name, h); 825 if (vp2 != NULL) 826 vp2->flag &= ~EXPORT; 827 } 828 if ((vp->flag&INTEGER)) { 829 /* integer to string */ 830 char *val; 831 val = str_val(vp); 832 vp->flag &= ~INTEGER; 833 setstr(vp, val); 834 } 835 XPput(env, vp->val.s); 836 } 837 XPput(env, NULL); 838 return (char **) XPclose(env); 839 } 840 841 /* 842 * handle special variables with side effects - PATH, SECONDS. 843 */ 844 845 /* Test if name is a special parameter */ 846 static int 847 special(name) 848 register const char * name; 849 { 850 register struct tbl *tp; 851 852 tp = tsearch(&specials, name, hash(name)); 853 return tp ? tp->type : V_NONE; 854 } 855 856 #ifdef KSH 857 static time_t seconds; /* time SECONDS last set */ 858 #endif /* KSH */ 859 860 static void 861 getspec(vp) 862 register struct tbl *vp; 863 { 864 switch (special(vp->name)) { 865 #ifdef KSH 866 case V_SECONDS: 867 vp->flag &= ~SPECIAL; 868 setint(vp, (long) (time((time_t *)0) - seconds)); 869 vp->flag |= SPECIAL; 870 break; 871 case V_RANDOM: 872 vp->flag &= ~SPECIAL; 873 setint(vp, (long) (rand() & 0x7fff)); 874 vp->flag |= SPECIAL; 875 break; 876 #endif /* KSH */ 877 #ifdef HISTORY 878 case V_HISTSIZE: 879 vp->flag &= ~SPECIAL; 880 setint(vp, (long) histsize); 881 vp->flag |= SPECIAL; 882 break; 883 #endif /* HISTORY */ 884 } 885 } 886 887 static void 888 setspec(vp) 889 register struct tbl *vp; 890 { 891 char *s; 892 893 switch (special(vp->name)) { 894 case V_PATH: 895 path = str_val(vp); 896 flushcom(1); /* clear tracked aliases */ 897 break; 898 case V_IFS: 899 setctypes(s = str_val(vp), C_IFS); 900 ifs0 = *s; 901 break; 902 case V_OPTIND: 903 getopts_reset((int) intval(vp)); 904 break; 905 case V_POSIXLY_CORRECT: 906 change_flag(FPOSIX, OF_SPECIAL, 1); 907 break; 908 case V_TMPDIR: 909 if (tmpdir) { 910 afree(tmpdir, APERM); 911 tmpdir = (char *) 0; 912 } 913 /* Use tmpdir iff it is an absolute path, is writable and 914 * searchable and is a directory... 915 */ 916 { 917 struct stat statb; 918 s = str_val(vp); 919 if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0 920 && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 921 tmpdir = str_save(s, APERM); 922 } 923 break; 924 #ifdef HISTORY 925 case V_HISTSIZE: 926 vp->flag &= ~SPECIAL; 927 sethistsize((int) intval(vp)); 928 vp->flag |= SPECIAL; 929 break; 930 case V_HISTFILE: 931 sethistfile(str_val(vp)); 932 break; 933 #endif /* HISTORY */ 934 #ifdef EDIT 935 case V_VISUAL: 936 set_editmode(str_val(vp)); 937 break; 938 case V_EDITOR: 939 if (!(global("VISUAL")->flag & ISSET)) 940 set_editmode(str_val(vp)); 941 break; 942 case V_COLUMNS: 943 if ((x_cols = intval(vp)) <= MIN_COLS) 944 x_cols = MIN_COLS; 945 break; 946 #endif /* EDIT */ 947 #ifdef KSH 948 case V_MAIL: 949 mbset(str_val(vp)); 950 break; 951 case V_MAILPATH: 952 mpset(str_val(vp)); 953 break; 954 case V_MAILCHECK: 955 /* mail_check_set(intval(vp)); */ 956 break; 957 case V_RANDOM: 958 vp->flag &= ~SPECIAL; 959 srand((unsigned int)intval(vp)); 960 vp->flag |= SPECIAL; 961 break; 962 case V_SECONDS: 963 vp->flag &= ~SPECIAL; 964 seconds = time((time_t*) 0) - intval(vp); 965 vp->flag |= SPECIAL; 966 break; 967 case V_TMOUT: 968 /* at&t ksh seems to do this (only listen if integer) */ 969 if (vp->flag & INTEGER) 970 ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; 971 break; 972 #endif /* KSH */ 973 } 974 } 975 976 static void 977 unsetspec(vp) 978 register struct tbl *vp; 979 { 980 switch (special(vp->name)) { 981 case V_PATH: 982 path = def_path; 983 flushcom(1); /* clear tracked aliases */ 984 break; 985 case V_IFS: 986 setctypes(" \t\n", C_IFS); 987 ifs0 = ' '; 988 break; 989 case V_TMPDIR: 990 /* should not become unspecial */ 991 if (tmpdir) { 992 afree(tmpdir, APERM); 993 tmpdir = (char *) 0; 994 } 995 break; 996 #ifdef KSH 997 case V_MAIL: 998 mbset((char *) 0); 999 break; 1000 case V_MAILPATH: 1001 mpset((char *) 0); 1002 break; 1003 case V_TMOUT: 1004 /* at&t ksh doesn't do this. TMOUT becomes unspecial so 1005 * future assignments don't have effect. Could be 1006 * useful (eg, after "TMOUT=60; unset TMOUT", user 1007 * can't get rid of the timeout...). Should be handled 1008 * by generic unset code... 1009 */ 1010 ksh_tmout = 0; 1011 break; 1012 #endif /* KSH */ 1013 /* todo: generic action for specials (at&t says variables 1014 * lose their special meaning when unset but global() checks 1015 * the name of new vars to see if they are special) 1016 * lose meaning: _, ERRNO, LINENO, MAILCHECK, 1017 * OPTARG, OPTIND, RANDOM, SECONDS, TMOUT. 1018 * unknown: MAIL, MAILPATH, HISTSIZE, HISTFILE, 1019 * no effect: IFS, COLUMNS, PATH, TMPDIR, 1020 * VISUAL, EDITOR, 1021 * POSIXLY_CORRECT (use set +o posix instead) 1022 */ 1023 } 1024 } 1025 1026 /* 1027 * Search for (and possibly create) a table entry starting with 1028 * vp, indexed by val. 1029 */ 1030 static struct tbl * 1031 arraysearch(vp, val) 1032 struct tbl *vp; 1033 int val; 1034 { 1035 struct tbl *prev, *curr, *new; 1036 1037 vp->flag |= ARRAY|DEFINED; 1038 1039 /* The table entry is always [0] */ 1040 if (val == 0) { 1041 vp->index = 0; 1042 return vp; 1043 } 1044 prev = vp; 1045 curr = vp->u.array; 1046 while (curr && curr->index < val) { 1047 prev = curr; 1048 curr = curr->u.array; 1049 } 1050 if (curr && curr->index == val) { 1051 if (curr->flag&ISSET) 1052 return curr; 1053 else 1054 new = curr; 1055 } else 1056 new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap); 1057 strcpy(new->name, vp->name); 1058 new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL); 1059 new->type = vp->type; 1060 new->areap = vp->areap; 1061 new->u2.field = vp->u2.field; 1062 new->index = val; 1063 if (curr != new) { /* not reusing old array entry */ 1064 prev->u.array = new; 1065 new->u.array = curr; 1066 } 1067 return new; 1068 } 1069 1070 /* Return the length of an array reference (eg, [1+2]) - cp is assumed 1071 * to point to the open bracket. Returns 0 if there is no matching closing 1072 * bracket. 1073 */ 1074 int 1075 array_ref_len(cp) 1076 const char *cp; 1077 { 1078 const char *s = cp; 1079 int c; 1080 int depth = 0; 1081 1082 while ((c = *s++) && (c != ']' || --depth)) 1083 if (c == '[') 1084 depth++; 1085 if (!c) 1086 return 0; 1087 return s - cp; 1088 } 1089 1090 /* 1091 * Make a copy of the base of an array name 1092 */ 1093 char * 1094 arrayname(str) 1095 const char *str; 1096 { 1097 const char *p; 1098 1099 if ((p = strchr(str, '[')) == 0) 1100 /* Shouldn't happen, but why worry? */ 1101 return (char *) str; 1102 1103 return str_nsave(str, p - str, ATEMP); 1104 } 1105 1106 /* Set (or overwrite, if !reset) the array variable var to the values in vals. 1107 */ 1108 void 1109 set_array(var, reset, vals) 1110 const char *var; 1111 int reset; 1112 char **vals; 1113 { 1114 struct tbl *vp, *vq; 1115 int i; 1116 1117 /* to get local array, use "typeset foo; set -A foo" */ 1118 vp = global(var); 1119 1120 /* Note: at&t ksh allows set -A but not set +A of a read-only var */ 1121 if ((vp->flag&RDONLY)) 1122 errorf("%s: is read only", var); 1123 /* This code is quite non-optimal */ 1124 if (reset > 0) 1125 /* trash existing values and attributes */ 1126 unset(vp, 0); 1127 /* todo: would be nice for assignment to completely succeed or 1128 * completely fail. Only really effects integer arrays: 1129 * evaluation of some of vals[] may fail... 1130 */ 1131 for (i = 0; vals[i]; i++) { 1132 vq = arraysearch(vp, i); 1133 setstr(vq, vals[i]); 1134 } 1135 } 1136