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