1*35ea0de3Skamil /* $NetBSD: gethex.c,v 1.7 2020/02/22 00:38:14 kamil Exp $ */
27684d5e0Skleink
37684d5e0Skleink /****************************************************************
47684d5e0Skleink
57684d5e0Skleink The author of this software is David M. Gay.
67684d5e0Skleink
77684d5e0Skleink Copyright (C) 1998 by Lucent Technologies
87684d5e0Skleink All Rights Reserved
97684d5e0Skleink
107684d5e0Skleink Permission to use, copy, modify, and distribute this software and
117684d5e0Skleink its documentation for any purpose and without fee is hereby
127684d5e0Skleink granted, provided that the above copyright notice appear in all
137684d5e0Skleink copies and that both that the copyright notice and this
147684d5e0Skleink permission notice and warranty disclaimer appear in supporting
157684d5e0Skleink documentation, and that the name of Lucent or any of its entities
167684d5e0Skleink not be used in advertising or publicity pertaining to
177684d5e0Skleink distribution of the software without specific, written prior
187684d5e0Skleink permission.
197684d5e0Skleink
207684d5e0Skleink LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
217684d5e0Skleink INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
227684d5e0Skleink IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
237684d5e0Skleink SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
247684d5e0Skleink WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
257684d5e0Skleink IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
267684d5e0Skleink ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
277684d5e0Skleink THIS SOFTWARE.
287684d5e0Skleink
297684d5e0Skleink ****************************************************************/
307684d5e0Skleink
317684d5e0Skleink /* Please send bug reports to David M. Gay (dmg at acm dot org,
327684d5e0Skleink * with " at " changed at "@" and " dot " changed to "."). */
337684d5e0Skleink
347684d5e0Skleink #include "gdtoaimp.h"
357684d5e0Skleink
367684d5e0Skleink #ifdef USE_LOCALE
377684d5e0Skleink #include "locale.h"
387684d5e0Skleink #endif
397684d5e0Skleink
407684d5e0Skleink int
gethex(CONST char ** sp,CONST FPI * fpi,Long * expt,Bigint ** bp,int sign,locale_t loc)410feb0f12Sjoerg gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign, locale_t loc)
427684d5e0Skleink {
437684d5e0Skleink Bigint *b;
4461e56760Schristos CONST char *decpt, *s, *s0, *s1;
4561e56760Schristos int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
467684d5e0Skleink ULong L, lostbits, *x;
477684d5e0Skleink Long e, e1;
487684d5e0Skleink #ifdef USE_LOCALE
4961e56760Schristos int i;
500feb0f12Sjoerg const char *decimalpoint = localeconv_l(loc)->decimal_point;
517684d5e0Skleink #endif
527684d5e0Skleink
5361e56760Schristos if (!hexdig[(unsigned char)'0'])
547684d5e0Skleink hexdig_init_D2A();
5561e56760Schristos *bp = 0;
567684d5e0Skleink havedig = 0;
5761e56760Schristos s0 = *(CONST char **)sp + 2;
587684d5e0Skleink while(s0[havedig] == '0')
597684d5e0Skleink havedig++;
607684d5e0Skleink s0 += havedig;
617684d5e0Skleink s = s0;
627684d5e0Skleink decpt = 0;
637684d5e0Skleink zret = 0;
647684d5e0Skleink e = 0;
6561e56760Schristos if (hexdig[(unsigned char)*s])
6661e56760Schristos havedig++;
6761e56760Schristos else {
687684d5e0Skleink zret = 1;
6961e56760Schristos #ifdef USE_LOCALE
7061e56760Schristos for(i = 0; decimalpoint[i]; ++i) {
7161e56760Schristos if (s[i] != decimalpoint[i])
7261e56760Schristos goto pcheck;
7361e56760Schristos }
7461e56760Schristos decpt = s += i;
7561e56760Schristos #else
7661e56760Schristos if (*s != '.')
777684d5e0Skleink goto pcheck;
787684d5e0Skleink decpt = ++s;
7961e56760Schristos #endif
8061e56760Schristos if (!hexdig[(unsigned char)*s])
817684d5e0Skleink goto pcheck;
827684d5e0Skleink while(*s == '0')
837684d5e0Skleink s++;
8461e56760Schristos if (hexdig[(unsigned char)*s])
857684d5e0Skleink zret = 0;
867684d5e0Skleink havedig = 1;
877684d5e0Skleink s0 = s;
887684d5e0Skleink }
8961e56760Schristos while(hexdig[(unsigned char)*s])
907684d5e0Skleink s++;
9161e56760Schristos #ifdef USE_LOCALE
9261e56760Schristos if (*s == *decimalpoint && !decpt) {
9361e56760Schristos for(i = 1; decimalpoint[i]; ++i) {
9461e56760Schristos if (s[i] != decimalpoint[i])
9561e56760Schristos goto pcheck;
967684d5e0Skleink }
9761e56760Schristos decpt = s += i;
9861e56760Schristos #else
9961e56760Schristos if (*s == '.' && !decpt) {
10061e56760Schristos decpt = ++s;
10161e56760Schristos #endif
10261e56760Schristos while(hexdig[(unsigned char)*s])
10361e56760Schristos s++;
10461e56760Schristos }/*}*/
1057684d5e0Skleink if (decpt)
1067684d5e0Skleink e = -(((Long)(s-decpt)) << 2);
1077684d5e0Skleink pcheck:
1087684d5e0Skleink s1 = s;
10961e56760Schristos big = esign = 0;
1107684d5e0Skleink switch(*s) {
1117684d5e0Skleink case 'p':
1127684d5e0Skleink case 'P':
1137684d5e0Skleink switch(*++s) {
1147684d5e0Skleink case '-':
1157684d5e0Skleink esign = 1;
116ac898a26Skleink /* FALLTHROUGH */
1177684d5e0Skleink case '+':
1187684d5e0Skleink s++;
1197684d5e0Skleink }
12061e56760Schristos if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) {
1217684d5e0Skleink s = s1;
1227684d5e0Skleink break;
1237684d5e0Skleink }
1247684d5e0Skleink e1 = n - 0x10;
12561e56760Schristos while((n = hexdig[(unsigned char)*++s]) !=0 && n <= 0x19) {
12661e56760Schristos if (e1 & 0xf8000000)
12761e56760Schristos big = 1;
1287684d5e0Skleink e1 = 10*e1 + n - 0x10;
12961e56760Schristos }
1307684d5e0Skleink if (esign)
1317684d5e0Skleink e1 = -e1;
1327684d5e0Skleink e += e1;
1337684d5e0Skleink }
134ac898a26Skleink *sp = __UNCONST(s);
13561e56760Schristos if (!havedig)
13661e56760Schristos *sp = (char*)__UNCONST(s0) - 1;
1377684d5e0Skleink if (zret)
13861e56760Schristos return STRTOG_Zero;
13961e56760Schristos if (big) {
14061e56760Schristos if (esign) {
14161e56760Schristos switch(fpi->rounding) {
14261e56760Schristos case FPI_Round_up:
14361e56760Schristos if (sign)
14461e56760Schristos break;
14561e56760Schristos goto ret_tiny;
14661e56760Schristos case FPI_Round_down:
14761e56760Schristos if (!sign)
14861e56760Schristos break;
14961e56760Schristos goto ret_tiny;
15061e56760Schristos }
15161e56760Schristos goto retz;
15261e56760Schristos ret_tiny:
15361e56760Schristos b = Balloc(0);
15461e56760Schristos b->wds = 1;
15561e56760Schristos b->x[0] = 1;
15661e56760Schristos goto dret;
15761e56760Schristos }
15861e56760Schristos switch(fpi->rounding) {
15961e56760Schristos case FPI_Round_near:
16061e56760Schristos goto ovfl1;
16161e56760Schristos case FPI_Round_up:
16261e56760Schristos if (!sign)
16361e56760Schristos goto ovfl1;
16461e56760Schristos goto ret_big;
16561e56760Schristos case FPI_Round_down:
16661e56760Schristos if (sign)
16761e56760Schristos goto ovfl1;
16861e56760Schristos goto ret_big;
16961e56760Schristos }
17061e56760Schristos ret_big:
17161e56760Schristos nbits = fpi->nbits;
17261e56760Schristos n0 = n = (unsigned int)nbits >> kshift;
17361e56760Schristos if (nbits & kmask)
17461e56760Schristos ++n;
17561e56760Schristos for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k);
17661e56760Schristos *bp = b = Balloc(k);
17761e56760Schristos b->wds = n;
17861e56760Schristos for(j = 0; j < n0; ++j)
17961e56760Schristos b->x[j] = ALL_ON;
18061e56760Schristos if (n > n0)
18161e56760Schristos b->x[j] = ULbits >> (ULbits - (nbits & kmask));
18261e56760Schristos *expt = fpi->emin;
18361e56760Schristos return STRTOG_Normal | STRTOG_Inexlo;
18461e56760Schristos }
18561e56760Schristos n = (int)(s1 - s0) - 1;
18661e56760Schristos for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1)
1877684d5e0Skleink k++;
1887684d5e0Skleink b = Balloc(k);
189ab625449Schristos if (b == NULL)
190ab625449Schristos return STRTOG_NoMemory;
1917684d5e0Skleink x = b->x;
1927684d5e0Skleink n = 0;
1937684d5e0Skleink L = 0;
19461e56760Schristos #ifdef USE_LOCALE
19561e56760Schristos for(i = 0; decimalpoint[i+1]; ++i);
19661e56760Schristos #endif
1977684d5e0Skleink while(s1 > s0) {
19861e56760Schristos #ifdef USE_LOCALE
19961e56760Schristos if (*--s1 == decimalpoint[i]) {
20061e56760Schristos s1 -= i;
2017684d5e0Skleink continue;
20261e56760Schristos }
20361e56760Schristos #else
20461e56760Schristos if (*--s1 == '.')
20561e56760Schristos continue;
20661e56760Schristos #endif
20761e56760Schristos if (n == ULbits) {
2087684d5e0Skleink *x++ = L;
2097684d5e0Skleink L = 0;
2107684d5e0Skleink n = 0;
2117684d5e0Skleink }
212*35ea0de3Skamil L |= (unsigned int)(hexdig[(unsigned char)*s1] & 0x0f) << n;
2137684d5e0Skleink n += 4;
2147684d5e0Skleink }
2157684d5e0Skleink *x++ = L;
21661e56760Schristos b->wds = n = (int)(x - b->x);
21761e56760Schristos n = ULbits*n - hi0bits(L);
2187684d5e0Skleink nbits = fpi->nbits;
2197684d5e0Skleink lostbits = 0;
2207684d5e0Skleink x = b->x;
2217684d5e0Skleink if (n > nbits) {
2227684d5e0Skleink n -= nbits;
2237684d5e0Skleink if (any_on(b,n)) {
2247684d5e0Skleink lostbits = 1;
2257684d5e0Skleink k = n - 1;
226ac898a26Skleink if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
2277684d5e0Skleink lostbits = 2;
22861e56760Schristos if (k > 0 && any_on(b,k))
2297684d5e0Skleink lostbits = 3;
2307684d5e0Skleink }
2317684d5e0Skleink }
2327684d5e0Skleink rshift(b, n);
2337684d5e0Skleink e += n;
2347684d5e0Skleink }
2357684d5e0Skleink else if (n < nbits) {
2367684d5e0Skleink n = nbits - n;
2377684d5e0Skleink b = lshift(b, n);
238ab625449Schristos if (b == NULL)
239ab625449Schristos return STRTOG_NoMemory;
2407684d5e0Skleink e -= n;
2417684d5e0Skleink x = b->x;
2427684d5e0Skleink }
2437684d5e0Skleink if (e > fpi->emax) {
2447684d5e0Skleink ovfl:
2457684d5e0Skleink Bfree(b);
24661e56760Schristos ovfl1:
24761e56760Schristos #ifndef NO_ERRNO
24861e56760Schristos errno = ERANGE;
24961e56760Schristos #endif
2507684d5e0Skleink return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
2517684d5e0Skleink }
2527684d5e0Skleink irv = STRTOG_Normal;
2537684d5e0Skleink if (e < fpi->emin) {
2547684d5e0Skleink irv = STRTOG_Denormal;
2557684d5e0Skleink n = fpi->emin - e;
2567684d5e0Skleink if (n >= nbits) {
2577684d5e0Skleink switch (fpi->rounding) {
2587684d5e0Skleink case FPI_Round_near:
2597684d5e0Skleink if (n == nbits && (n < 2 || any_on(b,n-1)))
2607684d5e0Skleink goto one_bit;
2617684d5e0Skleink break;
2627684d5e0Skleink case FPI_Round_up:
2637684d5e0Skleink if (!sign)
2647684d5e0Skleink goto one_bit;
2657684d5e0Skleink break;
2667684d5e0Skleink case FPI_Round_down:
2677684d5e0Skleink if (sign) {
2687684d5e0Skleink one_bit:
2697684d5e0Skleink x[0] = b->wds = 1;
27061e56760Schristos dret:
2717684d5e0Skleink *bp = b;
27261e56760Schristos *expt = fpi->emin;
27361e56760Schristos #ifndef NO_ERRNO
27461e56760Schristos errno = ERANGE;
27561e56760Schristos #endif
2767684d5e0Skleink return STRTOG_Denormal | STRTOG_Inexhi
2777684d5e0Skleink | STRTOG_Underflow;
2787684d5e0Skleink }
2797684d5e0Skleink }
2807684d5e0Skleink Bfree(b);
28161e56760Schristos retz:
28261e56760Schristos #ifndef NO_ERRNO
28361e56760Schristos errno = ERANGE;
28461e56760Schristos #endif
2857684d5e0Skleink return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
2867684d5e0Skleink }
2877684d5e0Skleink k = n - 1;
2887684d5e0Skleink if (lostbits)
2897684d5e0Skleink lostbits = 1;
2907684d5e0Skleink else if (k > 0)
2917684d5e0Skleink lostbits = any_on(b,k);
292ac898a26Skleink if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
2937684d5e0Skleink lostbits |= 2;
2947684d5e0Skleink nbits -= n;
2957684d5e0Skleink rshift(b,n);
2967684d5e0Skleink e = fpi->emin;
2977684d5e0Skleink }
2987684d5e0Skleink if (lostbits) {
2997684d5e0Skleink up = 0;
3007684d5e0Skleink switch(fpi->rounding) {
3017684d5e0Skleink case FPI_Round_zero:
3027684d5e0Skleink break;
3037684d5e0Skleink case FPI_Round_near:
3047684d5e0Skleink if (lostbits & 2
30561e56760Schristos && (lostbits | x[0]) & 1)
3067684d5e0Skleink up = 1;
3077684d5e0Skleink break;
3087684d5e0Skleink case FPI_Round_up:
3097684d5e0Skleink up = 1 - sign;
3107684d5e0Skleink break;
3117684d5e0Skleink case FPI_Round_down:
3127684d5e0Skleink up = sign;
3137684d5e0Skleink }
3147684d5e0Skleink if (up) {
3157684d5e0Skleink k = b->wds;
3167684d5e0Skleink b = increment(b);
3177684d5e0Skleink x = b->x;
3187684d5e0Skleink if (irv == STRTOG_Denormal) {
3197684d5e0Skleink if (nbits == fpi->nbits - 1
320ac898a26Skleink && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
3217684d5e0Skleink irv = STRTOG_Normal;
3227684d5e0Skleink }
3237684d5e0Skleink else if (b->wds > k
324ac898a26Skleink || ((n = nbits & kmask) !=0
325ac898a26Skleink && hi0bits(x[k-1]) < 32-n)) {
3267684d5e0Skleink rshift(b,1);
3277684d5e0Skleink if (++e > fpi->emax)
3287684d5e0Skleink goto ovfl;
3297684d5e0Skleink }
3307684d5e0Skleink irv |= STRTOG_Inexhi;
3317684d5e0Skleink }
3327684d5e0Skleink else
3337684d5e0Skleink irv |= STRTOG_Inexlo;
3347684d5e0Skleink }
3357684d5e0Skleink *bp = b;
336ac898a26Skleink *expt = e;
3377684d5e0Skleink return irv;
3387684d5e0Skleink }
339