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 "xlocale_private.h"
33
34#include "gdtoaimp.h"
35
36#include <sys/types.h>
37
38#ifdef USE_LOCALE
39#include "locale.h"
40#endif
41
42 int
43#ifdef KR_headers
44gethex(sp, fpi, exp, bp, sign, loc)
45	CONST char **sp; CONST FPI *fpi; Long *exp; Bigint **bp; int sign; locale_t loc;
46#else
47gethex( CONST char **sp, CONST FPI *fpi, Long *exp, Bigint **bp, int sign, locale_t loc)
48#endif
49{
50	Bigint *b;
51	CONST unsigned char *decpt, *s0, *s, *s1;
52	unsigned char *strunc;
53	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
54	ULong L, lostbits, *x;
55	Long e, e1;
56#ifdef USE_LOCALE
57	int i;
58	NORMALIZE_LOCALE(loc);
59#ifdef NO_LOCALE_CACHE
60	const unsigned char *decimalpoint = (unsigned char*)localeconv_l(loc)->decimal_point;
61#else
62	const unsigned char *decimalpoint;
63	static unsigned char *decimalpoint_cache;
64	if (!(s0 = decimalpoint_cache)) {
65		s0 = (unsigned char*)localeconv_l(loc)->decimal_point;
66		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
67			strcpy(decimalpoint_cache, s0);
68			s0 = decimalpoint_cache;
69			}
70		}
71	decimalpoint = s0;
72#endif
73#endif
74
75	if (!hexdig['0'])
76		hexdig_init_D2A();
77	*bp = 0;
78	havedig = 0;
79	s0 = *(CONST unsigned char **)sp + 2;
80	while(s0[havedig] == '0')
81		havedig++;
82	s0 += havedig;
83	s = s0;
84	decpt = 0;
85	zret = 0;
86	e = 0;
87	if (hexdig[*s])
88		havedig++;
89	else {
90		zret = 1;
91#ifdef USE_LOCALE
92		for(i = 0; decimalpoint[i]; ++i) {
93			if (s[i] != decimalpoint[i])
94				goto pcheck;
95			}
96		decpt = s += i;
97#else
98		if (*s != '.')
99			goto pcheck;
100		decpt = ++s;
101#endif
102		if (!hexdig[*s])
103			goto pcheck;
104		while(*s == '0')
105			s++;
106		if (hexdig[*s])
107			zret = 0;
108		havedig = 1;
109		s0 = s;
110		}
111	while(hexdig[*s])
112		s++;
113#ifdef USE_LOCALE
114	if (*s == *decimalpoint && !decpt) {
115		for(i = 1; decimalpoint[i]; ++i) {
116			if (s[i] != decimalpoint[i])
117				goto pcheck;
118			}
119		decpt = s += i;
120#else
121	if (*s == '.' && !decpt) {
122		decpt = ++s;
123#endif
124		while(hexdig[*s])
125			s++;
126		}/*}*/
127	if (decpt)
128		e = -(((Long)(s-decpt)) << 2);
129 pcheck:
130	s1 = s;
131	big = esign = 0;
132	switch(*s) {
133	  case 'p':
134	  case 'P':
135		switch(*++s) {
136		  case '-':
137			esign = 1;
138			/* no break */
139		  case '+':
140			s++;
141		  }
142		if ((n = hexdig[*s]) == 0 || n > 0x19) {
143			s = s1;
144			break;
145			}
146		e1 = n - 0x10;
147		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
148			if (e1 & 0xf8000000)
149				big = 1;
150			e1 = 10*e1 + n - 0x10;
151			}
152		if (esign)
153			e1 = -e1;
154		e += e1;
155	  }
156	*sp = (char*)s;
157	if (!havedig)
158		*sp = (char*)s0 - 1;
159	if (zret)
160		return STRTOG_Zero;
161	if (big) {
162		if (esign) {
163			switch(fpi->rounding) {
164			  case FPI_Round_up:
165				if (sign)
166					break;
167				goto ret_tiny;
168			  case FPI_Round_down:
169				if (!sign)
170					break;
171				goto ret_tiny;
172			  }
173			goto retz;
174 ret_tiny:
175			b = Balloc(0);
176			b->wds = 1;
177			b->x[0] = 1;
178			goto dret;
179			}
180		switch(fpi->rounding) {
181		  case FPI_Round_near:
182			goto ovfl1;
183		  case FPI_Round_up:
184			if (!sign)
185				goto ovfl1;
186			goto ret_big;
187		  case FPI_Round_down:
188			if (sign)
189				goto ovfl1;
190			goto ret_big;
191		  }
192 ret_big:
193		nbits = fpi->nbits;
194		n0 = n = nbits >> kshift;
195		if (nbits & kmask)
196			++n;
197		for(j = n, k = 0; j >>= 1; ++k);
198		*bp = b = Balloc(k);
199		b->wds = n;
200		for(j = 0; j < n0; ++j)
201			b->x[j] = ALL_ON;
202		if (n > n0)
203			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
204		*exp = fpi->emin;
205		return STRTOG_Normal | STRTOG_Inexlo;
206		}
207	/*
208	 * Truncate the hex string if it is longer than the precision needed,
209	 * to avoid denial-of-service issues with very large strings.  Use
210	 * additional digits to insure precision.  Scan to-be-truncated digits
211	 * and replace with either '1' or '0' to ensure proper rounding.
212	 */
213	{
214		int maxdigits = ((fpi->nbits + 3) >> 2) + 2;
215		size_t nd = s1 - s0;
216#ifdef USE_LOCALE
217		int dplen = strlen((const char *)decimalpoint);
218#else
219		int dplen = 1;
220#endif
221
222		if (decpt && s0 < decpt)
223			nd -= dplen;
224		if (nd > maxdigits && (strunc = alloca(maxdigits + dplen + 2)) != NULL) {
225			ssize_t nd0 = decpt ? decpt - s0 - dplen : nd;
226			unsigned char *tp = strunc + maxdigits;
227			int found = 0;
228			if ((nd0 -= maxdigits) >= 0 || s0 >= decpt)
229				memcpy(strunc, s0, maxdigits);
230			else {
231				memcpy(strunc, s0, maxdigits + dplen);
232				tp += dplen;
233				}
234			s0 += maxdigits;
235			e += (nd - (maxdigits + 1)) << 2;
236			if (nd0 > 0) {
237				while(nd0-- > 0)
238					if (*s0++ != '0') {
239						found++;
240						break;
241						}
242				s0 += dplen;
243				}
244			if (!found && decpt) {
245				while(s0 < s1)
246					if(*s0++ != '0') {
247						found++;
248						break;
249						}
250				}
251			*tp++ = found ? '1' : '0';
252			*tp = 0;
253			s0 = strunc;
254			s1 = tp;
255			}
256		}
257
258	n = s1 - s0 - 1;
259	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
260		k++;
261	b = Balloc(k);
262	x = b->x;
263	n = 0;
264	L = 0;
265#ifdef USE_LOCALE
266	for(i = 0; decimalpoint[i+1]; ++i);
267#endif
268	while(s1 > s0) {
269#ifdef USE_LOCALE
270		if (*--s1 == decimalpoint[i]) {
271			s1 -= i;
272			continue;
273			}
274#else
275		if (*--s1 == '.')
276			continue;
277#endif
278		if (n == ULbits) {
279			*x++ = L;
280			L = 0;
281			n = 0;
282			}
283		L |= (hexdig[*s1] & 0x0f) << n;
284		n += 4;
285		}
286	*x++ = L;
287	b->wds = n = x - b->x;
288	n = ULbits*n - hi0bits(L);
289	nbits = fpi->nbits;
290	lostbits = 0;
291	x = b->x;
292	if (n > nbits) {
293		n -= nbits;
294		if (any_on(b,n)) {
295			lostbits = 1;
296			k = n - 1;
297			if (x[k>>kshift] & 1 << (k & kmask)) {
298				lostbits = 2;
299				if (k > 0 && any_on(b,k))
300					lostbits = 3;
301				}
302			}
303		rshift(b, n);
304		e += n;
305		}
306	else if (n < nbits) {
307		n = nbits - n;
308		b = lshift(b, n);
309		e -= n;
310		x = b->x;
311		}
312	if (e > fpi->emax) {
313 ovfl:
314		Bfree(b);
315 ovfl1:
316#ifndef NO_ERRNO
317		errno = ERANGE;
318#endif
319		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
320		}
321	irv = STRTOG_Normal;
322	if (e < fpi->emin) {
323		irv = STRTOG_Denormal;
324		n = fpi->emin - e;
325		if (n >= nbits) {
326			switch (fpi->rounding) {
327			  case FPI_Round_near:
328				if (n == nbits && (n < 2 || any_on(b,n-1)))
329					goto one_bit;
330				break;
331			  case FPI_Round_up:
332				if (!sign)
333					goto one_bit;
334				break;
335			  case FPI_Round_down:
336				if (sign) {
337 one_bit:
338					x[0] = b->wds = 1;
339 dret:
340					*bp = b;
341					*exp = fpi->emin;
342#ifndef NO_ERRNO
343					errno = ERANGE;
344#endif
345					return STRTOG_Denormal | STRTOG_Inexhi
346						| STRTOG_Underflow;
347					}
348			  }
349			Bfree(b);
350 retz:
351#ifndef NO_ERRNO
352			errno = ERANGE;
353#endif
354			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
355			}
356		k = n - 1;
357		if (lostbits)
358			lostbits = 1;
359		else if (k > 0)
360			lostbits = any_on(b,k);
361		if (x[k>>kshift] & 1 << (k & kmask))
362			lostbits |= 2;
363		nbits -= n;
364		rshift(b,n);
365		e = fpi->emin;
366		}
367	if (lostbits) {
368		up = 0;
369		switch(fpi->rounding) {
370		  case FPI_Round_zero:
371			break;
372		  case FPI_Round_near:
373			if (lostbits & 2
374			 && (lostbits | x[0]) & 1)
375				up = 1;
376			break;
377		  case FPI_Round_up:
378			up = 1 - sign;
379			break;
380		  case FPI_Round_down:
381			up = sign;
382		  }
383		if (up) {
384			k = b->wds;
385			b = increment(b);
386			x = b->x;
387			if (irv == STRTOG_Denormal) {
388				if (nbits == fpi->nbits - 1
389				 && x[nbits >> kshift] & 1 << (nbits & kmask))
390					irv =  STRTOG_Normal;
391				}
392			else if (b->wds > k
393			 || ((n = nbits & kmask) !=0
394			      && hi0bits(x[k-1]) < 32-n)) {
395				rshift(b,1);
396				if (++e > fpi->emax)
397					goto ovfl;
398				}
399			irv |= STRTOG_Inexhi;
400			}
401		else
402			irv |= STRTOG_Inexlo;
403		}
404	*bp = b;
405	*exp = e;
406	return irv;
407	}
408