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