1 /* $OpenBSD: var.c,v 1.35 2013/04/05 01:31:30 tedu Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 5 * 2011, 2012, 2013 6 * Thorsten Glaser <tg (at) mirbsd.org> 7 * 8 * Provided that these terms and disclaimer and all copyright notices 9 * are retained or reproduced in an accompanying document, permission 10 * is granted to deal in this work without restriction, including un- 11 * limited rights to use, publicly perform, distribute, sell, modify, 12 * merge, give away, or sublicence. 13 * 14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 15 * the utmost extent permitted by applicable law, neither express nor 16 * implied; without malicious intent or gross negligence. In no event 17 * may a licensor, author or contributor be held liable for indirect, 18 * direct, other damage, loss, or other issues arising in any way out 19 * of dealing in the work, even if advised of the possibility of such 20 * damage or existence of a defect, except proven that it results out 21 * of said person's immediate fault when using the work as intended. 22 */ 23 24 #include "sh.h" 25 26 #if defined(__OpenBSD__) 27 #include <sys/sysctl.h> 28 #endif 29 30 __RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $"); 31 32 /*- 33 * Variables 34 * 35 * WARNING: unreadable code, needs a rewrite 36 * 37 * if (flag&INTEGER), val.i contains integer value, and type contains base. 38 * otherwise, (val.s + type) contains string value. 39 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. 40 */ 41 42 static struct table specials; 43 static uint32_t lcg_state = 5381; 44 45 static char *formatstr(struct tbl *, const char *); 46 static void exportprep(struct tbl *, const char *); 47 static int special(const char *); 48 static void unspecial(const char *); 49 static void getspec(struct tbl *); 50 static void setspec(struct tbl *); 51 static void unsetspec(struct tbl *); 52 static int getint(struct tbl *, mksh_ari_u *, bool); 53 static const char *array_index_calc(const char *, bool *, uint32_t *); 54 55 /* 56 * create a new block for function calls and simple commands 57 * assume caller has allocated and set up e->loc 58 */ 59 void 60 newblock(void) 61 { 62 struct block *l; 63 static const char *empty[] = { null }; 64 65 l = alloc(sizeof(struct block), ATEMP); 66 l->flags = 0; 67 /* TODO: could use e->area (l->area => l->areap) */ 68 ainit(&l->area); 69 if (!e->loc) { 70 l->argc = 0; 71 l->argv = empty; 72 } else { 73 l->argc = e->loc->argc; 74 l->argv = e->loc->argv; 75 } 76 l->exit = l->error = NULL; 77 ktinit(&l->area, &l->vars, 0); 78 ktinit(&l->area, &l->funs, 0); 79 l->next = e->loc; 80 e->loc = l; 81 } 82 83 /* 84 * pop a block handling special variables 85 */ 86 void 87 popblock(void) 88 { 89 ssize_t i; 90 struct block *l = e->loc; 91 struct tbl *vp, **vpp = l->vars.tbls, *vq; 92 93 /* pop block */ 94 e->loc = l->next; 95 96 i = 1 << (l->vars.tshift); 97 while (--i >= 0) 98 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) { 99 if ((vq = global(vp->name))->flag & ISSET) 100 setspec(vq); 101 else 102 unsetspec(vq); 103 } 104 if (l->flags & BF_DOGETOPTS) 105 user_opt = l->getopts_state; 106 afreeall(&l->area); 107 afree(l, ATEMP); 108 } 109 110 /* called by main() to initialise variable data structures */ 111 #define VARSPEC_DEFNS 112 #include "var_spec.h" 113 114 enum var_specs { 115 #define VARSPEC_ENUMS 116 #include "var_spec.h" 117 V_MAX 118 }; 119 120 /* this is biased with -1 relative to VARSPEC_ENUMS */ 121 static const char * const initvar_names[] = { 122 #define VARSPEC_ITEMS 123 #include "var_spec.h" 124 }; 125 126 void 127 initvar(void) 128 { 129 int i = 0; 130 struct tbl *tp; 131 132 ktinit(APERM, &specials, 133 /* currently 14 specials: 75% of 32 = 2^5 */ 134 5); 135 while (i < V_MAX - 1) { 136 tp = ktenter(&specials, initvar_names[i], 137 hash(initvar_names[i])); 138 tp->flag = DEFINED|ISSET; 139 tp->type = ++i; 140 } 141 } 142 143 /* common code for several functions below and c_typeset() */ 144 struct block * 145 varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) 146 { 147 register struct tbl *vp; 148 149 if (l) { 150 varsearch_loop: 151 if ((vp = ktsearch(&l->vars, vn, h)) != NULL) 152 goto varsearch_out; 153 if (l->next != NULL) { 154 l = l->next; 155 goto varsearch_loop; 156 } 157 } 158 vp = NULL; 159 varsearch_out: 160 *vpp = vp; 161 return (l); 162 } 163 164 /* 165 * Used to calculate an array index for global()/local(). Sets *arrayp 166 * to true if this is an array, sets *valp to the array index, returns 167 * the basename of the array. 168 */ 169 static const char * 170 array_index_calc(const char *n, bool *arrayp, uint32_t *valp) 171 { 172 const char *p; 173 size_t len; 174 char *ap = NULL; 175 176 *arrayp = false; 177 redo_from_ref: 178 p = skip_varname(n, false); 179 if (set_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { 180 struct tbl *vp; 181 char *vn; 182 183 strndupx(vn, n, p - n, ATEMP); 184 /* check if this is a reference */ 185 varsearch(e->loc, &vp, vn, hash(vn)); 186 afree(vn, ATEMP); 187 if (vp && (vp->flag & (DEFINED|ASSOC|ARRAY)) == 188 (DEFINED|ASSOC)) { 189 char *cp; 190 191 /* gotcha! */ 192 cp = shf_smprintf("%s%s", str_val(vp), p); 193 afree(ap, ATEMP); 194 n = ap = cp; 195 goto redo_from_ref; 196 } 197 } 198 199 if (p != n && *p == '[' && (len = array_ref_len(p))) { 200 char *sub, *tmp; 201 mksh_ari_t rval; 202 203 /* calculate the value of the subscript */ 204 *arrayp = true; 205 strndupx(tmp, p + 1, len - 2, ATEMP); 206 sub = substitute(tmp, 0); 207 afree(tmp, ATEMP); 208 strndupx(n, n, p - n, ATEMP); 209 evaluate(sub, &rval, KSH_UNWIND_ERROR, true); 210 *valp = (uint32_t)rval; 211 afree(sub, ATEMP); 212 } 213 return (n); 214 } 215 216 /* 217 * Search for variable, if not found create globally. 218 */ 219 struct tbl * 220 global(const char *n) 221 { 222 struct block *l = e->loc; 223 struct tbl *vp; 224 int c; 225 bool array; 226 uint32_t h, val; 227 228 /* Check to see if this is an array */ 229 n = array_index_calc(n, &array, &val); 230 h = hash(n); 231 c = n[0]; 232 if (!ksh_isalphx(c)) { 233 if (array) 234 errorf("bad substitution"); 235 vp = &vtemp; 236 vp->flag = DEFINED; 237 vp->type = 0; 238 vp->areap = ATEMP; 239 *vp->name = c; 240 if (ksh_isdigit(c)) { 241 for (c = 0; ksh_isdigit(*n); n++) 242 c = c*10 + *n-'0'; 243 if (c <= l->argc) 244 /* setstr can't fail here */ 245 setstr(vp, l->argv[c], KSH_RETURN_ERROR); 246 vp->flag |= RDONLY; 247 return (vp); 248 } 249 vp->flag |= RDONLY; 250 if (n[1] != '\0') 251 return (vp); 252 vp->flag |= ISSET|INTEGER; 253 switch (c) { 254 case '$': 255 vp->val.i = kshpid; 256 break; 257 case '!': 258 /* if no job, expand to nothing */ 259 if ((vp->val.i = j_async()) == 0) 260 vp->flag &= ~(ISSET|INTEGER); 261 break; 262 case '?': 263 vp->val.i = exstat & 0xFF; 264 break; 265 case '#': 266 vp->val.i = l->argc; 267 break; 268 case '-': 269 vp->flag &= ~INTEGER; 270 vp->val.s = getoptions(); 271 break; 272 default: 273 vp->flag &= ~(ISSET|INTEGER); 274 } 275 return (vp); 276 } 277 l = varsearch(e->loc, &vp, n, h); 278 if (vp != NULL) 279 return (array ? arraysearch(vp, val) : vp); 280 vp = ktenter(&l->vars, n, h); 281 if (array) 282 vp = arraysearch(vp, val); 283 vp->flag |= DEFINED; 284 if (special(n)) 285 vp->flag |= SPECIAL; 286 return (vp); 287 } 288 289 /* 290 * Search for local variable, if not found create locally. 291 */ 292 struct tbl * 293 local(const char *n, bool copy) 294 { 295 struct block *l = e->loc; 296 struct tbl *vp; 297 bool array; 298 uint32_t h, val; 299 300 /* check to see if this is an array */ 301 n = array_index_calc(n, &array, &val); 302 mkssert(n != NULL); 303 h = hash(n); 304 if (!ksh_isalphx(*n)) { 305 vp = &vtemp; 306 vp->flag = DEFINED|RDONLY; 307 vp->type = 0; 308 vp->areap = ATEMP; 309 return (vp); 310 } 311 vp = ktenter(&l->vars, n, h); 312 if (copy && !(vp->flag & DEFINED)) { 313 struct tbl *vq; 314 315 varsearch(l->next, &vq, n, h); 316 if (vq != NULL) { 317 vp->flag |= vq->flag & 318 (EXPORT | INTEGER | RDONLY | LJUST | RJUST | 319 ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); 320 if (vq->flag & INTEGER) 321 vp->type = vq->type; 322 vp->u2.field = vq->u2.field; 323 } 324 } 325 if (array) 326 vp = arraysearch(vp, val); 327 vp->flag |= DEFINED; 328 if (special(n)) 329 vp->flag |= SPECIAL; 330 return (vp); 331 } 332 333 /* get variable string value */ 334 char * 335 str_val(struct tbl *vp) 336 { 337 char *s; 338 339 if ((vp->flag&SPECIAL)) 340 getspec(vp); 341 if (!(vp->flag&ISSET)) 342 /* special to dollar() */ 343 s = null; 344 else if (!(vp->flag&INTEGER)) 345 /* string source */ 346 s = vp->val.s + vp->type; 347 else { 348 /* integer source */ 349 mksh_uari_t n; 350 unsigned int base; 351 /** 352 * worst case number length is when base == 2: 353 * 1 (minus) + 2 (base, up to 36) + 1 ('#') + 354 * number of bits in the mksh_uari_t + 1 (NUL) 355 */ 356 char strbuf[1 + 2 + 1 + 8 * sizeof(mksh_uari_t) + 1]; 357 const char *digits = (vp->flag & UCASEV_AL) ? 358 digits_uc : digits_lc; 359 360 s = strbuf + sizeof(strbuf); 361 if (vp->flag & INT_U) 362 n = vp->val.u; 363 else 364 n = (vp->val.i < 0) ? -vp->val.u : vp->val.u; 365 base = (vp->type == 0) ? 10U : (unsigned int)vp->type; 366 367 if (base == 1 && n == 0) 368 base = 2; 369 if (base == 1) { 370 size_t sz = 1; 371 372 *(s = strbuf) = '1'; 373 s[1] = '#'; 374 if (!UTFMODE || ((n & 0xFF80) == 0xEF80)) 375 /* OPTU-16 -> raw octet */ 376 s[2] = n & 0xFF; 377 else 378 sz = utf_wctomb(s + 2, n); 379 s[2 + sz] = '\0'; 380 } else { 381 *--s = '\0'; 382 do { 383 *--s = digits[n % base]; 384 n /= base; 385 } while (n != 0); 386 if (base != 10) { 387 *--s = '#'; 388 *--s = digits[base % 10]; 389 if (base >= 10) 390 *--s = digits[base / 10]; 391 } 392 if (!(vp->flag & INT_U) && vp->val.i < 0) 393 *--s = '-'; 394 } 395 if (vp->flag & (RJUST|LJUST)) 396 /* case already dealt with */ 397 s = formatstr(vp, s); 398 else 399 strdupx(s, s, ATEMP); 400 } 401 return (s); 402 } 403 404 /* set variable to string value */ 405 int 406 setstr(struct tbl *vq, const char *s, int error_ok) 407 { 408 char *salloc = NULL; 409 bool no_ro_check = tobool(error_ok & 0x4); 410 411 error_ok &= ~0x4; 412 if ((vq->flag & RDONLY) && !no_ro_check) { 413 warningf(true, "read-only: %s", vq->name); 414 if (!error_ok) 415 errorfxz(2); 416 return (0); 417 } 418 if (!(vq->flag&INTEGER)) { 419 /* string dest */ 420 if ((vq->flag&ALLOC)) { 421 #ifndef MKSH_SMALL 422 /* debugging */ 423 if (s >= vq->val.s && 424 s <= vq->val.s + strlen(vq->val.s)) { 425 internal_errorf( 426 "setstr: %s=%s: assigning to self", 427 vq->name, s); 428 } 429 #endif 430 afree(vq->val.s, vq->areap); 431 } 432 vq->flag &= ~(ISSET|ALLOC); 433 vq->type = 0; 434 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) 435 s = salloc = formatstr(vq, s); 436 if ((vq->flag&EXPORT)) 437 exportprep(vq, s); 438 else { 439 strdupx(vq->val.s, s, vq->areap); 440 vq->flag |= ALLOC; 441 } 442 } else { 443 /* integer dest */ 444 if (!v_evaluate(vq, s, error_ok, true)) 445 return (0); 446 } 447 vq->flag |= ISSET; 448 if ((vq->flag&SPECIAL)) 449 setspec(vq); 450 afree(salloc, ATEMP); 451 return (1); 452 } 453 454 /* set variable to integer */ 455 void 456 setint(struct tbl *vq, mksh_ari_t n) 457 { 458 if (!(vq->flag&INTEGER)) { 459 struct tbl *vp = &vtemp; 460 vp->flag = (ISSET|INTEGER); 461 vp->type = 0; 462 vp->areap = ATEMP; 463 vp->val.i = n; 464 /* setstr can't fail here */ 465 setstr(vq, str_val(vp), KSH_RETURN_ERROR); 466 } else 467 vq->val.i = n; 468 vq->flag |= ISSET; 469 if ((vq->flag&SPECIAL)) 470 setspec(vq); 471 } 472 473 static int 474 getint(struct tbl *vp, mksh_ari_u *nump, bool arith) 475 { 476 mksh_uari_t c, num, base; 477 const char *s; 478 bool have_base = false, neg = false; 479 480 if (vp->flag&SPECIAL) 481 getspec(vp); 482 /* XXX is it possible for ISSET to be set and val.s to be NULL? */ 483 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 484 return (-1); 485 if (vp->flag&INTEGER) { 486 nump->i = vp->val.i; 487 return (vp->type); 488 } 489 s = vp->val.s + vp->type; 490 base = 10; 491 num = 0; 492 if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') { 493 s += 2; 494 base = 16; 495 have_base = true; 496 } 497 if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) && 498 !(vp->flag & ZEROFIL)) { 499 /* interpret as octal (deprecated) */ 500 base = 8; 501 have_base = true; 502 } 503 while ((c = *s++)) { 504 if (c == '-') { 505 neg = true; 506 continue; 507 } else if (c == '#') { 508 if (have_base || num < 1 || num > 36) 509 return (-1); 510 if ((base = num) == 1) { 511 unsigned int wc; 512 513 if (!UTFMODE) 514 wc = *(const unsigned char *)s; 515 else if (utf_mbtowc(&wc, s) == (size_t)-1) 516 /* OPTU-8 -> OPTU-16 */ 517 /* 518 * (with a twist: 1#\uEF80 converts 519 * the same as 1#\x80 does, thus is 520 * not round-tripping correctly XXX) 521 */ 522 wc = 0xEF00 + *(const unsigned char *)s; 523 nump->u = (mksh_uari_t)wc; 524 return (1); 525 } 526 num = 0; 527 have_base = true; 528 continue; 529 } else if (ksh_isdigit(c)) 530 c -= '0'; 531 else if (ksh_islower(c)) 532 c -= 'a' - 10; 533 else if (ksh_isupper(c)) 534 c -= 'A' - 10; 535 else 536 return (-1); 537 if (c >= base) 538 return (-1); 539 num = num * base + c; 540 } 541 if (neg) 542 num = -num; 543 nump->u = num; 544 return (base); 545 } 546 547 /* 548 * convert variable vq to integer variable, setting its value from vp 549 * (vq and vp may be the same) 550 */ 551 struct tbl * 552 setint_v(struct tbl *vq, struct tbl *vp, bool arith) 553 { 554 int base; 555 mksh_ari_u num; 556 557 if ((base = getint(vp, &num, arith)) == -1) 558 return (NULL); 559 setint_n(vq, num.i, 0); 560 if (vq->type == 0) 561 /* default base */ 562 vq->type = base; 563 return (vq); 564 } 565 566 /* convert variable vq to integer variable, setting its value to num */ 567 void 568 setint_n(struct tbl *vq, mksh_ari_t num, int newbase) 569 { 570 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 571 vq->flag &= ~ALLOC; 572 vq->type = 0; 573 afree(vq->val.s, vq->areap); 574 } 575 vq->val.i = num; 576 if (newbase != 0) 577 vq->type = newbase; 578 vq->flag |= ISSET|INTEGER; 579 if (vq->flag&SPECIAL) 580 setspec(vq); 581 } 582 583 static char * 584 formatstr(struct tbl *vp, const char *s) 585 { 586 int olen, nlen; 587 char *p, *q; 588 size_t psiz; 589 590 olen = (int)utf_mbswidth(s); 591 592 if (vp->flag & (RJUST|LJUST)) { 593 if (!vp->u2.field) 594 /* default field width */ 595 vp->u2.field = olen; 596 nlen = vp->u2.field; 597 } else 598 nlen = olen; 599 600 p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); 601 if (vp->flag & (RJUST|LJUST)) { 602 int slen = olen, i = 0; 603 604 if (vp->flag & RJUST) { 605 const char *qq = s; 606 int n = 0; 607 608 while (i < slen) 609 i += utf_widthadj(qq, &qq); 610 /* strip trailing spaces (AT&T uses qq[-1] == ' ') */ 611 while (qq > s && ksh_isspace(qq[-1])) { 612 --qq; 613 --slen; 614 } 615 if (vp->flag & ZEROFIL && vp->flag & INTEGER) { 616 if (!s[0] || !s[1]) 617 goto uhm_no; 618 if (s[1] == '#') 619 n = 2; 620 else if (s[2] == '#') 621 n = 3; 622 uhm_no: 623 if (vp->u2.field <= n) 624 n = 0; 625 } 626 if (n) { 627 memcpy(p, s, n); 628 s += n; 629 } 630 while (slen > vp->u2.field) 631 slen -= utf_widthadj(s, &s); 632 if (vp->u2.field - slen) 633 memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ', 634 vp->u2.field - slen); 635 slen -= n; 636 shf_snprintf(p + vp->u2.field - slen, 637 psiz - (vp->u2.field - slen), 638 "%.*s", slen, s); 639 } else { 640 /* strip leading spaces/zeros */ 641 while (ksh_isspace(*s)) 642 s++; 643 if (vp->flag & ZEROFIL) 644 while (*s == '0') 645 s++; 646 shf_snprintf(p, nlen + 1, "%-*.*s", 647 vp->u2.field, vp->u2.field, s); 648 } 649 } else 650 memcpy(p, s, strlen(s) + 1); 651 652 if (vp->flag & UCASEV_AL) { 653 for (q = p; *q; q++) 654 *q = ksh_toupper(*q); 655 } else if (vp->flag & LCASEV) { 656 for (q = p; *q; q++) 657 *q = ksh_tolower(*q); 658 } 659 660 return (p); 661 } 662 663 /* 664 * make vp->val.s be "name=value" for quick exporting. 665 */ 666 static void 667 exportprep(struct tbl *vp, const char *val) 668 { 669 char *xp; 670 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 671 size_t namelen, vallen; 672 673 mkssert(val != NULL); 674 675 namelen = strlen(vp->name); 676 vallen = strlen(val) + 1; 677 678 vp->flag |= ALLOC; 679 /* since name+val are both in memory this can go unchecked */ 680 xp = alloc(namelen + 1 + vallen, vp->areap); 681 memcpy(vp->val.s = xp, vp->name, namelen); 682 xp += namelen; 683 *xp++ = '='; 684 /* offset to value */ 685 vp->type = xp - vp->val.s; 686 memcpy(xp, val, vallen); 687 if (op != NULL) 688 afree(op, vp->areap); 689 } 690 691 /* 692 * lookup variable (according to (set&LOCAL)), set its attributes 693 * (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, LCASEV, 694 * UCASEV_AL), and optionally set its value if an assignment. 695 */ 696 struct tbl * 697 typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) 698 { 699 struct tbl *vp; 700 struct tbl *vpbase, *t; 701 char *tvar; 702 const char *val; 703 size_t len; 704 bool vappend = false; 705 706 /* check for valid variable name, search for value */ 707 val = skip_varname(var, false); 708 if (val == var) { 709 /* no variable name given */ 710 return (NULL); 711 } 712 if (*val == '[') { 713 if (set_refflag != SRF_NOP) 714 errorf("%s: %s", var, 715 "reference variable can't be an array"); 716 len = array_ref_len(val); 717 if (len == 0) 718 return (NULL); 719 /* 720 * IMPORT is only used when the shell starts up and is 721 * setting up its environment. Allow only simple array 722 * references at this time since parameter/command 723 * substitution is performed on the [expression] which 724 * would be a major security hole. 725 */ 726 if (set & IMPORT) { 727 size_t i; 728 729 for (i = 1; i < len - 1; i++) 730 if (!ksh_isdigit(val[i])) 731 return (NULL); 732 } 733 val += len; 734 } 735 if (val[0] == '=' || (val[0] == '+' && val[1] == '=')) { 736 strndupx(tvar, var, val - var, ATEMP); 737 if (*val++ == '+') { 738 ++val; 739 vappend = true; 740 } 741 } else if ((val[0] != '\0') || (set & IMPORT)) { 742 /* 743 * must have a = when setting a variable by importing 744 * the original environment, otherwise be empty; we 745 * also end up here when a variable name was invalid 746 */ 747 return (NULL); 748 } else { 749 /* just varname with no value part nor equals sign */ 750 strdupx(tvar, var, ATEMP); 751 val = NULL; 752 /* handle foo[*] => foo (whole array) mapping for R39b */ 753 len = strlen(tvar); 754 if (len > 3 && tvar[len - 3] == '[' && tvar[len - 2] == '*' && 755 tvar[len - 1] == ']') 756 tvar[len - 3] = '\0'; 757 } 758 759 if (set_refflag == SRF_ENABLE) { 760 const char *qval; 761 762 /* bail out on 'nameref foo+=bar' */ 763 if (vappend) 764 errorfz(); 765 /* find value if variable already exists */ 766 if ((qval = val) == NULL) { 767 varsearch(e->loc, &vp, tvar, hash(tvar)); 768 if (vp != NULL) 769 qval = str_val(vp); 770 } 771 /* prevent nameref loops */ 772 while (qval) { 773 if (!strcmp(qval, tvar)) 774 errorf("%s: %s", qval, 775 "expression recurses on parameter"); 776 varsearch(e->loc, &vp, qval, hash(qval)); 777 qval = NULL; 778 if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC)) 779 qval = str_val(vp); 780 } 781 } 782 783 /* prevent typeset from creating a local PATH/ENV/SHELL */ 784 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 || 785 strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) 786 errorf("%s: %s", tvar, "restricted"); 787 788 vp = (set&LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : 789 global(tvar); 790 if (set_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) 791 vp->flag &= ~ASSOC; 792 else if (set_refflag == SRF_ENABLE) { 793 if (vp->flag & ARRAY) { 794 struct tbl *a, *tmp; 795 796 /* free up entire array */ 797 for (a = vp->u.array; a; ) { 798 tmp = a; 799 a = a->u.array; 800 if (tmp->flag & ALLOC) 801 afree(tmp->val.s, tmp->areap); 802 afree(tmp, tmp->areap); 803 } 804 vp->u.array = NULL; 805 vp->flag &= ~ARRAY; 806 } 807 vp->flag |= ASSOC; 808 } 809 810 set &= ~(LOCAL|LOCAL_COPY); 811 812 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; 813 814 /* 815 * only allow export flag to be set; AT&T ksh allows any 816 * attribute to be changed which means it can be truncated or 817 * modified (-L/-R/-Z/-i) 818 */ 819 if ((vpbase->flag&RDONLY) && 820 (val || clr || (set & ~EXPORT))) 821 /* XXX check calls - is error here ok by POSIX? */ 822 errorfx(2, "read-only: %s", tvar); 823 afree(tvar, ATEMP); 824 825 /* most calls are with set/clr == 0 */ 826 if (set | clr) { 827 bool ok = true; 828 829 /* 830 * XXX if x[0] isn't set, there will be problems: need 831 * to have one copy of attributes for arrays... 832 */ 833 for (t = vpbase; t; t = t->u.array) { 834 bool fake_assign; 835 char *s = NULL; 836 char *free_me = NULL; 837 838 fake_assign = (t->flag & ISSET) && (!val || t != vp) && 839 ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) || 840 ((t->flag & INTEGER) && (clr & INTEGER)) || 841 (!(t->flag & INTEGER) && (set & INTEGER))); 842 if (fake_assign) { 843 if (t->flag & INTEGER) { 844 s = str_val(t); 845 free_me = NULL; 846 } else { 847 s = t->val.s + t->type; 848 free_me = (t->flag & ALLOC) ? t->val.s : 849 NULL; 850 } 851 t->flag &= ~ALLOC; 852 } 853 if (!(t->flag & INTEGER) && (set & INTEGER)) { 854 t->type = 0; 855 t->flag &= ~ALLOC; 856 } 857 t->flag = (t->flag | set) & ~clr; 858 /* 859 * Don't change base if assignment is to be 860 * done, in case assignment fails. 861 */ 862 if ((set & INTEGER) && base > 0 && (!val || t != vp)) 863 t->type = base; 864 if (set & (LJUST|RJUST|ZEROFIL)) 865 t->u2.field = field; 866 if (fake_assign) { 867 if (!setstr(t, s, KSH_RETURN_ERROR)) { 868 /* 869 * Somewhat arbitrary action 870 * here: zap contents of 871 * variable, but keep the flag 872 * settings. 873 */ 874 ok = false; 875 if (t->flag & INTEGER) 876 t->flag &= ~ISSET; 877 else { 878 if (t->flag & ALLOC) 879 afree(t->val.s, t->areap); 880 t->flag &= ~(ISSET|ALLOC); 881 t->type = 0; 882 } 883 } 884 if (free_me) 885 afree(free_me, t->areap); 886 } 887 } 888 if (!ok) 889 errorfz(); 890 } 891 892 if (val != NULL) { 893 char *tval; 894 895 if (vappend) { 896 tval = shf_smprintf("%s%s", str_val(vp), val); 897 val = tval; 898 } else 899 tval = NULL; 900 901 if (vp->flag&INTEGER) { 902 /* do not zero base before assignment */ 903 setstr(vp, val, KSH_UNWIND_ERROR | 0x4); 904 /* done after assignment to override default */ 905 if (base > 0) 906 vp->type = base; 907 } else 908 /* setstr can't fail (readonly check already done) */ 909 setstr(vp, val, KSH_RETURN_ERROR | 0x4); 910 911 if (tval != NULL) 912 afree(tval, ATEMP); 913 } 914 915 /* only x[0] is ever exported, so use vpbase */ 916 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) && 917 vpbase->type == 0) 918 exportprep(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 919 920 return (vp); 921 } 922 923 /** 924 * Unset a variable. The flags can be: 925 * |1 = tear down entire array 926 * |2 = keep attributes, only unset content 927 */ 928 void 929 unset(struct tbl *vp, int flags) 930 { 931 if (vp->flag & ALLOC) 932 afree(vp->val.s, vp->areap); 933 if ((vp->flag & ARRAY) && (flags & 1)) { 934 struct tbl *a, *tmp; 935 936 /* free up entire array */ 937 for (a = vp->u.array; a; ) { 938 tmp = a; 939 a = a->u.array; 940 if (tmp->flag & ALLOC) 941 afree(tmp->val.s, tmp->areap); 942 afree(tmp, tmp->areap); 943 } 944 vp->u.array = NULL; 945 } 946 if (flags & 2) { 947 vp->flag &= ~(ALLOC|ISSET); 948 return; 949 } 950 /* if foo[0] is being unset, the remainder of the array is kept... */ 951 vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED); 952 if (vp->flag & SPECIAL) 953 /* responsible for 'unspecial'ing var */ 954 unsetspec(vp); 955 } 956 957 /* 958 * Return a pointer to the first char past a legal variable name 959 * (returns the argument if there is no legal name, returns a pointer to 960 * the terminating NUL if whole string is legal). 961 */ 962 const char * 963 skip_varname(const char *s, int aok) 964 { 965 size_t alen; 966 967 if (s && ksh_isalphx(*s)) { 968 while (*++s && ksh_isalnux(*s)) 969 ; 970 if (aok && *s == '[' && (alen = array_ref_len(s))) 971 s += alen; 972 } 973 return (s); 974 } 975 976 /* Return a pointer to the first character past any legal variable name */ 977 const char * 978 skip_wdvarname(const char *s, 979 /* skip array de-reference? */ 980 bool aok) 981 { 982 if (s[0] == CHAR && ksh_isalphx(s[1])) { 983 do { 984 s += 2; 985 } while (s[0] == CHAR && ksh_isalnux(s[1])); 986 if (aok && s[0] == CHAR && s[1] == '[') { 987 /* skip possible array de-reference */ 988 const char *p = s; 989 char c; 990 int depth = 0; 991 992 while (/* CONSTCOND */ 1) { 993 if (p[0] != CHAR) 994 break; 995 c = p[1]; 996 p += 2; 997 if (c == '[') 998 depth++; 999 else if (c == ']' && --depth == 0) { 1000 s = p; 1001 break; 1002 } 1003 } 1004 } 1005 } 1006 return (s); 1007 } 1008 1009 /* Check if coded string s is a variable name */ 1010 int 1011 is_wdvarname(const char *s, bool aok) 1012 { 1013 const char *p = skip_wdvarname(s, aok); 1014 1015 return (p != s && p[0] == EOS); 1016 } 1017 1018 /* Check if coded string s is a variable assignment */ 1019 int 1020 is_wdvarassign(const char *s) 1021 { 1022 const char *p = skip_wdvarname(s, true); 1023 1024 return (p != s && p[0] == CHAR && 1025 (p[1] == '=' || (p[1] == '+' && p[2] == CHAR && p[3] == '='))); 1026 } 1027 1028 /* 1029 * Make the exported environment from the exported names in the dictionary. 1030 */ 1031 char ** 1032 makenv(void) 1033 { 1034 ssize_t i; 1035 struct block *l; 1036 XPtrV denv; 1037 struct tbl *vp, **vpp; 1038 1039 XPinit(denv, 64); 1040 for (l = e->loc; l != NULL; l = l->next) { 1041 vpp = l->vars.tbls; 1042 i = 1 << (l->vars.tshift); 1043 while (--i >= 0) 1044 if ((vp = *vpp++) != NULL && 1045 (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 1046 struct block *l2; 1047 struct tbl *vp2; 1048 uint32_t h = hash(vp->name); 1049 1050 /* unexport any redefined instances */ 1051 for (l2 = l->next; l2 != NULL; l2 = l2->next) { 1052 vp2 = ktsearch(&l2->vars, vp->name, h); 1053 if (vp2 != NULL) 1054 vp2->flag &= ~EXPORT; 1055 } 1056 if ((vp->flag&INTEGER)) { 1057 /* integer to string */ 1058 char *val; 1059 val = str_val(vp); 1060 vp->flag &= ~(INTEGER|RDONLY|SPECIAL); 1061 /* setstr can't fail here */ 1062 setstr(vp, val, KSH_RETURN_ERROR); 1063 } 1064 XPput(denv, vp->val.s); 1065 } 1066 } 1067 XPput(denv, NULL); 1068 return ((char **)XPclose(denv)); 1069 } 1070 1071 /* 1072 * handle special variables with side effects - PATH, SECONDS. 1073 */ 1074 1075 /* Test if name is a special parameter */ 1076 static int 1077 special(const char *name) 1078 { 1079 struct tbl *tp; 1080 1081 tp = ktsearch(&specials, name, hash(name)); 1082 return (tp && (tp->flag & ISSET) ? tp->type : V_NONE); 1083 } 1084 1085 /* Make a variable non-special */ 1086 static void 1087 unspecial(const char *name) 1088 { 1089 struct tbl *tp; 1090 1091 tp = ktsearch(&specials, name, hash(name)); 1092 if (tp) 1093 ktdelete(tp); 1094 } 1095 1096 static time_t seconds; /* time SECONDS last set */ 1097 static int user_lineno; /* what user set $LINENO to */ 1098 1099 static void 1100 getspec(struct tbl *vp) 1101 { 1102 mksh_ari_u num; 1103 int st; 1104 struct timeval tv; 1105 1106 switch ((st = special(vp->name))) { 1107 case V_COLUMNS: 1108 case V_LINES: 1109 /* 1110 * Do NOT export COLUMNS/LINES. Many applications 1111 * check COLUMNS/LINES before checking ws.ws_col/row, 1112 * so if the app is started with C/L in the environ 1113 * and the window is then resized, the app won't 1114 * see the change cause the environ doesn't change. 1115 */ 1116 if (got_winch) 1117 change_winsz(); 1118 break; 1119 } 1120 switch (st) { 1121 case V_BASHPID: 1122 num.u = (mksh_uari_t)procpid; 1123 break; 1124 case V_COLUMNS: 1125 num.i = x_cols; 1126 break; 1127 case V_HISTSIZE: 1128 num.i = histsize; 1129 break; 1130 case V_LINENO: 1131 num.i = current_lineno + user_lineno; 1132 break; 1133 case V_LINES: 1134 num.i = x_lins; 1135 break; 1136 case V_EPOCHREALTIME: { 1137 /* 10(%u) + 1(.) + 6 + NUL */ 1138 char buf[18]; 1139 1140 vp->flag &= ~SPECIAL; 1141 mksh_TIME(tv); 1142 shf_snprintf(buf, sizeof(buf), "%u.%06u", 1143 (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); 1144 setstr(vp, buf, KSH_RETURN_ERROR | 0x4); 1145 vp->flag |= SPECIAL; 1146 return; 1147 } 1148 case V_OPTIND: 1149 num.i = user_opt.uoptind; 1150 break; 1151 case V_RANDOM: 1152 num.i = rndget(); 1153 break; 1154 case V_SECONDS: 1155 /* 1156 * On start up the value of SECONDS is used before 1157 * it has been set - don't do anything in this case 1158 * (see initcoms[] in main.c). 1159 */ 1160 if (vp->flag & ISSET) { 1161 mksh_TIME(tv); 1162 num.i = tv.tv_sec - seconds; 1163 } else 1164 return; 1165 break; 1166 default: 1167 /* do nothing, do not touch vp at all */ 1168 return; 1169 } 1170 vp->flag &= ~SPECIAL; 1171 setint_n(vp, num.i, 0); 1172 vp->flag |= SPECIAL; 1173 } 1174 1175 static void 1176 setspec(struct tbl *vp) 1177 { 1178 mksh_ari_u num; 1179 char *s; 1180 int st; 1181 1182 switch ((st = special(vp->name))) { 1183 #if HAVE_PERSISTENT_HISTORY 1184 case V_HISTFILE: 1185 sethistfile(str_val(vp)); 1186 return; 1187 #endif 1188 case V_IFS: 1189 setctypes(s = str_val(vp), C_IFS); 1190 ifs0 = *s; 1191 return; 1192 case V_PATH: 1193 if (path) 1194 afree(path, APERM); 1195 s = str_val(vp); 1196 strdupx(path, s, APERM); 1197 /* clear tracked aliases */ 1198 flushcom(true); 1199 return; 1200 case V_TMPDIR: 1201 if (tmpdir) { 1202 afree(tmpdir, APERM); 1203 tmpdir = NULL; 1204 } 1205 /* 1206 * Use tmpdir iff it is an absolute path, is writable 1207 * and searchable and is a directory... 1208 */ 1209 { 1210 struct stat statb; 1211 1212 s = str_val(vp); 1213 /* LINTED use of access */ 1214 if (s[0] == '/' && access(s, W_OK|X_OK) == 0 && 1215 stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 1216 strdupx(tmpdir, s, APERM); 1217 } 1218 return; 1219 /* common sub-cases */ 1220 case V_COLUMNS: 1221 case V_LINES: 1222 if (vp->flag & IMPORT) { 1223 /* do not touch */ 1224 unspecial(vp->name); 1225 vp->flag &= ~SPECIAL; 1226 return; 1227 } 1228 /* FALLTHROUGH */ 1229 case V_HISTSIZE: 1230 case V_LINENO: 1231 case V_OPTIND: 1232 case V_RANDOM: 1233 case V_SECONDS: 1234 case V_TMOUT: 1235 vp->flag &= ~SPECIAL; 1236 if (getint(vp, &num, false) == -1) { 1237 s = str_val(vp); 1238 if (st != V_RANDOM) 1239 errorf("%s: %s: %s", vp->name, "bad number", s); 1240 num.u = hash(s); 1241 } 1242 vp->flag |= SPECIAL; 1243 break; 1244 default: 1245 /* do nothing, do not touch vp at all */ 1246 return; 1247 } 1248 1249 /* process the singular parts of the common cases */ 1250 1251 switch (st) { 1252 case V_COLUMNS: 1253 if (num.i >= MIN_COLS) 1254 x_cols = num.i; 1255 break; 1256 case V_HISTSIZE: 1257 sethistsize(num.i); 1258 break; 1259 case V_LINENO: 1260 /* The -1 is because line numbering starts at 1. */ 1261 user_lineno = num.u - current_lineno - 1; 1262 break; 1263 case V_LINES: 1264 if (num.i >= MIN_LINS) 1265 x_lins = num.i; 1266 break; 1267 case V_OPTIND: 1268 getopts_reset((int)num.i); 1269 break; 1270 case V_RANDOM: 1271 /* 1272 * mksh R39d+ no longer has the traditional repeatability 1273 * of $RANDOM sequences, but always retains state 1274 */ 1275 rndset((unsigned long)num.u); 1276 break; 1277 case V_SECONDS: 1278 { 1279 struct timeval tv; 1280 1281 mksh_TIME(tv); 1282 seconds = tv.tv_sec - num.i; 1283 } 1284 break; 1285 case V_TMOUT: 1286 ksh_tmout = num.i >= 0 ? num.i : 0; 1287 break; 1288 } 1289 } 1290 1291 static void 1292 unsetspec(struct tbl *vp) 1293 { 1294 /* 1295 * AT&T ksh man page says OPTIND, OPTARG and _ lose special 1296 * meaning, but OPTARG does not (still set by getopts) and _ is 1297 * also still set in various places. Don't know what AT&T does 1298 * for HISTSIZE, HISTFILE. Unsetting these in AT&T ksh does not 1299 * loose the 'specialness': IFS, COLUMNS, PATH, TMPDIR 1300 */ 1301 1302 switch (special(vp->name)) { 1303 case V_IFS: 1304 setctypes(TC_IFSWS, C_IFS); 1305 ifs0 = ' '; 1306 break; 1307 case V_PATH: 1308 if (path) 1309 afree(path, APERM); 1310 strdupx(path, def_path, APERM); 1311 /* clear tracked aliases */ 1312 flushcom(true); 1313 break; 1314 case V_TMPDIR: 1315 /* should not become unspecial */ 1316 if (tmpdir) { 1317 afree(tmpdir, APERM); 1318 tmpdir = NULL; 1319 } 1320 break; 1321 case V_LINENO: 1322 case V_RANDOM: 1323 case V_SECONDS: 1324 case V_TMOUT: 1325 /* AT&T ksh leaves previous value in place */ 1326 unspecial(vp->name); 1327 break; 1328 } 1329 } 1330 1331 /* 1332 * Search for (and possibly create) a table entry starting with 1333 * vp, indexed by val. 1334 */ 1335 struct tbl * 1336 arraysearch(struct tbl *vp, uint32_t val) 1337 { 1338 struct tbl *prev, *curr, *news; 1339 size_t len; 1340 1341 vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC; 1342 /* the table entry is always [0] */ 1343 if (val == 0) 1344 return (vp); 1345 prev = vp; 1346 curr = vp->u.array; 1347 while (curr && curr->ua.index < val) { 1348 prev = curr; 1349 curr = curr->u.array; 1350 } 1351 if (curr && curr->ua.index == val) { 1352 if (curr->flag&ISSET) 1353 return (curr); 1354 news = curr; 1355 } else 1356 news = NULL; 1357 if (!news) { 1358 len = strlen(vp->name); 1359 checkoktoadd(len, 1 + offsetof(struct tbl, name[0])); 1360 news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap); 1361 memcpy(news->name, vp->name, len); 1362 } 1363 news->flag = (vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL)) | AINDEX; 1364 news->type = vp->type; 1365 news->areap = vp->areap; 1366 news->u2.field = vp->u2.field; 1367 news->ua.index = val; 1368 1369 if (curr != news) { 1370 /* not reusing old array entry */ 1371 prev->u.array = news; 1372 news->u.array = curr; 1373 } 1374 return (news); 1375 } 1376 1377 /* 1378 * Return the length of an array reference (eg, [1+2]) - cp is assumed 1379 * to point to the open bracket. Returns 0 if there is no matching 1380 * closing bracket. 1381 */ 1382 size_t 1383 array_ref_len(const char *cp) 1384 { 1385 const char *s = cp; 1386 char c; 1387 int depth = 0; 1388 1389 while ((c = *s++) && (c != ']' || --depth)) 1390 if (c == '[') 1391 depth++; 1392 if (!c) 1393 return (0); 1394 return (s - cp); 1395 } 1396 1397 /* 1398 * Make a copy of the base of an array name 1399 */ 1400 char * 1401 arrayname(const char *str) 1402 { 1403 const char *p; 1404 char *rv; 1405 1406 if ((p = cstrchr(str, '[')) == 0) 1407 /* Shouldn't happen, but why worry? */ 1408 strdupx(rv, str, ATEMP); 1409 else 1410 strndupx(rv, str, p - str, ATEMP); 1411 1412 return (rv); 1413 } 1414 1415 /* set (or overwrite, if reset) the array variable var to the values in vals */ 1416 mksh_uari_t 1417 set_array(const char *var, bool reset, const char **vals) 1418 { 1419 struct tbl *vp, *vq; 1420 mksh_uari_t i = 0, j = 0; 1421 const char *ccp = var; 1422 char *cp = NULL; 1423 size_t n; 1424 1425 /* to get local array, use "local foo; set -A foo" */ 1426 n = strlen(var); 1427 if (n > 0 && var[n - 1] == '+') { 1428 /* append mode */ 1429 reset = false; 1430 strndupx(cp, var, n - 1, ATEMP); 1431 ccp = cp; 1432 } 1433 vp = global(ccp); 1434 1435 /* Note: AT&T ksh allows set -A but not set +A of a read-only var */ 1436 if ((vp->flag&RDONLY)) 1437 errorfx(2, "read-only: %s", ccp); 1438 /* This code is quite non-optimal */ 1439 if (reset) { 1440 /* trash existing values and attributes */ 1441 unset(vp, 1); 1442 /* allocate-by-access the [0] element to keep in scope */ 1443 arraysearch(vp, 0); 1444 } 1445 /* 1446 * TODO: would be nice for assignment to completely succeed or 1447 * completely fail. Only really effects integer arrays: 1448 * evaluation of some of vals[] may fail... 1449 */ 1450 if (cp != NULL) { 1451 /* find out where to set when appending */ 1452 for (vq = vp; vq; vq = vq->u.array) { 1453 if (!(vq->flag & ISSET)) 1454 continue; 1455 if (arrayindex(vq) >= j) 1456 j = arrayindex(vq) + 1; 1457 } 1458 afree(cp, ATEMP); 1459 } 1460 while ((ccp = vals[i])) { 1461 if (*ccp == '[') { 1462 int level = 0; 1463 1464 while (*ccp) { 1465 if (*ccp == ']' && --level == 0) 1466 break; 1467 if (*ccp == '[') 1468 ++level; 1469 ++ccp; 1470 } 1471 if (*ccp == ']' && level == 0 && ccp[1] == '=') { 1472 strndupx(cp, vals[i] + 1, ccp - (vals[i] + 1), 1473 ATEMP); 1474 evaluate(substitute(cp, 0), (mksh_ari_t *)&j, 1475 KSH_UNWIND_ERROR, true); 1476 afree(cp, ATEMP); 1477 ccp += 2; 1478 } else 1479 ccp = vals[i]; 1480 } 1481 1482 vq = arraysearch(vp, j); 1483 /* would be nice to deal with errors here... (see above) */ 1484 setstr(vq, ccp, KSH_RETURN_ERROR); 1485 i++; 1486 j++; 1487 } 1488 1489 return (i); 1490 } 1491 1492 void 1493 change_winsz(void) 1494 { 1495 #ifdef TIOCGWINSZ 1496 /* check if window size has changed */ 1497 if (tty_init_fd() < 2) { 1498 struct winsize ws; 1499 1500 if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) { 1501 if (ws.ws_col) 1502 x_cols = ws.ws_col; 1503 if (ws.ws_row) 1504 x_lins = ws.ws_row; 1505 } 1506 } 1507 #endif 1508 1509 /* bounds check for sane values, use defaults otherwise */ 1510 if (x_cols < MIN_COLS) 1511 x_cols = 80; 1512 if (x_lins < MIN_LINS) 1513 x_lins = 24; 1514 1515 #ifdef SIGWINCH 1516 got_winch = 0; 1517 #endif 1518 } 1519 1520 uint32_t 1521 hash(const void *s) 1522 { 1523 register uint32_t h; 1524 1525 NZATInit(h); 1526 NZATUpdateString(h, s); 1527 NZAATFinish(h); 1528 return (h); 1529 } 1530 1531 mksh_ari_t 1532 rndget(void) 1533 { 1534 /* 1535 * this is the same Linear Congruential PRNG as Borland 1536 * C/C++ allegedly uses in its built-in rand() function 1537 */ 1538 return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF); 1539 } 1540 1541 void 1542 rndset(unsigned long v) 1543 { 1544 register uint32_t h; 1545 1546 NZATInit(h); 1547 NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); 1548 NZATUpdateMem(h, &v, sizeof(v)); 1549 1550 #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) 1551 /* 1552 * either we have very chap entropy get and push available, 1553 * with malloc() pulling in this code already anyway, or the 1554 * user requested us to use the old functions 1555 */ 1556 lcg_state = h; 1557 NZAATFinish(lcg_state); 1558 #if defined(arc4random_pushb_fast) 1559 arc4random_pushb_fast(&lcg_state, sizeof(lcg_state)); 1560 lcg_state = arc4random(); 1561 #else 1562 lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state)); 1563 #endif 1564 NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); 1565 #endif 1566 1567 NZAATFinish(h); 1568 lcg_state = h; 1569 } 1570