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