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