xref: /minix3/lib/libc/gdtoa/gethex.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1 /* $NetBSD: gethex.c,v 1.6 2013/04/19 10:41:53 joerg Exp $ */
2 
3 /****************************************************************
4 
5 The author of this software is David M. Gay.
6 
7 Copyright (C) 1998 by Lucent Technologies
8 All Rights Reserved
9 
10 Permission to use, copy, modify, and distribute this software and
11 its documentation for any purpose and without fee is hereby
12 granted, provided that the above copyright notice appear in all
13 copies and that both that the copyright notice and this
14 permission notice and warranty disclaimer appear in supporting
15 documentation, and that the name of Lucent or any of its entities
16 not be used in advertising or publicity pertaining to
17 distribution of the software without specific, written prior
18 permission.
19 
20 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
22 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
23 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
25 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27 THIS SOFTWARE.
28 
29 ****************************************************************/
30 
31 /* Please send bug reports to David M. Gay (dmg at acm dot org,
32  * with " at " changed at "@" and " dot " changed to ".").	*/
33 
34 #include "gdtoaimp.h"
35 
36 #ifdef USE_LOCALE
37 #include "locale.h"
38 #endif
39 
40  int
gethex(CONST char ** sp,CONST FPI * fpi,Long * expt,Bigint ** bp,int sign,locale_t loc)41 gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign, locale_t loc)
42 {
43 	Bigint *b;
44 	CONST char *decpt, *s, *s0, *s1;
45 	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
46 	ULong L, lostbits, *x;
47 	Long e, e1;
48 #ifdef USE_LOCALE
49 	int i;
50 	const char *decimalpoint = localeconv_l(loc)->decimal_point;
51 #endif
52 
53 	if (!hexdig[(unsigned char)'0'])
54 		hexdig_init_D2A();
55 	*bp = 0;
56 	havedig = 0;
57 	s0 = *(CONST char **)sp + 2;
58 	while(s0[havedig] == '0')
59 		havedig++;
60 	s0 += havedig;
61 	s = s0;
62 	decpt = 0;
63 	zret = 0;
64 	e = 0;
65 	if (hexdig[(unsigned char)*s])
66 		havedig++;
67 	else {
68 		zret = 1;
69 #ifdef USE_LOCALE
70 		for(i = 0; decimalpoint[i]; ++i) {
71 			if (s[i] != decimalpoint[i])
72 				goto pcheck;
73 			}
74 		decpt = s += i;
75 #else
76 		if (*s != '.')
77 			goto pcheck;
78 		decpt = ++s;
79 #endif
80 		if (!hexdig[(unsigned char)*s])
81 			goto pcheck;
82 		while(*s == '0')
83 			s++;
84 		if (hexdig[(unsigned char)*s])
85 			zret = 0;
86 		havedig = 1;
87 		s0 = s;
88 		}
89 	while(hexdig[(unsigned char)*s])
90 		s++;
91 #ifdef USE_LOCALE
92 	if (*s == *decimalpoint && !decpt) {
93 		for(i = 1; decimalpoint[i]; ++i) {
94 			if (s[i] != decimalpoint[i])
95 				goto pcheck;
96 			}
97 		decpt = s += i;
98 #else
99 	if (*s == '.' && !decpt) {
100 		decpt = ++s;
101 #endif
102 		while(hexdig[(unsigned char)*s])
103 			s++;
104 		}/*}*/
105 	if (decpt)
106 		e = -(((Long)(s-decpt)) << 2);
107  pcheck:
108 	s1 = s;
109 	big = esign = 0;
110 	switch(*s) {
111 	  case 'p':
112 	  case 'P':
113 		switch(*++s) {
114 		  case '-':
115 			esign = 1;
116 			/* FALLTHROUGH */
117 		  case '+':
118 			s++;
119 		  }
120 		if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) {
121 			s = s1;
122 			break;
123 			}
124 		e1 = n - 0x10;
125 		while((n = hexdig[(unsigned char)*++s]) !=0 && n <= 0x19) {
126 			if (e1 & 0xf8000000)
127 				big = 1;
128 			e1 = 10*e1 + n - 0x10;
129 			}
130 		if (esign)
131 			e1 = -e1;
132 		e += e1;
133 	  }
134 	*sp = __UNCONST(s);
135 	if (!havedig)
136 		*sp = (char*)__UNCONST(s0) - 1;
137 	if (zret)
138 		return STRTOG_Zero;
139 	if (big) {
140 		if (esign) {
141 			switch(fpi->rounding) {
142 			  case FPI_Round_up:
143 				if (sign)
144 					break;
145 				goto ret_tiny;
146 			  case FPI_Round_down:
147 				if (!sign)
148 					break;
149 				goto ret_tiny;
150 			  }
151 			goto retz;
152  ret_tiny:
153 			b = Balloc(0);
154 			b->wds = 1;
155 			b->x[0] = 1;
156 			goto dret;
157 			}
158 		switch(fpi->rounding) {
159 		  case FPI_Round_near:
160 			goto ovfl1;
161 		  case FPI_Round_up:
162 			if (!sign)
163 				goto ovfl1;
164 			goto ret_big;
165 		  case FPI_Round_down:
166 			if (sign)
167 				goto ovfl1;
168 			goto ret_big;
169 		  }
170  ret_big:
171 		nbits = fpi->nbits;
172 		n0 = n = (unsigned int)nbits >> kshift;
173 		if (nbits & kmask)
174 			++n;
175 		for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k);
176 		*bp = b = Balloc(k);
177 		b->wds = n;
178 		for(j = 0; j < n0; ++j)
179 			b->x[j] = ALL_ON;
180 		if (n > n0)
181 			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
182 		*expt = fpi->emin;
183 		return STRTOG_Normal | STRTOG_Inexlo;
184 		}
185 	n = (int)(s1 - s0) - 1;
186 	for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1)
187 		k++;
188 	b = Balloc(k);
189 	if (b == NULL)
190 		return STRTOG_NoMemory;
191 	x = b->x;
192 	n = 0;
193 	L = 0;
194 #ifdef USE_LOCALE
195 	for(i = 0; decimalpoint[i+1]; ++i);
196 #endif
197 	while(s1 > s0) {
198 #ifdef USE_LOCALE
199 		if (*--s1 == decimalpoint[i]) {
200 			s1 -= i;
201 			continue;
202 			}
203 #else
204 		if (*--s1 == '.')
205 			continue;
206 #endif
207 		if (n == ULbits) {
208 			*x++ = L;
209 			L = 0;
210 			n = 0;
211 			}
212 		L |= (hexdig[(unsigned char)*s1] & 0x0f) << n;
213 		n += 4;
214 		}
215 	*x++ = L;
216 	b->wds = n = (int)(x - b->x);
217 	n = ULbits*n - hi0bits(L);
218 	nbits = fpi->nbits;
219 	lostbits = 0;
220 	x = b->x;
221 	if (n > nbits) {
222 		n -= nbits;
223 		if (any_on(b,n)) {
224 			lostbits = 1;
225 			k = n - 1;
226 			if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
227 				lostbits = 2;
228 				if (k > 0 && any_on(b,k))
229 					lostbits = 3;
230 				}
231 			}
232 		rshift(b, n);
233 		e += n;
234 		}
235 	else if (n < nbits) {
236 		n = nbits - n;
237 		b = lshift(b, n);
238 		if (b == NULL)
239 			return STRTOG_NoMemory;
240 		e -= n;
241 		x = b->x;
242 		}
243 	if (e > fpi->emax) {
244  ovfl:
245 		Bfree(b);
246  ovfl1:
247 #ifndef NO_ERRNO
248 		errno = ERANGE;
249 #endif
250 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
251 		}
252 	irv = STRTOG_Normal;
253 	if (e < fpi->emin) {
254 		irv = STRTOG_Denormal;
255 		n = fpi->emin - e;
256 		if (n >= nbits) {
257 			switch (fpi->rounding) {
258 			  case FPI_Round_near:
259 				if (n == nbits && (n < 2 || any_on(b,n-1)))
260 					goto one_bit;
261 				break;
262 			  case FPI_Round_up:
263 				if (!sign)
264 					goto one_bit;
265 				break;
266 			  case FPI_Round_down:
267 				if (sign) {
268  one_bit:
269 					x[0] = b->wds = 1;
270  dret:
271 					*bp = b;
272 					*expt = fpi->emin;
273 #ifndef NO_ERRNO
274 					errno = ERANGE;
275 #endif
276 					return STRTOG_Denormal | STRTOG_Inexhi
277 						| STRTOG_Underflow;
278 					}
279 			  }
280 			Bfree(b);
281  retz:
282 #ifndef NO_ERRNO
283 			errno = ERANGE;
284 #endif
285 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
286 			}
287 		k = n - 1;
288 		if (lostbits)
289 			lostbits = 1;
290 		else if (k > 0)
291 			lostbits = any_on(b,k);
292 		if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
293 			lostbits |= 2;
294 		nbits -= n;
295 		rshift(b,n);
296 		e = fpi->emin;
297 		}
298 	if (lostbits) {
299 		up = 0;
300 		switch(fpi->rounding) {
301 		  case FPI_Round_zero:
302 			break;
303 		  case FPI_Round_near:
304 			if (lostbits & 2
305 			 && (lostbits | x[0]) & 1)
306 				up = 1;
307 			break;
308 		  case FPI_Round_up:
309 			up = 1 - sign;
310 			break;
311 		  case FPI_Round_down:
312 			up = sign;
313 		  }
314 		if (up) {
315 			k = b->wds;
316 			b = increment(b);
317 			x = b->x;
318 			if (irv == STRTOG_Denormal) {
319 				if (nbits == fpi->nbits - 1
320 				 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
321 					irv =  STRTOG_Normal;
322 				}
323 			else if (b->wds > k
324 			 || ((n = nbits & kmask) !=0
325 			      && hi0bits(x[k-1]) < 32-n)) {
326 				rshift(b,1);
327 				if (++e > fpi->emax)
328 					goto ovfl;
329 				}
330 			irv |= STRTOG_Inexhi;
331 			}
332 		else
333 			irv |= STRTOG_Inexlo;
334 		}
335 	*bp = b;
336 	*expt = e;
337 	return irv;
338 	}
339