1*84d9c625SLionel Sambuc /* $NetBSD: gethex.c,v 1.6 2013/04/19 10:41:53 joerg Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /****************************************************************
42fe8fb19SBen Gras
52fe8fb19SBen Gras The author of this software is David M. Gay.
62fe8fb19SBen Gras
72fe8fb19SBen Gras Copyright (C) 1998 by Lucent Technologies
82fe8fb19SBen Gras All Rights Reserved
92fe8fb19SBen Gras
102fe8fb19SBen Gras Permission to use, copy, modify, and distribute this software and
112fe8fb19SBen Gras its documentation for any purpose and without fee is hereby
122fe8fb19SBen Gras granted, provided that the above copyright notice appear in all
132fe8fb19SBen Gras copies and that both that the copyright notice and this
142fe8fb19SBen Gras permission notice and warranty disclaimer appear in supporting
152fe8fb19SBen Gras documentation, and that the name of Lucent or any of its entities
162fe8fb19SBen Gras not be used in advertising or publicity pertaining to
172fe8fb19SBen Gras distribution of the software without specific, written prior
182fe8fb19SBen Gras permission.
192fe8fb19SBen Gras
202fe8fb19SBen Gras LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
212fe8fb19SBen Gras INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
222fe8fb19SBen Gras IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
232fe8fb19SBen Gras SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
242fe8fb19SBen Gras WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
252fe8fb19SBen Gras IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
262fe8fb19SBen Gras ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
272fe8fb19SBen Gras THIS SOFTWARE.
282fe8fb19SBen Gras
292fe8fb19SBen Gras ****************************************************************/
302fe8fb19SBen Gras
312fe8fb19SBen Gras /* Please send bug reports to David M. Gay (dmg at acm dot org,
322fe8fb19SBen Gras * with " at " changed at "@" and " dot " changed to "."). */
332fe8fb19SBen Gras
342fe8fb19SBen Gras #include "gdtoaimp.h"
352fe8fb19SBen Gras
362fe8fb19SBen Gras #ifdef USE_LOCALE
372fe8fb19SBen Gras #include "locale.h"
382fe8fb19SBen Gras #endif
392fe8fb19SBen Gras
402fe8fb19SBen Gras int
gethex(CONST char ** sp,CONST FPI * fpi,Long * expt,Bigint ** bp,int sign,locale_t loc)41*84d9c625SLionel Sambuc gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign, locale_t loc)
422fe8fb19SBen Gras {
432fe8fb19SBen Gras Bigint *b;
44f14fb602SLionel Sambuc CONST char *decpt, *s, *s0, *s1;
45f14fb602SLionel Sambuc int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
462fe8fb19SBen Gras ULong L, lostbits, *x;
472fe8fb19SBen Gras Long e, e1;
482fe8fb19SBen Gras #ifdef USE_LOCALE
49f14fb602SLionel Sambuc int i;
50*84d9c625SLionel Sambuc const char *decimalpoint = localeconv_l(loc)->decimal_point;
512fe8fb19SBen Gras #endif
522fe8fb19SBen Gras
53f14fb602SLionel Sambuc if (!hexdig[(unsigned char)'0'])
542fe8fb19SBen Gras hexdig_init_D2A();
55f14fb602SLionel Sambuc *bp = 0;
562fe8fb19SBen Gras havedig = 0;
57f14fb602SLionel Sambuc s0 = *(CONST char **)sp + 2;
582fe8fb19SBen Gras while(s0[havedig] == '0')
592fe8fb19SBen Gras havedig++;
602fe8fb19SBen Gras s0 += havedig;
612fe8fb19SBen Gras s = s0;
622fe8fb19SBen Gras decpt = 0;
632fe8fb19SBen Gras zret = 0;
642fe8fb19SBen Gras e = 0;
65f14fb602SLionel Sambuc if (hexdig[(unsigned char)*s])
66f14fb602SLionel Sambuc havedig++;
67f14fb602SLionel Sambuc else {
682fe8fb19SBen Gras zret = 1;
69f14fb602SLionel Sambuc #ifdef USE_LOCALE
70f14fb602SLionel Sambuc for(i = 0; decimalpoint[i]; ++i) {
71f14fb602SLionel Sambuc if (s[i] != decimalpoint[i])
72f14fb602SLionel Sambuc goto pcheck;
73f14fb602SLionel Sambuc }
74f14fb602SLionel Sambuc decpt = s += i;
75f14fb602SLionel Sambuc #else
76f14fb602SLionel Sambuc if (*s != '.')
772fe8fb19SBen Gras goto pcheck;
782fe8fb19SBen Gras decpt = ++s;
79f14fb602SLionel Sambuc #endif
80f14fb602SLionel Sambuc if (!hexdig[(unsigned char)*s])
812fe8fb19SBen Gras goto pcheck;
822fe8fb19SBen Gras while(*s == '0')
832fe8fb19SBen Gras s++;
84f14fb602SLionel Sambuc if (hexdig[(unsigned char)*s])
852fe8fb19SBen Gras zret = 0;
862fe8fb19SBen Gras havedig = 1;
872fe8fb19SBen Gras s0 = s;
882fe8fb19SBen Gras }
89f14fb602SLionel Sambuc while(hexdig[(unsigned char)*s])
902fe8fb19SBen Gras s++;
91f14fb602SLionel Sambuc #ifdef USE_LOCALE
92f14fb602SLionel Sambuc if (*s == *decimalpoint && !decpt) {
93f14fb602SLionel Sambuc for(i = 1; decimalpoint[i]; ++i) {
94f14fb602SLionel Sambuc if (s[i] != decimalpoint[i])
95f14fb602SLionel Sambuc goto pcheck;
962fe8fb19SBen Gras }
97f14fb602SLionel Sambuc decpt = s += i;
98f14fb602SLionel Sambuc #else
99f14fb602SLionel Sambuc if (*s == '.' && !decpt) {
100f14fb602SLionel Sambuc decpt = ++s;
101f14fb602SLionel Sambuc #endif
102f14fb602SLionel Sambuc while(hexdig[(unsigned char)*s])
103f14fb602SLionel Sambuc s++;
104f14fb602SLionel Sambuc }/*}*/
1052fe8fb19SBen Gras if (decpt)
1062fe8fb19SBen Gras e = -(((Long)(s-decpt)) << 2);
1072fe8fb19SBen Gras pcheck:
1082fe8fb19SBen Gras s1 = s;
109f14fb602SLionel Sambuc big = esign = 0;
1102fe8fb19SBen Gras switch(*s) {
1112fe8fb19SBen Gras case 'p':
1122fe8fb19SBen Gras case 'P':
1132fe8fb19SBen Gras switch(*++s) {
1142fe8fb19SBen Gras case '-':
1152fe8fb19SBen Gras esign = 1;
1162fe8fb19SBen Gras /* FALLTHROUGH */
1172fe8fb19SBen Gras case '+':
1182fe8fb19SBen Gras s++;
1192fe8fb19SBen Gras }
120f14fb602SLionel Sambuc if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) {
1212fe8fb19SBen Gras s = s1;
1222fe8fb19SBen Gras break;
1232fe8fb19SBen Gras }
1242fe8fb19SBen Gras e1 = n - 0x10;
125f14fb602SLionel Sambuc while((n = hexdig[(unsigned char)*++s]) !=0 && n <= 0x19) {
126f14fb602SLionel Sambuc if (e1 & 0xf8000000)
127f14fb602SLionel Sambuc big = 1;
1282fe8fb19SBen Gras e1 = 10*e1 + n - 0x10;
129f14fb602SLionel Sambuc }
1302fe8fb19SBen Gras if (esign)
1312fe8fb19SBen Gras e1 = -e1;
1322fe8fb19SBen Gras e += e1;
1332fe8fb19SBen Gras }
1342fe8fb19SBen Gras *sp = __UNCONST(s);
135f14fb602SLionel Sambuc if (!havedig)
136f14fb602SLionel Sambuc *sp = (char*)__UNCONST(s0) - 1;
1372fe8fb19SBen Gras if (zret)
138f14fb602SLionel Sambuc return STRTOG_Zero;
139f14fb602SLionel Sambuc if (big) {
140f14fb602SLionel Sambuc if (esign) {
141f14fb602SLionel Sambuc switch(fpi->rounding) {
142f14fb602SLionel Sambuc case FPI_Round_up:
143f14fb602SLionel Sambuc if (sign)
144f14fb602SLionel Sambuc break;
145f14fb602SLionel Sambuc goto ret_tiny;
146f14fb602SLionel Sambuc case FPI_Round_down:
147f14fb602SLionel Sambuc if (!sign)
148f14fb602SLionel Sambuc break;
149f14fb602SLionel Sambuc goto ret_tiny;
150f14fb602SLionel Sambuc }
151f14fb602SLionel Sambuc goto retz;
152f14fb602SLionel Sambuc ret_tiny:
153f14fb602SLionel Sambuc b = Balloc(0);
154f14fb602SLionel Sambuc b->wds = 1;
155f14fb602SLionel Sambuc b->x[0] = 1;
156f14fb602SLionel Sambuc goto dret;
157f14fb602SLionel Sambuc }
158f14fb602SLionel Sambuc switch(fpi->rounding) {
159f14fb602SLionel Sambuc case FPI_Round_near:
160f14fb602SLionel Sambuc goto ovfl1;
161f14fb602SLionel Sambuc case FPI_Round_up:
162f14fb602SLionel Sambuc if (!sign)
163f14fb602SLionel Sambuc goto ovfl1;
164f14fb602SLionel Sambuc goto ret_big;
165f14fb602SLionel Sambuc case FPI_Round_down:
166f14fb602SLionel Sambuc if (sign)
167f14fb602SLionel Sambuc goto ovfl1;
168f14fb602SLionel Sambuc goto ret_big;
169f14fb602SLionel Sambuc }
170f14fb602SLionel Sambuc ret_big:
171f14fb602SLionel Sambuc nbits = fpi->nbits;
172f14fb602SLionel Sambuc n0 = n = (unsigned int)nbits >> kshift;
173f14fb602SLionel Sambuc if (nbits & kmask)
174f14fb602SLionel Sambuc ++n;
175f14fb602SLionel Sambuc for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k);
176f14fb602SLionel Sambuc *bp = b = Balloc(k);
177f14fb602SLionel Sambuc b->wds = n;
178f14fb602SLionel Sambuc for(j = 0; j < n0; ++j)
179f14fb602SLionel Sambuc b->x[j] = ALL_ON;
180f14fb602SLionel Sambuc if (n > n0)
181f14fb602SLionel Sambuc b->x[j] = ULbits >> (ULbits - (nbits & kmask));
182f14fb602SLionel Sambuc *expt = fpi->emin;
183f14fb602SLionel Sambuc return STRTOG_Normal | STRTOG_Inexlo;
184f14fb602SLionel Sambuc }
185f14fb602SLionel Sambuc n = (int)(s1 - s0) - 1;
186f14fb602SLionel Sambuc for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1)
1872fe8fb19SBen Gras k++;
1882fe8fb19SBen Gras b = Balloc(k);
1892fe8fb19SBen Gras if (b == NULL)
1902fe8fb19SBen Gras return STRTOG_NoMemory;
1912fe8fb19SBen Gras x = b->x;
1922fe8fb19SBen Gras n = 0;
1932fe8fb19SBen Gras L = 0;
194f14fb602SLionel Sambuc #ifdef USE_LOCALE
195f14fb602SLionel Sambuc for(i = 0; decimalpoint[i+1]; ++i);
196f14fb602SLionel Sambuc #endif
1972fe8fb19SBen Gras while(s1 > s0) {
198f14fb602SLionel Sambuc #ifdef USE_LOCALE
199f14fb602SLionel Sambuc if (*--s1 == decimalpoint[i]) {
200f14fb602SLionel Sambuc s1 -= i;
2012fe8fb19SBen Gras continue;
202f14fb602SLionel Sambuc }
203f14fb602SLionel Sambuc #else
204f14fb602SLionel Sambuc if (*--s1 == '.')
205f14fb602SLionel Sambuc continue;
206f14fb602SLionel Sambuc #endif
207f14fb602SLionel Sambuc if (n == ULbits) {
2082fe8fb19SBen Gras *x++ = L;
2092fe8fb19SBen Gras L = 0;
2102fe8fb19SBen Gras n = 0;
2112fe8fb19SBen Gras }
212f14fb602SLionel Sambuc L |= (hexdig[(unsigned char)*s1] & 0x0f) << n;
2132fe8fb19SBen Gras n += 4;
2142fe8fb19SBen Gras }
2152fe8fb19SBen Gras *x++ = L;
216f14fb602SLionel Sambuc b->wds = n = (int)(x - b->x);
217f14fb602SLionel Sambuc n = ULbits*n - hi0bits(L);
2182fe8fb19SBen Gras nbits = fpi->nbits;
2192fe8fb19SBen Gras lostbits = 0;
2202fe8fb19SBen Gras x = b->x;
2212fe8fb19SBen Gras if (n > nbits) {
2222fe8fb19SBen Gras n -= nbits;
2232fe8fb19SBen Gras if (any_on(b,n)) {
2242fe8fb19SBen Gras lostbits = 1;
2252fe8fb19SBen Gras k = n - 1;
2262fe8fb19SBen Gras if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
2272fe8fb19SBen Gras lostbits = 2;
228f14fb602SLionel Sambuc if (k > 0 && any_on(b,k))
2292fe8fb19SBen Gras lostbits = 3;
2302fe8fb19SBen Gras }
2312fe8fb19SBen Gras }
2322fe8fb19SBen Gras rshift(b, n);
2332fe8fb19SBen Gras e += n;
2342fe8fb19SBen Gras }
2352fe8fb19SBen Gras else if (n < nbits) {
2362fe8fb19SBen Gras n = nbits - n;
2372fe8fb19SBen Gras b = lshift(b, n);
2382fe8fb19SBen Gras if (b == NULL)
2392fe8fb19SBen Gras return STRTOG_NoMemory;
2402fe8fb19SBen Gras e -= n;
2412fe8fb19SBen Gras x = b->x;
2422fe8fb19SBen Gras }
2432fe8fb19SBen Gras if (e > fpi->emax) {
2442fe8fb19SBen Gras ovfl:
2452fe8fb19SBen Gras Bfree(b);
246f14fb602SLionel Sambuc ovfl1:
247f14fb602SLionel Sambuc #ifndef NO_ERRNO
248f14fb602SLionel Sambuc errno = ERANGE;
249f14fb602SLionel Sambuc #endif
2502fe8fb19SBen Gras return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
2512fe8fb19SBen Gras }
2522fe8fb19SBen Gras irv = STRTOG_Normal;
2532fe8fb19SBen Gras if (e < fpi->emin) {
2542fe8fb19SBen Gras irv = STRTOG_Denormal;
2552fe8fb19SBen Gras n = fpi->emin - e;
2562fe8fb19SBen Gras if (n >= nbits) {
2572fe8fb19SBen Gras switch (fpi->rounding) {
2582fe8fb19SBen Gras case FPI_Round_near:
2592fe8fb19SBen Gras if (n == nbits && (n < 2 || any_on(b,n-1)))
2602fe8fb19SBen Gras goto one_bit;
2612fe8fb19SBen Gras break;
2622fe8fb19SBen Gras case FPI_Round_up:
2632fe8fb19SBen Gras if (!sign)
2642fe8fb19SBen Gras goto one_bit;
2652fe8fb19SBen Gras break;
2662fe8fb19SBen Gras case FPI_Round_down:
2672fe8fb19SBen Gras if (sign) {
2682fe8fb19SBen Gras one_bit:
2692fe8fb19SBen Gras x[0] = b->wds = 1;
270f14fb602SLionel Sambuc dret:
2712fe8fb19SBen Gras *bp = b;
272f14fb602SLionel Sambuc *expt = fpi->emin;
273f14fb602SLionel Sambuc #ifndef NO_ERRNO
274f14fb602SLionel Sambuc errno = ERANGE;
275f14fb602SLionel Sambuc #endif
2762fe8fb19SBen Gras return STRTOG_Denormal | STRTOG_Inexhi
2772fe8fb19SBen Gras | STRTOG_Underflow;
2782fe8fb19SBen Gras }
2792fe8fb19SBen Gras }
2802fe8fb19SBen Gras Bfree(b);
281f14fb602SLionel Sambuc retz:
282f14fb602SLionel Sambuc #ifndef NO_ERRNO
283f14fb602SLionel Sambuc errno = ERANGE;
284f14fb602SLionel Sambuc #endif
2852fe8fb19SBen Gras return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
2862fe8fb19SBen Gras }
2872fe8fb19SBen Gras k = n - 1;
2882fe8fb19SBen Gras if (lostbits)
2892fe8fb19SBen Gras lostbits = 1;
2902fe8fb19SBen Gras else if (k > 0)
2912fe8fb19SBen Gras lostbits = any_on(b,k);
2922fe8fb19SBen Gras if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
2932fe8fb19SBen Gras lostbits |= 2;
2942fe8fb19SBen Gras nbits -= n;
2952fe8fb19SBen Gras rshift(b,n);
2962fe8fb19SBen Gras e = fpi->emin;
2972fe8fb19SBen Gras }
2982fe8fb19SBen Gras if (lostbits) {
2992fe8fb19SBen Gras up = 0;
3002fe8fb19SBen Gras switch(fpi->rounding) {
3012fe8fb19SBen Gras case FPI_Round_zero:
3022fe8fb19SBen Gras break;
3032fe8fb19SBen Gras case FPI_Round_near:
3042fe8fb19SBen Gras if (lostbits & 2
305f14fb602SLionel Sambuc && (lostbits | x[0]) & 1)
3062fe8fb19SBen Gras up = 1;
3072fe8fb19SBen Gras break;
3082fe8fb19SBen Gras case FPI_Round_up:
3092fe8fb19SBen Gras up = 1 - sign;
3102fe8fb19SBen Gras break;
3112fe8fb19SBen Gras case FPI_Round_down:
3122fe8fb19SBen Gras up = sign;
3132fe8fb19SBen Gras }
3142fe8fb19SBen Gras if (up) {
3152fe8fb19SBen Gras k = b->wds;
3162fe8fb19SBen Gras b = increment(b);
3172fe8fb19SBen Gras x = b->x;
3182fe8fb19SBen Gras if (irv == STRTOG_Denormal) {
3192fe8fb19SBen Gras if (nbits == fpi->nbits - 1
3202fe8fb19SBen Gras && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
3212fe8fb19SBen Gras irv = STRTOG_Normal;
3222fe8fb19SBen Gras }
3232fe8fb19SBen Gras else if (b->wds > k
3242fe8fb19SBen Gras || ((n = nbits & kmask) !=0
3252fe8fb19SBen Gras && hi0bits(x[k-1]) < 32-n)) {
3262fe8fb19SBen Gras rshift(b,1);
3272fe8fb19SBen Gras if (++e > fpi->emax)
3282fe8fb19SBen Gras goto ovfl;
3292fe8fb19SBen Gras }
3302fe8fb19SBen Gras irv |= STRTOG_Inexhi;
3312fe8fb19SBen Gras }
3322fe8fb19SBen Gras else
3332fe8fb19SBen Gras irv |= STRTOG_Inexlo;
3342fe8fb19SBen Gras }
3352fe8fb19SBen Gras *bp = b;
3362fe8fb19SBen Gras *expt = e;
3372fe8fb19SBen Gras return irv;
3382fe8fb19SBen Gras }
339