--- /dev/null
+/* $NetBSD: gethex.c,v 1.3.14.1 2008/04/08 21:10:55 jdc Exp $ */\r
+\r
+/****************************************************************\r
+\r
+The author of this software is David M. Gay.\r
+\r
+Copyright (C) 1998 by Lucent Technologies\r
+All Rights Reserved\r
+\r
+Permission to use, copy, modify, and distribute this software and\r
+its documentation for any purpose and without fee is hereby\r
+granted, provided that the above copyright notice appear in all\r
+copies and that both that the copyright notice and this\r
+permission notice and warranty disclaimer appear in supporting\r
+documentation, and that the name of Lucent or any of its entities\r
+not be used in advertising or publicity pertaining to\r
+distribution of the software without specific, written prior\r
+permission.\r
+\r
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,\r
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.\r
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY\r
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\r
+THIS SOFTWARE.\r
+\r
+****************************************************************/\r
+\r
+/* Please send bug reports to David M. Gay (dmg at acm dot org,\r
+ * with " at " changed at "@" and " dot " changed to "."). */\r
+#include <LibConfig.h>\r
+\r
+#include "gdtoaimp.h"\r
+\r
+#ifdef USE_LOCALE\r
+#include "locale.h"\r
+#endif\r
+\r
+ int\r
+gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign)\r
+{\r
+ Bigint *b;\r
+ CONST unsigned char *decpt, *s0, *s, *s1;\r
+ int esign, havedig, irv, k, n, nbits, up, zret;\r
+ ULong L, lostbits, *x;\r
+ Long e, e1;\r
+#ifdef USE_LOCALE\r
+ unsigned char decimalpoint = *localeconv()->decimal_point;\r
+#else\r
+#define decimalpoint '.'\r
+#endif\r
+\r
+ if (!hexdig['0'])\r
+ hexdig_init_D2A();\r
+ havedig = 0;\r
+ s0 = *(CONST unsigned char **)sp + 2;\r
+ while(s0[havedig] == '0')\r
+ havedig++;\r
+ s0 += havedig;\r
+ s = s0;\r
+ decpt = 0;\r
+ zret = 0;\r
+ e = 0;\r
+ if (!hexdig[*s]) {\r
+ zret = 1;\r
+ if (*s != decimalpoint)\r
+ goto pcheck;\r
+ decpt = ++s;\r
+ if (!hexdig[*s])\r
+ goto pcheck;\r
+ while(*s == '0')\r
+ s++;\r
+ if (hexdig[*s])\r
+ zret = 0;\r
+ havedig = 1;\r
+ s0 = s;\r
+ }\r
+ while(hexdig[*s])\r
+ s++;\r
+ if (*s == decimalpoint && !decpt) {\r
+ decpt = ++s;\r
+ while(hexdig[*s])\r
+ s++;\r
+ }\r
+ if (decpt)\r
+ e = -(((Long)(s-decpt)) << 2);\r
+ pcheck:\r
+ s1 = s;\r
+ switch(*s) {\r
+ case 'p':\r
+ case 'P':\r
+ esign = 0;\r
+ switch(*++s) {\r
+ case '-':\r
+ esign = 1;\r
+ /* FALLTHROUGH */\r
+ case '+':\r
+ s++;\r
+ }\r
+ if ((n = hexdig[*s]) == 0 || n > 0x19) {\r
+ s = s1;\r
+ break;\r
+ }\r
+ e1 = n - 0x10;\r
+ while((n = hexdig[*++s]) !=0 && n <= 0x19)\r
+ e1 = 10*e1 + n - 0x10;\r
+ if (esign)\r
+ e1 = -e1;\r
+ e += e1;\r
+ }\r
+ *sp = __UNCONST(s);\r
+ if (zret)\r
+ return havedig ? STRTOG_Zero : STRTOG_NoNumber;\r
+ n = (int)(s1 - s0 - 1);\r
+ for(k = 0; n > 7; n = (unsigned int)n >> 1)\r
+ k++;\r
+ b = Balloc(k);\r
+ if (b == NULL)\r
+ return STRTOG_NoMemory;\r
+ x = b->x;\r
+ n = 0;\r
+ L = 0;\r
+ while(s1 > s0) {\r
+ if (*--s1 == decimalpoint)\r
+ continue;\r
+ if (n == 32) {\r
+ *x++ = L;\r
+ L = 0;\r
+ n = 0;\r
+ }\r
+ L |= (hexdig[*s1] & 0x0f) << n;\r
+ n += 4;\r
+ }\r
+ *x++ = L;\r
+ b->wds = n = (int)(x - b->x);\r
+ n = 32*n - hi0bits(L);\r
+ nbits = fpi->nbits;\r
+ lostbits = 0;\r
+ x = b->x;\r
+ if (n > nbits) {\r
+ n -= nbits;\r
+ if (any_on(b,n)) {\r
+ lostbits = 1;\r
+ k = n - 1;\r
+ if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {\r
+ lostbits = 2;\r
+ if (k > 1 && any_on(b,k-1))\r
+ lostbits = 3;\r
+ }\r
+ }\r
+ rshift(b, n);\r
+ e += n;\r
+ }\r
+ else if (n < nbits) {\r
+ n = nbits - n;\r
+ b = lshift(b, n);\r
+ if (b == NULL)\r
+ return STRTOG_NoMemory;\r
+ e -= n;\r
+ x = b->x;\r
+ }\r
+ if (e > fpi->emax) {\r
+ ovfl:\r
+ Bfree(b);\r
+ *bp = 0;\r
+ return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;\r
+ }\r
+ irv = STRTOG_Normal;\r
+ if (e < fpi->emin) {\r
+ irv = STRTOG_Denormal;\r
+ n = fpi->emin - e;\r
+ if (n >= nbits) {\r
+ switch (fpi->rounding) {\r
+ case FPI_Round_near:\r
+ if (n == nbits && (n < 2 || any_on(b,n-1)))\r
+ goto one_bit;\r
+ break;\r
+ case FPI_Round_up:\r
+ if (!sign)\r
+ goto one_bit;\r
+ break;\r
+ case FPI_Round_down:\r
+ if (sign) {\r
+ one_bit:\r
+ *expt = fpi->emin;\r
+ x[0] = b->wds = 1;\r
+ *bp = b;\r
+ return STRTOG_Denormal | STRTOG_Inexhi\r
+ | STRTOG_Underflow;\r
+ }\r
+ }\r
+ Bfree(b);\r
+ *bp = 0;\r
+ return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;\r
+ }\r
+ k = n - 1;\r
+ if (lostbits)\r
+ lostbits = 1;\r
+ else if (k > 0)\r
+ lostbits = any_on(b,k);\r
+ if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))\r
+ lostbits |= 2;\r
+ nbits -= n;\r
+ rshift(b,n);\r
+ e = fpi->emin;\r
+ }\r
+ if (lostbits) {\r
+ up = 0;\r
+ switch(fpi->rounding) {\r
+ case FPI_Round_zero:\r
+ break;\r
+ case FPI_Round_near:\r
+ if (lostbits & 2\r
+ && (lostbits & 1) | (x[0] & 1))\r
+ up = 1;\r
+ break;\r
+ case FPI_Round_up:\r
+ up = 1 - sign;\r
+ break;\r
+ case FPI_Round_down:\r
+ up = sign;\r
+ }\r
+ if (up) {\r
+ k = b->wds;\r
+ b = increment(b);\r
+ x = b->x;\r
+ if (irv == STRTOG_Denormal) {\r
+ if (nbits == fpi->nbits - 1\r
+ && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))\r
+ irv = STRTOG_Normal;\r
+ }\r
+ else if (b->wds > k\r
+ || ((n = nbits & kmask) !=0\r
+ && hi0bits(x[k-1]) < 32-n)) {\r
+ rshift(b,1);\r
+ if (++e > fpi->emax)\r
+ goto ovfl;\r
+ }\r
+ irv |= STRTOG_Inexhi;\r
+ }\r
+ else\r
+ irv |= STRTOG_Inexlo;\r
+ }\r
+ *bp = b;\r
+ *expt = e;\r
+ return irv;\r
+ }\r