gethex.c revision 182709
1/****************************************************************
2
3The author of this software is David M. Gay.
4
5Copyright (C) 1998 by Lucent Technologies
6All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and
9its documentation for any purpose and without fee is hereby
10granted, provided that the above copyright notice appear in all
11copies and that both that the copyright notice and this
12permission notice and warranty disclaimer appear in supporting
13documentation, and that the name of Lucent or any of its entities
14not be used in advertising or publicity pertaining to
15distribution of the software without specific, written prior
16permission.
17
18LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25THIS 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
40gethex(sp, fpi, exp, bp, sign)
41	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
42#else
43gethex( 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	unsigned char decimalpoint = *localeconv()->decimal_point;
53#else
54#define decimalpoint '.'
55#endif
56
57	if (!hexdig['0'])
58		hexdig_init_D2A();
59	*bp = 0;
60	havedig = 0;
61	s0 = *(CONST unsigned char **)sp + 2;
62	while(s0[havedig] == '0')
63		havedig++;
64	s0 += havedig;
65	s = s0;
66	decpt = 0;
67	zret = 0;
68	e = 0;
69	if (!hexdig[*s]) {
70		zret = 1;
71		if (*s != decimalpoint)
72			goto pcheck;
73		decpt = ++s;
74		if (!hexdig[*s])
75			goto pcheck;
76		while(*s == '0')
77			s++;
78		if (hexdig[*s])
79			zret = 0;
80		havedig = 1;
81		s0 = s;
82		}
83	while(hexdig[*s])
84		s++;
85	if (*s == decimalpoint && !decpt) {
86		decpt = ++s;
87		while(hexdig[*s])
88			s++;
89		}
90	if (decpt)
91		e = -(((Long)(s-decpt)) << 2);
92 pcheck:
93	s1 = s;
94	big = esign = 0;
95	switch(*s) {
96	  case 'p':
97	  case 'P':
98		switch(*++s) {
99		  case '-':
100			esign = 1;
101			/* no break */
102		  case '+':
103			s++;
104		  }
105		if ((n = hexdig[*s]) == 0 || n > 0x19) {
106			s = s1;
107			break;
108			}
109		e1 = n - 0x10;
110		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
111			if (e1 & 0xf8000000)
112				big = 1;
113			e1 = 10*e1 + n - 0x10;
114			}
115		if (esign)
116			e1 = -e1;
117		e += e1;
118	  }
119	*sp = (char*)s;
120	if (!havedig)
121		*sp = s0 - 1;
122	if (zret)
123		return STRTOG_Zero;
124	if (big) {
125		if (esign) {
126			switch(fpi->rounding) {
127			  case FPI_Round_up:
128				if (sign)
129					break;
130				goto ret_tiny;
131			  case FPI_Round_down:
132				if (!sign)
133					break;
134				goto ret_tiny;
135			  }
136			goto retz;
137 ret_tiny:
138			b = Balloc(0);
139			b->wds = 1;
140			b->x[0] = 1;
141			goto dret;
142			}
143		switch(fpi->rounding) {
144		  case FPI_Round_near:
145			goto ovfl1;
146		  case FPI_Round_up:
147			if (!sign)
148				goto ovfl1;
149			goto ret_big;
150		  case FPI_Round_down:
151			if (sign)
152				goto ovfl1;
153			goto ret_big;
154		  }
155 ret_big:
156		nbits = fpi->nbits;
157		n0 = n = nbits >> kshift;
158		if (nbits & kmask)
159			++n;
160		for(j = n, k = 0; j >>= 1; ++k);
161		*bp = b = Balloc(k);
162		b->wds = n;
163		for(j = 0; j < n0; ++j)
164			b->x[j] = ALL_ON;
165		if (n > n0)
166			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
167		*exp = fpi->emin;
168		return STRTOG_Normal | STRTOG_Inexlo;
169		}
170	n = s1 - s0 - 1;
171	for(k = 0; n > 7; n >>= 1)
172		k++;
173	b = Balloc(k);
174	x = b->x;
175	n = 0;
176	L = 0;
177	while(s1 > s0) {
178		if (*--s1 == decimalpoint)
179			continue;
180		if (n == 32) {
181			*x++ = L;
182			L = 0;
183			n = 0;
184			}
185		L |= (hexdig[*s1] & 0x0f) << n;
186		n += 4;
187		}
188	*x++ = L;
189	b->wds = n = x - b->x;
190	n = 32*n - hi0bits(L);
191	nbits = fpi->nbits;
192	lostbits = 0;
193	x = b->x;
194	if (n > nbits) {
195		n -= nbits;
196		if (any_on(b,n)) {
197			lostbits = 1;
198			k = n - 1;
199			if (x[k>>kshift] & 1 << (k & kmask)) {
200				lostbits = 2;
201				if (k > 0 && any_on(b,k))
202					lostbits = 3;
203				}
204			}
205		rshift(b, n);
206		e += n;
207		}
208	else if (n < nbits) {
209		n = nbits - n;
210		b = lshift(b, n);
211		e -= n;
212		x = b->x;
213		}
214	if (e > fpi->emax) {
215 ovfl:
216		Bfree(b);
217 ovfl1:
218#ifndef NO_ERRNO
219		errno = ERANGE;
220#endif
221		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
222		}
223	irv = STRTOG_Normal;
224	if (e < fpi->emin) {
225		irv = STRTOG_Denormal;
226		n = fpi->emin - e;
227		if (n >= nbits) {
228			switch (fpi->rounding) {
229			  case FPI_Round_near:
230				if (n == nbits && (n < 2 || any_on(b,n-1)))
231					goto one_bit;
232				break;
233			  case FPI_Round_up:
234				if (!sign)
235					goto one_bit;
236				break;
237			  case FPI_Round_down:
238				if (sign) {
239 one_bit:
240					x[0] = b->wds = 1;
241 dret:
242					*bp = b;
243					*exp = fpi->emin;
244#ifndef NO_ERRNO
245					errno = ERANGE;
246#endif
247					return STRTOG_Denormal | STRTOG_Inexhi
248						| STRTOG_Underflow;
249					}
250			  }
251			Bfree(b);
252 retz:
253#ifndef NO_ERRNO
254			errno = ERANGE;
255#endif
256			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
257			}
258		k = n - 1;
259		if (lostbits)
260			lostbits = 1;
261		else if (k > 0)
262			lostbits = any_on(b,k);
263		if (x[k>>kshift] & 1 << (k & kmask))
264			lostbits |= 2;
265		nbits -= n;
266		rshift(b,n);
267		e = fpi->emin;
268		}
269	if (lostbits) {
270		up = 0;
271		switch(fpi->rounding) {
272		  case FPI_Round_zero:
273			break;
274		  case FPI_Round_near:
275			if (lostbits & 2
276			 && (lostbits & 1) | x[0] & 1)
277				up = 1;
278			break;
279		  case FPI_Round_up:
280			up = 1 - sign;
281			break;
282		  case FPI_Round_down:
283			up = sign;
284		  }
285		if (up) {
286			k = b->wds;
287			b = increment(b);
288			x = b->x;
289			if (irv == STRTOG_Denormal) {
290				if (nbits == fpi->nbits - 1
291				 && x[nbits >> kshift] & 1 << (nbits & kmask))
292					irv =  STRTOG_Normal;
293				}
294			else if (b->wds > k
295			 || (n = nbits & kmask) !=0
296			     && hi0bits(x[k-1]) < 32-n) {
297				rshift(b,1);
298				if (++e > fpi->emax)
299					goto ovfl;
300				}
301			irv |= STRTOG_Inexhi;
302			}
303		else
304			irv |= STRTOG_Inexlo;
305		}
306	*bp = b;
307	*exp = e;
308	return irv;
309	}
310