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