1 /* $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt 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.166 2013/02/18 22:24:52 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_t *, 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 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.i : vp->val.i; 365 base = (vp->type == 0) ? 10 : 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_t *nump, bool arith) 475 { 476 int c, base, neg; 477 mksh_uari_t num; 478 const char *s; 479 bool have_base = false; 480 481 if (vp->flag&SPECIAL) 482 getspec(vp); 483 /* XXX is it possible for ISSET to be set and val.s to be 0? */ 484 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 485 return (-1); 486 if (vp->flag&INTEGER) { 487 *nump = vp->val.i; 488 return (vp->type); 489 } 490 s = vp->val.s + vp->type; 491 base = 10; 492 num = 0; 493 neg = 0; 494 if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') { 495 s += 2; 496 base = 16; 497 have_base = true; 498 } 499 #ifdef MKSH_LEGACY_MODE 500 if (arith && s[0] == '0' && ksh_isdigit(s[1]) && 501 !(vp->flag & ZEROFIL)) { 502 /* interpret as octal (deprecated) */ 503 base = 8; 504 have_base = true; 505 } 506 #endif 507 while ((c = *s++)) { 508 if (c == '-') { 509 neg++; 510 continue; 511 } else if (c == '#') { 512 if (have_base || num < 1 || num > 36) 513 return (-1); 514 base = (int)num; 515 if (base == 1) { 516 unsigned int wc; 517 518 if (!UTFMODE) 519 wc = *(const unsigned char *)s; 520 else if (utf_mbtowc(&wc, s) == (size_t)-1) 521 /* OPTU-8 -> OPTU-16 */ 522 /* 523 * (with a twist: 1#\uEF80 converts 524 * the same as 1#\x80 does, thus is 525 * not round-tripping correctly XXX) 526 */ 527 wc = 0xEF00 + *(const unsigned char *)s; 528 *nump = (mksh_ari_t)wc; 529 return (1); 530 } 531 num = 0; 532 have_base = true; 533 continue; 534 } else if (ksh_isdigit(c)) 535 c -= '0'; 536 else if (ksh_islower(c)) 537 c -= 'a' - 10; 538 else if (ksh_isupper(c)) 539 c -= 'A' - 10; 540 else 541 return (-1); 542 if (c < 0 || c >= base) 543 return (-1); 544 num = num * base + c; 545 } 546 *nump = neg ? -((mksh_ari_t)num) : (mksh_ari_t)num; 547 return (base); 548 } 549 550 /* 551 * convert variable vq to integer variable, setting its value from vp 552 * (vq and vp may be the same) 553 */ 554 struct tbl * 555 setint_v(struct tbl *vq, struct tbl *vp, bool arith) 556 { 557 int base; 558 mksh_ari_t num; 559 560 if ((base = getint(vp, &num, arith)) == -1) 561 return (NULL); 562 setint_n(vq, num, 0); 563 if (vq->type == 0) 564 /* default base */ 565 vq->type = base; 566 return (vq); 567 } 568 569 /* convert variable vq to integer variable, setting its value to num */ 570 void 571 setint_n(struct tbl *vq, mksh_ari_t num, int newbase) 572 { 573 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 574 vq->flag &= ~ALLOC; 575 vq->type = 0; 576 afree(vq->val.s, vq->areap); 577 } 578 vq->val.i = num; 579 if (newbase != 0) 580 vq->type = newbase; 581 vq->flag |= ISSET|INTEGER; 582 if (vq->flag&SPECIAL) 583 setspec(vq); 584 } 585 586 static char * 587 formatstr(struct tbl *vp, const char *s) 588 { 589 int olen, nlen; 590 char *p, *q; 591 size_t psiz; 592 593 olen = (int)utf_mbswidth(s); 594 595 if (vp->flag & (RJUST|LJUST)) { 596 if (!vp->u2.field) 597 /* default field width */ 598 vp->u2.field = olen; 599 nlen = vp->u2.field; 600 } else 601 nlen = olen; 602 603 p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); 604 if (vp->flag & (RJUST|LJUST)) { 605 int slen = olen, i = 0; 606 607 if (vp->flag & RJUST) { 608 const char *qq = s; 609 int n = 0; 610 611 while (i < slen) 612 i += utf_widthadj(qq, &qq); 613 /* strip trailing spaces (AT&T uses qq[-1] == ' ') */ 614 while (qq > s && ksh_isspace(qq[-1])) { 615 --qq; 616 --slen; 617 } 618 if (vp->flag & ZEROFIL && vp->flag & INTEGER) { 619 if (!s[0] || !s[1]) 620 goto uhm_no; 621 if (s[1] == '#') 622 n = 2; 623 else if (s[2] == '#') 624 n = 3; 625 uhm_no: 626 if (vp->u2.field <= n) 627 n = 0; 628 } 629 if (n) { 630 memcpy(p, s, n); 631 s += n; 632 } 633 while (slen > vp->u2.field) 634 slen -= utf_widthadj(s, &s); 635 if (vp->u2.field - slen) 636 memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ', 637 vp->u2.field - slen); 638 slen -= n; 639 shf_snprintf(p + vp->u2.field - slen, 640 psiz - (vp->u2.field - slen), 641 "%.*s", slen, s); 642 } else { 643 /* strip leading spaces/zeros */ 644 while (ksh_isspace(*s)) 645 s++; 646 if (vp->flag & ZEROFIL) 647 while (*s == '0') 648 s++; 649 shf_snprintf(p, nlen + 1, "%-*.*s", 650 vp->u2.field, vp->u2.field, s); 651 } 652 } else 653 memcpy(p, s, strlen(s) + 1); 654 655 if (vp->flag & UCASEV_AL) { 656 for (q = p; *q; q++) 657 *q = ksh_toupper(*q); 658 } else if (vp->flag & LCASEV) { 659 for (q = p; *q; q++) 660 *q = ksh_tolower(*q); 661 } 662 663 return (p); 664 } 665 666 /* 667 * make vp->val.s be "name=value" for quick exporting. 668 */ 669 static void 670 exportprep(struct tbl *vp, const char *val) 671 { 672 char *xp; 673 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 674 size_t namelen, vallen; 675 676 mkssert(val != NULL); 677 678 namelen = strlen(vp->name); 679 vallen = strlen(val) + 1; 680 681 vp->flag |= ALLOC; 682 /* since name+val are both in memory this can go unchecked */ 683 xp = alloc(namelen + 1 + vallen, vp->areap); 684 memcpy(vp->val.s = xp, vp->name, namelen); 685 xp += namelen; 686 *xp++ = '='; 687 /* offset to value */ 688 vp->type = xp - vp->val.s; 689 memcpy(xp, val, vallen); 690 if (op != NULL) 691 afree(op, vp->areap); 692 } 693 694 /* 695 * lookup variable (according to (set&LOCAL)), set its attributes 696 * (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, LCASEV, 697 * UCASEV_AL), and optionally set its value if an assignment. 698 */ 699 struct tbl * 700 typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) 701 { 702 struct tbl *vp; 703 struct tbl *vpbase, *t; 704 char *tvar; 705 const char *val; 706 size_t len; 707 bool vappend = false; 708 709 /* check for valid variable name, search for value */ 710 val = skip_varname(var, false); 711 if (*val == '[') { 712 if (set_refflag != SRF_NOP) 713 errorf("%s: %s", var, 714 "reference variable can't be an array"); 715 len = array_ref_len(val); 716 if (len == 0) 717 return (NULL); 718 /* 719 * IMPORT is only used when the shell starts up and is 720 * setting up its environment. Allow only simple array 721 * references at this time since parameter/command 722 * substitution is performed on the [expression] which 723 * would be a major security hole. 724 */ 725 if (set & IMPORT) { 726 size_t i; 727 728 for (i = 1; i < len - 1; i++) 729 if (!ksh_isdigit(val[i])) 730 return (NULL); 731 } 732 val += len; 733 } 734 if (val[0] == '=' || (val[0] == '+' && val[1] == '=')) { 735 strndupx(tvar, var, val - var, ATEMP); 736 if (*val++ == '+') { 737 ++val; 738 vappend = true; 739 } 740 } else if ((val[0] != '\0') || (set & IMPORT)) { 741 /* 742 * must have a = when setting a variable by importing 743 * the original environment, otherwise be empty; we 744 * also end up here when a variable name was invalid 745 * or none given 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 /* silently ignore 'nameref foo=foo' */ 772 if (qval != NULL && !strcmp(qval, tvar)) { 773 afree(tvar, ATEMP); 774 return (&vtemp); 775 } 776 } 777 778 /* prevent typeset from creating a local PATH/ENV/SHELL */ 779 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 || 780 strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) 781 errorf("%s: %s", tvar, "restricted"); 782 783 vp = (set&LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : 784 global(tvar); 785 if (set_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) 786 vp->flag &= ~ASSOC; 787 else if (set_refflag == SRF_ENABLE) { 788 if (vp->flag & ARRAY) { 789 struct tbl *a, *tmp; 790 791 /* free up entire array */ 792 for (a = vp->u.array; a; ) { 793 tmp = a; 794 a = a->u.array; 795 if (tmp->flag & ALLOC) 796 afree(tmp->val.s, tmp->areap); 797 afree(tmp, tmp->areap); 798 } 799 vp->u.array = NULL; 800 vp->flag &= ~ARRAY; 801 } 802 vp->flag |= ASSOC; 803 } 804 805 set &= ~(LOCAL|LOCAL_COPY); 806 807 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; 808 809 /* 810 * only allow export flag to be set; AT&T ksh allows any 811 * attribute to be changed which means it can be truncated or 812 * modified (-L/-R/-Z/-i) 813 */ 814 if ((vpbase->flag&RDONLY) && 815 (val || clr || (set & ~EXPORT))) 816 /* XXX check calls - is error here ok by POSIX? */ 817 errorfx(2, "read-only: %s", tvar); 818 afree(tvar, ATEMP); 819 820 /* most calls are with set/clr == 0 */ 821 if (set | clr) { 822 bool ok = true; 823 824 /* 825 * XXX if x[0] isn't set, there will be problems: need 826 * to have one copy of attributes for arrays... 827 */ 828 for (t = vpbase; t; t = t->u.array) { 829 bool fake_assign; 830 char *s = NULL; 831 char *free_me = NULL; 832 833 fake_assign = (t->flag & ISSET) && (!val || t != vp) && 834 ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) || 835 ((t->flag & INTEGER) && (clr & INTEGER)) || 836 (!(t->flag & INTEGER) && (set & INTEGER))); 837 if (fake_assign) { 838 if (t->flag & INTEGER) { 839 s = str_val(t); 840 free_me = NULL; 841 } else { 842 s = t->val.s + t->type; 843 free_me = (t->flag & ALLOC) ? t->val.s : 844 NULL; 845 } 846 t->flag &= ~ALLOC; 847 } 848 if (!(t->flag & INTEGER) && (set & INTEGER)) { 849 t->type = 0; 850 t->flag &= ~ALLOC; 851 } 852 t->flag = (t->flag | set) & ~clr; 853 /* 854 * Don't change base if assignment is to be 855 * done, in case assignment fails. 856 */ 857 if ((set & INTEGER) && base > 0 && (!val || t != vp)) 858 t->type = base; 859 if (set & (LJUST|RJUST|ZEROFIL)) 860 t->u2.field = field; 861 if (fake_assign) { 862 if (!setstr(t, s, KSH_RETURN_ERROR)) { 863 /* 864 * Somewhat arbitrary action 865 * here: zap contents of 866 * variable, but keep the flag 867 * settings. 868 */ 869 ok = false; 870 if (t->flag & INTEGER) 871 t->flag &= ~ISSET; 872 else { 873 if (t->flag & ALLOC) 874 afree(t->val.s, t->areap); 875 t->flag &= ~(ISSET|ALLOC); 876 t->type = 0; 877 } 878 } 879 if (free_me) 880 afree(free_me, t->areap); 881 } 882 } 883 if (!ok) 884 errorfz(); 885 } 886 887 if (val != NULL) { 888 char *tval; 889 890 if (vappend) { 891 tval = shf_smprintf("%s%s", str_val(vp), val); 892 val = tval; 893 } else 894 tval = NULL; 895 896 if (vp->flag&INTEGER) { 897 /* do not zero base before assignment */ 898 setstr(vp, val, KSH_UNWIND_ERROR | 0x4); 899 /* done after assignment to override default */ 900 if (base > 0) 901 vp->type = base; 902 } else 903 /* setstr can't fail (readonly check already done) */ 904 setstr(vp, val, KSH_RETURN_ERROR | 0x4); 905 906 if (tval != NULL) 907 afree(tval, ATEMP); 908 } 909 910 /* only x[0] is ever exported, so use vpbase */ 911 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) && 912 vpbase->type == 0) 913 exportprep(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 914 915 return (vp); 916 } 917 918 /** 919 * Unset a variable. The flags can be: 920 * |1 = tear down entire array 921 * |2 = keep attributes, only unset content 922 */ 923 void 924 unset(struct tbl *vp, int flags) 925 { 926 if (vp->flag & ALLOC) 927 afree(vp->val.s, vp->areap); 928 if ((vp->flag & ARRAY) && (flags & 1)) { 929 struct tbl *a, *tmp; 930 931 /* free up entire array */ 932 for (a = vp->u.array; a; ) { 933 tmp = a; 934 a = a->u.array; 935 if (tmp->flag & ALLOC) 936 afree(tmp->val.s, tmp->areap); 937 afree(tmp, tmp->areap); 938 } 939 vp->u.array = NULL; 940 } 941 if (flags & 2) { 942 vp->flag &= ~(ALLOC|ISSET); 943 return; 944 } 945 /* if foo[0] is being unset, the remainder of the array is kept... */ 946 vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED); 947 if (vp->flag & SPECIAL) 948 /* responsible for 'unspecial'ing var */ 949 unsetspec(vp); 950 } 951 952 /* 953 * Return a pointer to the first char past a legal variable name 954 * (returns the argument if there is no legal name, returns a pointer to 955 * the terminating NUL if whole string is legal). 956 */ 957 const char * 958 skip_varname(const char *s, int aok) 959 { 960 size_t alen; 961 962 if (s && ksh_isalphx(*s)) { 963 while (*++s && ksh_isalnux(*s)) 964 ; 965 if (aok && *s == '[' && (alen = array_ref_len(s))) 966 s += alen; 967 } 968 return (s); 969 } 970 971 /* Return a pointer to the first character past any legal variable name */ 972 const char * 973 skip_wdvarname(const char *s, 974 /* skip array de-reference? */ 975 bool aok) 976 { 977 if (s[0] == CHAR && ksh_isalphx(s[1])) { 978 do { 979 s += 2; 980 } while (s[0] == CHAR && ksh_isalnux(s[1])); 981 if (aok && s[0] == CHAR && s[1] == '[') { 982 /* skip possible array de-reference */ 983 const char *p = s; 984 char c; 985 int depth = 0; 986 987 while (/* CONSTCOND */ 1) { 988 if (p[0] != CHAR) 989 break; 990 c = p[1]; 991 p += 2; 992 if (c == '[') 993 depth++; 994 else if (c == ']' && --depth == 0) { 995 s = p; 996 break; 997 } 998 } 999 } 1000 } 1001 return (s); 1002 } 1003 1004 /* Check if coded string s is a variable name */ 1005 int 1006 is_wdvarname(const char *s, bool aok) 1007 { 1008 const char *p = skip_wdvarname(s, aok); 1009 1010 return (p != s && p[0] == EOS); 1011 } 1012 1013 /* Check if coded string s is a variable assignment */ 1014 int 1015 is_wdvarassign(const char *s) 1016 { 1017 const char *p = skip_wdvarname(s, true); 1018 1019 return (p != s && p[0] == CHAR && 1020 (p[1] == '=' || (p[1] == '+' && p[2] == CHAR && p[3] == '='))); 1021 } 1022 1023 /* 1024 * Make the exported environment from the exported names in the dictionary. 1025 */ 1026 char ** 1027 makenv(void) 1028 { 1029 ssize_t i; 1030 struct block *l; 1031 XPtrV denv; 1032 struct tbl *vp, **vpp; 1033 1034 XPinit(denv, 64); 1035 for (l = e->loc; l != NULL; l = l->next) { 1036 vpp = l->vars.tbls; 1037 i = 1 << (l->vars.tshift); 1038 while (--i >= 0) 1039 if ((vp = *vpp++) != NULL && 1040 (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 1041 struct block *l2; 1042 struct tbl *vp2; 1043 uint32_t h = hash(vp->name); 1044 1045 /* unexport any redefined instances */ 1046 for (l2 = l->next; l2 != NULL; l2 = l2->next) { 1047 vp2 = ktsearch(&l2->vars, vp->name, h); 1048 if (vp2 != NULL) 1049 vp2->flag &= ~EXPORT; 1050 } 1051 if ((vp->flag&INTEGER)) { 1052 /* integer to string */ 1053 char *val; 1054 val = str_val(vp); 1055 vp->flag &= ~(INTEGER|RDONLY|SPECIAL); 1056 /* setstr can't fail here */ 1057 setstr(vp, val, KSH_RETURN_ERROR); 1058 } 1059 XPput(denv, vp->val.s); 1060 } 1061 } 1062 XPput(denv, NULL); 1063 return ((char **)XPclose(denv)); 1064 } 1065 1066 /* 1067 * handle special variables with side effects - PATH, SECONDS. 1068 */ 1069 1070 /* Test if name is a special parameter */ 1071 static int 1072 special(const char *name) 1073 { 1074 struct tbl *tp; 1075 1076 tp = ktsearch(&specials, name, hash(name)); 1077 return (tp && (tp->flag & ISSET) ? tp->type : V_NONE); 1078 } 1079 1080 /* Make a variable non-special */ 1081 static void 1082 unspecial(const char *name) 1083 { 1084 struct tbl *tp; 1085 1086 tp = ktsearch(&specials, name, hash(name)); 1087 if (tp) 1088 ktdelete(tp); 1089 } 1090 1091 static time_t seconds; /* time SECONDS last set */ 1092 static int user_lineno; /* what user set $LINENO to */ 1093 1094 static void 1095 getspec(struct tbl *vp) 1096 { 1097 register mksh_ari_t i; 1098 int st; 1099 struct timeval tv; 1100 1101 switch ((st = special(vp->name))) { 1102 case V_COLUMNS: 1103 case V_LINES: 1104 /* 1105 * Do NOT export COLUMNS/LINES. Many applications 1106 * check COLUMNS/LINES before checking ws.ws_col/row, 1107 * so if the app is started with C/L in the environ 1108 * and the window is then resized, the app won't 1109 * see the change cause the environ doesn't change. 1110 */ 1111 if (got_winch) 1112 change_winsz(); 1113 break; 1114 } 1115 switch (st) { 1116 case V_BASHPID: 1117 i = (mksh_ari_t)procpid; 1118 break; 1119 case V_COLUMNS: 1120 i = x_cols; 1121 break; 1122 case V_HISTSIZE: 1123 i = histsize; 1124 break; 1125 case V_LINENO: 1126 i = current_lineno + user_lineno; 1127 break; 1128 case V_LINES: 1129 i = x_lins; 1130 break; 1131 case V_EPOCHREALTIME: { 1132 /* 10(%u) + 1(.) + 6 + NUL */ 1133 char buf[18]; 1134 1135 vp->flag &= ~SPECIAL; 1136 mksh_TIME(tv); 1137 shf_snprintf(buf, sizeof(buf), "%u.%06u", 1138 (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); 1139 setstr(vp, buf, KSH_RETURN_ERROR | 0x4); 1140 vp->flag |= SPECIAL; 1141 return; 1142 } 1143 case V_OPTIND: 1144 i = user_opt.uoptind; 1145 break; 1146 case V_RANDOM: 1147 i = rndget(); 1148 break; 1149 case V_SECONDS: 1150 /* 1151 * On start up the value of SECONDS is used before 1152 * it has been set - don't do anything in this case 1153 * (see initcoms[] in main.c). 1154 */ 1155 if (vp->flag & ISSET) { 1156 mksh_TIME(tv); 1157 i = tv.tv_sec - seconds; 1158 } else 1159 return; 1160 break; 1161 default: 1162 /* do nothing, do not touch vp at all */ 1163 return; 1164 } 1165 vp->flag &= ~SPECIAL; 1166 setint_n(vp, i, 0); 1167 vp->flag |= SPECIAL; 1168 } 1169 1170 static void 1171 setspec(struct tbl *vp) 1172 { 1173 mksh_ari_t i; 1174 char *s; 1175 int st; 1176 1177 switch ((st = special(vp->name))) { 1178 #if HAVE_PERSISTENT_HISTORY 1179 case V_HISTFILE: 1180 sethistfile(str_val(vp)); 1181 return; 1182 #endif 1183 case V_IFS: 1184 setctypes(s = str_val(vp), C_IFS); 1185 ifs0 = *s; 1186 return; 1187 case V_PATH: 1188 if (path) 1189 afree(path, APERM); 1190 s = str_val(vp); 1191 strdupx(path, s, APERM); 1192 /* clear tracked aliases */ 1193 flushcom(true); 1194 return; 1195 case V_TMPDIR: 1196 if (tmpdir) { 1197 afree(tmpdir, APERM); 1198 tmpdir = NULL; 1199 } 1200 /* 1201 * Use tmpdir iff it is an absolute path, is writable 1202 * and searchable and is a directory... 1203 */ 1204 { 1205 struct stat statb; 1206 1207 s = str_val(vp); 1208 /* LINTED use of access */ 1209 if (s[0] == '/' && access(s, W_OK|X_OK) == 0 && 1210 stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 1211 strdupx(tmpdir, s, APERM); 1212 } 1213 return; 1214 /* common sub-cases */ 1215 case V_COLUMNS: 1216 case V_LINES: 1217 if (vp->flag & IMPORT) { 1218 /* do not touch */ 1219 unspecial(vp->name); 1220 vp->flag &= ~SPECIAL; 1221 return; 1222 } 1223 /* FALLTHROUGH */ 1224 case V_HISTSIZE: 1225 case V_LINENO: 1226 case V_OPTIND: 1227 case V_RANDOM: 1228 case V_SECONDS: 1229 case V_TMOUT: 1230 vp->flag &= ~SPECIAL; 1231 if (getint(vp, &i, false) == -1) { 1232 s = str_val(vp); 1233 if (st != V_RANDOM) 1234 errorf("%s: %s: %s", vp->name, "bad number", s); 1235 i = hash(s); 1236 } 1237 vp->flag |= SPECIAL; 1238 break; 1239 default: 1240 /* do nothing, do not touch vp at all */ 1241 return; 1242 } 1243 1244 /* process the singular parts of the common cases */ 1245 1246 switch (st) { 1247 case V_COLUMNS: 1248 if (i >= MIN_COLS) 1249 x_cols = i; 1250 break; 1251 case V_HISTSIZE: 1252 sethistsize(i); 1253 break; 1254 case V_LINENO: 1255 /* The -1 is because line numbering starts at 1. */ 1256 user_lineno = (unsigned int)i - current_lineno - 1; 1257 break; 1258 case V_LINES: 1259 if (i >= MIN_LINS) 1260 x_lins = i; 1261 break; 1262 case V_OPTIND: 1263 getopts_reset((int)i); 1264 break; 1265 case V_RANDOM: 1266 /* 1267 * mksh R39d+ no longer has the traditional repeatability 1268 * of $RANDOM sequences, but always retains state 1269 */ 1270 rndset((long)i); 1271 break; 1272 case V_SECONDS: 1273 { 1274 struct timeval tv; 1275 1276 mksh_TIME(tv); 1277 seconds = tv.tv_sec - i; 1278 } 1279 break; 1280 case V_TMOUT: 1281 ksh_tmout = i >= 0 ? i : 0; 1282 break; 1283 } 1284 } 1285 1286 static void 1287 unsetspec(struct tbl *vp) 1288 { 1289 /* 1290 * AT&T ksh man page says OPTIND, OPTARG and _ lose special 1291 * meaning, but OPTARG does not (still set by getopts) and _ is 1292 * also still set in various places. Don't know what AT&T does 1293 * for HISTSIZE, HISTFILE. Unsetting these in AT&T ksh does not 1294 * loose the 'specialness': IFS, COLUMNS, PATH, TMPDIR 1295 */ 1296 1297 switch (special(vp->name)) { 1298 case V_IFS: 1299 setctypes(TC_IFSWS, C_IFS); 1300 ifs0 = ' '; 1301 break; 1302 case V_PATH: 1303 if (path) 1304 afree(path, APERM); 1305 strdupx(path, def_path, APERM); 1306 /* clear tracked aliases */ 1307 flushcom(true); 1308 break; 1309 case V_TMPDIR: 1310 /* should not become unspecial */ 1311 if (tmpdir) { 1312 afree(tmpdir, APERM); 1313 tmpdir = NULL; 1314 } 1315 break; 1316 case V_LINENO: 1317 case V_RANDOM: 1318 case V_SECONDS: 1319 case V_TMOUT: 1320 /* AT&T ksh leaves previous value in place */ 1321 unspecial(vp->name); 1322 break; 1323 } 1324 } 1325 1326 /* 1327 * Search for (and possibly create) a table entry starting with 1328 * vp, indexed by val. 1329 */ 1330 struct tbl * 1331 arraysearch(struct tbl *vp, uint32_t val) 1332 { 1333 struct tbl *prev, *curr, *news; 1334 size_t len; 1335 1336 vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC; 1337 /* the table entry is always [0] */ 1338 if (val == 0) 1339 return (vp); 1340 prev = vp; 1341 curr = vp->u.array; 1342 while (curr && curr->ua.index < val) { 1343 prev = curr; 1344 curr = curr->u.array; 1345 } 1346 if (curr && curr->ua.index == val) { 1347 if (curr->flag&ISSET) 1348 return (curr); 1349 news = curr; 1350 } else 1351 news = NULL; 1352 if (!news) { 1353 len = strlen(vp->name); 1354 checkoktoadd(len, 1 + offsetof(struct tbl, name[0])); 1355 news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap); 1356 memcpy(news->name, vp->name, len); 1357 } 1358 news->flag = (vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL)) | AINDEX; 1359 news->type = vp->type; 1360 news->areap = vp->areap; 1361 news->u2.field = vp->u2.field; 1362 news->ua.index = val; 1363 1364 if (curr != news) { 1365 /* not reusing old array entry */ 1366 prev->u.array = news; 1367 news->u.array = curr; 1368 } 1369 return (news); 1370 } 1371 1372 /* 1373 * Return the length of an array reference (eg, [1+2]) - cp is assumed 1374 * to point to the open bracket. Returns 0 if there is no matching 1375 * closing bracket. 1376 */ 1377 size_t 1378 array_ref_len(const char *cp) 1379 { 1380 const char *s = cp; 1381 char c; 1382 int depth = 0; 1383 1384 while ((c = *s++) && (c != ']' || --depth)) 1385 if (c == '[') 1386 depth++; 1387 if (!c) 1388 return (0); 1389 return (s - cp); 1390 } 1391 1392 /* 1393 * Make a copy of the base of an array name 1394 */ 1395 char * 1396 arrayname(const char *str) 1397 { 1398 const char *p; 1399 char *rv; 1400 1401 if ((p = cstrchr(str, '[')) == 0) 1402 /* Shouldn't happen, but why worry? */ 1403 strdupx(rv, str, ATEMP); 1404 else 1405 strndupx(rv, str, p - str, ATEMP); 1406 1407 return (rv); 1408 } 1409 1410 /* set (or overwrite, if reset) the array variable var to the values in vals */ 1411 mksh_uari_t 1412 set_array(const char *var, bool reset, const char **vals) 1413 { 1414 struct tbl *vp, *vq; 1415 mksh_uari_t i = 0, j = 0; 1416 const char *ccp = var; 1417 char *cp = NULL; 1418 size_t n; 1419 1420 /* to get local array, use "local foo; set -A foo" */ 1421 n = strlen(var); 1422 if (n > 0 && var[n - 1] == '+') { 1423 /* append mode */ 1424 reset = false; 1425 strndupx(cp, var, n - 1, ATEMP); 1426 ccp = cp; 1427 } 1428 vp = global(ccp); 1429 1430 /* Note: AT&T ksh allows set -A but not set +A of a read-only var */ 1431 if ((vp->flag&RDONLY)) 1432 errorfx(2, "read-only: %s", ccp); 1433 /* This code is quite non-optimal */ 1434 if (reset) { 1435 /* trash existing values and attributes */ 1436 unset(vp, 1); 1437 /* allocate-by-access the [0] element to keep in scope */ 1438 arraysearch(vp, 0); 1439 } 1440 /* 1441 * TODO: would be nice for assignment to completely succeed or 1442 * completely fail. Only really effects integer arrays: 1443 * evaluation of some of vals[] may fail... 1444 */ 1445 if (cp != NULL) { 1446 /* find out where to set when appending */ 1447 for (vq = vp; vq; vq = vq->u.array) { 1448 if (!(vq->flag & ISSET)) 1449 continue; 1450 if (arrayindex(vq) >= j) 1451 j = arrayindex(vq) + 1; 1452 } 1453 afree(cp, ATEMP); 1454 } 1455 while ((ccp = vals[i])) { 1456 if (*ccp == '[') { 1457 int level = 0; 1458 1459 while (*ccp) { 1460 if (*ccp == ']' && --level == 0) 1461 break; 1462 if (*ccp == '[') 1463 ++level; 1464 ++ccp; 1465 } 1466 if (*ccp == ']' && level == 0 && ccp[1] == '=') { 1467 strndupx(cp, vals[i] + 1, ccp - (vals[i] + 1), 1468 ATEMP); 1469 evaluate(substitute(cp, 0), (mksh_ari_t *)&j, 1470 KSH_UNWIND_ERROR, true); 1471 afree(cp, ATEMP); 1472 ccp += 2; 1473 } else 1474 ccp = vals[i]; 1475 } 1476 1477 vq = arraysearch(vp, j); 1478 /* would be nice to deal with errors here... (see above) */ 1479 setstr(vq, ccp, KSH_RETURN_ERROR); 1480 i++; 1481 j++; 1482 } 1483 1484 return (i); 1485 } 1486 1487 void 1488 change_winsz(void) 1489 { 1490 #ifdef TIOCGWINSZ 1491 /* check if window size has changed */ 1492 if (tty_init_fd() < 2) { 1493 struct winsize ws; 1494 1495 if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) { 1496 if (ws.ws_col) 1497 x_cols = ws.ws_col; 1498 if (ws.ws_row) 1499 x_lins = ws.ws_row; 1500 } 1501 } 1502 #endif 1503 1504 /* bounds check for sane values, use defaults otherwise */ 1505 if (x_cols < MIN_COLS) 1506 x_cols = 80; 1507 if (x_lins < MIN_LINS) 1508 x_lins = 24; 1509 1510 #ifdef SIGWINCH 1511 got_winch = 0; 1512 #endif 1513 } 1514 1515 uint32_t 1516 hash(const void *s) 1517 { 1518 register uint32_t h; 1519 1520 NZATInit(h); 1521 NZATUpdateString(h, s); 1522 NZAATFinish(h); 1523 return (h); 1524 } 1525 1526 mksh_ari_t 1527 rndget(void) 1528 { 1529 /* 1530 * this is the same Linear Congruential PRNG as Borland 1531 * C/C++ allegedly uses in its built-in rand() function 1532 */ 1533 return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF); 1534 } 1535 1536 void 1537 rndset(long v) 1538 { 1539 register uint32_t h; 1540 1541 NZATInit(h); 1542 NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); 1543 NZATUpdateMem(h, &v, sizeof(v)); 1544 1545 #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) 1546 /* 1547 * either we have very chap entropy get and push available, 1548 * with malloc() pulling in this code already anyway, or the 1549 * user requested us to use the old functions 1550 */ 1551 lcg_state = h; 1552 NZAATFinish(lcg_state); 1553 #if defined(arc4random_pushb_fast) 1554 arc4random_pushb_fast(&lcg_state, sizeof(lcg_state)); 1555 lcg_state = arc4random(); 1556 #else 1557 lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state)); 1558 #endif 1559 NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); 1560 #endif 1561 1562 NZAATFinish(h); 1563 lcg_state = h; 1564 } 1565