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