Home | History | Annotate | Line # | Download | only in gdtoa
gethex.c revision 1.1.1.1
      1 /* $NetBSD: gethex.c,v 1.1.1.1 2006/01/25 15:18:48 kleink 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 #ifdef KR_headers
     42 gethex(sp, fpi, exp, bp, sign)
     43 	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
     44 #else
     45 gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
     46 #endif
     47 {
     48 	Bigint *b;
     49 	CONST unsigned char *decpt, *s0, *s, *s1;
     50 	int esign, havedig, irv, k, n, nbits, up, zret;
     51 	ULong L, lostbits, *x;
     52 	Long e, e1;
     53 #ifdef USE_LOCALE
     54 	unsigned char decimalpoint = *localeconv()->decimal_point;
     55 #else
     56 #define decimalpoint '.'
     57 #endif
     58 
     59 	if (!hexdig['0'])
     60 		hexdig_init_D2A();
     61 	havedig = 0;
     62 	s0 = *(CONST unsigned char **)sp + 2;
     63 	while(s0[havedig] == '0')
     64 		havedig++;
     65 	s0 += havedig;
     66 	s = s0;
     67 	decpt = 0;
     68 	zret = 0;
     69 	e = 0;
     70 	if (!hexdig[*s]) {
     71 		zret = 1;
     72 		if (*s != decimalpoint)
     73 			goto pcheck;
     74 		decpt = ++s;
     75 		if (!hexdig[*s])
     76 			goto pcheck;
     77 		while(*s == '0')
     78 			s++;
     79 		if (hexdig[*s])
     80 			zret = 0;
     81 		havedig = 1;
     82 		s0 = s;
     83 		}
     84 	while(hexdig[*s])
     85 		s++;
     86 	if (*s == decimalpoint && !decpt) {
     87 		decpt = ++s;
     88 		while(hexdig[*s])
     89 			s++;
     90 		}
     91 	if (decpt)
     92 		e = -(((Long)(s-decpt)) << 2);
     93  pcheck:
     94 	s1 = s;
     95 	switch(*s) {
     96 	  case 'p':
     97 	  case 'P':
     98 		esign = 0;
     99 		switch(*++s) {
    100 		  case '-':
    101 			esign = 1;
    102 			/* no break */
    103 		  case '+':
    104 			s++;
    105 		  }
    106 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
    107 			s = s1;
    108 			break;
    109 			}
    110 		e1 = n - 0x10;
    111 		while((n = hexdig[*++s]) !=0 && n <= 0x19)
    112 			e1 = 10*e1 + n - 0x10;
    113 		if (esign)
    114 			e1 = -e1;
    115 		e += e1;
    116 	  }
    117 	*sp = (char*)s;
    118 	if (zret)
    119 		return havedig ? STRTOG_Zero : STRTOG_NoNumber;
    120 	n = s1 - s0 - 1;
    121 	for(k = 0; n > 7; n >>= 1)
    122 		k++;
    123 	b = Balloc(k);
    124 	x = b->x;
    125 	n = 0;
    126 	L = 0;
    127 	while(s1 > s0) {
    128 		if (*--s1 == decimalpoint)
    129 			continue;
    130 		if (n == 32) {
    131 			*x++ = L;
    132 			L = 0;
    133 			n = 0;
    134 			}
    135 		L |= (hexdig[*s1] & 0x0f) << n;
    136 		n += 4;
    137 		}
    138 	*x++ = L;
    139 	b->wds = n = x - b->x;
    140 	n = 32*n - hi0bits(L);
    141 	nbits = fpi->nbits;
    142 	lostbits = 0;
    143 	x = b->x;
    144 	if (n > nbits) {
    145 		n -= nbits;
    146 		if (any_on(b,n)) {
    147 			lostbits = 1;
    148 			k = n - 1;
    149 			if (x[k>>kshift] & 1 << (k & kmask)) {
    150 				lostbits = 2;
    151 				if (k > 1 && any_on(b,k-1))
    152 					lostbits = 3;
    153 				}
    154 			}
    155 		rshift(b, n);
    156 		e += n;
    157 		}
    158 	else if (n < nbits) {
    159 		n = nbits - n;
    160 		b = lshift(b, n);
    161 		e -= n;
    162 		x = b->x;
    163 		}
    164 	if (e > fpi->emax) {
    165  ovfl:
    166 		Bfree(b);
    167 		*bp = 0;
    168 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
    169 		}
    170 	irv = STRTOG_Normal;
    171 	if (e < fpi->emin) {
    172 		irv = STRTOG_Denormal;
    173 		n = fpi->emin - e;
    174 		if (n >= nbits) {
    175 			switch (fpi->rounding) {
    176 			  case FPI_Round_near:
    177 				if (n == nbits && (n < 2 || any_on(b,n-1)))
    178 					goto one_bit;
    179 				break;
    180 			  case FPI_Round_up:
    181 				if (!sign)
    182 					goto one_bit;
    183 				break;
    184 			  case FPI_Round_down:
    185 				if (sign) {
    186  one_bit:
    187 					*exp = fpi->emin;
    188 					x[0] = b->wds = 1;
    189 					*bp = b;
    190 					return STRTOG_Denormal | STRTOG_Inexhi
    191 						| STRTOG_Underflow;
    192 					}
    193 			  }
    194 			Bfree(b);
    195 			*bp = 0;
    196 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
    197 			}
    198 		k = n - 1;
    199 		if (lostbits)
    200 			lostbits = 1;
    201 		else if (k > 0)
    202 			lostbits = any_on(b,k);
    203 		if (x[k>>kshift] & 1 << (k & kmask))
    204 			lostbits |= 2;
    205 		nbits -= n;
    206 		rshift(b,n);
    207 		e = fpi->emin;
    208 		}
    209 	if (lostbits) {
    210 		up = 0;
    211 		switch(fpi->rounding) {
    212 		  case FPI_Round_zero:
    213 			break;
    214 		  case FPI_Round_near:
    215 			if (lostbits & 2
    216 			 && (lostbits & 1) | x[0] & 1)
    217 				up = 1;
    218 			break;
    219 		  case FPI_Round_up:
    220 			up = 1 - sign;
    221 			break;
    222 		  case FPI_Round_down:
    223 			up = sign;
    224 		  }
    225 		if (up) {
    226 			k = b->wds;
    227 			b = increment(b);
    228 			x = b->x;
    229 			if (irv == STRTOG_Denormal) {
    230 				if (nbits == fpi->nbits - 1
    231 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
    232 					irv =  STRTOG_Normal;
    233 				}
    234 			else if (b->wds > k
    235 			 || (n = nbits & kmask) !=0
    236 			     && hi0bits(x[k-1]) < 32-n) {
    237 				rshift(b,1);
    238 				if (++e > fpi->emax)
    239 					goto ovfl;
    240 				}
    241 			irv |= STRTOG_Inexhi;
    242 			}
    243 		else
    244 			irv |= STRTOG_Inexlo;
    245 		}
    246 	*bp = b;
    247 	*exp = e;
    248 	return irv;
    249 	}
    250