1 /* $NetBSD: gethex.c,v 1.3.14.1 2008/04/08 21:10:55 jdc Exp $ */
2 
3 /****************************************************************
4 
5 The author of this software is David M. Gay.
6 
7 Copyright (C) 1998 by Lucent Technologies
8 All Rights Reserved
9 
10 Permission to use, copy, modify, and distribute this software and
11 its documentation for any purpose and without fee is hereby
12 granted, provided that the above copyright notice appear in all
13 copies and that both that the copyright notice and this
14 permission notice and warranty disclaimer appear in supporting
15 documentation, and that the name of Lucent or any of its entities
16 not be used in advertising or publicity pertaining to
17 distribution of the software without specific, written prior
18 permission.
19 
20 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
22 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
23 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
25 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27 THIS 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 #include  <LibConfig.h>
34 
35 #include "gdtoaimp.h"
36 
37 #ifdef USE_LOCALE
38 #include "locale.h"
39 #endif
40 
41  int
gethex(CONST char ** sp,CONST FPI * fpi,Long * expt,Bigint ** bp,int sign)42 gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign)
43 {
44   Bigint *b;
45   CONST unsigned char *decpt, *s0, *s, *s1;
46   int esign, havedig, irv, k, n, nbits, up, zret;
47   ULong L, lostbits, *x;
48   Long e, e1;
49 #ifdef USE_LOCALE
50   unsigned char decimalpoint = *localeconv()->decimal_point;
51 #else
52 #define decimalpoint '.'
53 #endif
54 
55   if (!hexdig['0'])
56     hexdig_init_D2A();
57   havedig = 0;
58   s0 = *(CONST unsigned char **)sp + 2;
59   while(s0[havedig] == '0')
60     havedig++;
61   s0 += havedig;
62   s = s0;
63   decpt = 0;
64   zret = 0;
65   e = 0;
66   if (!hexdig[*s]) {
67     zret = 1;
68     if (*s != decimalpoint)
69       goto pcheck;
70     decpt = ++s;
71     if (!hexdig[*s])
72       goto pcheck;
73     while(*s == '0')
74       s++;
75     if (hexdig[*s])
76       zret = 0;
77     havedig = 1;
78     s0 = s;
79     }
80   while(hexdig[*s])
81     s++;
82   if (*s == decimalpoint && !decpt) {
83     decpt = ++s;
84     while(hexdig[*s])
85       s++;
86     }
87   if (decpt)
88     e = -(((Long)(s-decpt)) << 2);
89  pcheck:
90   s1 = s;
91   switch(*s) {
92     case 'p':
93     case 'P':
94     esign = 0;
95     switch(*++s) {
96       case '-':
97       esign = 1;
98       /* FALLTHROUGH */
99       case '+':
100       s++;
101       }
102     if ((n = hexdig[*s]) == 0 || n > 0x19) {
103       s = s1;
104       break;
105       }
106     e1 = n - 0x10;
107     while((n = hexdig[*++s]) !=0 && n <= 0x19)
108       e1 = 10*e1 + n - 0x10;
109     if (esign)
110       e1 = -e1;
111     e += e1;
112     }
113   *sp = __UNCONST(s);
114   if (zret)
115     return havedig ? STRTOG_Zero : STRTOG_NoNumber;
116   n = (int)(s1 - s0 - 1);
117   for(k = 0; n > 7; n = (unsigned int)n >> 1)
118     k++;
119   b = Balloc(k);
120   if (b == NULL)
121     return STRTOG_NoMemory;
122   x = b->x;
123   n = 0;
124   L = 0;
125   while(s1 > s0) {
126     if (*--s1 == decimalpoint)
127       continue;
128     if (n == 32) {
129       *x++ = L;
130       L = 0;
131       n = 0;
132       }
133     L |= (hexdig[*s1] & 0x0f) << n;
134     n += 4;
135     }
136   *x++ = L;
137   b->wds = n = (int)(x - b->x);
138   n = 32*n - hi0bits(L);
139   nbits = fpi->nbits;
140   lostbits = 0;
141   x = b->x;
142   if (n > nbits) {
143     n -= nbits;
144     if (any_on(b,n)) {
145       lostbits = 1;
146       k = n - 1;
147       if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
148         lostbits = 2;
149         if (k > 1 && any_on(b,k-1))
150           lostbits = 3;
151         }
152       }
153     rshift(b, n);
154     e += n;
155     }
156   else if (n < nbits) {
157     n = nbits - n;
158     b = lshift(b, n);
159     if (b == NULL)
160       return STRTOG_NoMemory;
161     e -= n;
162     x = b->x;
163     }
164   if (e > fpi->emax) {
165  ovfl:
166     Bfree(b);
167     *bp = 0;
168     return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
169     }
170   irv = STRTOG_Normal;
171   if (e < fpi->emin) {
172     irv = STRTOG_Denormal;
173     n = fpi->emin - e;
174     if (n >= nbits) {
175       switch (fpi->rounding) {
176         case FPI_Round_near:
177         if (n == nbits && (n < 2 || any_on(b,n-1)))
178           goto one_bit;
179         break;
180         case FPI_Round_up:
181         if (!sign)
182           goto one_bit;
183         break;
184         case FPI_Round_down:
185         if (sign) {
186  one_bit:
187           *expt = fpi->emin;
188           x[0] = b->wds = 1;
189           *bp = b;
190           return STRTOG_Denormal | STRTOG_Inexhi
191             | STRTOG_Underflow;
192           }
193         }
194       Bfree(b);
195       *bp = 0;
196       return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
197       }
198     k = n - 1;
199     if (lostbits)
200       lostbits = 1;
201     else if (k > 0)
202       lostbits = any_on(b,k);
203     if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
204       lostbits |= 2;
205     nbits -= n;
206     rshift(b,n);
207     e = fpi->emin;
208     }
209   if (lostbits) {
210     up = 0;
211     switch(fpi->rounding) {
212       case FPI_Round_zero:
213       break;
214       case FPI_Round_near:
215       if (lostbits & 2
216        && (lostbits & 1) | (x[0] & 1))
217         up = 1;
218       break;
219       case FPI_Round_up:
220       up = 1 - sign;
221       break;
222       case FPI_Round_down:
223       up = sign;
224       }
225     if (up) {
226       k = b->wds;
227       b = increment(b);
228       x = b->x;
229       if (irv == STRTOG_Denormal) {
230         if (nbits == fpi->nbits - 1
231          && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
232           irv =  STRTOG_Normal;
233         }
234       else if (b->wds > k
235        || ((n = nbits & kmask) !=0
236            && hi0bits(x[k-1]) < 32-n)) {
237         rshift(b,1);
238         if (++e > fpi->emax)
239           goto ovfl;
240         }
241       irv |= STRTOG_Inexhi;
242       }
243     else
244       irv |= STRTOG_Inexlo;
245     }
246   *bp = b;
247   *expt = e;
248   return irv;
249   }
250