gethex.c revision 112620
1112158Sdas/****************************************************************
2112158Sdas
3112158SdasThe author of this software is David M. Gay.
4112158Sdas
5112158SdasCopyright (C) 1998 by Lucent Technologies
6112158SdasAll Rights Reserved
7112158Sdas
8112158SdasPermission to use, copy, modify, and distribute this software and
9112158Sdasits documentation for any purpose and without fee is hereby
10112158Sdasgranted, provided that the above copyright notice appear in all
11112158Sdascopies and that both that the copyright notice and this
12112158Sdaspermission notice and warranty disclaimer appear in supporting
13112158Sdasdocumentation, and that the name of Lucent or any of its entities
14112158Sdasnot be used in advertising or publicity pertaining to
15112158Sdasdistribution of the software without specific, written prior
16112158Sdaspermission.
17112158Sdas
18112158SdasLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19112158SdasINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20112158SdasIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21112158SdasSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22112158SdasWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23112158SdasIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24112158SdasARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25112158SdasTHIS SOFTWARE.
26112158Sdas
27112158Sdas****************************************************************/
28112158Sdas
29112158Sdas/* Please send bug reports to
30112158Sdas	David M. Gay
31112620Sdas	dmg@acm.org
32112158Sdas */
33112158Sdas
34112158Sdas#include "gdtoaimp.h"
35112158Sdas
36112620Sdas#ifdef USE_LOCALE
37112620Sdas#include "locale.h"
38112620Sdas#endif
39112620Sdas
40112158Sdas int
41112158Sdas#ifdef KR_headers
42112158Sdasgethex(sp, fpi, exp, bp, sign)
43112158Sdas	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
44112158Sdas#else
45112158Sdasgethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
46112158Sdas#endif
47112158Sdas{
48112158Sdas	Bigint *b;
49112158Sdas	CONST unsigned char *decpt, *s0, *s, *s1;
50112158Sdas	int esign, havedig, irv, k, n, nbits, up;
51112158Sdas	ULong L, lostbits, *x;
52112158Sdas	Long e, e1;
53112620Sdas#ifdef USE_LOCALE
54112620Sdas	char decimalpoint = *localeconv()->decimal_point;
55112620Sdas#else
56112620Sdas#define decimalpoint '.'
57112620Sdas#endif
58112158Sdas
59112158Sdas	if (!hexdig['0'])
60112158Sdas		hexdig_init_D2A();
61112158Sdas	havedig = 0;
62112158Sdas	s0 = *(CONST unsigned char **)sp + 2;
63112158Sdas	while(s0[havedig] == '0')
64112158Sdas		havedig++;
65112158Sdas	s0 += havedig;
66112158Sdas	s = s0;
67112158Sdas	decpt = 0;
68112158Sdas	if (!hexdig[*s]) {
69112620Sdas		if (*s == decimalpoint) {
70112158Sdas			decpt = ++s;
71112158Sdas			if (!hexdig[*s])
72112158Sdas				goto ret0;
73112158Sdas			}
74112158Sdas		else {
75112158Sdas ret0:
76112158Sdas			*sp = (char*)s;
77112158Sdas			return havedig ? STRTOG_Zero : STRTOG_NoNumber;
78112158Sdas			}
79112158Sdas		while(*s == '0')
80112158Sdas			s++;
81112158Sdas		havedig = 1;
82112158Sdas		if (!hexdig[*s])
83112158Sdas			goto ret0;
84112158Sdas		s0 = s;
85112158Sdas		}
86112158Sdas	while(hexdig[*s])
87112158Sdas		s++;
88112620Sdas	if (*s == decimalpoint && !decpt) {
89112158Sdas		decpt = ++s;
90112158Sdas		while(hexdig[*s])
91112158Sdas			s++;
92112158Sdas		}
93112158Sdas	e = 0;
94112158Sdas	if (decpt)
95112158Sdas		e = -(((Long)(s-decpt)) << 2);
96112158Sdas	s1 = s;
97112158Sdas	switch(*s) {
98112158Sdas	  case 'p':
99112158Sdas	  case 'P':
100112158Sdas		esign = 0;
101112158Sdas		switch(*++s) {
102112158Sdas		  case '-':
103112158Sdas			esign = 1;
104112158Sdas			/* no break */
105112158Sdas		  case '+':
106112158Sdas			s++;
107112158Sdas		  }
108112158Sdas		if ((n = hexdig[*s]) == 0 || n > 0x19) {
109112158Sdas			s = s1;
110112158Sdas			break;
111112158Sdas			}
112112158Sdas		e1 = n - 0x10;
113112158Sdas		while((n = hexdig[*++s]) !=0 && n <= 0x19)
114112158Sdas			e1 = 10*e1 + n - 0x10;
115112158Sdas		if (esign)
116112158Sdas			e1 = -e1;
117112158Sdas		e += e1;
118112158Sdas	  }
119112158Sdas	*sp = (char*)s;
120112158Sdas	n = s1 - s0 - 1;
121112158Sdas	for(k = 0; n > 7; n >>= 1)
122112158Sdas		k++;
123112158Sdas	b = Balloc(k);
124112158Sdas	x = b->x;
125112158Sdas	n = 0;
126112158Sdas	L = 0;
127112158Sdas	while(s1 > s0) {
128112620Sdas		if (*--s1 == decimalpoint)
129112158Sdas			continue;
130112158Sdas		if (n == 32) {
131112158Sdas			*x++ = L;
132112158Sdas			L = 0;
133112158Sdas			n = 0;
134112158Sdas			}
135112158Sdas		L |= (hexdig[*s1] & 0x0f) << n;
136112158Sdas		n += 4;
137112158Sdas		}
138112158Sdas	*x++ = L;
139112158Sdas	b->wds = n = x - b->x;
140112158Sdas	n = 32*n - hi0bits(L);
141112158Sdas	nbits = fpi->nbits;
142112158Sdas	lostbits = 0;
143112158Sdas	x = b->x;
144112158Sdas	if (n > nbits) {
145112158Sdas		n -= nbits;
146112158Sdas		if (any_on(b,n)) {
147112158Sdas			lostbits = 1;
148112158Sdas			k = n - 1;
149112158Sdas			if (x[k>>kshift] & 1 << (k & kmask)) {
150112158Sdas				lostbits = 2;
151112158Sdas				if (k > 1 && any_on(b,k-1))
152112158Sdas					lostbits = 3;
153112158Sdas				}
154112158Sdas			}
155112158Sdas		rshift(b, n);
156112158Sdas		e += n;
157112158Sdas		}
158112158Sdas	else if (n < nbits) {
159112158Sdas		n = nbits - n;
160112158Sdas		b = lshift(b, n);
161112158Sdas		e -= n;
162112158Sdas		x = b->x;
163112158Sdas		}
164112158Sdas	if (e > fpi->emax) {
165112158Sdas ovfl:
166112158Sdas		Bfree(b);
167112158Sdas		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
168112158Sdas		}
169112158Sdas	irv = STRTOG_Normal;
170112158Sdas	if (e < fpi->emin) {
171112158Sdas		irv = STRTOG_Denormal;
172112158Sdas		n = fpi->emin - e;
173112158Sdas		if (n >= nbits) {
174112158Sdas			switch (fpi->rounding) {
175112158Sdas			  case FPI_Round_near:
176112158Sdas				if (n == nbits && n < 2 || any_on(b,n-1))
177112158Sdas					goto one_bit;
178112158Sdas				break;
179112158Sdas			  case FPI_Round_up:
180112158Sdas				if (!sign)
181112158Sdas					goto one_bit;
182112158Sdas				break;
183112158Sdas			  case FPI_Round_down:
184112158Sdas				if (sign) {
185112158Sdas one_bit:
186112158Sdas					*exp = fpi->emin;
187112158Sdas					x[0] = b->wds = 1;
188112158Sdas					*bp = b;
189112158Sdas					return STRTOG_Denormal | STRTOG_Inexhi
190112158Sdas						| STRTOG_Underflow;
191112158Sdas					}
192112158Sdas			  }
193112158Sdas			Bfree(b);
194112158Sdas			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
195112158Sdas			}
196112158Sdas		k = n - 1;
197112158Sdas		if (lostbits)
198112158Sdas			lostbits = 1;
199112158Sdas		else if (k > 0)
200112158Sdas			lostbits = any_on(b,k);
201112158Sdas		if (x[k>>kshift] & 1 << (k & kmask))
202112158Sdas			lostbits |= 2;
203112158Sdas		nbits -= n;
204112158Sdas		rshift(b,n);
205112158Sdas		e = fpi->emin;
206112158Sdas		}
207112158Sdas	if (lostbits) {
208112158Sdas		up = 0;
209112158Sdas		switch(fpi->rounding) {
210112158Sdas		  case FPI_Round_zero:
211112158Sdas			break;
212112158Sdas		  case FPI_Round_near:
213112158Sdas			if (lostbits & 2
214112158Sdas			 && (lostbits & 1) | x[0] & 1)
215112158Sdas				up = 1;
216112158Sdas			break;
217112158Sdas		  case FPI_Round_up:
218112158Sdas			up = 1 - sign;
219112158Sdas			break;
220112158Sdas		  case FPI_Round_down:
221112158Sdas			up = sign;
222112158Sdas		  }
223112158Sdas		if (up) {
224112158Sdas			k = b->wds;
225112158Sdas			b = increment(b);
226112158Sdas			x = b->x;
227112158Sdas			if (b->wds > k
228112158Sdas			 || (n = nbits & kmask) !=0
229112158Sdas			     && hi0bits(x[k-1]) < 32-n) {
230112158Sdas				rshift(b,1);
231112158Sdas				if (++e > fpi->emax)
232112158Sdas					goto ovfl;
233112158Sdas				}
234112158Sdas			else if (irv == STRTOG_Denormal) {
235112158Sdas				k = nbits - 1;
236112158Sdas				if (x[k >> kshift] & 1 << (k & kmask))
237112158Sdas					irv = STRTOG_Normal;
238112158Sdas				}
239112158Sdas			irv |= STRTOG_Inexhi;
240112158Sdas			}
241112158Sdas		else
242112158Sdas			irv |= STRTOG_Inexlo;
243112158Sdas		}
244112158Sdas	*bp = b;
245112158Sdas	*exp = e;
246112158Sdas	return irv;
247112158Sdas	}
248