gethex.c revision 165743
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 esign, havedig, irv, k, n, 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	havedig = 0;
60	s0 = *(CONST unsigned char **)sp + 2;
61	while(s0[havedig] == '0')
62		havedig++;
63	s0 += havedig;
64	s = s0;
65	decpt = 0;
66	zret = 0;
67	e = 0;
68	if (!hexdig[*s]) {
69		zret = 1;
70		if (*s != decimalpoint)
71			goto pcheck;
72		decpt = ++s;
73		if (!hexdig[*s])
74			goto pcheck;
75		while(*s == '0')
76			s++;
77		if (hexdig[*s])
78			zret = 0;
79		havedig = 1;
80		s0 = s;
81		}
82	while(hexdig[*s])
83		s++;
84	if (*s == decimalpoint && !decpt) {
85		decpt = ++s;
86		while(hexdig[*s])
87			s++;
88		}
89	if (decpt)
90		e = -(((Long)(s-decpt)) << 2);
91 pcheck:
92	s1 = s;
93	switch(*s) {
94	  case 'p':
95	  case 'P':
96		esign = 0;
97		switch(*++s) {
98		  case '-':
99			esign = 1;
100			/* no break */
101		  case '+':
102			s++;
103		  }
104		if ((n = hexdig[*s]) == 0 || n > 0x19) {
105			s = s1;
106			break;
107			}
108		e1 = n - 0x10;
109		while((n = hexdig[*++s]) !=0 && n <= 0x19)
110			e1 = 10*e1 + n - 0x10;
111		if (esign)
112			e1 = -e1;
113		e += e1;
114	  }
115	*sp = (char*)s;
116	if (zret)
117		return havedig ? STRTOG_Zero : STRTOG_NoNumber;
118	n = s1 - s0 - 1;
119	for(k = 0; n > 7; n >>= 1)
120		k++;
121	b = Balloc(k);
122	x = b->x;
123	n = 0;
124	L = 0;
125	while(s1 > s0) {
126		if (*--s1 == decimalpoint)
127			continue;
128		if (n == 32) {
129			*x++ = L;
130			L = 0;
131			n = 0;
132			}
133		L |= (hexdig[*s1] & 0x0f) << n;
134		n += 4;
135		}
136	*x++ = L;
137	b->wds = n = x - b->x;
138	n = 32*n - hi0bits(L);
139	nbits = fpi->nbits;
140	lostbits = 0;
141	x = b->x;
142	if (n > nbits) {
143		n -= nbits;
144		if (any_on(b,n)) {
145			lostbits = 1;
146			k = n - 1;
147			if (x[k>>kshift] & 1 << (k & kmask)) {
148				lostbits = 2;
149				if (k > 1 && any_on(b,k-1))
150					lostbits = 3;
151				}
152			}
153		rshift(b, n);
154		e += n;
155		}
156	else if (n < nbits) {
157		n = nbits - n;
158		b = lshift(b, n);
159		e -= n;
160		x = b->x;
161		}
162	if (e > fpi->emax) {
163 ovfl:
164		Bfree(b);
165		*bp = 0;
166		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
167		}
168	irv = STRTOG_Normal;
169	if (e < fpi->emin) {
170		irv = STRTOG_Denormal;
171		n = fpi->emin - e;
172		if (n >= nbits) {
173			switch (fpi->rounding) {
174			  case FPI_Round_near:
175				if (n == nbits && (n < 2 || any_on(b,n-1)))
176					goto one_bit;
177				break;
178			  case FPI_Round_up:
179				if (!sign)
180					goto one_bit;
181				break;
182			  case FPI_Round_down:
183				if (sign) {
184 one_bit:
185					*exp = fpi->emin;
186					x[0] = b->wds = 1;
187					*bp = b;
188					return STRTOG_Denormal | STRTOG_Inexhi
189						| STRTOG_Underflow;
190					}
191			  }
192			Bfree(b);
193			*bp = 0;
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 (irv == STRTOG_Denormal) {
228				if (nbits == fpi->nbits - 1
229				 && x[nbits >> kshift] & 1 << (nbits & kmask))
230					irv =  STRTOG_Normal;
231				}
232			else if (b->wds > k
233			 || (n = nbits & kmask) !=0
234			     && hi0bits(x[k-1]) < 32-n) {
235				rshift(b,1);
236				if (++e > fpi->emax)
237					goto ovfl;
238				}
239			irv |= STRTOG_Inexhi;
240			}
241		else
242			irv |= STRTOG_Inexlo;
243		}
244	*bp = b;
245	*exp = e;
246	return irv;
247	}
248