xref: /minix3/lib/libc/gdtoa/gethex.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
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