xref: /freebsd/contrib/gdtoa/gethex.c (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
1 /****************************************************************
2 
3 The author of this software is David M. Gay.
4 
5 Copyright (C) 1998 by Lucent Technologies
6 All Rights Reserved
7 
8 Permission to use, copy, modify, and distribute this software and
9 its documentation for any purpose and without fee is hereby
10 granted, provided that the above copyright notice appear in all
11 copies and that both that the copyright notice and this
12 permission notice and warranty disclaimer appear in supporting
13 documentation, and that the name of Lucent or any of its entities
14 not be used in advertising or publicity pertaining to
15 distribution of the software without specific, written prior
16 permission.
17 
18 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25 THIS SOFTWARE.
26 
27 ****************************************************************/
28 
29 /* Please send bug reports to David M. Gay (dmg at acm dot org,
30  * with " at " changed at "@" and " dot " changed to ".").	*/
31 
32 #include "gdtoaimp.h"
33 
34 #ifdef USE_LOCALE
35 #include "locale.h"
36 #endif
37 
38  int
39 #ifdef KR_headers
40 gethex(sp, fpi, exp, bp, sign)
41 	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
42 #else
43 gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
44 #endif
45 {
46 	Bigint *b;
47 	CONST unsigned char *decpt, *s0, *s, *s1;
48 	int esign, havedig, irv, k, n, nbits, up, zret;
49 	ULong L, lostbits, *x;
50 	Long e, e1;
51 #ifdef USE_LOCALE
52 	unsigned char decimalpoint = *localeconv()->decimal_point;
53 #else
54 #define decimalpoint '.'
55 #endif
56 
57 	if (!hexdig['0'])
58 		hexdig_init_D2A();
59 	havedig = 0;
60 	s0 = *(CONST unsigned char **)sp + 2;
61 	while(s0[havedig] == '0')
62 		havedig++;
63 	s0 += havedig;
64 	s = s0;
65 	decpt = 0;
66 	zret = 0;
67 	e = 0;
68 	if (!hexdig[*s]) {
69 		zret = 1;
70 		if (*s != decimalpoint)
71 			goto pcheck;
72 		decpt = ++s;
73 		if (!hexdig[*s])
74 			goto pcheck;
75 		while(*s == '0')
76 			s++;
77 		if (hexdig[*s])
78 			zret = 0;
79 		havedig = 1;
80 		s0 = s;
81 		}
82 	while(hexdig[*s])
83 		s++;
84 	if (*s == decimalpoint && !decpt) {
85 		decpt = ++s;
86 		while(hexdig[*s])
87 			s++;
88 		}
89 	if (decpt)
90 		e = -(((Long)(s-decpt)) << 2);
91  pcheck:
92 	s1 = s;
93 	switch(*s) {
94 	  case 'p':
95 	  case 'P':
96 		esign = 0;
97 		switch(*++s) {
98 		  case '-':
99 			esign = 1;
100 			/* no break */
101 		  case '+':
102 			s++;
103 		  }
104 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
105 			s = s1;
106 			break;
107 			}
108 		e1 = n - 0x10;
109 		while((n = hexdig[*++s]) !=0 && n <= 0x19)
110 			e1 = 10*e1 + n - 0x10;
111 		if (esign)
112 			e1 = -e1;
113 		e += e1;
114 	  }
115 	*sp = (char*)s;
116 	if (zret)
117 		return havedig ? STRTOG_Zero : STRTOG_NoNumber;
118 	n = s1 - s0 - 1;
119 	for(k = 0; n > 7; n >>= 1)
120 		k++;
121 	b = Balloc(k);
122 	x = b->x;
123 	n = 0;
124 	L = 0;
125 	while(s1 > s0) {
126 		if (*--s1 == decimalpoint)
127 			continue;
128 		if (n == 32) {
129 			*x++ = L;
130 			L = 0;
131 			n = 0;
132 			}
133 		L |= (hexdig[*s1] & 0x0f) << n;
134 		n += 4;
135 		}
136 	*x++ = L;
137 	b->wds = n = x - b->x;
138 	n = 32*n - hi0bits(L);
139 	nbits = fpi->nbits;
140 	lostbits = 0;
141 	x = b->x;
142 	if (n > nbits) {
143 		n -= nbits;
144 		if (any_on(b,n)) {
145 			lostbits = 1;
146 			k = n - 1;
147 			if (x[k>>kshift] & 1 << (k & kmask)) {
148 				lostbits = 2;
149 				if (k > 1 && any_on(b,k-1))
150 					lostbits = 3;
151 				}
152 			}
153 		rshift(b, n);
154 		e += n;
155 		}
156 	else if (n < nbits) {
157 		n = nbits - n;
158 		b = lshift(b, n);
159 		e -= n;
160 		x = b->x;
161 		}
162 	if (e > fpi->emax) {
163  ovfl:
164 		Bfree(b);
165 		*bp = 0;
166 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
167 		}
168 	irv = STRTOG_Normal;
169 	if (e < fpi->emin) {
170 		irv = STRTOG_Denormal;
171 		n = fpi->emin - e;
172 		if (n >= nbits) {
173 			switch (fpi->rounding) {
174 			  case FPI_Round_near:
175 				if (n == nbits && (n < 2 || any_on(b,n-1)))
176 					goto one_bit;
177 				break;
178 			  case FPI_Round_up:
179 				if (!sign)
180 					goto one_bit;
181 				break;
182 			  case FPI_Round_down:
183 				if (sign) {
184  one_bit:
185 					*exp = fpi->emin;
186 					x[0] = b->wds = 1;
187 					*bp = b;
188 					return STRTOG_Denormal | STRTOG_Inexhi
189 						| STRTOG_Underflow;
190 					}
191 			  }
192 			Bfree(b);
193 			*bp = 0;
194 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
195 			}
196 		k = n - 1;
197 		if (lostbits)
198 			lostbits = 1;
199 		else if (k > 0)
200 			lostbits = any_on(b,k);
201 		if (x[k>>kshift] & 1 << (k & kmask))
202 			lostbits |= 2;
203 		nbits -= n;
204 		rshift(b,n);
205 		e = fpi->emin;
206 		}
207 	if (lostbits) {
208 		up = 0;
209 		switch(fpi->rounding) {
210 		  case FPI_Round_zero:
211 			break;
212 		  case FPI_Round_near:
213 			if (lostbits & 2
214 			 && (lostbits & 1) | x[0] & 1)
215 				up = 1;
216 			break;
217 		  case FPI_Round_up:
218 			up = 1 - sign;
219 			break;
220 		  case FPI_Round_down:
221 			up = sign;
222 		  }
223 		if (up) {
224 			k = b->wds;
225 			b = increment(b);
226 			x = b->x;
227 			if (irv == STRTOG_Denormal) {
228 				if (nbits == fpi->nbits - 1
229 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
230 					irv =  STRTOG_Normal;
231 				}
232 			else if (b->wds > k
233 			 || (n = nbits & kmask) !=0
234 			     && hi0bits(x[k-1]) < 32-n) {
235 				rshift(b,1);
236 				if (++e > fpi->emax)
237 					goto ovfl;
238 				}
239 			irv |= STRTOG_Inexhi;
240 			}
241 		else
242 			irv |= STRTOG_Inexlo;
243 		}
244 	*bp = b;
245 	*exp = e;
246 	return irv;
247 	}
248