1 /* $NetBSD: misc.c,v 1.2 2006/01/25 15:27:42 kleink Exp $ */ 2 3 /**************************************************************** 4 5 The author of this software is David M. Gay. 6 7 Copyright (C) 1998, 1999 by Lucent Technologies 8 All Rights Reserved 9 10 Permission to use, copy, modify, and distribute this software and 11 its documentation for any purpose and without fee is hereby 12 granted, provided that the above copyright notice appear in all 13 copies and that both that the copyright notice and this 14 permission notice and warranty disclaimer appear in supporting 15 documentation, and that the name of Lucent or any of its entities 16 not be used in advertising or publicity pertaining to 17 distribution of the software without specific, written prior 18 permission. 19 20 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 21 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 22 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 23 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 25 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 26 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 27 THIS SOFTWARE. 28 29 ****************************************************************/ 30 31 /* Please send bug reports to David M. Gay (dmg at acm dot org, 32 * with " at " changed at "@" and " dot " changed to "."). */ 33 34 #include "gdtoaimp.h" 35 36 static Bigint *freelist[Kmax+1]; 37 #ifndef Omit_Private_Memory 38 #ifndef PRIVATE_MEM 39 #define PRIVATE_MEM 2304 40 #endif 41 #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) 42 static double private_mem[PRIVATE_mem], *pmem_next = private_mem; 43 #endif 44 45 Bigint * 46 Balloc 47 #ifdef KR_headers 48 (k) int k; 49 #else 50 (int k) 51 #endif 52 { 53 int x; 54 Bigint *rv; 55 #ifndef Omit_Private_Memory 56 unsigned int len; 57 #endif 58 59 ACQUIRE_DTOA_LOCK(0); 60 if ( (rv = freelist[k]) !=0) { 61 freelist[k] = rv->next; 62 } 63 else { 64 x = 1 << k; 65 #ifdef Omit_Private_Memory 66 rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); 67 #else 68 len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) 69 /sizeof(double); 70 if (pmem_next - private_mem + len <= PRIVATE_mem) { 71 rv = (Bigint*)(void *)pmem_next; 72 pmem_next += len; 73 } 74 else 75 rv = (Bigint*)MALLOC(len*sizeof(double)); 76 #endif 77 rv->k = k; 78 rv->maxwds = x; 79 } 80 FREE_DTOA_LOCK(0); 81 rv->sign = rv->wds = 0; 82 return rv; 83 } 84 85 void 86 Bfree 87 #ifdef KR_headers 88 (v) Bigint *v; 89 #else 90 (Bigint *v) 91 #endif 92 { 93 if (v) { 94 ACQUIRE_DTOA_LOCK(0); 95 v->next = freelist[v->k]; 96 freelist[v->k] = v; 97 FREE_DTOA_LOCK(0); 98 } 99 } 100 101 int 102 lo0bits 103 #ifdef KR_headers 104 (y) ULong *y; 105 #else 106 (ULong *y) 107 #endif 108 { 109 int k; 110 ULong x = *y; 111 112 if (x & 7) { 113 if (x & 1) 114 return 0; 115 if (x & 2) { 116 *y = x >> 1; 117 return 1; 118 } 119 *y = x >> 2; 120 return 2; 121 } 122 k = 0; 123 if (!(x & 0xffff)) { 124 k = 16; 125 x >>= 16; 126 } 127 if (!(x & 0xff)) { 128 k += 8; 129 x >>= 8; 130 } 131 if (!(x & 0xf)) { 132 k += 4; 133 x >>= 4; 134 } 135 if (!(x & 0x3)) { 136 k += 2; 137 x >>= 2; 138 } 139 if (!(x & 1)) { 140 k++; 141 x >>= 1; 142 if (!x) 143 return 32; 144 } 145 *y = x; 146 return k; 147 } 148 149 Bigint * 150 multadd 151 #ifdef KR_headers 152 (b, m, a) Bigint *b; int m, a; 153 #else 154 (Bigint *b, int m, int a) /* multiply by m and add a */ 155 #endif 156 { 157 int i, wds; 158 #ifdef ULLong 159 ULong *x; 160 ULLong carry, y; 161 #else 162 ULong carry, *x, y; 163 #ifdef Pack_32 164 ULong xi, z; 165 #endif 166 #endif 167 Bigint *b1; 168 169 wds = b->wds; 170 x = b->x; 171 i = 0; 172 carry = a; 173 do { 174 #ifdef ULLong 175 y = *x * (ULLong)m + carry; 176 carry = y >> 32; 177 /* LINTED conversion */ 178 *x++ = y & 0xffffffffUL; 179 #else 180 #ifdef Pack_32 181 xi = *x; 182 y = (xi & 0xffff) * m + carry; 183 z = (xi >> 16) * m + (y >> 16); 184 carry = z >> 16; 185 *x++ = (z << 16) + (y & 0xffff); 186 #else 187 y = *x * m + carry; 188 carry = y >> 16; 189 *x++ = y & 0xffff; 190 #endif 191 #endif 192 } 193 while(++i < wds); 194 if (carry) { 195 if (wds >= b->maxwds) { 196 b1 = Balloc(b->k+1); 197 Bcopy(b1, b); 198 Bfree(b); 199 b = b1; 200 } 201 /* LINTED conversion */ 202 b->x[wds++] = carry; 203 b->wds = wds; 204 } 205 return b; 206 } 207 208 int 209 hi0bits_D2A 210 #ifdef KR_headers 211 (x) ULong x; 212 #else 213 (ULong x) 214 #endif 215 { 216 int k = 0; 217 218 if (!(x & 0xffff0000)) { 219 k = 16; 220 x <<= 16; 221 } 222 if (!(x & 0xff000000)) { 223 k += 8; 224 x <<= 8; 225 } 226 if (!(x & 0xf0000000)) { 227 k += 4; 228 x <<= 4; 229 } 230 if (!(x & 0xc0000000)) { 231 k += 2; 232 x <<= 2; 233 } 234 if (!(x & 0x80000000)) { 235 k++; 236 if (!(x & 0x40000000)) 237 return 32; 238 } 239 return k; 240 } 241 242 Bigint * 243 i2b 244 #ifdef KR_headers 245 (i) int i; 246 #else 247 (int i) 248 #endif 249 { 250 Bigint *b; 251 252 b = Balloc(1); 253 b->x[0] = i; 254 b->wds = 1; 255 return b; 256 } 257 258 Bigint * 259 mult 260 #ifdef KR_headers 261 (a, b) Bigint *a, *b; 262 #else 263 (Bigint *a, Bigint *b) 264 #endif 265 { 266 Bigint *c; 267 int k, wa, wb, wc; 268 ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; 269 ULong y; 270 #ifdef ULLong 271 ULLong carry, z; 272 #else 273 ULong carry, z; 274 #ifdef Pack_32 275 ULong z2; 276 #endif 277 #endif 278 279 if (a->wds < b->wds) { 280 c = a; 281 a = b; 282 b = c; 283 } 284 k = a->k; 285 wa = a->wds; 286 wb = b->wds; 287 wc = wa + wb; 288 if (wc > a->maxwds) 289 k++; 290 c = Balloc(k); 291 for(x = c->x, xa = x + wc; x < xa; x++) 292 *x = 0; 293 xa = a->x; 294 xae = xa + wa; 295 xb = b->x; 296 xbe = xb + wb; 297 xc0 = c->x; 298 #ifdef ULLong 299 for(; xb < xbe; xc0++) { 300 if ( (y = *xb++) !=0) { 301 x = xa; 302 xc = xc0; 303 carry = 0; 304 do { 305 z = *x++ * (ULLong)y + *xc + carry; 306 carry = z >> 32; 307 /* LINTED conversion */ 308 *xc++ = z & 0xffffffffUL; 309 } 310 while(x < xae); 311 /* LINTED conversion */ 312 *xc = carry; 313 } 314 } 315 #else 316 #ifdef Pack_32 317 for(; xb < xbe; xb++, xc0++) { 318 if ( (y = *xb & 0xffff) !=0) { 319 x = xa; 320 xc = xc0; 321 carry = 0; 322 do { 323 z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; 324 carry = z >> 16; 325 z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; 326 carry = z2 >> 16; 327 Storeinc(xc, z2, z); 328 } 329 while(x < xae); 330 *xc = carry; 331 } 332 if ( (y = *xb >> 16) !=0) { 333 x = xa; 334 xc = xc0; 335 carry = 0; 336 z2 = *xc; 337 do { 338 z = (*x & 0xffff) * y + (*xc >> 16) + carry; 339 carry = z >> 16; 340 Storeinc(xc, z, z2); 341 z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; 342 carry = z2 >> 16; 343 } 344 while(x < xae); 345 *xc = z2; 346 } 347 } 348 #else 349 for(; xb < xbe; xc0++) { 350 if ( (y = *xb++) !=0) { 351 x = xa; 352 xc = xc0; 353 carry = 0; 354 do { 355 z = *x++ * y + *xc + carry; 356 carry = z >> 16; 357 *xc++ = z & 0xffff; 358 } 359 while(x < xae); 360 *xc = carry; 361 } 362 } 363 #endif 364 #endif 365 for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; 366 c->wds = wc; 367 return c; 368 } 369 370 static Bigint *p5s; 371 372 Bigint * 373 pow5mult 374 #ifdef KR_headers 375 (b, k) Bigint *b; int k; 376 #else 377 (Bigint *b, int k) 378 #endif 379 { 380 Bigint *b1, *p5, *p51; 381 int i; 382 CONST static int p05[3] = { 5, 25, 125 }; 383 384 if ( (i = k & 3) !=0) 385 b = multadd(b, p05[i-1], 0); 386 387 if (!(k = (unsigned int)k >> 2)) 388 return b; 389 if ((p5 = p5s) == 0) { 390 /* first time */ 391 #ifdef MULTIPLE_THREADS 392 ACQUIRE_DTOA_LOCK(1); 393 if (!(p5 = p5s)) { 394 p5 = p5s = i2b(625); 395 p5->next = 0; 396 } 397 FREE_DTOA_LOCK(1); 398 #else 399 p5 = p5s = i2b(625); 400 p5->next = 0; 401 #endif 402 } 403 for(;;) { 404 if (k & 1) { 405 b1 = mult(b, p5); 406 Bfree(b); 407 b = b1; 408 } 409 if (!(k = (unsigned int)k >> 1)) 410 break; 411 if ((p51 = p5->next) == 0) { 412 #ifdef MULTIPLE_THREADS 413 ACQUIRE_DTOA_LOCK(1); 414 if (!(p51 = p5->next)) { 415 p51 = p5->next = mult(p5,p5); 416 p51->next = 0; 417 } 418 FREE_DTOA_LOCK(1); 419 #else 420 p51 = p5->next = mult(p5,p5); 421 p51->next = 0; 422 #endif 423 } 424 p5 = p51; 425 } 426 return b; 427 } 428 429 Bigint * 430 lshift 431 #ifdef KR_headers 432 (b, k) Bigint *b; int k; 433 #else 434 (Bigint *b, int k) 435 #endif 436 { 437 int i, k1, n, n1; 438 Bigint *b1; 439 ULong *x, *x1, *xe, z; 440 441 n = (unsigned int)k >> kshift; 442 k1 = b->k; 443 n1 = n + b->wds + 1; 444 for(i = b->maxwds; n1 > i; i <<= 1) 445 k1++; 446 b1 = Balloc(k1); 447 x1 = b1->x; 448 for(i = 0; i < n; i++) 449 *x1++ = 0; 450 x = b->x; 451 xe = x + b->wds; 452 if (k &= kmask) { 453 #ifdef Pack_32 454 k1 = 32 - k; 455 z = 0; 456 do { 457 *x1++ = *x << k | z; 458 z = *x++ >> k1; 459 } 460 while(x < xe); 461 if ((*x1 = z) !=0) 462 ++n1; 463 #else 464 k1 = 16 - k; 465 z = 0; 466 do { 467 *x1++ = *x << k & 0xffff | z; 468 z = *x++ >> k1; 469 } 470 while(x < xe); 471 if (*x1 = z) 472 ++n1; 473 #endif 474 } 475 else do 476 *x1++ = *x++; 477 while(x < xe); 478 b1->wds = n1 - 1; 479 Bfree(b); 480 return b1; 481 } 482 483 int 484 cmp 485 #ifdef KR_headers 486 (a, b) Bigint *a, *b; 487 #else 488 (Bigint *a, Bigint *b) 489 #endif 490 { 491 ULong *xa, *xa0, *xb, *xb0; 492 int i, j; 493 494 i = a->wds; 495 j = b->wds; 496 #ifdef DEBUG 497 if (i > 1 && !a->x[i-1]) 498 Bug("cmp called with a->x[a->wds-1] == 0"); 499 if (j > 1 && !b->x[j-1]) 500 Bug("cmp called with b->x[b->wds-1] == 0"); 501 #endif 502 if (i -= j) 503 return i; 504 xa0 = a->x; 505 xa = xa0 + j; 506 xb0 = b->x; 507 xb = xb0 + j; 508 for(;;) { 509 if (*--xa != *--xb) 510 return *xa < *xb ? -1 : 1; 511 if (xa <= xa0) 512 break; 513 } 514 return 0; 515 } 516 517 Bigint * 518 diff 519 #ifdef KR_headers 520 (a, b) Bigint *a, *b; 521 #else 522 (Bigint *a, Bigint *b) 523 #endif 524 { 525 Bigint *c; 526 int i, wa, wb; 527 ULong *xa, *xae, *xb, *xbe, *xc; 528 #ifdef ULLong 529 ULLong borrow, y; 530 #else 531 ULong borrow, y; 532 #ifdef Pack_32 533 ULong z; 534 #endif 535 #endif 536 537 i = cmp(a,b); 538 if (!i) { 539 c = Balloc(0); 540 c->wds = 1; 541 c->x[0] = 0; 542 return c; 543 } 544 if (i < 0) { 545 c = a; 546 a = b; 547 b = c; 548 i = 1; 549 } 550 else 551 i = 0; 552 c = Balloc(a->k); 553 c->sign = i; 554 wa = a->wds; 555 xa = a->x; 556 xae = xa + wa; 557 wb = b->wds; 558 xb = b->x; 559 xbe = xb + wb; 560 xc = c->x; 561 borrow = 0; 562 #ifdef ULLong 563 do { 564 y = (ULLong)*xa++ - *xb++ - borrow; 565 borrow = y >> 32 & 1UL; 566 /* LINTED conversion */ 567 *xc++ = y & 0xffffffffUL; 568 } 569 while(xb < xbe); 570 while(xa < xae) { 571 y = *xa++ - borrow; 572 borrow = y >> 32 & 1UL; 573 /* LINTED conversion */ 574 *xc++ = y & 0xffffffffUL; 575 } 576 #else 577 #ifdef Pack_32 578 do { 579 y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; 580 borrow = (y & 0x10000) >> 16; 581 z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; 582 borrow = (z & 0x10000) >> 16; 583 Storeinc(xc, z, y); 584 } 585 while(xb < xbe); 586 while(xa < xae) { 587 y = (*xa & 0xffff) - borrow; 588 borrow = (y & 0x10000) >> 16; 589 z = (*xa++ >> 16) - borrow; 590 borrow = (z & 0x10000) >> 16; 591 Storeinc(xc, z, y); 592 } 593 #else 594 do { 595 y = *xa++ - *xb++ - borrow; 596 borrow = (y & 0x10000) >> 16; 597 *xc++ = y & 0xffff; 598 } 599 while(xb < xbe); 600 while(xa < xae) { 601 y = *xa++ - borrow; 602 borrow = (y & 0x10000) >> 16; 603 *xc++ = y & 0xffff; 604 } 605 #endif 606 #endif 607 while(!*--xc) 608 wa--; 609 c->wds = wa; 610 return c; 611 } 612 613 double 614 b2d 615 #ifdef KR_headers 616 (a, e) Bigint *a; int *e; 617 #else 618 (Bigint *a, int *e) 619 #endif 620 { 621 ULong *xa, *xa0, w, y, z; 622 int k; 623 double d; 624 #ifdef VAX 625 ULong d0, d1; 626 #else 627 #define d0 word0(d) 628 #define d1 word1(d) 629 #endif 630 631 xa0 = a->x; 632 xa = xa0 + a->wds; 633 y = *--xa; 634 #ifdef DEBUG 635 if (!y) Bug("zero y in b2d"); 636 #endif 637 k = hi0bits(y); 638 *e = 32 - k; 639 #ifdef Pack_32 640 if (k < Ebits) { 641 d0 = Exp_1 | y >> (Ebits - k); 642 w = xa > xa0 ? *--xa : 0; 643 d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); 644 goto ret_d; 645 } 646 z = xa > xa0 ? *--xa : 0; 647 if (k -= Ebits) { 648 d0 = Exp_1 | y << k | z >> (32 - k); 649 y = xa > xa0 ? *--xa : 0; 650 d1 = z << k | y >> (32 - k); 651 } 652 else { 653 d0 = Exp_1 | y; 654 d1 = z; 655 } 656 #else 657 if (k < Ebits + 16) { 658 z = xa > xa0 ? *--xa : 0; 659 d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; 660 w = xa > xa0 ? *--xa : 0; 661 y = xa > xa0 ? *--xa : 0; 662 d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; 663 goto ret_d; 664 } 665 z = xa > xa0 ? *--xa : 0; 666 w = xa > xa0 ? *--xa : 0; 667 k -= Ebits + 16; 668 d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; 669 y = xa > xa0 ? *--xa : 0; 670 d1 = w << k + 16 | y << k; 671 #endif 672 ret_d: 673 #ifdef VAX 674 word0(d) = d0 >> 16 | d0 << 16; 675 word1(d) = d1 >> 16 | d1 << 16; 676 #endif 677 return dval(d); 678 } 679 #undef d0 680 #undef d1 681 682 Bigint * 683 d2b 684 #ifdef KR_headers 685 (d, e, bits) double d; int *e, *bits; 686 #else 687 (double d, int *e, int *bits) 688 #endif 689 { 690 Bigint *b; 691 #ifndef Sudden_Underflow 692 int i; 693 #endif 694 int de, k; 695 ULong *x, y, z; 696 #ifdef VAX 697 ULong d0, d1; 698 d0 = word0(d) >> 16 | word0(d) << 16; 699 d1 = word1(d) >> 16 | word1(d) << 16; 700 #else 701 #define d0 word0(d) 702 #define d1 word1(d) 703 #endif 704 705 #ifdef Pack_32 706 b = Balloc(1); 707 #else 708 b = Balloc(2); 709 #endif 710 x = b->x; 711 712 z = d0 & Frac_mask; 713 d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ 714 #ifdef Sudden_Underflow 715 de = (int)(d0 >> Exp_shift); 716 #ifndef IBM 717 z |= Exp_msk11; 718 #endif 719 #else 720 if ( (de = (int)(d0 >> Exp_shift)) !=0) 721 z |= Exp_msk1; 722 #endif 723 #ifdef Pack_32 724 if ( (y = d1) !=0) { 725 if ( (k = lo0bits(&y)) !=0) { 726 x[0] = y | z << (32 - k); 727 z >>= k; 728 } 729 else 730 x[0] = y; 731 #ifndef Sudden_Underflow 732 i = 733 #endif 734 b->wds = (x[1] = z) !=0 ? 2 : 1; 735 } 736 else { 737 #ifdef DEBUG 738 if (!z) 739 Bug("Zero passed to d2b"); 740 #endif 741 k = lo0bits(&z); 742 x[0] = z; 743 #ifndef Sudden_Underflow 744 i = 745 #endif 746 b->wds = 1; 747 k += 32; 748 } 749 #else 750 if ( (y = d1) !=0) { 751 if ( (k = lo0bits(&y)) !=0) 752 if (k >= 16) { 753 x[0] = y | z << 32 - k & 0xffff; 754 x[1] = z >> k - 16 & 0xffff; 755 x[2] = z >> k; 756 i = 2; 757 } 758 else { 759 x[0] = y & 0xffff; 760 x[1] = y >> 16 | z << 16 - k & 0xffff; 761 x[2] = z >> k & 0xffff; 762 x[3] = z >> k+16; 763 i = 3; 764 } 765 else { 766 x[0] = y & 0xffff; 767 x[1] = y >> 16; 768 x[2] = z & 0xffff; 769 x[3] = z >> 16; 770 i = 3; 771 } 772 } 773 else { 774 #ifdef DEBUG 775 if (!z) 776 Bug("Zero passed to d2b"); 777 #endif 778 k = lo0bits(&z); 779 if (k >= 16) { 780 x[0] = z; 781 i = 0; 782 } 783 else { 784 x[0] = z & 0xffff; 785 x[1] = z >> 16; 786 i = 1; 787 } 788 k += 32; 789 } 790 while(!x[i]) 791 --i; 792 b->wds = i + 1; 793 #endif 794 #ifndef Sudden_Underflow 795 if (de) { 796 #endif 797 #ifdef IBM 798 *e = (de - Bias - (P-1) << 2) + k; 799 *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); 800 #else 801 *e = de - Bias - (P-1) + k; 802 *bits = P - k; 803 #endif 804 #ifndef Sudden_Underflow 805 } 806 else { 807 *e = de - Bias - (P-1) + 1 + k; 808 #ifdef Pack_32 809 *bits = 32*i - hi0bits(x[i-1]); 810 #else 811 *bits = (i+2)*16 - hi0bits(x[i]); 812 #endif 813 } 814 #endif 815 return b; 816 } 817 #undef d0 818 #undef d1 819 820 CONST double 821 #ifdef IEEE_Arith 822 bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; 823 CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 824 }; 825 #else 826 #ifdef IBM 827 bigtens[] = { 1e16, 1e32, 1e64 }; 828 CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; 829 #else 830 bigtens[] = { 1e16, 1e32 }; 831 CONST double tinytens[] = { 1e-16, 1e-32 }; 832 #endif 833 #endif 834 835 CONST double 836 tens[] = { 837 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 838 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 839 1e20, 1e21, 1e22 840 #ifdef VAX 841 , 1e23, 1e24 842 #endif 843 }; 844 845 char * 846 #ifdef KR_headers 847 strcp_D2A(a, b) char *a; char *b; 848 #else 849 strcp_D2A(char *a, CONST char *b) 850 #endif 851 { 852 while((*a = *b++)) 853 a++; 854 return a; 855 } 856 857 #ifdef NO_STRING_H 858 859 Char * 860 #ifdef KR_headers 861 memcpy_D2A(a, b, len) Char *a; Char *b; size_t len; 862 #else 863 memcpy_D2A(void *a1, void *b1, size_t len) 864 #endif 865 { 866 char *a = (char*)a1, *ae = a + len; 867 char *b = (char*)b1, *a0 = a; 868 while(a < ae) 869 *a++ = *b++; 870 return a0; 871 } 872 873 #endif /* NO_STRING_H */ 874