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