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