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