gethex.c revision 187808
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	int i;
53#ifdef NO_LOCALE_CACHE
54	const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
55#else
56	const unsigned char *decimalpoint;
57	static unsigned char *decimalpoint_cache;
58	if (!(s0 = decimalpoint_cache)) {
59		s0 = (unsigned char*)localeconv()->decimal_point;
60		if ((decimalpoint_cache = (char*)malloc(strlen(s0) + 1))) {
61			strcpy(decimalpoint_cache, s0);
62			s0 = decimalpoint_cache;
63			}
64		}
65	decimalpoint = s0;
66#endif
67#endif
68
69	if (!hexdig['0'])
70		hexdig_init_D2A();
71	*bp = 0;
72	havedig = 0;
73	s0 = *(CONST unsigned char **)sp + 2;
74	while(s0[havedig] == '0')
75		havedig++;
76	s0 += havedig;
77	s = s0;
78	decpt = 0;
79	zret = 0;
80	e = 0;
81	if (hexdig[*s])
82		havedig++;
83	else {
84		zret = 1;
85#ifdef USE_LOCALE
86		for(i = 0; decimalpoint[i]; ++i) {
87			if (s[i] != decimalpoint[i])
88				goto pcheck;
89			}
90		decpt = s += i;
91#else
92		if (*s != '.')
93			goto pcheck;
94		decpt = ++s;
95#endif
96		if (!hexdig[*s])
97			goto pcheck;
98		while(*s == '0')
99			s++;
100		if (hexdig[*s])
101			zret = 0;
102		havedig = 1;
103		s0 = s;
104		}
105	while(hexdig[*s])
106		s++;
107#ifdef USE_LOCALE
108	if (*s == *decimalpoint && !decpt) {
109		for(i = 1; decimalpoint[i]; ++i) {
110			if (s[i] != decimalpoint[i])
111				goto pcheck;
112			}
113		decpt = s += i;
114#else
115	if (*s == '.' && !decpt) {
116		decpt = ++s;
117#endif
118		while(hexdig[*s])
119			s++;
120		}/*}*/
121	if (decpt)
122		e = -(((Long)(s-decpt)) << 2);
123 pcheck:
124	s1 = s;
125	big = esign = 0;
126	switch(*s) {
127	  case 'p':
128	  case 'P':
129		switch(*++s) {
130		  case '-':
131			esign = 1;
132			/* no break */
133		  case '+':
134			s++;
135		  }
136		if ((n = hexdig[*s]) == 0 || n > 0x19) {
137			s = s1;
138			break;
139			}
140		e1 = n - 0x10;
141		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
142			if (e1 & 0xf8000000)
143				big = 1;
144			e1 = 10*e1 + n - 0x10;
145			}
146		if (esign)
147			e1 = -e1;
148		e += e1;
149	  }
150	*sp = (char*)s;
151	if (!havedig)
152		*sp = (char*)s0 - 1;
153	if (zret)
154		return STRTOG_Zero;
155	if (big) {
156		if (esign) {
157			switch(fpi->rounding) {
158			  case FPI_Round_up:
159				if (sign)
160					break;
161				goto ret_tiny;
162			  case FPI_Round_down:
163				if (!sign)
164					break;
165				goto ret_tiny;
166			  }
167			goto retz;
168 ret_tiny:
169			b = Balloc(0);
170			b->wds = 1;
171			b->x[0] = 1;
172			goto dret;
173			}
174		switch(fpi->rounding) {
175		  case FPI_Round_near:
176			goto ovfl1;
177		  case FPI_Round_up:
178			if (!sign)
179				goto ovfl1;
180			goto ret_big;
181		  case FPI_Round_down:
182			if (sign)
183				goto ovfl1;
184			goto ret_big;
185		  }
186 ret_big:
187		nbits = fpi->nbits;
188		n0 = n = nbits >> kshift;
189		if (nbits & kmask)
190			++n;
191		for(j = n, k = 0; j >>= 1; ++k);
192		*bp = b = Balloc(k);
193		b->wds = n;
194		for(j = 0; j < n0; ++j)
195			b->x[j] = ALL_ON;
196		if (n > n0)
197			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
198		*exp = fpi->emin;
199		return STRTOG_Normal | STRTOG_Inexlo;
200		}
201	n = s1 - s0 - 1;
202	for(k = 0; n > (1 << kshift-2) - 1; n >>= 1)
203		k++;
204	b = Balloc(k);
205	x = b->x;
206	n = 0;
207	L = 0;
208#ifdef USE_LOCALE
209	for(i = 0; decimalpoint[i+1]; ++i);
210#endif
211	while(s1 > s0) {
212#ifdef USE_LOCALE
213		if (*--s1 == decimalpoint[i]) {
214			s1 -= i;
215			continue;
216			}
217#else
218		if (*--s1 == '.')
219			continue;
220#endif
221		if (n == ULbits) {
222			*x++ = L;
223			L = 0;
224			n = 0;
225			}
226		L |= (hexdig[*s1] & 0x0f) << n;
227		n += 4;
228		}
229	*x++ = L;
230	b->wds = n = x - b->x;
231	n = ULbits*n - hi0bits(L);
232	nbits = fpi->nbits;
233	lostbits = 0;
234	x = b->x;
235	if (n > nbits) {
236		n -= nbits;
237		if (any_on(b,n)) {
238			lostbits = 1;
239			k = n - 1;
240			if (x[k>>kshift] & 1 << (k & kmask)) {
241				lostbits = 2;
242				if (k > 0 && any_on(b,k))
243					lostbits = 3;
244				}
245			}
246		rshift(b, n);
247		e += n;
248		}
249	else if (n < nbits) {
250		n = nbits - n;
251		b = lshift(b, n);
252		e -= n;
253		x = b->x;
254		}
255	if (e > fpi->emax) {
256 ovfl:
257		Bfree(b);
258 ovfl1:
259#ifndef NO_ERRNO
260		errno = ERANGE;
261#endif
262		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
263		}
264	irv = STRTOG_Normal;
265	if (e < fpi->emin) {
266		irv = STRTOG_Denormal;
267		n = fpi->emin - e;
268		if (n >= nbits) {
269			switch (fpi->rounding) {
270			  case FPI_Round_near:
271				if (n == nbits && (n < 2 || any_on(b,n-1)))
272					goto one_bit;
273				break;
274			  case FPI_Round_up:
275				if (!sign)
276					goto one_bit;
277				break;
278			  case FPI_Round_down:
279				if (sign) {
280 one_bit:
281					x[0] = b->wds = 1;
282 dret:
283					*bp = b;
284					*exp = fpi->emin;
285#ifndef NO_ERRNO
286					errno = ERANGE;
287#endif
288					return STRTOG_Denormal | STRTOG_Inexhi
289						| STRTOG_Underflow;
290					}
291			  }
292			Bfree(b);
293 retz:
294#ifndef NO_ERRNO
295			errno = ERANGE;
296#endif
297			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
298			}
299		k = n - 1;
300		if (lostbits)
301			lostbits = 1;
302		else if (k > 0)
303			lostbits = any_on(b,k);
304		if (x[k>>kshift] & 1 << (k & kmask))
305			lostbits |= 2;
306		nbits -= n;
307		rshift(b,n);
308		e = fpi->emin;
309		}
310	if (lostbits) {
311		up = 0;
312		switch(fpi->rounding) {
313		  case FPI_Round_zero:
314			break;
315		  case FPI_Round_near:
316			if (lostbits & 2
317			 && (lostbits & 1) | x[0] & 1)
318				up = 1;
319			break;
320		  case FPI_Round_up:
321			up = 1 - sign;
322			break;
323		  case FPI_Round_down:
324			up = sign;
325		  }
326		if (up) {
327			k = b->wds;
328			b = increment(b);
329			x = b->x;
330			if (irv == STRTOG_Denormal) {
331				if (nbits == fpi->nbits - 1
332				 && x[nbits >> kshift] & 1 << (nbits & kmask))
333					irv =  STRTOG_Normal;
334				}
335			else if (b->wds > k
336			 || (n = nbits & kmask) !=0
337			     && hi0bits(x[k-1]) < 32-n) {
338				rshift(b,1);
339				if (++e > fpi->emax)
340					goto ovfl;
341				}
342			irv |= STRTOG_Inexhi;
343			}
344		else
345			irv |= STRTOG_Inexlo;
346		}
347	*bp = b;
348	*exp = e;
349	return irv;
350	}
351