]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/gdtoa/gethex.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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                 if (!havedig)
118                         *sp = s0 - 1;
119                 return STRTOG_Zero;
120                 }
121         n = s1 - s0 - 1;
122         for(k = 0; n > 7; n >>= 1)
123                 k++;
124         b = Balloc(k);
125         x = b->x;
126         n = 0;
127         L = 0;
128         while(s1 > s0) {
129                 if (*--s1 == decimalpoint)
130                         continue;
131                 if (n == 32) {
132                         *x++ = L;
133                         L = 0;
134                         n = 0;
135                         }
136                 L |= (hexdig[*s1] & 0x0f) << n;
137                 n += 4;
138                 }
139         *x++ = L;
140         b->wds = n = x - b->x;
141         n = 32*n - hi0bits(L);
142         nbits = fpi->nbits;
143         lostbits = 0;
144         x = b->x;
145         if (n > nbits) {
146                 n -= nbits;
147                 if (any_on(b,n)) {
148                         lostbits = 1;
149                         k = n - 1;
150                         if (x[k>>kshift] & 1 << (k & kmask)) {
151                                 lostbits = 2;
152                                 if (k > 1 && any_on(b,k-1))
153                                         lostbits = 3;
154                                 }
155                         }
156                 rshift(b, n);
157                 e += n;
158                 }
159         else if (n < nbits) {
160                 n = nbits - n;
161                 b = lshift(b, n);
162                 e -= n;
163                 x = b->x;
164                 }
165         if (e > fpi->emax) {
166  ovfl:
167                 Bfree(b);
168                 *bp = 0;
169                 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
170                 }
171         irv = STRTOG_Normal;
172         if (e < fpi->emin) {
173                 irv = STRTOG_Denormal;
174                 n = fpi->emin - e;
175                 if (n >= nbits) {
176                         switch (fpi->rounding) {
177                           case FPI_Round_near:
178                                 if (n == nbits && (n < 2 || any_on(b,n-1)))
179                                         goto one_bit;
180                                 break;
181                           case FPI_Round_up:
182                                 if (!sign)
183                                         goto one_bit;
184                                 break;
185                           case FPI_Round_down:
186                                 if (sign) {
187  one_bit:
188                                         *exp = fpi->emin;
189                                         x[0] = b->wds = 1;
190                                         *bp = b;
191                                         return STRTOG_Denormal | STRTOG_Inexhi
192                                                 | STRTOG_Underflow;
193                                         }
194                           }
195                         Bfree(b);
196                         *bp = 0;
197                         return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
198                         }
199                 k = n - 1;
200                 if (lostbits)
201                         lostbits = 1;
202                 else if (k > 0)
203                         lostbits = any_on(b,k);
204                 if (x[k>>kshift] & 1 << (k & kmask))
205                         lostbits |= 2;
206                 nbits -= n;
207                 rshift(b,n);
208                 e = fpi->emin;
209                 }
210         if (lostbits) {
211                 up = 0;
212                 switch(fpi->rounding) {
213                   case FPI_Round_zero:
214                         break;
215                   case FPI_Round_near:
216                         if (lostbits & 2
217                          && (lostbits & 1) | x[0] & 1)
218                                 up = 1;
219                         break;
220                   case FPI_Round_up:
221                         up = 1 - sign;
222                         break;
223                   case FPI_Round_down:
224                         up = sign;
225                   }
226                 if (up) {
227                         k = b->wds;
228                         b = increment(b);
229                         x = b->x;
230                         if (irv == STRTOG_Denormal) {
231                                 if (nbits == fpi->nbits - 1
232                                  && x[nbits >> kshift] & 1 << (nbits & kmask))
233                                         irv =  STRTOG_Normal;
234                                 }
235                         else if (b->wds > k
236                          || (n = nbits & kmask) !=0
237                              && hi0bits(x[k-1]) < 32-n) {
238                                 rshift(b,1);
239                                 if (++e > fpi->emax)
240                                         goto ovfl;
241                                 }
242                         irv |= STRTOG_Inexhi;
243                         }
244                 else
245                         irv |= STRTOG_Inexlo;
246                 }
247         *bp = b;
248         *exp = e;
249         return irv;
250         }