source: trunk/libs/newlib/src/newlib/libc/stdlib/gdtoa-gethex.c @ 577

Last change on this file since 577 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 7.6 KB
Line 
1/****************************************************************
2
3The author of this software is David M. Gay.
4
5Copyright (C) 1998 by Lucent Technologies
6All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and
9its documentation for any purpose and without fee is hereby
10granted, provided that the above copyright notice appear in all
11copies and that both that the copyright notice and this
12permission notice and warranty disclaimer appear in supporting
13documentation, and that the name of Lucent or any of its entities
14not be used in advertising or publicity pertaining to
15distribution of the software without specific, written prior
16permission.
17
18LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25THIS 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 <_ansi.h>
33#include <reent.h>
34#include <string.h>
35#include <locale.h>
36#include "mprec.h"
37#include "gdtoa.h"
38#include "gd_qnan.h"
39
40#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG)
41const unsigned char __hexdig[256]=
42{
43        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46        16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,
47        0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,
48        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
49        0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,
50        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
51        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
53        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
54        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
55        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
56        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
57        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
58        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
59};
60#else /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG) */
61unsigned char
62__hexdig_fun (unsigned char c)
63{
64        if(c>='0' && c<='9') return c-'0'+0x10;
65        else if(c>='a' && c<='f') return c-'a'+0x10+10;
66        else if(c>='A' && c<='F') return c-'A'+0x10+10;
67        else return 0;
68}
69#endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG) */
70
71static void
72rshift (_Bigint *b,
73        int k)
74{
75        __ULong *x, *x1, *xe, y;
76        int n;
77
78        x = x1 = b->_x;
79        n = k >> kshift;
80        if (n < b->_wds) {
81                xe = x + b->_wds;
82                x += n;
83                if (k &= kmask) {
84                        n = ULbits - k;
85                        y = *x++ >> k;
86                        while(x < xe) {
87                                *x1++ = (y | (*x << n)) & ALL_ON;
88                                y = *x++ >> k;
89                                }
90                        if ((*x1 = y) !=0)
91                                x1++;
92                        }
93                else
94                        while(x < xe)
95                                *x1++ = *x++;
96                }
97        if ((b->_wds = x1 - b->_x) == 0)
98                b->_x[0] = 0;
99}
100
101static _Bigint *
102increment (struct _reent *ptr,
103        _Bigint *b)
104{
105        __ULong *x, *xe;
106        _Bigint *b1;
107#ifdef Pack_16
108        __ULong carry = 1, y;
109#endif
110
111        x = b->_x;
112        xe = x + b->_wds;
113#ifdef Pack_32
114        do {
115                if (*x < (__ULong)0xffffffffL) {
116                        ++*x;
117                        return b;
118                        }
119                *x++ = 0;
120                } while(x < xe);
121#else
122        do {
123                y = *x + carry;
124                carry = y >> 16;
125                *x++ = y & 0xffff;
126                if (!carry)
127                        return b;
128                } while(x < xe);
129        if (carry)
130#endif
131        {
132                if (b->_wds >= b->_maxwds) {
133                        b1 = Balloc(ptr, b->_k+1);
134                        Bcopy(b1, b);
135                        Bfree(ptr, b);
136                        b = b1;
137                        }
138                b->_x[b->_wds++] = 1;
139                }
140        return b;
141}
142
143
144int
145gethex (struct _reent *ptr, const char **sp, const FPI *fpi,
146        Long *exp, _Bigint **bp, int sign, locale_t loc)
147{
148        _Bigint *b;
149        const unsigned char *decpt, *s0, *s, *s1;
150        int esign, havedig, irv, k, n, nbits, up, zret;
151        __ULong L, lostbits, *x;
152        Long e, e1;
153        unsigned char *decimalpoint = (unsigned char *)
154                                      __localeconv_l (loc)->decimal_point;
155        size_t decp_len = strlen ((const char *) decimalpoint);
156        unsigned char decp_end = decimalpoint[decp_len - 1];
157
158        havedig = 0;
159        s0 = *(const unsigned char **)sp + 2;
160        while(s0[havedig] == '0')
161                havedig++;
162        s0 += havedig;
163        s = s0;
164        decpt = 0;
165        zret = 0;
166        e = 0;
167        if (!__get_hexdig(*s)) {
168                zret = 1;
169                if (strncmp ((const char *) s, (const char *) decimalpoint,
170                             decp_len) != 0)
171                        goto pcheck;
172                decpt = (s += decp_len);
173                if (!__get_hexdig(*s))
174                        goto pcheck;
175                while(*s == '0')
176                        s++;
177                if (__get_hexdig(*s))
178                        zret = 0;
179                havedig = 1;
180                s0 = s;
181                }
182        while(__get_hexdig(*s))
183                s++;
184        if (strncmp ((const char *) s, (const char *) decimalpoint,
185                     decp_len) == 0
186            && !decpt) {
187                decpt = (s += decp_len);
188                while(__get_hexdig(*s))
189                        s++;
190                }
191        if (decpt)
192                e = -(((Long)(s-decpt)) << 2);
193 pcheck:
194        s1 = s;
195        switch(*s) {
196          case 'p':
197          case 'P':
198                esign = 0;
199                switch(*++s) {
200                  case '-':
201                        esign = 1;
202                        /* no break */
203                  case '+':
204                        s++;
205                  }
206                if ((n = __get_hexdig(*s)) == 0 || n > 0x19) {
207                        s = s1;
208                        break;
209                        }
210                e1 = n - 0x10;
211                while((n = __get_hexdig(*++s)) !=0 && n <= 0x19)
212                        e1 = 10*e1 + n - 0x10;
213                if (esign)
214                        e1 = -e1;
215                e += e1;
216          }
217        *sp = (char*)s;
218        if (zret)
219                return havedig ? STRTOG_Zero : STRTOG_NoNumber;
220        n = s1 - s0 - 1;
221        for(k = 0; n > 7; n >>= 1)
222                k++;
223        b = Balloc(ptr, k);
224        x = b->_x;
225        n = 0;
226        L = 0;
227        while(s1 > s0) {
228                if (*--s1 == decp_end && s1 - decp_len + 1 >= s0
229                    && strncmp ((const char *) s1 - decp_len + 1,
230                                (const char *) decimalpoint, decp_len) == 0) {
231                        s1 -= decp_len - 1; /* Note the --s1 above! */
232                        continue;
233                }
234                if (n == 32) {
235                        *x++ = L;
236                        L = 0;
237                        n = 0;
238                        }
239                L |= (__get_hexdig(*s1) & 0x0f) << n;
240                n += 4;
241                }
242        *x++ = L;
243        b->_wds = n = x - b->_x;
244        n = 32*n - hi0bits(L);
245        nbits = fpi->nbits;
246        lostbits = 0;
247        x = b->_x;
248        if (n > nbits) {
249                n -= nbits;
250                if (any_on(b,n)) {
251                        lostbits = 1;
252                        k = n - 1;
253                        if (x[k>>kshift] & 1 << (k & kmask)) {
254                                lostbits = 2;
255                                if (k > 1 && any_on(b,k-1))
256                                        lostbits = 3;
257                                }
258                        }
259                rshift(b, n);
260                e += n;
261                }
262        else if (n < nbits) {
263                n = nbits - n;
264                b = lshift(ptr, b, n);
265                e -= n;
266                x = b->_x;
267                }
268        if (e > fpi->emax) {
269 ovfl:
270                Bfree(ptr, b);
271                *bp = 0;
272                return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
273                }
274        irv = STRTOG_Normal;
275        if (e < fpi->emin) {
276                irv = STRTOG_Denormal;
277                n = fpi->emin - e;
278                if (n >= nbits) {
279                        switch (fpi->rounding) {
280                          case FPI_Round_near:
281                                if (n == nbits && (n < 2 || any_on(b,n-1)))
282                                        goto one_bit;
283                                break;
284                          case FPI_Round_up:
285                                if (!sign)
286                                        goto one_bit;
287                                break;
288                          case FPI_Round_down:
289                                if (sign) {
290 one_bit:
291                                        *exp = fpi->emin;
292                                        x[0] = b->_wds = 1;
293                                        *bp = b;
294                                        return STRTOG_Denormal | STRTOG_Inexhi
295                                                | STRTOG_Underflow;
296                                        }
297                          }
298                        Bfree(ptr, b);
299                        *bp = 0;
300                        return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
301                        }
302                k = n - 1;
303                if (lostbits)
304                        lostbits = 1;
305                else if (k > 0)
306                        lostbits = any_on(b,k);
307                if (x[k>>kshift] & 1 << (k & kmask))
308                        lostbits |= 2;
309                nbits -= n;
310                rshift(b,n);
311                e = fpi->emin;
312                }
313        if (lostbits) {
314                up = 0;
315                switch(fpi->rounding) {
316                  case FPI_Round_zero:
317                        break;
318                  case FPI_Round_near:
319                    if ((lostbits & 2)
320                            && ((lostbits & 1) | (x[0] & 1)))
321                                up = 1;
322                        break;
323                  case FPI_Round_up:
324                        up = 1 - sign;
325                        break;
326                  case FPI_Round_down:
327                        up = sign;
328                  }
329                if (up) {
330                        k = b->_wds;
331                        b = increment(ptr, b);
332                        x = b->_x;
333                        if (irv == STRTOG_Denormal) {
334                                if (nbits == fpi->nbits - 1
335                                 && x[nbits >> kshift] & 1 << (nbits & kmask))
336                                        irv =  STRTOG_Normal;
337                                }
338                        else if ((b->_wds > k)
339                         || ((n = nbits & kmask) !=0
340                             && (hi0bits(x[k-1]) < 32-n))) {
341                                rshift(b,1);
342                                if (++e > fpi->emax)
343                                        goto ovfl;
344                                }
345                        irv |= STRTOG_Inexhi;
346                        }
347                else
348                        irv |= STRTOG_Inexlo;
349                }
350        *bp = b;
351        *exp = e;
352        return irv;
353}
354
Note: See TracBrowser for help on using the repository browser.