gethex.c revision 4bd97cee28dd815fff54fc97560be60d566c1fa5
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			strlcpy(decimalpoint_cache, s0, strlen(s0) + 1);
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			if (b == NULL)
171				return (STRTOG_NoMemory);
172			b->wds = 1;
173			b->x[0] = 1;
174			goto dret;
175			}
176		switch(fpi->rounding) {
177		  case FPI_Round_near:
178			goto ovfl1;
179		  case FPI_Round_up:
180			if (!sign)
181				goto ovfl1;
182			goto ret_big;
183		  case FPI_Round_down:
184			if (sign)
185				goto ovfl1;
186			goto ret_big;
187		  }
188 ret_big:
189		nbits = fpi->nbits;
190		n0 = n = nbits >> kshift;
191		if (nbits & kmask)
192			++n;
193		for(j = n, k = 0; j >>= 1; ++k);
194		*bp = b = Balloc(k);
195		if (*bp == NULL)
196			return (STRTOG_NoMemory);
197		b->wds = n;
198		for(j = 0; j < n0; ++j)
199			b->x[j] = ALL_ON;
200		if (n > n0)
201			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
202		*exp = fpi->emin;
203		return STRTOG_Normal | STRTOG_Inexlo;
204		}
205	n = s1 - s0 - 1;
206	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
207		k++;
208	b = Balloc(k);
209	if (b == NULL)
210		return (STRTOG_NoMemory);
211	x = b->x;
212	n = 0;
213	L = 0;
214#ifdef USE_LOCALE
215	for(i = 0; decimalpoint[i+1]; ++i);
216#endif
217	while(s1 > s0) {
218#ifdef USE_LOCALE
219		if (*--s1 == decimalpoint[i]) {
220			s1 -= i;
221			continue;
222			}
223#else
224		if (*--s1 == '.')
225			continue;
226#endif
227		if (n == ULbits) {
228			*x++ = L;
229			L = 0;
230			n = 0;
231			}
232		L |= (hexdig[*s1] & 0x0f) << n;
233		n += 4;
234		}
235	*x++ = L;
236	b->wds = n = x - b->x;
237	n = ULbits*n - hi0bits(L);
238	nbits = fpi->nbits;
239	lostbits = 0;
240	x = b->x;
241	if (n > nbits) {
242		n -= nbits;
243		if (any_on(b,n)) {
244			lostbits = 1;
245			k = n - 1;
246			if (x[k>>kshift] & 1 << (k & kmask)) {
247				lostbits = 2;
248				if (k > 0 && any_on(b,k))
249					lostbits = 3;
250				}
251			}
252		rshift(b, n);
253		e += n;
254		}
255	else if (n < nbits) {
256		n = nbits - n;
257		b = lshift(b, n);
258		if (b == NULL)
259			return (STRTOG_NoMemory);
260		e -= n;
261		x = b->x;
262		}
263	if (e > fpi->emax) {
264 ovfl:
265		Bfree(b);
266 ovfl1:
267#ifndef NO_ERRNO
268		errno = ERANGE;
269#endif
270		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
271		}
272	irv = STRTOG_Normal;
273	if (e < fpi->emin) {
274		irv = STRTOG_Denormal;
275		n = fpi->emin - e;
276		if (n >= nbits) {
277			switch (fpi->rounding) {
278			  case FPI_Round_near:
279				if (n == nbits && (n < 2 || any_on(b,n-1)))
280					goto one_bit;
281				break;
282			  case FPI_Round_up:
283				if (!sign)
284					goto one_bit;
285				break;
286			  case FPI_Round_down:
287				if (sign) {
288 one_bit:
289					x[0] = b->wds = 1;
290 dret:
291					*bp = b;
292					*exp = fpi->emin;
293#ifndef NO_ERRNO
294					errno = ERANGE;
295#endif
296					return STRTOG_Denormal | STRTOG_Inexhi
297						| STRTOG_Underflow;
298					}
299			  }
300			Bfree(b);
301 retz:
302#ifndef NO_ERRNO
303			errno = ERANGE;
304#endif
305			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
306			}
307		k = n - 1;
308		if (lostbits)
309			lostbits = 1;
310		else if (k > 0)
311			lostbits = any_on(b,k);
312		if (x[k>>kshift] & 1 << (k & kmask))
313			lostbits |= 2;
314		nbits -= n;
315		rshift(b,n);
316		e = fpi->emin;
317		}
318	if (lostbits) {
319		up = 0;
320		switch(fpi->rounding) {
321		  case FPI_Round_zero:
322			break;
323		  case FPI_Round_near:
324			if (lostbits & 2
325			 && (lostbits | x[0]) & 1)
326				up = 1;
327			break;
328		  case FPI_Round_up:
329			up = 1 - sign;
330			break;
331		  case FPI_Round_down:
332			up = sign;
333		  }
334		if (up) {
335			k = b->wds;
336			b = increment(b);
337			if (b == NULL)
338				return (STRTOG_NoMemory);
339			x = b->x;
340			if (irv == STRTOG_Denormal) {
341				if (nbits == fpi->nbits - 1
342				 && x[nbits >> kshift] & 1 << (nbits & kmask))
343					irv =  STRTOG_Normal;
344				}
345			else if (b->wds > k
346			 || ((n = nbits & kmask) !=0
347			      && hi0bits(x[k-1]) < 32-n)) {
348				rshift(b,1);
349				if (++e > fpi->emax)
350					goto ovfl;
351				}
352			irv |= STRTOG_Inexhi;
353			}
354		else
355			irv |= STRTOG_Inexlo;
356		}
357	*bp = b;
358	*exp = e;
359	return irv;
360	}
361