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