1112158Sdas/**************************************************************** 2112158Sdas 3112158SdasThe author of this software is David M. Gay. 4112158Sdas 5112158SdasCopyright (C) 1998 by Lucent Technologies 6112158SdasAll Rights Reserved 7112158Sdas 8112158SdasPermission to use, copy, modify, and distribute this software and 9112158Sdasits documentation for any purpose and without fee is hereby 10112158Sdasgranted, provided that the above copyright notice appear in all 11112158Sdascopies and that both that the copyright notice and this 12112158Sdaspermission notice and warranty disclaimer appear in supporting 13112158Sdasdocumentation, and that the name of Lucent or any of its entities 14112158Sdasnot be used in advertising or publicity pertaining to 15112158Sdasdistribution of the software without specific, written prior 16112158Sdaspermission. 17112158Sdas 18112158SdasLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19112158SdasINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 20112158SdasIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 21112158SdasSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22112158SdasWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 23112158SdasIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 24112158SdasARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 25112158SdasTHIS SOFTWARE. 26112158Sdas 27112158Sdas****************************************************************/ 28112158Sdas 29165743Sdas/* Please send bug reports to David M. Gay (dmg at acm dot org, 30165743Sdas * with " at " changed at "@" and " dot " changed to "."). */ 31112158Sdas 32112158Sdas#include "gdtoaimp.h" 33112158Sdas 34112620Sdas#ifdef USE_LOCALE 35112620Sdas#include "locale.h" 36112620Sdas#endif 37112620Sdas 38112158Sdas int 39112158Sdas#ifdef KR_headers 40112158Sdasgethex(sp, fpi, exp, bp, sign) 41112158Sdas CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 42112158Sdas#else 43112158Sdasgethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 44112158Sdas#endif 45112158Sdas{ 46112158Sdas Bigint *b; 47112158Sdas CONST unsigned char *decpt, *s0, *s, *s1; 48182709Sdas int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; 49112158Sdas ULong L, lostbits, *x; 50112158Sdas Long e, e1; 51112620Sdas#ifdef USE_LOCALE 52187808Sdas int i; 53187808Sdas#ifdef NO_LOCALE_CACHE 54187808Sdas const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; 55112620Sdas#else 56187808Sdas const unsigned char *decimalpoint; 57187808Sdas static unsigned char *decimalpoint_cache; 58187808Sdas if (!(s0 = decimalpoint_cache)) { 59187808Sdas s0 = (unsigned char*)localeconv()->decimal_point; 60219557Sdas if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { 61187808Sdas strcpy(decimalpoint_cache, s0); 62187808Sdas s0 = decimalpoint_cache; 63187808Sdas } 64187808Sdas } 65187808Sdas decimalpoint = s0; 66112620Sdas#endif 67187808Sdas#endif 68112158Sdas 69112158Sdas if (!hexdig['0']) 70112158Sdas hexdig_init_D2A(); 71182709Sdas *bp = 0; 72112158Sdas havedig = 0; 73112158Sdas s0 = *(CONST unsigned char **)sp + 2; 74112158Sdas while(s0[havedig] == '0') 75112158Sdas havedig++; 76112158Sdas s0 += havedig; 77112158Sdas s = s0; 78112158Sdas decpt = 0; 79165743Sdas zret = 0; 80165743Sdas e = 0; 81187808Sdas if (hexdig[*s]) 82187808Sdas havedig++; 83187808Sdas else { 84165743Sdas zret = 1; 85187808Sdas#ifdef USE_LOCALE 86187808Sdas for(i = 0; decimalpoint[i]; ++i) { 87187808Sdas if (s[i] != decimalpoint[i]) 88187808Sdas goto pcheck; 89187808Sdas } 90187808Sdas decpt = s += i; 91187808Sdas#else 92187808Sdas if (*s != '.') 93165743Sdas goto pcheck; 94165743Sdas decpt = ++s; 95187808Sdas#endif 96165743Sdas if (!hexdig[*s]) 97165743Sdas goto pcheck; 98112158Sdas while(*s == '0') 99112158Sdas s++; 100165743Sdas if (hexdig[*s]) 101165743Sdas zret = 0; 102112158Sdas havedig = 1; 103112158Sdas s0 = s; 104112158Sdas } 105112158Sdas while(hexdig[*s]) 106112158Sdas s++; 107187808Sdas#ifdef USE_LOCALE 108187808Sdas if (*s == *decimalpoint && !decpt) { 109187808Sdas for(i = 1; decimalpoint[i]; ++i) { 110187808Sdas if (s[i] != decimalpoint[i]) 111187808Sdas goto pcheck; 112187808Sdas } 113187808Sdas decpt = s += i; 114187808Sdas#else 115187808Sdas if (*s == '.' && !decpt) { 116112158Sdas decpt = ++s; 117187808Sdas#endif 118112158Sdas while(hexdig[*s]) 119112158Sdas s++; 120187808Sdas }/*}*/ 121112158Sdas if (decpt) 122112158Sdas e = -(((Long)(s-decpt)) << 2); 123165743Sdas pcheck: 124112158Sdas s1 = s; 125182709Sdas big = esign = 0; 126112158Sdas switch(*s) { 127112158Sdas case 'p': 128112158Sdas case 'P': 129112158Sdas switch(*++s) { 130112158Sdas case '-': 131112158Sdas esign = 1; 132112158Sdas /* no break */ 133112158Sdas case '+': 134112158Sdas s++; 135112158Sdas } 136112158Sdas if ((n = hexdig[*s]) == 0 || n > 0x19) { 137112158Sdas s = s1; 138112158Sdas break; 139112158Sdas } 140112158Sdas e1 = n - 0x10; 141182709Sdas while((n = hexdig[*++s]) !=0 && n <= 0x19) { 142182709Sdas if (e1 & 0xf8000000) 143182709Sdas big = 1; 144112158Sdas e1 = 10*e1 + n - 0x10; 145182709Sdas } 146112158Sdas if (esign) 147112158Sdas e1 = -e1; 148112158Sdas e += e1; 149112158Sdas } 150112158Sdas *sp = (char*)s; 151182709Sdas if (!havedig) 152187808Sdas *sp = (char*)s0 - 1; 153182709Sdas if (zret) 154179918Sdas return STRTOG_Zero; 155182709Sdas if (big) { 156182709Sdas if (esign) { 157182709Sdas switch(fpi->rounding) { 158182709Sdas case FPI_Round_up: 159182709Sdas if (sign) 160182709Sdas break; 161182709Sdas goto ret_tiny; 162182709Sdas case FPI_Round_down: 163182709Sdas if (!sign) 164182709Sdas break; 165182709Sdas goto ret_tiny; 166182709Sdas } 167182709Sdas goto retz; 168182709Sdas ret_tiny: 169182709Sdas b = Balloc(0); 170182709Sdas b->wds = 1; 171182709Sdas b->x[0] = 1; 172182709Sdas goto dret; 173182709Sdas } 174182709Sdas switch(fpi->rounding) { 175182709Sdas case FPI_Round_near: 176182709Sdas goto ovfl1; 177182709Sdas case FPI_Round_up: 178182709Sdas if (!sign) 179182709Sdas goto ovfl1; 180182709Sdas goto ret_big; 181182709Sdas case FPI_Round_down: 182182709Sdas if (sign) 183182709Sdas goto ovfl1; 184182709Sdas goto ret_big; 185182709Sdas } 186182709Sdas ret_big: 187182709Sdas nbits = fpi->nbits; 188182709Sdas n0 = n = nbits >> kshift; 189182709Sdas if (nbits & kmask) 190182709Sdas ++n; 191182709Sdas for(j = n, k = 0; j >>= 1; ++k); 192182709Sdas *bp = b = Balloc(k); 193182709Sdas b->wds = n; 194182709Sdas for(j = 0; j < n0; ++j) 195182709Sdas b->x[j] = ALL_ON; 196182709Sdas if (n > n0) 197182709Sdas b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 198182709Sdas *exp = fpi->emin; 199182709Sdas return STRTOG_Normal | STRTOG_Inexlo; 200179918Sdas } 201112158Sdas n = s1 - s0 - 1; 202219557Sdas for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) 203112158Sdas k++; 204112158Sdas b = Balloc(k); 205112158Sdas x = b->x; 206112158Sdas n = 0; 207112158Sdas L = 0; 208187808Sdas#ifdef USE_LOCALE 209187808Sdas for(i = 0; decimalpoint[i+1]; ++i); 210187808Sdas#endif 211112158Sdas while(s1 > s0) { 212187808Sdas#ifdef USE_LOCALE 213187808Sdas if (*--s1 == decimalpoint[i]) { 214187808Sdas s1 -= i; 215112158Sdas continue; 216187808Sdas } 217187808Sdas#else 218187808Sdas if (*--s1 == '.') 219187808Sdas continue; 220187808Sdas#endif 221187808Sdas if (n == ULbits) { 222112158Sdas *x++ = L; 223112158Sdas L = 0; 224112158Sdas n = 0; 225112158Sdas } 226112158Sdas L |= (hexdig[*s1] & 0x0f) << n; 227112158Sdas n += 4; 228112158Sdas } 229112158Sdas *x++ = L; 230112158Sdas b->wds = n = x - b->x; 231187808Sdas n = ULbits*n - hi0bits(L); 232112158Sdas nbits = fpi->nbits; 233112158Sdas lostbits = 0; 234112158Sdas x = b->x; 235112158Sdas if (n > nbits) { 236112158Sdas n -= nbits; 237112158Sdas if (any_on(b,n)) { 238112158Sdas lostbits = 1; 239112158Sdas k = n - 1; 240112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) { 241112158Sdas lostbits = 2; 242182709Sdas if (k > 0 && any_on(b,k)) 243112158Sdas lostbits = 3; 244112158Sdas } 245112158Sdas } 246112158Sdas rshift(b, n); 247112158Sdas e += n; 248112158Sdas } 249112158Sdas else if (n < nbits) { 250112158Sdas n = nbits - n; 251112158Sdas b = lshift(b, n); 252112158Sdas e -= n; 253112158Sdas x = b->x; 254112158Sdas } 255112158Sdas if (e > fpi->emax) { 256112158Sdas ovfl: 257112158Sdas Bfree(b); 258182709Sdas ovfl1: 259182709Sdas#ifndef NO_ERRNO 260182709Sdas errno = ERANGE; 261182709Sdas#endif 262112158Sdas return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 263112158Sdas } 264112158Sdas irv = STRTOG_Normal; 265112158Sdas if (e < fpi->emin) { 266112158Sdas irv = STRTOG_Denormal; 267112158Sdas n = fpi->emin - e; 268112158Sdas if (n >= nbits) { 269112158Sdas switch (fpi->rounding) { 270112158Sdas case FPI_Round_near: 271124703Sdas if (n == nbits && (n < 2 || any_on(b,n-1))) 272112158Sdas goto one_bit; 273112158Sdas break; 274112158Sdas case FPI_Round_up: 275112158Sdas if (!sign) 276112158Sdas goto one_bit; 277112158Sdas break; 278112158Sdas case FPI_Round_down: 279112158Sdas if (sign) { 280112158Sdas one_bit: 281112158Sdas x[0] = b->wds = 1; 282182709Sdas dret: 283112158Sdas *bp = b; 284182709Sdas *exp = fpi->emin; 285182709Sdas#ifndef NO_ERRNO 286182709Sdas errno = ERANGE; 287182709Sdas#endif 288112158Sdas return STRTOG_Denormal | STRTOG_Inexhi 289112158Sdas | STRTOG_Underflow; 290112158Sdas } 291112158Sdas } 292112158Sdas Bfree(b); 293182709Sdas retz: 294182709Sdas#ifndef NO_ERRNO 295182709Sdas errno = ERANGE; 296182709Sdas#endif 297112158Sdas return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 298112158Sdas } 299112158Sdas k = n - 1; 300112158Sdas if (lostbits) 301112158Sdas lostbits = 1; 302112158Sdas else if (k > 0) 303112158Sdas lostbits = any_on(b,k); 304112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) 305112158Sdas lostbits |= 2; 306112158Sdas nbits -= n; 307112158Sdas rshift(b,n); 308112158Sdas e = fpi->emin; 309112158Sdas } 310112158Sdas if (lostbits) { 311112158Sdas up = 0; 312112158Sdas switch(fpi->rounding) { 313112158Sdas case FPI_Round_zero: 314112158Sdas break; 315112158Sdas case FPI_Round_near: 316112158Sdas if (lostbits & 2 317219557Sdas && (lostbits | x[0]) & 1) 318112158Sdas up = 1; 319112158Sdas break; 320112158Sdas case FPI_Round_up: 321112158Sdas up = 1 - sign; 322112158Sdas break; 323112158Sdas case FPI_Round_down: 324112158Sdas up = sign; 325112158Sdas } 326112158Sdas if (up) { 327112158Sdas k = b->wds; 328112158Sdas b = increment(b); 329112158Sdas x = b->x; 330124703Sdas if (irv == STRTOG_Denormal) { 331124703Sdas if (nbits == fpi->nbits - 1 332124703Sdas && x[nbits >> kshift] & 1 << (nbits & kmask)) 333124703Sdas irv = STRTOG_Normal; 334124703Sdas } 335124703Sdas else if (b->wds > k 336219557Sdas || ((n = nbits & kmask) !=0 337219557Sdas && hi0bits(x[k-1]) < 32-n)) { 338112158Sdas rshift(b,1); 339112158Sdas if (++e > fpi->emax) 340112158Sdas goto ovfl; 341112158Sdas } 342112158Sdas irv |= STRTOG_Inexhi; 343112158Sdas } 344112158Sdas else 345112158Sdas irv |= STRTOG_Inexlo; 346112158Sdas } 347112158Sdas *bp = b; 348112158Sdas *exp = e; 349112158Sdas return irv; 350112158Sdas } 351