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