xref: /netbsd-src/lib/libc/gdtoa/gethex.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /* $NetBSD: gethex.c,v 1.5 2011/03/20 23:15:35 christos 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
41 #ifdef KR_headers
42 gethex(sp, fpi, expt, bp, sign)
43 	CONST char **sp; CONST FPI *fpi; Long *expt; Bigint **bp; int sign;
44 #else
45 gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign)
46 #endif
47 {
48 	Bigint *b;
49 	CONST char *decpt, *s, *s0, *s1;
50 	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
51 	ULong L, lostbits, *x;
52 	Long e, e1;
53 #ifdef USE_LOCALE
54 	int i;
55 #ifdef NO_LOCALE_CACHE
56 	const char *decimalpoint = localeconv()->decimal_point;
57 #else
58 	const unsigned char *decimalpoint;
59 	static char *decimalpoint_cache;
60 	if (!(s0 = decimalpoint_cache)) {
61 		s0 = localeconv()->decimal_point;
62 		if ((decimalpoint_cache = MALLOC(strlen(s0) + 1)) != NULL) {
63 			strcpy(decimalpoint_cache, s0);
64 			s0 = decimalpoint_cache;
65 			}
66 		}
67 	decimalpoint = __UNCONST(s0);
68 #endif
69 #endif
70 
71 	if (!hexdig[(unsigned char)'0'])
72 		hexdig_init_D2A();
73 	*bp = 0;
74 	havedig = 0;
75 	s0 = *(CONST char **)sp + 2;
76 	while(s0[havedig] == '0')
77 		havedig++;
78 	s0 += havedig;
79 	s = s0;
80 	decpt = 0;
81 	zret = 0;
82 	e = 0;
83 	if (hexdig[(unsigned char)*s])
84 		havedig++;
85 	else {
86 		zret = 1;
87 #ifdef USE_LOCALE
88 		for(i = 0; decimalpoint[i]; ++i) {
89 			if (s[i] != decimalpoint[i])
90 				goto pcheck;
91 			}
92 		decpt = s += i;
93 #else
94 		if (*s != '.')
95 			goto pcheck;
96 		decpt = ++s;
97 #endif
98 		if (!hexdig[(unsigned char)*s])
99 			goto pcheck;
100 		while(*s == '0')
101 			s++;
102 		if (hexdig[(unsigned char)*s])
103 			zret = 0;
104 		havedig = 1;
105 		s0 = s;
106 		}
107 	while(hexdig[(unsigned char)*s])
108 		s++;
109 #ifdef USE_LOCALE
110 	if (*s == *decimalpoint && !decpt) {
111 		for(i = 1; decimalpoint[i]; ++i) {
112 			if (s[i] != decimalpoint[i])
113 				goto pcheck;
114 			}
115 		decpt = s += i;
116 #else
117 	if (*s == '.' && !decpt) {
118 		decpt = ++s;
119 #endif
120 		while(hexdig[(unsigned char)*s])
121 			s++;
122 		}/*}*/
123 	if (decpt)
124 		e = -(((Long)(s-decpt)) << 2);
125  pcheck:
126 	s1 = s;
127 	big = esign = 0;
128 	switch(*s) {
129 	  case 'p':
130 	  case 'P':
131 		switch(*++s) {
132 		  case '-':
133 			esign = 1;
134 			/* FALLTHROUGH */
135 		  case '+':
136 			s++;
137 		  }
138 		if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) {
139 			s = s1;
140 			break;
141 			}
142 		e1 = n - 0x10;
143 		while((n = hexdig[(unsigned char)*++s]) !=0 && n <= 0x19) {
144 			if (e1 & 0xf8000000)
145 				big = 1;
146 			e1 = 10*e1 + n - 0x10;
147 			}
148 		if (esign)
149 			e1 = -e1;
150 		e += e1;
151 	  }
152 	*sp = __UNCONST(s);
153 	if (!havedig)
154 		*sp = (char*)__UNCONST(s0) - 1;
155 	if (zret)
156 		return STRTOG_Zero;
157 	if (big) {
158 		if (esign) {
159 			switch(fpi->rounding) {
160 			  case FPI_Round_up:
161 				if (sign)
162 					break;
163 				goto ret_tiny;
164 			  case FPI_Round_down:
165 				if (!sign)
166 					break;
167 				goto ret_tiny;
168 			  }
169 			goto retz;
170  ret_tiny:
171 			b = Balloc(0);
172 			b->wds = 1;
173 			b->x[0] = 1;
174 			goto dret;
175 			}
176 		switch(fpi->rounding) {
177 		  case FPI_Round_near:
178 			goto ovfl1;
179 		  case FPI_Round_up:
180 			if (!sign)
181 				goto ovfl1;
182 			goto ret_big;
183 		  case FPI_Round_down:
184 			if (sign)
185 				goto ovfl1;
186 			goto ret_big;
187 		  }
188  ret_big:
189 		nbits = fpi->nbits;
190 		n0 = n = (unsigned int)nbits >> kshift;
191 		if (nbits & kmask)
192 			++n;
193 		for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k);
194 		*bp = b = Balloc(k);
195 		b->wds = n;
196 		for(j = 0; j < n0; ++j)
197 			b->x[j] = ALL_ON;
198 		if (n > n0)
199 			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
200 		*expt = fpi->emin;
201 		return STRTOG_Normal | STRTOG_Inexlo;
202 		}
203 	n = (int)(s1 - s0) - 1;
204 	for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1)
205 		k++;
206 	b = Balloc(k);
207 	if (b == NULL)
208 		return STRTOG_NoMemory;
209 	x = b->x;
210 	n = 0;
211 	L = 0;
212 #ifdef USE_LOCALE
213 	for(i = 0; decimalpoint[i+1]; ++i);
214 #endif
215 	while(s1 > s0) {
216 #ifdef USE_LOCALE
217 		if (*--s1 == decimalpoint[i]) {
218 			s1 -= i;
219 			continue;
220 			}
221 #else
222 		if (*--s1 == '.')
223 			continue;
224 #endif
225 		if (n == ULbits) {
226 			*x++ = L;
227 			L = 0;
228 			n = 0;
229 			}
230 		L |= (hexdig[(unsigned char)*s1] & 0x0f) << n;
231 		n += 4;
232 		}
233 	*x++ = L;
234 	b->wds = n = (int)(x - b->x);
235 	n = ULbits*n - hi0bits(L);
236 	nbits = fpi->nbits;
237 	lostbits = 0;
238 	x = b->x;
239 	if (n > nbits) {
240 		n -= nbits;
241 		if (any_on(b,n)) {
242 			lostbits = 1;
243 			k = n - 1;
244 			if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
245 				lostbits = 2;
246 				if (k > 0 && any_on(b,k))
247 					lostbits = 3;
248 				}
249 			}
250 		rshift(b, n);
251 		e += n;
252 		}
253 	else if (n < nbits) {
254 		n = nbits - n;
255 		b = lshift(b, n);
256 		if (b == NULL)
257 			return STRTOG_NoMemory;
258 		e -= n;
259 		x = b->x;
260 		}
261 	if (e > fpi->emax) {
262  ovfl:
263 		Bfree(b);
264  ovfl1:
265 #ifndef NO_ERRNO
266 		errno = ERANGE;
267 #endif
268 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
269 		}
270 	irv = STRTOG_Normal;
271 	if (e < fpi->emin) {
272 		irv = STRTOG_Denormal;
273 		n = fpi->emin - e;
274 		if (n >= nbits) {
275 			switch (fpi->rounding) {
276 			  case FPI_Round_near:
277 				if (n == nbits && (n < 2 || any_on(b,n-1)))
278 					goto one_bit;
279 				break;
280 			  case FPI_Round_up:
281 				if (!sign)
282 					goto one_bit;
283 				break;
284 			  case FPI_Round_down:
285 				if (sign) {
286  one_bit:
287 					x[0] = b->wds = 1;
288  dret:
289 					*bp = b;
290 					*expt = fpi->emin;
291 #ifndef NO_ERRNO
292 					errno = ERANGE;
293 #endif
294 					return STRTOG_Denormal | STRTOG_Inexhi
295 						| STRTOG_Underflow;
296 					}
297 			  }
298 			Bfree(b);
299  retz:
300 #ifndef NO_ERRNO
301 			errno = ERANGE;
302 #endif
303 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
304 			}
305 		k = n - 1;
306 		if (lostbits)
307 			lostbits = 1;
308 		else if (k > 0)
309 			lostbits = any_on(b,k);
310 		if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
311 			lostbits |= 2;
312 		nbits -= n;
313 		rshift(b,n);
314 		e = fpi->emin;
315 		}
316 	if (lostbits) {
317 		up = 0;
318 		switch(fpi->rounding) {
319 		  case FPI_Round_zero:
320 			break;
321 		  case FPI_Round_near:
322 			if (lostbits & 2
323 			 && (lostbits | x[0]) & 1)
324 				up = 1;
325 			break;
326 		  case FPI_Round_up:
327 			up = 1 - sign;
328 			break;
329 		  case FPI_Round_down:
330 			up = sign;
331 		  }
332 		if (up) {
333 			k = b->wds;
334 			b = increment(b);
335 			x = b->x;
336 			if (irv == STRTOG_Denormal) {
337 				if (nbits == fpi->nbits - 1
338 				 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
339 					irv =  STRTOG_Normal;
340 				}
341 			else if (b->wds > k
342 			 || ((n = nbits & kmask) !=0
343 			      && hi0bits(x[k-1]) < 32-n)) {
344 				rshift(b,1);
345 				if (++e > fpi->emax)
346 					goto ovfl;
347 				}
348 			irv |= STRTOG_Inexhi;
349 			}
350 		else
351 			irv |= STRTOG_Inexlo;
352 		}
353 	*bp = b;
354 	*expt = e;
355 	return irv;
356 	}
357