| /* $NetBSD: hexnan.c,v 1.3 2006/03/11 18:38:14 kleink Exp $ */ | |
| /**************************************************************** | |
| The author of this software is David M. Gay. | |
| Copyright (C) 2000 by Lucent Technologies | |
| All Rights Reserved | |
| Permission to use, copy, modify, and distribute this software and | |
| its documentation for any purpose and without fee is hereby | |
| granted, provided that the above copyright notice appear in all | |
| copies and that both that the copyright notice and this | |
| permission notice and warranty disclaimer appear in supporting | |
| documentation, and that the name of Lucent or any of its entities | |
| not be used in advertising or publicity pertaining to | |
| distribution of the software without specific, written prior | |
| permission. | |
| 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 ANY | |
| SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
| IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| THIS SOFTWARE. | |
| ****************************************************************/ | |
| /* Please send bug reports to David M. Gay (dmg at acm dot org, | |
| * with " at " changed at "@" and " dot " changed to "."). */ | |
| #include <LibConfig.h> | |
| #include "gdtoaimp.h" | |
| static void | |
| #ifdef KR_headers | |
| L_shift(x, x1, i) ULong *x; ULong *x1; int i; | |
| #else | |
| L_shift(ULong *x, ULong *x1, int i) | |
| #endif | |
| { | |
| int j; | |
| i = 8 - i; | |
| i <<= 2; | |
| j = ULbits - i; | |
| do { | |
| *x |= x[1] << j; | |
| x[1] >>= i; | |
| } while(++x < x1); | |
| } | |
| int | |
| #ifdef KR_headers | |
| hexnan(sp, fpi, x0) | |
| CONST char **sp; CONST FPI *fpi; ULong *x0; | |
| #else | |
| hexnan( CONST char **sp, CONST FPI *fpi, ULong *x0) | |
| #endif | |
| { | |
| ULong c, h, *x, *x1, *xe; | |
| CONST char *s; | |
| int havedig, hd0, i, nbits; | |
| if (!hexdig['0']) | |
| hexdig_init_D2A(); | |
| nbits = fpi->nbits; | |
| x = x0 + ((unsigned int)nbits >> kshift); | |
| if (nbits & kmask) | |
| x++; | |
| *--x = 0; | |
| x1 = xe = x; | |
| havedig = hd0 = i = 0; | |
| s = *sp; | |
| while((c = *(CONST unsigned char*)++s) != 0) { | |
| if ((h = hexdig[c]) == 0) { | |
| if (c <= ' ') { | |
| if (hd0 < havedig) { | |
| if (x < x1 && i < 8) | |
| L_shift(x, x1, i); | |
| if (x <= x0) { | |
| i = 8; | |
| continue; | |
| } | |
| hd0 = havedig; | |
| *--x = 0; | |
| x1 = x; | |
| i = 0; | |
| } | |
| continue; | |
| } | |
| if (/*(*/ c == ')' && havedig) { | |
| *sp = s + 1; | |
| break; | |
| } | |
| return STRTOG_NaN; | |
| } | |
| havedig++; | |
| if (++i > 8) { | |
| if (x <= x0) | |
| continue; | |
| i = 1; | |
| *--x = 0; | |
| } | |
| *x = (*x << 4) | (h & 0xf); | |
| } | |
| if (!havedig) | |
| return STRTOG_NaN; | |
| if (x < x1 && i < 8) | |
| L_shift(x, x1, i); | |
| if (x > x0) { | |
| x1 = x0; | |
| do *x1++ = *x++; | |
| while(x <= xe); | |
| do *x1++ = 0; | |
| while(x1 <= xe); | |
| } | |
| else { | |
| /* truncate high-order word if necessary */ | |
| if ( (i = nbits & (ULbits-1)) !=0) | |
| *xe &= ((ULong)0xffffffff) >> (ULbits - i); | |
| } | |
| for(x1 = xe;; --x1) { | |
| if (*x1 != 0) | |
| break; | |
| if (x1 == x0) { | |
| *x1 = 1; | |
| break; | |
| } | |
| } | |
| return STRTOG_NaNbits; | |
| } |