gethex.c revision 179918
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		if (!havedig)
118			*sp = s0 - 1;
119		return STRTOG_Zero;
120		}
121	n = s1 - s0 - 1;
122	for(k = 0; n > 7; n >>= 1)
123		k++;
124	b = Balloc(k);
125	x = b->x;
126	n = 0;
127	L = 0;
128	while(s1 > s0) {
129		if (*--s1 == decimalpoint)
130			continue;
131		if (n == 32) {
132			*x++ = L;
133			L = 0;
134			n = 0;
135			}
136		L |= (hexdig[*s1] & 0x0f) << n;
137		n += 4;
138		}
139	*x++ = L;
140	b->wds = n = x - b->x;
141	n = 32*n - hi0bits(L);
142	nbits = fpi->nbits;
143	lostbits = 0;
144	x = b->x;
145	if (n > nbits) {
146		n -= nbits;
147		if (any_on(b,n)) {
148			lostbits = 1;
149			k = n - 1;
150			if (x[k>>kshift] & 1 << (k & kmask)) {
151				lostbits = 2;
152				if (k > 1 && any_on(b,k-1))
153					lostbits = 3;
154				}
155			}
156		rshift(b, n);
157		e += n;
158		}
159	else if (n < nbits) {
160		n = nbits - n;
161		b = lshift(b, n);
162		e -= n;
163		x = b->x;
164		}
165	if (e > fpi->emax) {
166 ovfl:
167		Bfree(b);
168		*bp = 0;
169		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
170		}
171	irv = STRTOG_Normal;
172	if (e < fpi->emin) {
173		irv = STRTOG_Denormal;
174		n = fpi->emin - e;
175		if (n >= nbits) {
176			switch (fpi->rounding) {
177			  case FPI_Round_near:
178				if (n == nbits && (n < 2 || any_on(b,n-1)))
179					goto one_bit;
180				break;
181			  case FPI_Round_up:
182				if (!sign)
183					goto one_bit;
184				break;
185			  case FPI_Round_down:
186				if (sign) {
187 one_bit:
188					*exp = fpi->emin;
189					x[0] = b->wds = 1;
190					*bp = b;
191					return STRTOG_Denormal | STRTOG_Inexhi
192						| STRTOG_Underflow;
193					}
194			  }
195			Bfree(b);
196			*bp = 0;
197			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
198			}
199		k = n - 1;
200		if (lostbits)
201			lostbits = 1;
202		else if (k > 0)
203			lostbits = any_on(b,k);
204		if (x[k>>kshift] & 1 << (k & kmask))
205			lostbits |= 2;
206		nbits -= n;
207		rshift(b,n);
208		e = fpi->emin;
209		}
210	if (lostbits) {
211		up = 0;
212		switch(fpi->rounding) {
213		  case FPI_Round_zero:
214			break;
215		  case FPI_Round_near:
216			if (lostbits & 2
217			 && (lostbits & 1) | x[0] & 1)
218				up = 1;
219			break;
220		  case FPI_Round_up:
221			up = 1 - sign;
222			break;
223		  case FPI_Round_down:
224			up = sign;
225		  }
226		if (up) {
227			k = b->wds;
228			b = increment(b);
229			x = b->x;
230			if (irv == STRTOG_Denormal) {
231				if (nbits == fpi->nbits - 1
232				 && x[nbits >> kshift] & 1 << (nbits & kmask))
233					irv =  STRTOG_Normal;
234				}
235			else if (b->wds > k
236			 || (n = nbits & kmask) !=0
237			     && hi0bits(x[k-1]) < 32-n) {
238				rshift(b,1);
239				if (++e > fpi->emax)
240					goto ovfl;
241				}
242			irv |= STRTOG_Inexhi;
243			}
244		else
245			irv |= STRTOG_Inexlo;
246		}
247	*bp = b;
248	*exp = e;
249	return irv;
250	}
251