gethex.c revision 112620
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 29112158Sdas/* Please send bug reports to 30112158Sdas David M. Gay 31112620Sdas dmg@acm.org 32112158Sdas */ 33112158Sdas 34112158Sdas#include "gdtoaimp.h" 35112158Sdas 36112620Sdas#ifdef USE_LOCALE 37112620Sdas#include "locale.h" 38112620Sdas#endif 39112620Sdas 40112158Sdas int 41112158Sdas#ifdef KR_headers 42112158Sdasgethex(sp, fpi, exp, bp, sign) 43112158Sdas CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 44112158Sdas#else 45112158Sdasgethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 46112158Sdas#endif 47112158Sdas{ 48112158Sdas Bigint *b; 49112158Sdas CONST unsigned char *decpt, *s0, *s, *s1; 50112158Sdas int esign, havedig, irv, k, n, nbits, up; 51112158Sdas ULong L, lostbits, *x; 52112158Sdas Long e, e1; 53112620Sdas#ifdef USE_LOCALE 54112620Sdas char decimalpoint = *localeconv()->decimal_point; 55112620Sdas#else 56112620Sdas#define decimalpoint '.' 57112620Sdas#endif 58112158Sdas 59112158Sdas if (!hexdig['0']) 60112158Sdas hexdig_init_D2A(); 61112158Sdas havedig = 0; 62112158Sdas s0 = *(CONST unsigned char **)sp + 2; 63112158Sdas while(s0[havedig] == '0') 64112158Sdas havedig++; 65112158Sdas s0 += havedig; 66112158Sdas s = s0; 67112158Sdas decpt = 0; 68112158Sdas if (!hexdig[*s]) { 69112620Sdas if (*s == decimalpoint) { 70112158Sdas decpt = ++s; 71112158Sdas if (!hexdig[*s]) 72112158Sdas goto ret0; 73112158Sdas } 74112158Sdas else { 75112158Sdas ret0: 76112158Sdas *sp = (char*)s; 77112158Sdas return havedig ? STRTOG_Zero : STRTOG_NoNumber; 78112158Sdas } 79112158Sdas while(*s == '0') 80112158Sdas s++; 81112158Sdas havedig = 1; 82112158Sdas if (!hexdig[*s]) 83112158Sdas goto ret0; 84112158Sdas s0 = s; 85112158Sdas } 86112158Sdas while(hexdig[*s]) 87112158Sdas s++; 88112620Sdas if (*s == decimalpoint && !decpt) { 89112158Sdas decpt = ++s; 90112158Sdas while(hexdig[*s]) 91112158Sdas s++; 92112158Sdas } 93112158Sdas e = 0; 94112158Sdas if (decpt) 95112158Sdas e = -(((Long)(s-decpt)) << 2); 96112158Sdas s1 = s; 97112158Sdas switch(*s) { 98112158Sdas case 'p': 99112158Sdas case 'P': 100112158Sdas esign = 0; 101112158Sdas switch(*++s) { 102112158Sdas case '-': 103112158Sdas esign = 1; 104112158Sdas /* no break */ 105112158Sdas case '+': 106112158Sdas s++; 107112158Sdas } 108112158Sdas if ((n = hexdig[*s]) == 0 || n > 0x19) { 109112158Sdas s = s1; 110112158Sdas break; 111112158Sdas } 112112158Sdas e1 = n - 0x10; 113112158Sdas while((n = hexdig[*++s]) !=0 && n <= 0x19) 114112158Sdas e1 = 10*e1 + n - 0x10; 115112158Sdas if (esign) 116112158Sdas e1 = -e1; 117112158Sdas e += e1; 118112158Sdas } 119112158Sdas *sp = (char*)s; 120112158Sdas n = s1 - s0 - 1; 121112158Sdas for(k = 0; n > 7; n >>= 1) 122112158Sdas k++; 123112158Sdas b = Balloc(k); 124112158Sdas x = b->x; 125112158Sdas n = 0; 126112158Sdas L = 0; 127112158Sdas while(s1 > s0) { 128112620Sdas if (*--s1 == decimalpoint) 129112158Sdas continue; 130112158Sdas if (n == 32) { 131112158Sdas *x++ = L; 132112158Sdas L = 0; 133112158Sdas n = 0; 134112158Sdas } 135112158Sdas L |= (hexdig[*s1] & 0x0f) << n; 136112158Sdas n += 4; 137112158Sdas } 138112158Sdas *x++ = L; 139112158Sdas b->wds = n = x - b->x; 140112158Sdas n = 32*n - hi0bits(L); 141112158Sdas nbits = fpi->nbits; 142112158Sdas lostbits = 0; 143112158Sdas x = b->x; 144112158Sdas if (n > nbits) { 145112158Sdas n -= nbits; 146112158Sdas if (any_on(b,n)) { 147112158Sdas lostbits = 1; 148112158Sdas k = n - 1; 149112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) { 150112158Sdas lostbits = 2; 151112158Sdas if (k > 1 && any_on(b,k-1)) 152112158Sdas lostbits = 3; 153112158Sdas } 154112158Sdas } 155112158Sdas rshift(b, n); 156112158Sdas e += n; 157112158Sdas } 158112158Sdas else if (n < nbits) { 159112158Sdas n = nbits - n; 160112158Sdas b = lshift(b, n); 161112158Sdas e -= n; 162112158Sdas x = b->x; 163112158Sdas } 164112158Sdas if (e > fpi->emax) { 165112158Sdas ovfl: 166112158Sdas Bfree(b); 167112158Sdas return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 168112158Sdas } 169112158Sdas irv = STRTOG_Normal; 170112158Sdas if (e < fpi->emin) { 171112158Sdas irv = STRTOG_Denormal; 172112158Sdas n = fpi->emin - e; 173112158Sdas if (n >= nbits) { 174112158Sdas switch (fpi->rounding) { 175112158Sdas case FPI_Round_near: 176112158Sdas if (n == nbits && n < 2 || any_on(b,n-1)) 177112158Sdas goto one_bit; 178112158Sdas break; 179112158Sdas case FPI_Round_up: 180112158Sdas if (!sign) 181112158Sdas goto one_bit; 182112158Sdas break; 183112158Sdas case FPI_Round_down: 184112158Sdas if (sign) { 185112158Sdas one_bit: 186112158Sdas *exp = fpi->emin; 187112158Sdas x[0] = b->wds = 1; 188112158Sdas *bp = b; 189112158Sdas return STRTOG_Denormal | STRTOG_Inexhi 190112158Sdas | STRTOG_Underflow; 191112158Sdas } 192112158Sdas } 193112158Sdas Bfree(b); 194112158Sdas return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 195112158Sdas } 196112158Sdas k = n - 1; 197112158Sdas if (lostbits) 198112158Sdas lostbits = 1; 199112158Sdas else if (k > 0) 200112158Sdas lostbits = any_on(b,k); 201112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) 202112158Sdas lostbits |= 2; 203112158Sdas nbits -= n; 204112158Sdas rshift(b,n); 205112158Sdas e = fpi->emin; 206112158Sdas } 207112158Sdas if (lostbits) { 208112158Sdas up = 0; 209112158Sdas switch(fpi->rounding) { 210112158Sdas case FPI_Round_zero: 211112158Sdas break; 212112158Sdas case FPI_Round_near: 213112158Sdas if (lostbits & 2 214112158Sdas && (lostbits & 1) | x[0] & 1) 215112158Sdas up = 1; 216112158Sdas break; 217112158Sdas case FPI_Round_up: 218112158Sdas up = 1 - sign; 219112158Sdas break; 220112158Sdas case FPI_Round_down: 221112158Sdas up = sign; 222112158Sdas } 223112158Sdas if (up) { 224112158Sdas k = b->wds; 225112158Sdas b = increment(b); 226112158Sdas x = b->x; 227112158Sdas if (b->wds > k 228112158Sdas || (n = nbits & kmask) !=0 229112158Sdas && hi0bits(x[k-1]) < 32-n) { 230112158Sdas rshift(b,1); 231112158Sdas if (++e > fpi->emax) 232112158Sdas goto ovfl; 233112158Sdas } 234112158Sdas else if (irv == STRTOG_Denormal) { 235112158Sdas k = nbits - 1; 236112158Sdas if (x[k >> kshift] & 1 << (k & kmask)) 237112158Sdas irv = STRTOG_Normal; 238112158Sdas } 239112158Sdas irv |= STRTOG_Inexhi; 240112158Sdas } 241112158Sdas else 242112158Sdas irv |= STRTOG_Inexlo; 243112158Sdas } 244112158Sdas *bp = b; 245112158Sdas *exp = e; 246112158Sdas return irv; 247112158Sdas } 248