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