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