OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / winsup / mingw / mingwex / gdtoa / gethex.c
diff --git a/winsup/mingw/mingwex/gdtoa/gethex.c b/winsup/mingw/mingwex/gdtoa/gethex.c
new file mode 100755 (executable)
index 0000000..b123e91
--- /dev/null
@@ -0,0 +1,340 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").     */
+
+#include "gdtoaimp.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+int gethex (const char **sp, 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;
+#ifdef USE_LOCALE
+       int i;
+       const unsigned char *decimalpoint;
+#ifdef NO_LOCALE_CACHE
+       decimalpoint = (unsigned char *)localeconv()->decimal_point;
+#else
+       static unsigned char *decimalpoint_cache;
+       if (!(s0 = decimalpoint_cache)) {
+               s0 = (unsigned char *)localeconv()->decimal_point;
+               decimalpoint_cache = (unsigned char *)
+                                       MALLOC(strlen((char *)s0) + 1);
+               if (decimalpoint_cache) {
+                       strcpy((char *)decimalpoint_cache, (char *)s0);
+                       s0 = decimalpoint_cache;
+               }
+       }
+       decimalpoint = s0;
+#endif
+#endif
+
+       if (!hexdig['0'])
+               hexdig_init_D2A();
+       *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 (hexdig[*s])
+               havedig++;
+       else {
+               zret = 1;
+#ifdef USE_LOCALE
+               for(i = 0; decimalpoint[i]; ++i) {
+                       if (s[i] != decimalpoint[i])
+                               goto pcheck;
+               }
+               decpt = s += i;
+#else
+               if (*s != '.')
+                       goto pcheck;
+               decpt = ++s;
+#endif
+               if (!hexdig[*s])
+                       goto pcheck;
+               while(*s == '0')
+                       s++;
+               if (hexdig[*s])
+                       zret = 0;
+               havedig = 1;
+               s0 = s;
+       }
+       while(hexdig[*s])
+               s++;
+#ifdef USE_LOCALE
+       if (*s == *decimalpoint && !decpt) {
+               for(i = 1; decimalpoint[i]; ++i) {
+                       if (s[i] != decimalpoint[i])
+                               goto pcheck;
+               }
+               decpt = s += i;
+#else
+       if (*s == '.' && !decpt) {
+               decpt = ++s;
+#endif
+               while(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 = hexdig[*s]) == 0 || n > 0x19) {
+                       s = s1;
+                       break;
+               }
+               e1 = n - 0x10;
+               while((n = 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 = 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;
+                       goto ret_big;
+               }
+ ret_big:
+               nbits = fpi->nbits;
+               n0 = n = nbits >> kshift;
+               if (nbits & kmask)
+                       ++n;
+               for(j = n, k = 0; j >>= 1; ++k);
+               *bp = b = Balloc(k);
+               b->wds = n;
+               for(j = 0; j < n0; ++j)
+                       b->x[j] = ALL_ON;
+               if (n > n0)
+                       b->x[j] = ULbits >> (ULbits - (nbits & kmask));
+               *exp = fpi->emin;
+               return STRTOG_Normal | STRTOG_Inexlo;
+       }
+       n = s1 - s0 - 1;
+       for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
+               k++;
+       b = Balloc(k);
+       x = b->x;
+       n = 0;
+       L = 0;
+#ifdef USE_LOCALE
+       for(i = 0; decimalpoint[i+1]; ++i);
+#endif
+       while(s1 > s0) {
+#ifdef USE_LOCALE
+               if (*--s1 == decimalpoint[i]) {
+                       s1 -= i;
+                       continue;
+               }
+#else
+               if (*--s1 == '.')
+                       continue;
+#endif
+               if (n == ULbits) {
+                       *x++ = L;
+                       L = 0;
+                       n = 0;
+               }
+               L |= (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 (any_on(b,n)) {
+                       lostbits = 1;
+                       k = n - 1;
+                       if (x[k>>kshift] & 1 << (k & kmask)) {
+                               lostbits = 2;
+                               if (k > 0 && any_on(b,k))
+                                       lostbits = 3;
+                       }
+               }
+               rshift(b, n);
+               e += n;
+       }
+       else if (n < nbits) {
+               n = nbits - n;
+               b = lshift(b, n);
+               e -= n;
+               x = b->x;
+       }
+       if (e > fpi->emax) {
+ ovfl:
+               Bfree(b);
+ ovfl1:
+               SET_ERRNO(ERANGE);
+               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 || 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;
+                                       SET_ERRNO(ERANGE);
+                                       return STRTOG_Denormal | STRTOG_Inexhi
+                                               | STRTOG_Underflow;
+                               }
+                       }
+                       Bfree(b);
+ retz:
+                       SET_ERRNO(ERANGE);
+                       return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
+               }
+               k = n - 1;
+               if (lostbits)
+                       lostbits = 1;
+               else if (k > 0)
+                       lostbits = any_on(b,k);
+               if (x[k>>kshift] & 1 << (k & kmask))
+                       lostbits |= 2;
+               nbits -= n;
+               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 = 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)) {
+                               rshift(b,1);
+                               if (++e > fpi->emax)
+                                       goto ovfl;
+                       }
+                       irv |= STRTOG_Inexhi;
+               }
+               else
+                       irv |= STRTOG_Inexlo;
+       }
+       *bp = b;
+       *exp = e;
+       return irv;
+}