/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ │vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ ╚──────────────────────────────────────────────────────────────────────────────╝ │ │ │ The author of this software is David M. Gay. │ │ Please send bug reports to David M. Gay │ │ or Justine Tunney │ │ │ │ Copyright (C) 1998, 1999 by Lucent Technologies │ │ All Rights Reserved │ │ │ │ Permission to use, copy, modify, and distribute this software and │ │ its documentation for any purpose and without fee is hereby │ │ granted, provided that the above copyright notice appear in all │ │ copies and that both that the copyright notice and this │ │ permission notice and warranty disclaimer appear in supporting │ │ documentation, and that the name of Lucent or any of its entities │ │ not be used in advertising or publicity pertaining to │ │ distribution of the software without specific, written prior │ │ permission. │ │ │ │ LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, │ │ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. │ │ IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY │ │ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES │ │ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER │ │ IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, │ │ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF │ │ THIS SOFTWARE. │ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" #include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ int __gdtoa_gethex(const char **sp, const FPI *fpi, Long *exp, Bigint **bp, int sign) { Bigint *b; const unsigned char *decpt, *s0, *s, *s1; int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; ULong L, lostbits, *x; Long e, e1; /**** if (!__gdtoa_hexdig['0']) __gdtoa_hexdig_init(); ****/ *bp = 0; havedig = 0; s0 = *(const unsigned char **)sp + 2; while(s0[havedig] == '0') havedig++; s0 += havedig; s = s0; decpt = 0; zret = 0; e = 0; if (__gdtoa_hexdig[*s]) havedig++; else { zret = 1; if (*s != '.') goto pcheck; decpt = ++s; if (!__gdtoa_hexdig[*s]) goto pcheck; while(*s == '0') s++; if (__gdtoa_hexdig[*s]) zret = 0; havedig = 1; s0 = s; } while(__gdtoa_hexdig[*s]) s++; if (*s == '.' && !decpt) { decpt = ++s; while(__gdtoa_hexdig[*s]) s++; }/*}*/ if (decpt) e = -(((Long)(s-decpt)) << 2); pcheck: s1 = s; big = esign = 0; switch(*s) { case 'p': case 'P': switch(*++s) { case '-': esign = 1; /* no break */ case '+': s++; } if ((n = __gdtoa_hexdig[*s]) == 0 || n > 0x19) { s = s1; break; } e1 = n - 0x10; while((n = __gdtoa_hexdig[*++s]) !=0 && n <= 0x19) { if (e1 & 0xf8000000) big = 1; e1 = 10*e1 + n - 0x10; } if (esign) e1 = -e1; e += e1; } *sp = (char*)s; if (!havedig) *sp = (char*)s0 - 1; if (zret) return STRTOG_Zero; if (big) { if (esign) { switch(fpi->rounding) { case FPI_Round_up: if (sign) break; goto ret_tiny; case FPI_Round_down: if (!sign) break; goto ret_tiny; } goto retz; ret_tiny: b = __gdtoa_Balloc(0); b->wds = 1; b->x[0] = 1; goto dret; } switch(fpi->rounding) { case FPI_Round_near: goto ovfl1; case FPI_Round_up: if (!sign) goto ovfl1; goto ret_big; case FPI_Round_down: if (sign) goto ovfl1; } ret_big: nbits = fpi->nbits; n0 = n = nbits >> kshift; if (nbits & kmask) ++n; for(j = n, k = 0; j >>= 1; ++k); *bp = b = __gdtoa_Balloc(k); b->wds = n; for(j = 0; j < n0; ++j) b->x[j] = ALL_ON; if (n > n0) b->x[j] = ALL_ON >> (ULbits - (nbits & kmask)); *exp = fpi->emax; return STRTOG_Normal | STRTOG_Inexlo; } n = s1 - s0 - 1; for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) k++; b = __gdtoa_Balloc(k); x = b->x; n = 0; L = 0; while(s1 > s0) { if (*--s1 == '.') continue; if (n == ULbits) { *x++ = L; L = 0; n = 0; } L |= (__gdtoa_hexdig[*s1] & 0x0f) << n; n += 4; } *x++ = L; b->wds = n = x - b->x; n = ULbits*n - hi0bits(L); nbits = fpi->nbits; lostbits = 0; x = b->x; if (n > nbits) { n -= nbits; if (__gdtoa_any_on(b,n)) { lostbits = 1; k = n - 1; if (x[k>>kshift] & 1 << (k & kmask)) { lostbits = 2; if (k > 0 && __gdtoa_any_on(b,k)) lostbits = 3; } } __gdtoa_rshift(b, n); e += n; } else if (n < nbits) { n = nbits - n; b = __gdtoa_lshift(b, n); e -= n; x = b->x; } if (e > fpi->emax) { ovfl: __gdtoa_Bfree(b); ovfl1: errno = ERANGE; switch (fpi->rounding) { case FPI_Round_zero: goto ret_big; case FPI_Round_down: if (!sign) goto ret_big; break; case FPI_Round_up: if (sign) goto ret_big; } return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; } irv = STRTOG_Normal; if (e < fpi->emin) { irv = STRTOG_Denormal; n = fpi->emin - e; if (n >= nbits) { switch (fpi->rounding) { case FPI_Round_near: if (n == nbits && (n < 2 || lostbits || __gdtoa_any_on(b,n-1))) goto one_bit; break; case FPI_Round_up: if (!sign) goto one_bit; break; case FPI_Round_down: if (sign) { one_bit: x[0] = b->wds = 1; dret: *bp = b; *exp = fpi->emin; errno = ERANGE; return STRTOG_Denormal | STRTOG_Inexhi | STRTOG_Underflow; } } __gdtoa_Bfree(b); retz: errno = ERANGE; return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; } k = n - 1; if (lostbits) lostbits = 1; else if (k > 0) lostbits = __gdtoa_any_on(b,k); if (x[k>>kshift] & 1 << (k & kmask)) lostbits |= 2; nbits -= n; __gdtoa_rshift(b,n); e = fpi->emin; } if (lostbits) { up = 0; switch(fpi->rounding) { case FPI_Round_zero: break; case FPI_Round_near: if (lostbits & 2 && (lostbits | x[0]) & 1) up = 1; break; case FPI_Round_up: up = 1 - sign; break; case FPI_Round_down: up = sign; } if (up) { k = b->wds; b = __gdtoa_increment(b); x = b->x; if (irv == STRTOG_Denormal) { if (nbits == fpi->nbits - 1 && x[nbits >> kshift] & 1 << (nbits & kmask)) irv = STRTOG_Normal; } else if (b->wds > k || ((n = nbits & kmask) !=0 && hi0bits(x[k-1]) < 32-n)) { __gdtoa_rshift(b,1); if (++e > fpi->emax) goto ovfl; } irv |= STRTOG_Inexhi; } else irv |= STRTOG_Inexlo; } *bp = b; *exp = e; return irv; }