gethex.c revision 112620
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
30	David M. Gay
31	dmg@acm.org
32 */
33
34#include "gdtoaimp.h"
35
36#ifdef USE_LOCALE
37#include "locale.h"
38#endif
39
40 int
41#ifdef KR_headers
42gethex(sp, fpi, exp, bp, sign)
43	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
44#else
45gethex( CONST char **sp, FPI *fpi, Long *exp, 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;
51	ULong L, lostbits, *x;
52	Long e, e1;
53#ifdef USE_LOCALE
54	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	if (!hexdig[*s]) {
69		if (*s == decimalpoint) {
70			decpt = ++s;
71			if (!hexdig[*s])
72				goto ret0;
73			}
74		else {
75 ret0:
76			*sp = (char*)s;
77			return havedig ? STRTOG_Zero : STRTOG_NoNumber;
78			}
79		while(*s == '0')
80			s++;
81		havedig = 1;
82		if (!hexdig[*s])
83			goto ret0;
84		s0 = s;
85		}
86	while(hexdig[*s])
87		s++;
88	if (*s == decimalpoint && !decpt) {
89		decpt = ++s;
90		while(hexdig[*s])
91			s++;
92		}
93	e = 0;
94	if (decpt)
95		e = -(((Long)(s-decpt)) << 2);
96	s1 = s;
97	switch(*s) {
98	  case 'p':
99	  case 'P':
100		esign = 0;
101		switch(*++s) {
102		  case '-':
103			esign = 1;
104			/* no break */
105		  case '+':
106			s++;
107		  }
108		if ((n = hexdig[*s]) == 0 || n > 0x19) {
109			s = s1;
110			break;
111			}
112		e1 = n - 0x10;
113		while((n = hexdig[*++s]) !=0 && n <= 0x19)
114			e1 = 10*e1 + n - 0x10;
115		if (esign)
116			e1 = -e1;
117		e += e1;
118	  }
119	*sp = (char*)s;
120	n = s1 - s0 - 1;
121	for(k = 0; n > 7; n >>= 1)
122		k++;
123	b = Balloc(k);
124	x = b->x;
125	n = 0;
126	L = 0;
127	while(s1 > s0) {
128		if (*--s1 == decimalpoint)
129			continue;
130		if (n == 32) {
131			*x++ = L;
132			L = 0;
133			n = 0;
134			}
135		L |= (hexdig[*s1] & 0x0f) << n;
136		n += 4;
137		}
138	*x++ = L;
139	b->wds = n = x - b->x;
140	n = 32*n - hi0bits(L);
141	nbits = fpi->nbits;
142	lostbits = 0;
143	x = b->x;
144	if (n > nbits) {
145		n -= nbits;
146		if (any_on(b,n)) {
147			lostbits = 1;
148			k = n - 1;
149			if (x[k>>kshift] & 1 << (k & kmask)) {
150				lostbits = 2;
151				if (k > 1 && any_on(b,k-1))
152					lostbits = 3;
153				}
154			}
155		rshift(b, n);
156		e += n;
157		}
158	else if (n < nbits) {
159		n = nbits - n;
160		b = lshift(b, n);
161		e -= n;
162		x = b->x;
163		}
164	if (e > fpi->emax) {
165 ovfl:
166		Bfree(b);
167		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
168		}
169	irv = STRTOG_Normal;
170	if (e < fpi->emin) {
171		irv = STRTOG_Denormal;
172		n = fpi->emin - e;
173		if (n >= nbits) {
174			switch (fpi->rounding) {
175			  case FPI_Round_near:
176				if (n == nbits && n < 2 || any_on(b,n-1))
177					goto one_bit;
178				break;
179			  case FPI_Round_up:
180				if (!sign)
181					goto one_bit;
182				break;
183			  case FPI_Round_down:
184				if (sign) {
185 one_bit:
186					*exp = fpi->emin;
187					x[0] = b->wds = 1;
188					*bp = b;
189					return STRTOG_Denormal | STRTOG_Inexhi
190						| STRTOG_Underflow;
191					}
192			  }
193			Bfree(b);
194			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
195			}
196		k = n - 1;
197		if (lostbits)
198			lostbits = 1;
199		else if (k > 0)
200			lostbits = any_on(b,k);
201		if (x[k>>kshift] & 1 << (k & kmask))
202			lostbits |= 2;
203		nbits -= n;
204		rshift(b,n);
205		e = fpi->emin;
206		}
207	if (lostbits) {
208		up = 0;
209		switch(fpi->rounding) {
210		  case FPI_Round_zero:
211			break;
212		  case FPI_Round_near:
213			if (lostbits & 2
214			 && (lostbits & 1) | x[0] & 1)
215				up = 1;
216			break;
217		  case FPI_Round_up:
218			up = 1 - sign;
219			break;
220		  case FPI_Round_down:
221			up = sign;
222		  }
223		if (up) {
224			k = b->wds;
225			b = increment(b);
226			x = b->x;
227			if (b->wds > k
228			 || (n = nbits & kmask) !=0
229			     && hi0bits(x[k-1]) < 32-n) {
230				rshift(b,1);
231				if (++e > fpi->emax)
232					goto ovfl;
233				}
234			else if (irv == STRTOG_Denormal) {
235				k = nbits - 1;
236				if (x[k >> kshift] & 1 << (k & kmask))
237					irv = STRTOG_Normal;
238				}
239			irv |= STRTOG_Inexhi;
240			}
241		else
242			irv |= STRTOG_Inexlo;
243		}
244	*bp = b;
245	*exp = e;
246	return irv;
247	}
248