xref: /freebsd/contrib/gdtoa/gethex.c (revision 4a5216a6dc0c3ce4cf5f2d3ee8af0c3ff3402c4f)
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 big, esign, havedig, irv, j, k, n, n0, 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 	*bp = 0;
60 	havedig = 0;
61 	s0 = *(CONST unsigned char **)sp + 2;
62 	while(s0[havedig] == '0')
63 		havedig++;
64 	s0 += havedig;
65 	s = s0;
66 	decpt = 0;
67 	zret = 0;
68 	e = 0;
69 	if (!hexdig[*s]) {
70 		zret = 1;
71 		if (*s != decimalpoint)
72 			goto pcheck;
73 		decpt = ++s;
74 		if (!hexdig[*s])
75 			goto pcheck;
76 		while(*s == '0')
77 			s++;
78 		if (hexdig[*s])
79 			zret = 0;
80 		havedig = 1;
81 		s0 = s;
82 		}
83 	while(hexdig[*s])
84 		s++;
85 	if (*s == decimalpoint && !decpt) {
86 		decpt = ++s;
87 		while(hexdig[*s])
88 			s++;
89 		}
90 	if (decpt)
91 		e = -(((Long)(s-decpt)) << 2);
92  pcheck:
93 	s1 = s;
94 	big = esign = 0;
95 	switch(*s) {
96 	  case 'p':
97 	  case 'P':
98 		switch(*++s) {
99 		  case '-':
100 			esign = 1;
101 			/* no break */
102 		  case '+':
103 			s++;
104 		  }
105 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
106 			s = s1;
107 			break;
108 			}
109 		e1 = n - 0x10;
110 		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
111 			if (e1 & 0xf8000000)
112 				big = 1;
113 			e1 = 10*e1 + n - 0x10;
114 			}
115 		if (esign)
116 			e1 = -e1;
117 		e += e1;
118 	  }
119 	*sp = (char*)s;
120 	if (!havedig)
121 		*sp = s0 - 1;
122 	if (zret)
123 		return STRTOG_Zero;
124 	if (big) {
125 		if (esign) {
126 			switch(fpi->rounding) {
127 			  case FPI_Round_up:
128 				if (sign)
129 					break;
130 				goto ret_tiny;
131 			  case FPI_Round_down:
132 				if (!sign)
133 					break;
134 				goto ret_tiny;
135 			  }
136 			goto retz;
137  ret_tiny:
138 			b = Balloc(0);
139 			b->wds = 1;
140 			b->x[0] = 1;
141 			goto dret;
142 			}
143 		switch(fpi->rounding) {
144 		  case FPI_Round_near:
145 			goto ovfl1;
146 		  case FPI_Round_up:
147 			if (!sign)
148 				goto ovfl1;
149 			goto ret_big;
150 		  case FPI_Round_down:
151 			if (sign)
152 				goto ovfl1;
153 			goto ret_big;
154 		  }
155  ret_big:
156 		nbits = fpi->nbits;
157 		n0 = n = nbits >> kshift;
158 		if (nbits & kmask)
159 			++n;
160 		for(j = n, k = 0; j >>= 1; ++k);
161 		*bp = b = Balloc(k);
162 		b->wds = n;
163 		for(j = 0; j < n0; ++j)
164 			b->x[j] = ALL_ON;
165 		if (n > n0)
166 			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
167 		*exp = fpi->emin;
168 		return STRTOG_Normal | STRTOG_Inexlo;
169 		}
170 	n = s1 - s0 - 1;
171 	for(k = 0; n > 7; n >>= 1)
172 		k++;
173 	b = Balloc(k);
174 	x = b->x;
175 	n = 0;
176 	L = 0;
177 	while(s1 > s0) {
178 		if (*--s1 == decimalpoint)
179 			continue;
180 		if (n == 32) {
181 			*x++ = L;
182 			L = 0;
183 			n = 0;
184 			}
185 		L |= (hexdig[*s1] & 0x0f) << n;
186 		n += 4;
187 		}
188 	*x++ = L;
189 	b->wds = n = x - b->x;
190 	n = 32*n - hi0bits(L);
191 	nbits = fpi->nbits;
192 	lostbits = 0;
193 	x = b->x;
194 	if (n > nbits) {
195 		n -= nbits;
196 		if (any_on(b,n)) {
197 			lostbits = 1;
198 			k = n - 1;
199 			if (x[k>>kshift] & 1 << (k & kmask)) {
200 				lostbits = 2;
201 				if (k > 0 && any_on(b,k))
202 					lostbits = 3;
203 				}
204 			}
205 		rshift(b, n);
206 		e += n;
207 		}
208 	else if (n < nbits) {
209 		n = nbits - n;
210 		b = lshift(b, n);
211 		e -= n;
212 		x = b->x;
213 		}
214 	if (e > fpi->emax) {
215  ovfl:
216 		Bfree(b);
217  ovfl1:
218 #ifndef NO_ERRNO
219 		errno = ERANGE;
220 #endif
221 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
222 		}
223 	irv = STRTOG_Normal;
224 	if (e < fpi->emin) {
225 		irv = STRTOG_Denormal;
226 		n = fpi->emin - e;
227 		if (n >= nbits) {
228 			switch (fpi->rounding) {
229 			  case FPI_Round_near:
230 				if (n == nbits && (n < 2 || any_on(b,n-1)))
231 					goto one_bit;
232 				break;
233 			  case FPI_Round_up:
234 				if (!sign)
235 					goto one_bit;
236 				break;
237 			  case FPI_Round_down:
238 				if (sign) {
239  one_bit:
240 					x[0] = b->wds = 1;
241  dret:
242 					*bp = b;
243 					*exp = fpi->emin;
244 #ifndef NO_ERRNO
245 					errno = ERANGE;
246 #endif
247 					return STRTOG_Denormal | STRTOG_Inexhi
248 						| STRTOG_Underflow;
249 					}
250 			  }
251 			Bfree(b);
252  retz:
253 #ifndef NO_ERRNO
254 			errno = ERANGE;
255 #endif
256 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
257 			}
258 		k = n - 1;
259 		if (lostbits)
260 			lostbits = 1;
261 		else if (k > 0)
262 			lostbits = any_on(b,k);
263 		if (x[k>>kshift] & 1 << (k & kmask))
264 			lostbits |= 2;
265 		nbits -= n;
266 		rshift(b,n);
267 		e = fpi->emin;
268 		}
269 	if (lostbits) {
270 		up = 0;
271 		switch(fpi->rounding) {
272 		  case FPI_Round_zero:
273 			break;
274 		  case FPI_Round_near:
275 			if (lostbits & 2
276 			 && (lostbits & 1) | x[0] & 1)
277 				up = 1;
278 			break;
279 		  case FPI_Round_up:
280 			up = 1 - sign;
281 			break;
282 		  case FPI_Round_down:
283 			up = sign;
284 		  }
285 		if (up) {
286 			k = b->wds;
287 			b = increment(b);
288 			x = b->x;
289 			if (irv == STRTOG_Denormal) {
290 				if (nbits == fpi->nbits - 1
291 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
292 					irv =  STRTOG_Normal;
293 				}
294 			else if (b->wds > k
295 			 || (n = nbits & kmask) !=0
296 			     && hi0bits(x[k-1]) < 32-n) {
297 				rshift(b,1);
298 				if (++e > fpi->emax)
299 					goto ovfl;
300 				}
301 			irv |= STRTOG_Inexhi;
302 			}
303 		else
304 			irv |= STRTOG_Inexlo;
305 		}
306 	*bp = b;
307 	*exp = e;
308 	return irv;
309 	}
310