xref: /freebsd-src/contrib/gdtoa/gethex.c (revision 50dad48bb740a8e56d185d9e8c165e0758f46e25)
1cc36ccd1SDavid Schultz /****************************************************************
2cc36ccd1SDavid Schultz 
3cc36ccd1SDavid Schultz The author of this software is David M. Gay.
4cc36ccd1SDavid Schultz 
5cc36ccd1SDavid Schultz Copyright (C) 1998 by Lucent Technologies
6cc36ccd1SDavid Schultz All Rights Reserved
7cc36ccd1SDavid Schultz 
8cc36ccd1SDavid Schultz Permission to use, copy, modify, and distribute this software and
9cc36ccd1SDavid Schultz its documentation for any purpose and without fee is hereby
10cc36ccd1SDavid Schultz granted, provided that the above copyright notice appear in all
11cc36ccd1SDavid Schultz copies and that both that the copyright notice and this
12cc36ccd1SDavid Schultz permission notice and warranty disclaimer appear in supporting
13cc36ccd1SDavid Schultz documentation, and that the name of Lucent or any of its entities
14cc36ccd1SDavid Schultz not be used in advertising or publicity pertaining to
15cc36ccd1SDavid Schultz distribution of the software without specific, written prior
16cc36ccd1SDavid Schultz permission.
17cc36ccd1SDavid Schultz 
18cc36ccd1SDavid Schultz LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19cc36ccd1SDavid Schultz INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20cc36ccd1SDavid Schultz IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21cc36ccd1SDavid Schultz SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22cc36ccd1SDavid Schultz WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23cc36ccd1SDavid Schultz IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24cc36ccd1SDavid Schultz ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25cc36ccd1SDavid Schultz THIS SOFTWARE.
26cc36ccd1SDavid Schultz 
27cc36ccd1SDavid Schultz ****************************************************************/
28cc36ccd1SDavid Schultz 
29c88250a5SDavid Schultz /* Please send bug reports to David M. Gay (dmg at acm dot org,
30c88250a5SDavid Schultz  * with " at " changed at "@" and " dot " changed to ".").	*/
31cc36ccd1SDavid Schultz 
32cc36ccd1SDavid Schultz #include "gdtoaimp.h"
33cc36ccd1SDavid Schultz 
348f7c2af4SDavid Schultz #ifdef USE_LOCALE
358f7c2af4SDavid Schultz #include "locale.h"
368f7c2af4SDavid Schultz #endif
378f7c2af4SDavid Schultz 
38cc36ccd1SDavid Schultz  int
39cc36ccd1SDavid Schultz #ifdef KR_headers
gethex(sp,fpi,exp,bp,sign)40cc36ccd1SDavid Schultz gethex(sp, fpi, exp, bp, sign)
41cc36ccd1SDavid Schultz 	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
42cc36ccd1SDavid Schultz #else
43cc36ccd1SDavid Schultz gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
44cc36ccd1SDavid Schultz #endif
45cc36ccd1SDavid Schultz {
46cc36ccd1SDavid Schultz 	Bigint *b;
47cc36ccd1SDavid Schultz 	CONST unsigned char *decpt, *s0, *s, *s1;
48ae2cbf4cSDavid Schultz 	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
49cc36ccd1SDavid Schultz 	ULong L, lostbits, *x;
50cc36ccd1SDavid Schultz 	Long e, e1;
518f7c2af4SDavid Schultz #ifdef USE_LOCALE
524848dd08SDavid Schultz 	int i;
534848dd08SDavid Schultz #ifdef NO_LOCALE_CACHE
544848dd08SDavid Schultz 	const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
558f7c2af4SDavid Schultz #else
564848dd08SDavid Schultz 	const unsigned char *decimalpoint;
574848dd08SDavid Schultz 	static unsigned char *decimalpoint_cache;
584848dd08SDavid Schultz 	if (!(s0 = decimalpoint_cache)) {
594848dd08SDavid Schultz 		s0 = (unsigned char*)localeconv()->decimal_point;
60*50dad48bSDavid Schultz 		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
614848dd08SDavid Schultz 			strcpy(decimalpoint_cache, s0);
624848dd08SDavid Schultz 			s0 = decimalpoint_cache;
634848dd08SDavid Schultz 			}
644848dd08SDavid Schultz 		}
654848dd08SDavid Schultz 	decimalpoint = s0;
664848dd08SDavid Schultz #endif
678f7c2af4SDavid Schultz #endif
68cc36ccd1SDavid Schultz 
69cc36ccd1SDavid Schultz 	if (!hexdig['0'])
70cc36ccd1SDavid Schultz 		hexdig_init_D2A();
71ae2cbf4cSDavid Schultz 	*bp = 0;
72cc36ccd1SDavid Schultz 	havedig = 0;
73cc36ccd1SDavid Schultz 	s0 = *(CONST unsigned char **)sp + 2;
74cc36ccd1SDavid Schultz 	while(s0[havedig] == '0')
75cc36ccd1SDavid Schultz 		havedig++;
76cc36ccd1SDavid Schultz 	s0 += havedig;
77cc36ccd1SDavid Schultz 	s = s0;
78cc36ccd1SDavid Schultz 	decpt = 0;
79c88250a5SDavid Schultz 	zret = 0;
80c88250a5SDavid Schultz 	e = 0;
814848dd08SDavid Schultz 	if (hexdig[*s])
824848dd08SDavid Schultz 		havedig++;
834848dd08SDavid Schultz 	else {
84c88250a5SDavid Schultz 		zret = 1;
854848dd08SDavid Schultz #ifdef USE_LOCALE
864848dd08SDavid Schultz 		for(i = 0; decimalpoint[i]; ++i) {
874848dd08SDavid Schultz 			if (s[i] != decimalpoint[i])
884848dd08SDavid Schultz 				goto pcheck;
894848dd08SDavid Schultz 			}
904848dd08SDavid Schultz 		decpt = s += i;
914848dd08SDavid Schultz #else
924848dd08SDavid Schultz 		if (*s != '.')
93c88250a5SDavid Schultz 			goto pcheck;
94cc36ccd1SDavid Schultz 		decpt = ++s;
954848dd08SDavid Schultz #endif
96cc36ccd1SDavid Schultz 		if (!hexdig[*s])
97c88250a5SDavid Schultz 			goto pcheck;
98cc36ccd1SDavid Schultz 		while(*s == '0')
99cc36ccd1SDavid Schultz 			s++;
100c88250a5SDavid Schultz 		if (hexdig[*s])
101c88250a5SDavid Schultz 			zret = 0;
102cc36ccd1SDavid Schultz 		havedig = 1;
103cc36ccd1SDavid Schultz 		s0 = s;
104cc36ccd1SDavid Schultz 		}
105cc36ccd1SDavid Schultz 	while(hexdig[*s])
106cc36ccd1SDavid Schultz 		s++;
1074848dd08SDavid Schultz #ifdef USE_LOCALE
1084848dd08SDavid Schultz 	if (*s == *decimalpoint && !decpt) {
1094848dd08SDavid Schultz 		for(i = 1; decimalpoint[i]; ++i) {
1104848dd08SDavid Schultz 			if (s[i] != decimalpoint[i])
1114848dd08SDavid Schultz 				goto pcheck;
1124848dd08SDavid Schultz 			}
1134848dd08SDavid Schultz 		decpt = s += i;
1144848dd08SDavid Schultz #else
1154848dd08SDavid Schultz 	if (*s == '.' && !decpt) {
116cc36ccd1SDavid Schultz 		decpt = ++s;
1174848dd08SDavid Schultz #endif
118cc36ccd1SDavid Schultz 		while(hexdig[*s])
119cc36ccd1SDavid Schultz 			s++;
1204848dd08SDavid Schultz 		}/*}*/
121cc36ccd1SDavid Schultz 	if (decpt)
122cc36ccd1SDavid Schultz 		e = -(((Long)(s-decpt)) << 2);
123c88250a5SDavid Schultz  pcheck:
124cc36ccd1SDavid Schultz 	s1 = s;
125ae2cbf4cSDavid Schultz 	big = esign = 0;
126cc36ccd1SDavid Schultz 	switch(*s) {
127cc36ccd1SDavid Schultz 	  case 'p':
128cc36ccd1SDavid Schultz 	  case 'P':
129cc36ccd1SDavid Schultz 		switch(*++s) {
130cc36ccd1SDavid Schultz 		  case '-':
131cc36ccd1SDavid Schultz 			esign = 1;
132cc36ccd1SDavid Schultz 			/* no break */
133cc36ccd1SDavid Schultz 		  case '+':
134cc36ccd1SDavid Schultz 			s++;
135cc36ccd1SDavid Schultz 		  }
136cc36ccd1SDavid Schultz 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
137cc36ccd1SDavid Schultz 			s = s1;
138cc36ccd1SDavid Schultz 			break;
139cc36ccd1SDavid Schultz 			}
140cc36ccd1SDavid Schultz 		e1 = n - 0x10;
141ae2cbf4cSDavid Schultz 		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
142ae2cbf4cSDavid Schultz 			if (e1 & 0xf8000000)
143ae2cbf4cSDavid Schultz 				big = 1;
144cc36ccd1SDavid Schultz 			e1 = 10*e1 + n - 0x10;
145ae2cbf4cSDavid Schultz 			}
146cc36ccd1SDavid Schultz 		if (esign)
147cc36ccd1SDavid Schultz 			e1 = -e1;
148cc36ccd1SDavid Schultz 		e += e1;
149cc36ccd1SDavid Schultz 	  }
150cc36ccd1SDavid Schultz 	*sp = (char*)s;
151c713eaa6SDavid Schultz 	if (!havedig)
1524848dd08SDavid Schultz 		*sp = (char*)s0 - 1;
153ae2cbf4cSDavid Schultz 	if (zret)
154c713eaa6SDavid Schultz 		return STRTOG_Zero;
155ae2cbf4cSDavid Schultz 	if (big) {
156ae2cbf4cSDavid Schultz 		if (esign) {
157ae2cbf4cSDavid Schultz 			switch(fpi->rounding) {
158ae2cbf4cSDavid Schultz 			  case FPI_Round_up:
159ae2cbf4cSDavid Schultz 				if (sign)
160ae2cbf4cSDavid Schultz 					break;
161ae2cbf4cSDavid Schultz 				goto ret_tiny;
162ae2cbf4cSDavid Schultz 			  case FPI_Round_down:
163ae2cbf4cSDavid Schultz 				if (!sign)
164ae2cbf4cSDavid Schultz 					break;
165ae2cbf4cSDavid Schultz 				goto ret_tiny;
166ae2cbf4cSDavid Schultz 			  }
167ae2cbf4cSDavid Schultz 			goto retz;
168ae2cbf4cSDavid Schultz  ret_tiny:
169ae2cbf4cSDavid Schultz 			b = Balloc(0);
170ae2cbf4cSDavid Schultz 			b->wds = 1;
171ae2cbf4cSDavid Schultz 			b->x[0] = 1;
172ae2cbf4cSDavid Schultz 			goto dret;
173ae2cbf4cSDavid Schultz 			}
174ae2cbf4cSDavid Schultz 		switch(fpi->rounding) {
175ae2cbf4cSDavid Schultz 		  case FPI_Round_near:
176ae2cbf4cSDavid Schultz 			goto ovfl1;
177ae2cbf4cSDavid Schultz 		  case FPI_Round_up:
178ae2cbf4cSDavid Schultz 			if (!sign)
179ae2cbf4cSDavid Schultz 				goto ovfl1;
180ae2cbf4cSDavid Schultz 			goto ret_big;
181ae2cbf4cSDavid Schultz 		  case FPI_Round_down:
182ae2cbf4cSDavid Schultz 			if (sign)
183ae2cbf4cSDavid Schultz 				goto ovfl1;
184ae2cbf4cSDavid Schultz 			goto ret_big;
185ae2cbf4cSDavid Schultz 		  }
186ae2cbf4cSDavid Schultz  ret_big:
187ae2cbf4cSDavid Schultz 		nbits = fpi->nbits;
188ae2cbf4cSDavid Schultz 		n0 = n = nbits >> kshift;
189ae2cbf4cSDavid Schultz 		if (nbits & kmask)
190ae2cbf4cSDavid Schultz 			++n;
191ae2cbf4cSDavid Schultz 		for(j = n, k = 0; j >>= 1; ++k);
192ae2cbf4cSDavid Schultz 		*bp = b = Balloc(k);
193ae2cbf4cSDavid Schultz 		b->wds = n;
194ae2cbf4cSDavid Schultz 		for(j = 0; j < n0; ++j)
195ae2cbf4cSDavid Schultz 			b->x[j] = ALL_ON;
196ae2cbf4cSDavid Schultz 		if (n > n0)
197ae2cbf4cSDavid Schultz 			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
198ae2cbf4cSDavid Schultz 		*exp = fpi->emin;
199ae2cbf4cSDavid Schultz 		return STRTOG_Normal | STRTOG_Inexlo;
200c713eaa6SDavid Schultz 		}
201cc36ccd1SDavid Schultz 	n = s1 - s0 - 1;
202*50dad48bSDavid Schultz 	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
203cc36ccd1SDavid Schultz 		k++;
204cc36ccd1SDavid Schultz 	b = Balloc(k);
205cc36ccd1SDavid Schultz 	x = b->x;
206cc36ccd1SDavid Schultz 	n = 0;
207cc36ccd1SDavid Schultz 	L = 0;
2084848dd08SDavid Schultz #ifdef USE_LOCALE
2094848dd08SDavid Schultz 	for(i = 0; decimalpoint[i+1]; ++i);
2104848dd08SDavid Schultz #endif
211cc36ccd1SDavid Schultz 	while(s1 > s0) {
2124848dd08SDavid Schultz #ifdef USE_LOCALE
2134848dd08SDavid Schultz 		if (*--s1 == decimalpoint[i]) {
2144848dd08SDavid Schultz 			s1 -= i;
215cc36ccd1SDavid Schultz 			continue;
2164848dd08SDavid Schultz 			}
2174848dd08SDavid Schultz #else
2184848dd08SDavid Schultz 		if (*--s1 == '.')
2194848dd08SDavid Schultz 			continue;
2204848dd08SDavid Schultz #endif
2214848dd08SDavid Schultz 		if (n == ULbits) {
222cc36ccd1SDavid Schultz 			*x++ = L;
223cc36ccd1SDavid Schultz 			L = 0;
224cc36ccd1SDavid Schultz 			n = 0;
225cc36ccd1SDavid Schultz 			}
226cc36ccd1SDavid Schultz 		L |= (hexdig[*s1] & 0x0f) << n;
227cc36ccd1SDavid Schultz 		n += 4;
228cc36ccd1SDavid Schultz 		}
229cc36ccd1SDavid Schultz 	*x++ = L;
230cc36ccd1SDavid Schultz 	b->wds = n = x - b->x;
2314848dd08SDavid Schultz 	n = ULbits*n - hi0bits(L);
232cc36ccd1SDavid Schultz 	nbits = fpi->nbits;
233cc36ccd1SDavid Schultz 	lostbits = 0;
234cc36ccd1SDavid Schultz 	x = b->x;
235cc36ccd1SDavid Schultz 	if (n > nbits) {
236cc36ccd1SDavid Schultz 		n -= nbits;
237cc36ccd1SDavid Schultz 		if (any_on(b,n)) {
238cc36ccd1SDavid Schultz 			lostbits = 1;
239cc36ccd1SDavid Schultz 			k = n - 1;
240cc36ccd1SDavid Schultz 			if (x[k>>kshift] & 1 << (k & kmask)) {
241cc36ccd1SDavid Schultz 				lostbits = 2;
242ae2cbf4cSDavid Schultz 				if (k > 0 && any_on(b,k))
243cc36ccd1SDavid Schultz 					lostbits = 3;
244cc36ccd1SDavid Schultz 				}
245cc36ccd1SDavid Schultz 			}
246cc36ccd1SDavid Schultz 		rshift(b, n);
247cc36ccd1SDavid Schultz 		e += n;
248cc36ccd1SDavid Schultz 		}
249cc36ccd1SDavid Schultz 	else if (n < nbits) {
250cc36ccd1SDavid Schultz 		n = nbits - n;
251cc36ccd1SDavid Schultz 		b = lshift(b, n);
252cc36ccd1SDavid Schultz 		e -= n;
253cc36ccd1SDavid Schultz 		x = b->x;
254cc36ccd1SDavid Schultz 		}
255cc36ccd1SDavid Schultz 	if (e > fpi->emax) {
256cc36ccd1SDavid Schultz  ovfl:
257cc36ccd1SDavid Schultz 		Bfree(b);
258ae2cbf4cSDavid Schultz  ovfl1:
259ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
260ae2cbf4cSDavid Schultz 		errno = ERANGE;
261ae2cbf4cSDavid Schultz #endif
262cc36ccd1SDavid Schultz 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
263cc36ccd1SDavid Schultz 		}
264cc36ccd1SDavid Schultz 	irv = STRTOG_Normal;
265cc36ccd1SDavid Schultz 	if (e < fpi->emin) {
266cc36ccd1SDavid Schultz 		irv = STRTOG_Denormal;
267cc36ccd1SDavid Schultz 		n = fpi->emin - e;
268cc36ccd1SDavid Schultz 		if (n >= nbits) {
269cc36ccd1SDavid Schultz 			switch (fpi->rounding) {
270cc36ccd1SDavid Schultz 			  case FPI_Round_near:
27119927830SDavid Schultz 				if (n == nbits && (n < 2 || any_on(b,n-1)))
272cc36ccd1SDavid Schultz 					goto one_bit;
273cc36ccd1SDavid Schultz 				break;
274cc36ccd1SDavid Schultz 			  case FPI_Round_up:
275cc36ccd1SDavid Schultz 				if (!sign)
276cc36ccd1SDavid Schultz 					goto one_bit;
277cc36ccd1SDavid Schultz 				break;
278cc36ccd1SDavid Schultz 			  case FPI_Round_down:
279cc36ccd1SDavid Schultz 				if (sign) {
280cc36ccd1SDavid Schultz  one_bit:
281cc36ccd1SDavid Schultz 					x[0] = b->wds = 1;
282ae2cbf4cSDavid Schultz  dret:
283cc36ccd1SDavid Schultz 					*bp = b;
284ae2cbf4cSDavid Schultz 					*exp = fpi->emin;
285ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
286ae2cbf4cSDavid Schultz 					errno = ERANGE;
287ae2cbf4cSDavid Schultz #endif
288cc36ccd1SDavid Schultz 					return STRTOG_Denormal | STRTOG_Inexhi
289cc36ccd1SDavid Schultz 						| STRTOG_Underflow;
290cc36ccd1SDavid Schultz 					}
291cc36ccd1SDavid Schultz 			  }
292cc36ccd1SDavid Schultz 			Bfree(b);
293ae2cbf4cSDavid Schultz  retz:
294ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
295ae2cbf4cSDavid Schultz 			errno = ERANGE;
296ae2cbf4cSDavid Schultz #endif
297cc36ccd1SDavid Schultz 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
298cc36ccd1SDavid Schultz 			}
299cc36ccd1SDavid Schultz 		k = n - 1;
300cc36ccd1SDavid Schultz 		if (lostbits)
301cc36ccd1SDavid Schultz 			lostbits = 1;
302cc36ccd1SDavid Schultz 		else if (k > 0)
303cc36ccd1SDavid Schultz 			lostbits = any_on(b,k);
304cc36ccd1SDavid Schultz 		if (x[k>>kshift] & 1 << (k & kmask))
305cc36ccd1SDavid Schultz 			lostbits |= 2;
306cc36ccd1SDavid Schultz 		nbits -= n;
307cc36ccd1SDavid Schultz 		rshift(b,n);
308cc36ccd1SDavid Schultz 		e = fpi->emin;
309cc36ccd1SDavid Schultz 		}
310cc36ccd1SDavid Schultz 	if (lostbits) {
311cc36ccd1SDavid Schultz 		up = 0;
312cc36ccd1SDavid Schultz 		switch(fpi->rounding) {
313cc36ccd1SDavid Schultz 		  case FPI_Round_zero:
314cc36ccd1SDavid Schultz 			break;
315cc36ccd1SDavid Schultz 		  case FPI_Round_near:
316cc36ccd1SDavid Schultz 			if (lostbits & 2
317*50dad48bSDavid Schultz 			 && (lostbits | x[0]) & 1)
318cc36ccd1SDavid Schultz 				up = 1;
319cc36ccd1SDavid Schultz 			break;
320cc36ccd1SDavid Schultz 		  case FPI_Round_up:
321cc36ccd1SDavid Schultz 			up = 1 - sign;
322cc36ccd1SDavid Schultz 			break;
323cc36ccd1SDavid Schultz 		  case FPI_Round_down:
324cc36ccd1SDavid Schultz 			up = sign;
325cc36ccd1SDavid Schultz 		  }
326cc36ccd1SDavid Schultz 		if (up) {
327cc36ccd1SDavid Schultz 			k = b->wds;
328cc36ccd1SDavid Schultz 			b = increment(b);
329cc36ccd1SDavid Schultz 			x = b->x;
33019927830SDavid Schultz 			if (irv == STRTOG_Denormal) {
33119927830SDavid Schultz 				if (nbits == fpi->nbits - 1
33219927830SDavid Schultz 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
33319927830SDavid Schultz 					irv =  STRTOG_Normal;
33419927830SDavid Schultz 				}
33519927830SDavid Schultz 			else if (b->wds > k
336*50dad48bSDavid Schultz 			 || ((n = nbits & kmask) !=0
337*50dad48bSDavid Schultz 			      && hi0bits(x[k-1]) < 32-n)) {
338cc36ccd1SDavid Schultz 				rshift(b,1);
339cc36ccd1SDavid Schultz 				if (++e > fpi->emax)
340cc36ccd1SDavid Schultz 					goto ovfl;
341cc36ccd1SDavid Schultz 				}
342cc36ccd1SDavid Schultz 			irv |= STRTOG_Inexhi;
343cc36ccd1SDavid Schultz 			}
344cc36ccd1SDavid Schultz 		else
345cc36ccd1SDavid Schultz 			irv |= STRTOG_Inexlo;
346cc36ccd1SDavid Schultz 		}
347cc36ccd1SDavid Schultz 	*bp = b;
348cc36ccd1SDavid Schultz 	*exp = e;
349cc36ccd1SDavid Schultz 	return irv;
350cc36ccd1SDavid Schultz 	}
351