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