Merge branch 'vendor/GCC44'
[dragonfly.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 big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
49         ULong L, lostbits, *x;
50         Long e, e1;
51 #ifdef USE_LOCALE
52         int i;
53 #ifdef NO_LOCALE_CACHE
54         const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
55 #else
56         const unsigned char *decimalpoint;
57         static unsigned char *decimalpoint_cache;
58         if (!(s0 = decimalpoint_cache)) {
59                 s0 = (unsigned char*)localeconv()->decimal_point;
60                 if ((decimalpoint_cache = (char*)malloc(strlen(s0) + 1))) {
61                         strcpy(decimalpoint_cache, s0);
62                         s0 = decimalpoint_cache;
63                         }
64                 }
65         decimalpoint = s0;
66 #endif
67 #endif
68
69         if (!hexdig['0'])
70                 hexdig_init_D2A();
71         *bp = 0;
72         havedig = 0;
73         s0 = *(CONST unsigned char **)sp + 2;
74         while(s0[havedig] == '0')
75                 havedig++;
76         s0 += havedig;
77         s = s0;
78         decpt = 0;
79         zret = 0;
80         e = 0;
81         if (hexdig[*s])
82                 havedig++;
83         else {
84                 zret = 1;
85 #ifdef USE_LOCALE
86                 for(i = 0; decimalpoint[i]; ++i) {
87                         if (s[i] != decimalpoint[i])
88                                 goto pcheck;
89                         }
90                 decpt = s += i;
91 #else
92                 if (*s != '.')
93                         goto pcheck;
94                 decpt = ++s;
95 #endif
96                 if (!hexdig[*s])
97                         goto pcheck;
98                 while(*s == '0')
99                         s++;
100                 if (hexdig[*s])
101                         zret = 0;
102                 havedig = 1;
103                 s0 = s;
104                 }
105         while(hexdig[*s])
106                 s++;
107 #ifdef USE_LOCALE
108         if (*s == *decimalpoint && !decpt) {
109                 for(i = 1; decimalpoint[i]; ++i) {
110                         if (s[i] != decimalpoint[i])
111                                 goto pcheck;
112                         }
113                 decpt = s += i;
114 #else
115         if (*s == '.' && !decpt) {
116                 decpt = ++s;
117 #endif
118                 while(hexdig[*s])
119                         s++;
120                 }/*}*/
121         if (decpt)
122                 e = -(((Long)(s-decpt)) << 2);
123  pcheck:
124         s1 = s;
125         big = esign = 0;
126         switch(*s) {
127           case 'p':
128           case 'P':
129                 switch(*++s) {
130                   case '-':
131                         esign = 1;
132                         /* no break */
133                   case '+':
134                         s++;
135                   }
136                 if ((n = hexdig[*s]) == 0 || n > 0x19) {
137                         s = s1;
138                         break;
139                         }
140                 e1 = n - 0x10;
141                 while((n = hexdig[*++s]) !=0 && n <= 0x19) {
142                         if (e1 & 0xf8000000)
143                                 big = 1;
144                         e1 = 10*e1 + n - 0x10;
145                         }
146                 if (esign)
147                         e1 = -e1;
148                 e += e1;
149           }
150         *sp = (char*)s;
151         if (!havedig)
152                 *sp = (char*)s0 - 1;
153         if (zret)
154                 return STRTOG_Zero;
155         if (big) {
156                 if (esign) {
157                         switch(fpi->rounding) {
158                           case FPI_Round_up:
159                                 if (sign)
160                                         break;
161                                 goto ret_tiny;
162                           case FPI_Round_down:
163                                 if (!sign)
164                                         break;
165                                 goto ret_tiny;
166                           }
167                         goto retz;
168  ret_tiny:
169                         b = Balloc(0);
170                         b->wds = 1;
171                         b->x[0] = 1;
172                         goto dret;
173                         }
174                 switch(fpi->rounding) {
175                   case FPI_Round_near:
176                         goto ovfl1;
177                   case FPI_Round_up:
178                         if (!sign)
179                                 goto ovfl1;
180                         goto ret_big;
181                   case FPI_Round_down:
182                         if (sign)
183                                 goto ovfl1;
184                         goto ret_big;
185                   }
186  ret_big:
187                 nbits = fpi->nbits;
188                 n0 = n = nbits >> kshift;
189                 if (nbits & kmask)
190                         ++n;
191                 for(j = n, k = 0; j >>= 1; ++k);
192                 *bp = b = Balloc(k);
193                 b->wds = n;
194                 for(j = 0; j < n0; ++j)
195                         b->x[j] = ALL_ON;
196                 if (n > n0)
197                         b->x[j] = ULbits >> (ULbits - (nbits & kmask));
198                 *exp = fpi->emin;
199                 return STRTOG_Normal | STRTOG_Inexlo;
200                 }
201         n = s1 - s0 - 1;
202         for(k = 0; n > (1 << kshift-2) - 1; n >>= 1)
203                 k++;
204         b = Balloc(k);
205         x = b->x;
206         n = 0;
207         L = 0;
208 #ifdef USE_LOCALE
209         for(i = 0; decimalpoint[i+1]; ++i);
210 #endif
211         while(s1 > s0) {
212 #ifdef USE_LOCALE
213                 if (*--s1 == decimalpoint[i]) {
214                         s1 -= i;
215                         continue;
216                         }
217 #else
218                 if (*--s1 == '.')
219                         continue;
220 #endif
221                 if (n == ULbits) {
222                         *x++ = L;
223                         L = 0;
224                         n = 0;
225                         }
226                 L |= (hexdig[*s1] & 0x0f) << n;
227                 n += 4;
228                 }
229         *x++ = L;
230         b->wds = n = x - b->x;
231         n = ULbits*n - hi0bits(L);
232         nbits = fpi->nbits;
233         lostbits = 0;
234         x = b->x;
235         if (n > nbits) {
236                 n -= nbits;
237                 if (any_on(b,n)) {
238                         lostbits = 1;
239                         k = n - 1;
240                         if (x[k>>kshift] & 1 << (k & kmask)) {
241                                 lostbits = 2;
242                                 if (k > 0 && any_on(b,k))
243                                         lostbits = 3;
244                                 }
245                         }
246                 rshift(b, n);
247                 e += n;
248                 }
249         else if (n < nbits) {
250                 n = nbits - n;
251                 b = lshift(b, n);
252                 e -= n;
253                 x = b->x;
254                 }
255         if (e > fpi->emax) {
256  ovfl:
257                 Bfree(b);
258  ovfl1:
259 #ifndef NO_ERRNO
260                 errno = ERANGE;
261 #endif
262                 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
263                 }
264         irv = STRTOG_Normal;
265         if (e < fpi->emin) {
266                 irv = STRTOG_Denormal;
267                 n = fpi->emin - e;
268                 if (n >= nbits) {
269                         switch (fpi->rounding) {
270                           case FPI_Round_near:
271                                 if (n == nbits && (n < 2 || any_on(b,n-1)))
272                                         goto one_bit;
273                                 break;
274                           case FPI_Round_up:
275                                 if (!sign)
276                                         goto one_bit;
277                                 break;
278                           case FPI_Round_down:
279                                 if (sign) {
280  one_bit:
281                                         x[0] = b->wds = 1;
282  dret:
283                                         *bp = b;
284                                         *exp = fpi->emin;
285 #ifndef NO_ERRNO
286                                         errno = ERANGE;
287 #endif
288                                         return STRTOG_Denormal | STRTOG_Inexhi
289                                                 | STRTOG_Underflow;
290                                         }
291                           }
292                         Bfree(b);
293  retz:
294 #ifndef NO_ERRNO
295                         errno = ERANGE;
296 #endif
297                         return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
298                         }
299                 k = n - 1;
300                 if (lostbits)
301                         lostbits = 1;
302                 else if (k > 0)
303                         lostbits = any_on(b,k);
304                 if (x[k>>kshift] & 1 << (k & kmask))
305                         lostbits |= 2;
306                 nbits -= n;
307                 rshift(b,n);
308                 e = fpi->emin;
309                 }
310         if (lostbits) {
311                 up = 0;
312                 switch(fpi->rounding) {
313                   case FPI_Round_zero:
314                         break;
315                   case FPI_Round_near:
316                         if (lostbits & 2
317                          && (lostbits & 1) | x[0] & 1)
318                                 up = 1;
319                         break;
320                   case FPI_Round_up:
321                         up = 1 - sign;
322                         break;
323                   case FPI_Round_down:
324                         up = sign;
325                   }
326                 if (up) {
327                         k = b->wds;
328                         b = increment(b);
329                         x = b->x;
330                         if (irv == STRTOG_Denormal) {
331                                 if (nbits == fpi->nbits - 1
332                                  && x[nbits >> kshift] & 1 << (nbits & kmask))
333                                         irv =  STRTOG_Normal;
334                                 }
335                         else if (b->wds > k
336                          || (n = nbits & kmask) !=0
337                              && hi0bits(x[k-1]) < 32-n) {
338                                 rshift(b,1);
339                                 if (++e > fpi->emax)
340                                         goto ovfl;
341                                 }
342                         irv |= STRTOG_Inexhi;
343                         }
344                 else
345                         irv |= STRTOG_Inexlo;
346                 }
347         *bp = b;
348         *exp = e;
349         return irv;
350         }