1/* $NetBSD: gethex.c,v 1.4 2008/03/21 23:13:48 christos Exp $ */ 2 3/**************************************************************** 4 5The author of this software is David M. Gay. 6 7Copyright (C) 1998 by Lucent Technologies 8All Rights Reserved 9 10Permission to use, copy, modify, and distribute this software and 11its documentation for any purpose and without fee is hereby 12granted, provided that the above copyright notice appear in all 13copies and that both that the copyright notice and this 14permission notice and warranty disclaimer appear in supporting 15documentation, and that the name of Lucent or any of its entities 16not be used in advertising or publicity pertaining to 17distribution of the software without specific, written prior 18permission. 19 20LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 21INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 22IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 23SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 25IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 26ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 27THIS 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 42gethex(sp, fpi, expt, bp, sign) 43 CONST char **sp; CONST FPI *fpi; Long *expt; Bigint **bp; int sign; 44#else 45gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign) 46#endif 47{ 48 Bigint *b; 49 CONST char *decpt, *s, *s0, *s1; 50 int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; 51 ULong L, lostbits, *x; 52 Long e, e1; 53#ifdef USE_LOCALE 54 int i; 55#ifdef NO_LOCALE_CACHE 56 const char *decimalpoint = localeconv()->decimal_point; 57#else 58 const unsigned char *decimalpoint; 59 static char *decimalpoint_cache; 60 if (!(s0 = decimalpoint_cache)) { 61 s0 = localeconv()->decimal_point; 62 if ((decimalpoint_cache = MALLOC(strlen(s0) + 1)) != NULL) { 63 strcpy(decimalpoint_cache, s0); 64 s0 = decimalpoint_cache; 65 } 66 } 67 decimalpoint = __UNCONST(s0); 68#endif 69#endif 70 71 if (!hexdig[(unsigned char)'0']) 72 hexdig_init_D2A(); 73 *bp = 0; 74 havedig = 0; 75 s0 = *(CONST 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[(unsigned char)*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[(unsigned char)*s]) 99 goto pcheck; 100 while(*s == '0') 101 s++; 102 if (hexdig[(unsigned char)*s]) 103 zret = 0; 104 havedig = 1; 105 s0 = s; 106 } 107 while(hexdig[(unsigned char)*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[(unsigned char)*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 /* FALLTHROUGH */ 135 case '+': 136 s++; 137 } 138 if ((n = hexdig[(unsigned char)*s]) == 0 || n > 0x19) { 139 s = s1; 140 break; 141 } 142 e1 = n - 0x10; 143 while((n = hexdig[(unsigned char)*++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 = __UNCONST(s); 153 if (!havedig) 154 *sp = (char*)__UNCONST(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 b->wds = 1; 173 b->x[0] = 1; 174 goto dret; 175 } 176 switch(fpi->rounding) { 177 case FPI_Round_near: 178 goto ovfl1; 179 case FPI_Round_up: 180 if (!sign) 181 goto ovfl1; 182 goto ret_big; 183 case FPI_Round_down: 184 if (sign) 185 goto ovfl1; 186 goto ret_big; 187 } 188 ret_big: 189 nbits = fpi->nbits; 190 n0 = n = (unsigned int)nbits >> kshift; 191 if (nbits & kmask) 192 ++n; 193 for(j = n, k = 0; (j = (unsigned int)j >> 1) != 0; ++k); 194 *bp = b = Balloc(k); 195 b->wds = n; 196 for(j = 0; j < n0; ++j) 197 b->x[j] = ALL_ON; 198 if (n > n0) 199 b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 200 *expt = fpi->emin; 201 return STRTOG_Normal | STRTOG_Inexlo; 202 } 203 n = (int)(s1 - s0) - 1; 204 for(k = 0; n > (1 << (kshift-2)) - 1; n = (unsigned int)n >> 1) 205 k++; 206 b = Balloc(k); 207 if (b == NULL) 208 return STRTOG_NoMemory; 209 x = b->x; 210 n = 0; 211 L = 0; 212#ifdef USE_LOCALE 213 for(i = 0; decimalpoint[i+1]; ++i); 214#endif 215 while(s1 > s0) { 216#ifdef USE_LOCALE 217 if (*--s1 == decimalpoint[i]) { 218 s1 -= i; 219 continue; 220 } 221#else 222 if (*--s1 == '.') 223 continue; 224#endif 225 if (n == ULbits) { 226 *x++ = L; 227 L = 0; 228 n = 0; 229 } 230 L |= (hexdig[(unsigned char)*s1] & 0x0f) << n; 231 n += 4; 232 } 233 *x++ = L; 234 b->wds = n = (int)(x - b->x); 235 n = ULbits*n - hi0bits(L); 236 nbits = fpi->nbits; 237 lostbits = 0; 238 x = b->x; 239 if (n > nbits) { 240 n -= nbits; 241 if (any_on(b,n)) { 242 lostbits = 1; 243 k = n - 1; 244 if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) { 245 lostbits = 2; 246 if (k > 0 && any_on(b,k)) 247 lostbits = 3; 248 } 249 } 250 rshift(b, n); 251 e += n; 252 } 253 else if (n < nbits) { 254 n = nbits - n; 255 b = lshift(b, n); 256 if (b == NULL) 257 return STRTOG_NoMemory; 258 e -= n; 259 x = b->x; 260 } 261 if (e > fpi->emax) { 262 ovfl: 263 Bfree(b); 264 ovfl1: 265#ifndef NO_ERRNO 266 errno = ERANGE; 267#endif 268 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 269 } 270 irv = STRTOG_Normal; 271 if (e < fpi->emin) { 272 irv = STRTOG_Denormal; 273 n = fpi->emin - e; 274 if (n >= nbits) { 275 switch (fpi->rounding) { 276 case FPI_Round_near: 277 if (n == nbits && (n < 2 || any_on(b,n-1))) 278 goto one_bit; 279 break; 280 case FPI_Round_up: 281 if (!sign) 282 goto one_bit; 283 break; 284 case FPI_Round_down: 285 if (sign) { 286 one_bit: 287 x[0] = b->wds = 1; 288 dret: 289 *bp = b; 290 *expt = fpi->emin; 291#ifndef NO_ERRNO 292 errno = ERANGE; 293#endif 294 return STRTOG_Denormal | STRTOG_Inexhi 295 | STRTOG_Underflow; 296 } 297 } 298 Bfree(b); 299 retz: 300#ifndef NO_ERRNO 301 errno = ERANGE; 302#endif 303 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 304 } 305 k = n - 1; 306 if (lostbits) 307 lostbits = 1; 308 else if (k > 0) 309 lostbits = any_on(b,k); 310 if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) 311 lostbits |= 2; 312 nbits -= n; 313 rshift(b,n); 314 e = fpi->emin; 315 } 316 if (lostbits) { 317 up = 0; 318 switch(fpi->rounding) { 319 case FPI_Round_zero: 320 break; 321 case FPI_Round_near: 322 if (lostbits & 2 323 && (lostbits | x[0]) & 1) 324 up = 1; 325 break; 326 case FPI_Round_up: 327 up = 1 - sign; 328 break; 329 case FPI_Round_down: 330 up = sign; 331 } 332 if (up) { 333 k = b->wds; 334 b = increment(b); 335 x = b->x; 336 if (irv == STRTOG_Denormal) { 337 if (nbits == fpi->nbits - 1 338 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask)) 339 irv = STRTOG_Normal; 340 } 341 else if (b->wds > k 342 || ((n = nbits & kmask) !=0 343 && hi0bits(x[k-1]) < 32-n)) { 344 rshift(b,1); 345 if (++e > fpi->emax) 346 goto ovfl; 347 } 348 irv |= STRTOG_Inexhi; 349 } 350 else 351 irv |= STRTOG_Inexlo; 352 } 353 *bp = b; 354 *expt = e; 355 return irv; 356 } 357