| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 | /****************************************************************The author of this software is David M. Gay.Copyright (C) 1998 by Lucent TechnologiesAll Rights ReservedPermission to use, copy, modify, and distribute this software andits documentation for any purpose and without fee is herebygranted, provided that the above copyright notice appear in allcopies and that both that the copyright notice and thispermission notice and warranty disclaimer appear in supportingdocumentation, and that the name of Lucent or any of its entitiesnot be used in advertising or publicity pertaining todistribution of the software without specific, written priorpermission.LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANYSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGESWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHERIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OFTHIS SOFTWARE.****************************************************************//* Please send bug reports to David M. Gay (dmg at acm dot org, * with " at " changed at "@" and " dot " changed to ".").	*/#include "gdtoaimp.h"#ifdef USE_LOCALE#include "locale.h"#endif int#ifdef KR_headersgethex(sp, fpi, exp, bp, sign)	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;#elsegethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)#endif{	Bigint *b;	CONST unsigned char *decpt, *s0, *s, *s1;	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;	ULong L, lostbits, *x;	Long e, e1;#ifdef USE_LOCALE	int i;#ifdef NO_LOCALE_CACHE	const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;#else	const unsigned char *decimalpoint;	static unsigned char *decimalpoint_cache;	if (!(s0 = decimalpoint_cache)) {		s0 = (unsigned char*)localeconv()->decimal_point;		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {			strlcpy(decimalpoint_cache, s0, strlen(s0) + 1);			s0 = decimalpoint_cache;			}		}	decimalpoint = s0;#endif#endif	if (!hexdig['0'])		hexdig_init_D2A();	*bp = 0;	havedig = 0;	s0 = *(CONST unsigned char **)sp + 2;	while(s0[havedig] == '0')		havedig++;	s0 += havedig;	s = s0;	decpt = 0;	zret = 0;	e = 0;	if (hexdig[*s])		havedig++;	else {		zret = 1;#ifdef USE_LOCALE		for(i = 0; decimalpoint[i]; ++i) {			if (s[i] != decimalpoint[i])				goto pcheck;			}		decpt = s += i;#else		if (*s != '.')			goto pcheck;		decpt = ++s;#endif		if (!hexdig[*s])			goto pcheck;		while(*s == '0')			s++;		if (hexdig[*s])			zret = 0;		havedig = 1;		s0 = s;		}	while(hexdig[*s])		s++;#ifdef USE_LOCALE	if (*s == *decimalpoint && !decpt) {		for(i = 1; decimalpoint[i]; ++i) {			if (s[i] != decimalpoint[i])				goto pcheck;			}		decpt = s += i;#else	if (*s == '.' && !decpt) {		decpt = ++s;#endif		while(hexdig[*s])			s++;		}/*}*/	if (decpt)		e = -(((Long)(s-decpt)) << 2); pcheck:	s1 = s;	big = esign = 0;	switch(*s) {	  case 'p':	  case 'P':		switch(*++s) {		  case '-':			esign = 1;			/* no break */		  case '+':			s++;		  }		if ((n = hexdig[*s]) == 0 || n > 0x19) {			s = s1;			break;			}		e1 = n - 0x10;		while((n = hexdig[*++s]) !=0 && n <= 0x19) {			if (e1 & 0xf8000000)				big = 1;			e1 = 10*e1 + n - 0x10;			}		if (esign)			e1 = -e1;		e += e1;	  }	*sp = (char*)s;	if (!havedig)		*sp = (char*)s0 - 1;	if (zret)		return STRTOG_Zero;	if (big) {		if (esign) {			switch(fpi->rounding) {			  case FPI_Round_up:				if (sign)					break;				goto ret_tiny;			  case FPI_Round_down:				if (!sign)					break;				goto ret_tiny;			  }			goto retz; ret_tiny:			b = Balloc(0);			if (b == NULL)				return (STRTOG_NoMemory);			b->wds = 1;			b->x[0] = 1;			goto dret;			}		switch(fpi->rounding) {		  case FPI_Round_near:			goto ovfl1;		  case FPI_Round_up:			if (!sign)				goto ovfl1;			goto ret_big;		  case FPI_Round_down:			if (sign)				goto ovfl1;			goto ret_big;		  } ret_big:		nbits = fpi->nbits;		n0 = n = nbits >> kshift;		if (nbits & kmask)			++n;		for(j = n, k = 0; j >>= 1; ++k);		*bp = b = Balloc(k);		if (*bp == NULL)			return (STRTOG_NoMemory);		b->wds = n;		for(j = 0; j < n0; ++j)			b->x[j] = ALL_ON;		if (n > n0)			b->x[j] = ULbits >> (ULbits - (nbits & kmask));		*exp = fpi->emin;		return STRTOG_Normal | STRTOG_Inexlo;		}	n = s1 - s0 - 1;	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)		k++;	b = Balloc(k);	if (b == NULL)		return (STRTOG_NoMemory);	x = b->x;	n = 0;	L = 0;#ifdef USE_LOCALE	for(i = 0; decimalpoint[i+1]; ++i);#endif	while(s1 > s0) {#ifdef USE_LOCALE		if (*--s1 == decimalpoint[i]) {			s1 -= i;			continue;			}#else		if (*--s1 == '.')			continue;#endif		if (n == ULbits) {			*x++ = L;			L = 0;			n = 0;			}		L |= (hexdig[*s1] & 0x0f) << n;		n += 4;		}	*x++ = L;	b->wds = n = x - b->x;	n = ULbits*n - hi0bits(L);	nbits = fpi->nbits;	lostbits = 0;	x = b->x;	if (n > nbits) {		n -= nbits;		if (any_on(b,n)) {			lostbits = 1;			k = n - 1;			if (x[k>>kshift] & 1 << (k & kmask)) {				lostbits = 2;				if (k > 0 && any_on(b,k))					lostbits = 3;				}			}		rshift(b, n);		e += n;		}	else if (n < nbits) {		n = nbits - n;		b = lshift(b, n);		if (b == NULL)			return (STRTOG_NoMemory);		e -= n;		x = b->x;		}	if (e > fpi->emax) { ovfl:		Bfree(b); ovfl1:#ifndef NO_ERRNO		errno = ERANGE;#endif		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;		}	irv = STRTOG_Normal;	if (e < fpi->emin) {		irv = STRTOG_Denormal;		n = fpi->emin - e;		if (n >= nbits) {			switch (fpi->rounding) {			  case FPI_Round_near:				if (n == nbits && (n < 2 || any_on(b,n-1)))					goto one_bit;				break;			  case FPI_Round_up:				if (!sign)					goto one_bit;				break;			  case FPI_Round_down:				if (sign) { one_bit:					x[0] = b->wds = 1; dret:					*bp = b;					*exp = fpi->emin;#ifndef NO_ERRNO					errno = ERANGE;#endif					return STRTOG_Denormal | STRTOG_Inexhi						| STRTOG_Underflow;					}			  }			Bfree(b); retz:#ifndef NO_ERRNO			errno = ERANGE;#endif			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;			}		k = n - 1;		if (lostbits)			lostbits = 1;		else if (k > 0)			lostbits = any_on(b,k);		if (x[k>>kshift] & 1 << (k & kmask))			lostbits |= 2;		nbits -= n;		rshift(b,n);		e = fpi->emin;		}	if (lostbits) {		up = 0;		switch(fpi->rounding) {		  case FPI_Round_zero:			break;		  case FPI_Round_near:			if (lostbits & 2			 && (lostbits | x[0]) & 1)				up = 1;			break;		  case FPI_Round_up:			up = 1 - sign;			break;		  case FPI_Round_down:			up = sign;		  }		if (up) {			k = b->wds;			b = increment(b);			if (b == NULL)				return (STRTOG_NoMemory);			x = b->x;			if (irv == STRTOG_Denormal) {				if (nbits == fpi->nbits - 1				 && x[nbits >> kshift] & 1 << (nbits & kmask))					irv =  STRTOG_Normal;				}			else if (b->wds > k			 || ((n = nbits & kmask) !=0			      && hi0bits(x[k-1]) < 32-n)) {				rshift(b,1);				if (++e > fpi->emax)					goto ovfl;				}			irv |= STRTOG_Inexhi;			}		else			irv |= STRTOG_Inexlo;		}	*bp = b;	*exp = e;	return irv;	}
 |