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 39 #ifdef KR_headers 40 gethex(sp, fpi, exp, bp, sign) 41 CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 42 #else 43 gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 44 #endif 45 { 46 Bigint *b; 47 CONST unsigned char *decpt, *s0, *s, *s1; 48 int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; 49 ULong L, lostbits, *x; 50 Long e, e1; 51 #ifdef USE_LOCALE 52 int i; 53 #ifdef NO_LOCALE_CACHE 54 const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; 55 #else 56 const unsigned char *decimalpoint; 57 static unsigned char *decimalpoint_cache; 58 if (!(s0 = decimalpoint_cache)) { 59 size_t len; 60 s0 = (unsigned char*)localeconv()->decimal_point; 61 len = strlen(s0) + 1; 62 if ((decimalpoint_cache = (char*)malloc(len))) { 63 strlcpy(decimalpoint_cache, s0, len); 64 s0 = decimalpoint_cache; 65 } 66 } 67 decimalpoint = s0; 68 #endif 69 #endif 70 71 if (!hexdig['0']) 72 hexdig_init_D2A(); 73 *bp = 0; 74 havedig = 0; 75 s0 = *(CONST unsigned char **)sp + 2; 76 while(s0[havedig] == '0') 77 havedig++; 78 s0 += havedig; 79 s = s0; 80 decpt = 0; 81 zret = 0; 82 e = 0; 83 if (hexdig[*s]) 84 havedig++; 85 else { 86 zret = 1; 87 #ifdef USE_LOCALE 88 for(i = 0; decimalpoint[i]; ++i) { 89 if (s[i] != decimalpoint[i]) 90 goto pcheck; 91 } 92 decpt = s += i; 93 #else 94 if (*s != '.') 95 goto pcheck; 96 decpt = ++s; 97 #endif 98 if (!hexdig[*s]) 99 goto pcheck; 100 while(*s == '0') 101 s++; 102 if (hexdig[*s]) 103 zret = 0; 104 havedig = 1; 105 s0 = s; 106 } 107 while(hexdig[*s]) 108 s++; 109 #ifdef USE_LOCALE 110 if (*s == *decimalpoint && !decpt) { 111 for(i = 1; decimalpoint[i]; ++i) { 112 if (s[i] != decimalpoint[i]) 113 goto pcheck; 114 } 115 decpt = s += i; 116 #else 117 if (*s == '.' && !decpt) { 118 decpt = ++s; 119 #endif 120 while(hexdig[*s]) 121 s++; 122 }/*}*/ 123 if (decpt) 124 e = -(((Long)(s-decpt)) << 2); 125 pcheck: 126 s1 = s; 127 big = esign = 0; 128 switch(*s) { 129 case 'p': 130 case 'P': 131 switch(*++s) { 132 case '-': 133 esign = 1; 134 /* no break */ 135 case '+': 136 s++; 137 } 138 if ((n = hexdig[*s]) == 0 || n > 0x19) { 139 s = s1; 140 break; 141 } 142 e1 = n - 0x10; 143 while((n = hexdig[*++s]) !=0 && n <= 0x19) { 144 if (e1 & 0xf8000000) 145 big = 1; 146 e1 = 10*e1 + n - 0x10; 147 } 148 if (esign) 149 e1 = -e1; 150 e += e1; 151 } 152 *sp = (char*)s; 153 if (!havedig) 154 *sp = (char*)s0 - 1; 155 if (zret) 156 return STRTOG_Zero; 157 if (big) { 158 if (esign) { 159 switch(fpi->rounding) { 160 case FPI_Round_up: 161 if (sign) 162 break; 163 goto ret_tiny; 164 case FPI_Round_down: 165 if (!sign) 166 break; 167 goto ret_tiny; 168 } 169 goto retz; 170 ret_tiny: 171 b = Balloc(0); 172 if (b == NULL) 173 return (STRTOG_NoMemory); 174 b->wds = 1; 175 b->x[0] = 1; 176 goto dret; 177 } 178 switch(fpi->rounding) { 179 case FPI_Round_near: 180 goto ovfl1; 181 case FPI_Round_up: 182 if (!sign) 183 goto ovfl1; 184 goto ret_big; 185 case FPI_Round_down: 186 if (sign) 187 goto ovfl1; 188 goto ret_big; 189 } 190 ret_big: 191 nbits = fpi->nbits; 192 n0 = n = nbits >> kshift; 193 if (nbits & kmask) 194 ++n; 195 for(j = n, k = 0; j >>= 1; ++k); 196 *bp = b = Balloc(k); 197 if (b == NULL) 198 return (STRTOG_NoMemory); 199 b->wds = n; 200 for(j = 0; j < n0; ++j) 201 b->x[j] = ALL_ON; 202 if (n > n0) 203 b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 204 *exp = fpi->emin; 205 return STRTOG_Normal | STRTOG_Inexlo; 206 } 207 n = s1 - s0 - 1; 208 for(k = 0; n > 7; n >>= 1) 209 k++; 210 b = Balloc(k); 211 if (b == NULL) 212 return (STRTOG_NoMemory); 213 x = b->x; 214 n = 0; 215 L = 0; 216 #ifdef USE_LOCALE 217 for(i = 0; decimalpoint[i+1]; ++i); 218 #endif 219 while(s1 > s0) { 220 #ifdef USE_LOCALE 221 if (*--s1 == decimalpoint[i]) { 222 s1 -= i; 223 continue; 224 } 225 #else 226 if (*--s1 == '.') 227 continue; 228 #endif 229 if (n == 32) { 230 *x++ = L; 231 L = 0; 232 n = 0; 233 } 234 L |= (hexdig[*s1] & 0x0f) << n; 235 n += 4; 236 } 237 *x++ = L; 238 b->wds = n = x - b->x; 239 n = 32*n - hi0bits(L); 240 nbits = fpi->nbits; 241 lostbits = 0; 242 x = b->x; 243 if (n > nbits) { 244 n -= nbits; 245 if (any_on(b,n)) { 246 lostbits = 1; 247 k = n - 1; 248 if (x[k>>kshift] & 1 << (k & kmask)) { 249 lostbits = 2; 250 if (k > 0 && any_on(b,k)) 251 lostbits = 3; 252 } 253 } 254 rshift(b, n); 255 e += n; 256 } 257 else if (n < nbits) { 258 n = nbits - n; 259 b = lshift(b, n); 260 if (b == NULL) 261 return (STRTOG_NoMemory); 262 e -= n; 263 x = b->x; 264 } 265 if (e > fpi->emax) { 266 ovfl: 267 Bfree(b); 268 ovfl1: 269 #ifndef NO_ERRNO 270 errno = ERANGE; 271 #endif 272 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 273 } 274 irv = STRTOG_Normal; 275 if (e < fpi->emin) { 276 irv = STRTOG_Denormal; 277 n = fpi->emin - e; 278 if (n >= nbits) { 279 switch (fpi->rounding) { 280 case FPI_Round_near: 281 if (n == nbits && (n < 2 || any_on(b,n-1))) 282 goto one_bit; 283 break; 284 case FPI_Round_up: 285 if (!sign) 286 goto one_bit; 287 break; 288 case FPI_Round_down: 289 if (sign) { 290 one_bit: 291 x[0] = b->wds = 1; 292 dret: 293 *bp = b; 294 *exp = fpi->emin; 295 #ifndef NO_ERRNO 296 errno = ERANGE; 297 #endif 298 return STRTOG_Denormal | STRTOG_Inexhi 299 | STRTOG_Underflow; 300 } 301 } 302 Bfree(b); 303 retz: 304 #ifndef NO_ERRNO 305 errno = ERANGE; 306 #endif 307 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 308 } 309 k = n - 1; 310 if (lostbits) 311 lostbits = 1; 312 else if (k > 0) 313 lostbits = any_on(b,k); 314 if (x[k>>kshift] & 1 << (k & kmask)) 315 lostbits |= 2; 316 nbits -= n; 317 rshift(b,n); 318 e = fpi->emin; 319 } 320 if (lostbits) { 321 up = 0; 322 switch(fpi->rounding) { 323 case FPI_Round_zero: 324 break; 325 case FPI_Round_near: 326 if (lostbits & 2 327 && (lostbits & 1) | x[0] & 1) 328 up = 1; 329 break; 330 case FPI_Round_up: 331 up = 1 - sign; 332 break; 333 case FPI_Round_down: 334 up = sign; 335 } 336 if (up) { 337 k = b->wds; 338 b = increment(b); 339 if (b == NULL) 340 return (STRTOG_NoMemory); 341 x = b->x; 342 if (irv == STRTOG_Denormal) { 343 if (nbits == fpi->nbits - 1 344 && x[nbits >> kshift] & 1 << (nbits & kmask)) 345 irv = STRTOG_Normal; 346 } 347 else if (b->wds > k 348 || (n = nbits & kmask) !=0 349 && hi0bits(x[k-1]) < 32-n) { 350 rshift(b,1); 351 if (++e > fpi->emax) 352 goto ovfl; 353 } 354 irv |= STRTOG_Inexhi; 355 } 356 else 357 irv |= STRTOG_Inexlo; 358 } 359 *bp = b; 360 *exp = e; 361 return irv; 362 } 363