1/* $NetBSD: gethex.c,v 1.4 2008/03/21 23:13:48 christos Exp $ */
2
3/****************************************************************
4
5The author of this software is David M. Gay.
6
7Copyright (C) 1998 by Lucent Technologies
8All Rights Reserved
9
10Permission to use, copy, modify, and distribute this software and
11its documentation for any purpose and without fee is hereby
12granted, provided that the above copyright notice appear in all
13copies and that both that the copyright notice and this
14permission notice and warranty disclaimer appear in supporting
15documentation, and that the name of Lucent or any of its entities
16not be used in advertising or publicity pertaining to
17distribution of the software without specific, written prior
18permission.
19
20LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
22IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
23SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
25IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27THIS SOFTWARE.
28
29****************************************************************/
30
31/* Please send bug reports to David M. Gay (dmg at acm dot org,
32 * with " at " changed at "@" and " dot " changed to ".").	*/
33
34#include "gdtoaimp.h"
35
36#ifdef USE_LOCALE
37#include "locale.h"
38#endif
39
40 int
41#ifdef KR_headers
42gethex(sp, fpi, expt, bp, sign)
43	CONST char **sp; CONST FPI *fpi; Long *expt; Bigint **bp; int sign;
44#else
45gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign)
46#endif
47{
48	Bigint *b;
49	CONST char *decpt, *s, *s0, *s1;
50	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
51	ULong L, lostbits, *x;
52	Long e, e1;
53#ifdef USE_LOCALE
54	int i;
55#ifdef NO_LOCALE_CACHE
56	const char *decimalpoint = localeconv()->decimal_point;
57#else
58	const unsigned char *decimalpoint;
59	static char *decimalpoint_cache;
60	if (!(s0 = decimalpoint_cache)) {
61		s0 = localeconv()->decimal_point;
62		if ((decimalpoint_cache = MALLOC(strlen(s0) + 1)) != NULL) {
63			strcpy(decimalpoint_cache, s0);
64			s0 = decimalpoint_cache;
65			}
66		}
67	decimalpoint = __UNCONST(s0);
68#endif
69#endif
70
71	if (!hexdig[(unsigned char)'0'])
72		hexdig_init_D2A();
73	*bp = 0;
74	havedig = 0;
75	s0 = *(CONST char **)sp + 2;
76	while(s0[havedig] == '0')
77		havedig++;
78	s0 += havedig;
79	s = s0;
80	decpt = 0;
81	zret = 0;
82	e = 0;
83	if (hexdig[(unsigned char)*s])
84		havedig++;
85	else {
86		zret = 1;
87#ifdef USE_LOCALE
88		for(i = 0; decimalpoint[i]; ++i) {
89			if (s[i] != decimalpoint[i])
90				goto pcheck;
91			}
92		decpt = s += i;
93#else
94		if (*s != '.')
95			goto pcheck;
96		decpt = ++s;
97#endif
98		if (!hexdig[(unsigned char)*s])
99			goto pcheck;
100		while(*s == '0')
101			s++;
102		if (hexdig[(unsigned char)*s])
103			zret = 0;
104		havedig = 1;
105		s0 = s;
106		}
107	while(hexdig[(unsigned char)*s])
108		s++;
109#ifdef USE_LOCALE
110	if (*s == *decimalpoint && !decpt) {
111		for(i = 1; decimalpoint[i]; ++i) {
112			if (s[i] != decimalpoint[i])
113				goto pcheck;
114			}
115		decpt = s += i;
116#else
117	if (*s == '.' && !decpt) {
118		decpt = ++s;
119#endif
120		while(hexdig[(unsigned char)*s])
121			s++;
122		}/*}*/
123	if (decpt)
124		e = -(((Long)(s-decpt)) << 2);
125 pcheck:
126	s1 = s;
127	big = esign = 0;
128	switch(*s) {
129	  case 'p':
130	  case 'P':
131		switch(*++s) {
132		  case '-':
133			esign = 1;
134			/* FALLTHROUGH */
135		  case '+':
136			s++;
137		  }
138		if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) {
139			s = s1;
140			break;
141			}
142		e1 = n - 0x10;
143		while((n = hexdig[(unsigned char)*++s]) !=0 && n <= 0x19) {
144			if (e1 & 0xf8000000)
145				big = 1;
146			e1 = 10*e1 + n - 0x10;
147			}
148		if (esign)
149			e1 = -e1;
150		e += e1;
151	  }
152	*sp = __UNCONST(s);
153	if (!havedig)
154		*sp = (char*)__UNCONST(s0) - 1;
155	if (zret)
156		return STRTOG_Zero;
157	if (big) {
158		if (esign) {
159			switch(fpi->rounding) {
160			  case FPI_Round_up:
161				if (sign)
162					break;
163				goto ret_tiny;
164			  case FPI_Round_down:
165				if (!sign)
166					break;
167				goto ret_tiny;
168			  }
169			goto retz;
170 ret_tiny:
171			b = Balloc(0);
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 = (unsigned int)nbits >> kshift;
191		if (nbits & kmask)
192			++n;
193		for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k);
194		*bp = b = Balloc(k);
195		b->wds = n;
196		for(j = 0; j < n0; ++j)
197			b->x[j] = ALL_ON;
198		if (n > n0)
199			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
200		*expt = fpi->emin;
201		return STRTOG_Normal | STRTOG_Inexlo;
202		}
203	n = (int)(s1 - s0) - 1;
204	for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1)
205		k++;
206	b = Balloc(k);
207	if (b == NULL)
208		return STRTOG_NoMemory;
209	x = b->x;
210	n = 0;
211	L = 0;
212#ifdef USE_LOCALE
213	for(i = 0; decimalpoint[i+1]; ++i);
214#endif
215	while(s1 > s0) {
216#ifdef USE_LOCALE
217		if (*--s1 == decimalpoint[i]) {
218			s1 -= i;
219			continue;
220			}
221#else
222		if (*--s1 == '.')
223			continue;
224#endif
225		if (n == ULbits) {
226			*x++ = L;
227			L = 0;
228			n = 0;
229			}
230		L |= (hexdig[(unsigned char)*s1] & 0x0f) << n;
231		n += 4;
232		}
233	*x++ = L;
234	b->wds = n = (int)(x - b->x);
235	n = ULbits*n - hi0bits(L);
236	nbits = fpi->nbits;
237	lostbits = 0;
238	x = b->x;
239	if (n > nbits) {
240		n -= nbits;
241		if (any_on(b,n)) {
242			lostbits = 1;
243			k = n - 1;
244			if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
245				lostbits = 2;
246				if (k > 0 && any_on(b,k))
247					lostbits = 3;
248				}
249			}
250		rshift(b, n);
251		e += n;
252		}
253	else if (n < nbits) {
254		n = nbits - n;
255		b = lshift(b, n);
256		if (b == NULL)
257			return STRTOG_NoMemory;
258		e -= n;
259		x = b->x;
260		}
261	if (e > fpi->emax) {
262 ovfl:
263		Bfree(b);
264 ovfl1:
265#ifndef NO_ERRNO
266		errno = ERANGE;
267#endif
268		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
269		}
270	irv = STRTOG_Normal;
271	if (e < fpi->emin) {
272		irv = STRTOG_Denormal;
273		n = fpi->emin - e;
274		if (n >= nbits) {
275			switch (fpi->rounding) {
276			  case FPI_Round_near:
277				if (n == nbits && (n < 2 || any_on(b,n-1)))
278					goto one_bit;
279				break;
280			  case FPI_Round_up:
281				if (!sign)
282					goto one_bit;
283				break;
284			  case FPI_Round_down:
285				if (sign) {
286 one_bit:
287					x[0] = b->wds = 1;
288 dret:
289					*bp = b;
290					*expt = fpi->emin;
291#ifndef NO_ERRNO
292					errno = ERANGE;
293#endif
294					return STRTOG_Denormal | STRTOG_Inexhi
295						| STRTOG_Underflow;
296					}
297			  }
298			Bfree(b);
299 retz:
300#ifndef NO_ERRNO
301			errno = ERANGE;
302#endif
303			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
304			}
305		k = n - 1;
306		if (lostbits)
307			lostbits = 1;
308		else if (k > 0)
309			lostbits = any_on(b,k);
310		if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
311			lostbits |= 2;
312		nbits -= n;
313		rshift(b,n);
314		e = fpi->emin;
315		}
316	if (lostbits) {
317		up = 0;
318		switch(fpi->rounding) {
319		  case FPI_Round_zero:
320			break;
321		  case FPI_Round_near:
322			if (lostbits & 2
323			 && (lostbits | x[0]) & 1)
324				up = 1;
325			break;
326		  case FPI_Round_up:
327			up = 1 - sign;
328			break;
329		  case FPI_Round_down:
330			up = sign;
331		  }
332		if (up) {
333			k = b->wds;
334			b = increment(b);
335			x = b->x;
336			if (irv == STRTOG_Denormal) {
337				if (nbits == fpi->nbits - 1
338				 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
339					irv =  STRTOG_Normal;
340				}
341			else if (b->wds > k
342			 || ((n = nbits & kmask) !=0
343			      && hi0bits(x[k-1]) < 32-n)) {
344				rshift(b,1);
345				if (++e > fpi->emax)
346					goto ovfl;
347				}
348			irv |= STRTOG_Inexhi;
349			}
350		else
351			irv |= STRTOG_Inexlo;
352		}
353	*bp = b;
354	*expt = e;
355	return irv;
356	}
357