xref: /netbsd-src/lib/libc/gdtoa/gethex.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* $NetBSD: gethex.c,v 1.4 2008/03/21 23:13:48 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 unsigned char *decpt, *s0, *s, *s1;
50 	int esign, havedig, irv, k, n, nbits, up, zret;
51 	ULong L, lostbits, *x;
52 	Long e, e1;
53 #ifdef USE_LOCALE
54 	unsigned char decimalpoint = *localeconv()->decimal_point;
55 #else
56 #define decimalpoint '.'
57 #endif
58 
59 	if (!hexdig['0'])
60 		hexdig_init_D2A();
61 	havedig = 0;
62 	s0 = *(CONST unsigned char **)sp + 2;
63 	while(s0[havedig] == '0')
64 		havedig++;
65 	s0 += havedig;
66 	s = s0;
67 	decpt = 0;
68 	zret = 0;
69 	e = 0;
70 	if (!hexdig[*s]) {
71 		zret = 1;
72 		if (*s != decimalpoint)
73 			goto pcheck;
74 		decpt = ++s;
75 		if (!hexdig[*s])
76 			goto pcheck;
77 		while(*s == '0')
78 			s++;
79 		if (hexdig[*s])
80 			zret = 0;
81 		havedig = 1;
82 		s0 = s;
83 		}
84 	while(hexdig[*s])
85 		s++;
86 	if (*s == decimalpoint && !decpt) {
87 		decpt = ++s;
88 		while(hexdig[*s])
89 			s++;
90 		}
91 	if (decpt)
92 		e = -(((Long)(s-decpt)) << 2);
93  pcheck:
94 	s1 = s;
95 	switch(*s) {
96 	  case 'p':
97 	  case 'P':
98 		esign = 0;
99 		switch(*++s) {
100 		  case '-':
101 			esign = 1;
102 			/* FALLTHROUGH */
103 		  case '+':
104 			s++;
105 		  }
106 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
107 			s = s1;
108 			break;
109 			}
110 		e1 = n - 0x10;
111 		while((n = hexdig[*++s]) !=0 && n <= 0x19)
112 			e1 = 10*e1 + n - 0x10;
113 		if (esign)
114 			e1 = -e1;
115 		e += e1;
116 	  }
117 	*sp = __UNCONST(s);
118 	if (zret)
119 		return havedig ? STRTOG_Zero : STRTOG_NoNumber;
120 	n = s1 - s0 - 1;
121 	for(k = 0; n > 7; n = (unsigned int)n >> 1)
122 		k++;
123 	b = Balloc(k);
124 	if (b == NULL)
125 		return STRTOG_NoMemory;
126 	x = b->x;
127 	n = 0;
128 	L = 0;
129 	while(s1 > s0) {
130 		if (*--s1 == decimalpoint)
131 			continue;
132 		if (n == 32) {
133 			*x++ = L;
134 			L = 0;
135 			n = 0;
136 			}
137 		L |= (hexdig[*s1] & 0x0f) << n;
138 		n += 4;
139 		}
140 	*x++ = L;
141 	b->wds = n = x - b->x;
142 	n = 32*n - hi0bits(L);
143 	nbits = fpi->nbits;
144 	lostbits = 0;
145 	x = b->x;
146 	if (n > nbits) {
147 		n -= nbits;
148 		if (any_on(b,n)) {
149 			lostbits = 1;
150 			k = n - 1;
151 			if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
152 				lostbits = 2;
153 				if (k > 1 && any_on(b,k-1))
154 					lostbits = 3;
155 				}
156 			}
157 		rshift(b, n);
158 		e += n;
159 		}
160 	else if (n < nbits) {
161 		n = nbits - n;
162 		b = lshift(b, n);
163 		if (b == NULL)
164 			return STRTOG_NoMemory;
165 		e -= n;
166 		x = b->x;
167 		}
168 	if (e > fpi->emax) {
169  ovfl:
170 		Bfree(b);
171 		*bp = 0;
172 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
173 		}
174 	irv = STRTOG_Normal;
175 	if (e < fpi->emin) {
176 		irv = STRTOG_Denormal;
177 		n = fpi->emin - e;
178 		if (n >= nbits) {
179 			switch (fpi->rounding) {
180 			  case FPI_Round_near:
181 				if (n == nbits && (n < 2 || any_on(b,n-1)))
182 					goto one_bit;
183 				break;
184 			  case FPI_Round_up:
185 				if (!sign)
186 					goto one_bit;
187 				break;
188 			  case FPI_Round_down:
189 				if (sign) {
190  one_bit:
191 					*expt = fpi->emin;
192 					x[0] = b->wds = 1;
193 					*bp = b;
194 					return STRTOG_Denormal | STRTOG_Inexhi
195 						| STRTOG_Underflow;
196 					}
197 			  }
198 			Bfree(b);
199 			*bp = 0;
200 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
201 			}
202 		k = n - 1;
203 		if (lostbits)
204 			lostbits = 1;
205 		else if (k > 0)
206 			lostbits = any_on(b,k);
207 		if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
208 			lostbits |= 2;
209 		nbits -= n;
210 		rshift(b,n);
211 		e = fpi->emin;
212 		}
213 	if (lostbits) {
214 		up = 0;
215 		switch(fpi->rounding) {
216 		  case FPI_Round_zero:
217 			break;
218 		  case FPI_Round_near:
219 			if (lostbits & 2
220 			 && (lostbits & 1) | (x[0] & 1))
221 				up = 1;
222 			break;
223 		  case FPI_Round_up:
224 			up = 1 - sign;
225 			break;
226 		  case FPI_Round_down:
227 			up = sign;
228 		  }
229 		if (up) {
230 			k = b->wds;
231 			b = increment(b);
232 			x = b->x;
233 			if (irv == STRTOG_Denormal) {
234 				if (nbits == fpi->nbits - 1
235 				 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
236 					irv =  STRTOG_Normal;
237 				}
238 			else if (b->wds > k
239 			 || ((n = nbits & kmask) !=0
240 			     && hi0bits(x[k-1]) < 32-n)) {
241 				rshift(b,1);
242 				if (++e > fpi->emax)
243 					goto ovfl;
244 				}
245 			irv |= STRTOG_Inexhi;
246 			}
247 		else
248 			irv |= STRTOG_Inexlo;
249 		}
250 	*bp = b;
251 	*expt = e;
252 	return irv;
253 	}
254