]> git.saurik.com Git - apple/libc.git/blame - gdtoa/gdtoa-gethex-fbsd.c
Libc-498.1.1.tar.gz
[apple/libc.git] / gdtoa / gdtoa-gethex-fbsd.c
CommitLineData
224c7076
A
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 "xlocale_private.h"
33
34#include "gdtoaimp.h"
35
36#ifdef USE_LOCALE
37#include "locale.h"
38#endif
39
40 int
41#ifdef KR_headers
42gethex(sp, fpi, exp, bp, sign, loc)
43 CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; locale_t loc;
44#else
45gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign, locale_t loc)
46#endif
47{
48 Bigint *b;
49 CONST unsigned char *decpt, *s0, *s, *s1;
50 int esign, havedig, irv, k, n, nbits, up, zret;
51 ULong L, lostbits, *x;
52 Long e, e1;
53#ifdef USE_LOCALE
54 char *decimalpoint;
55 unsigned char *decimalpointend = NULL;
56 int decimalpointlen;
57
58 NORMALIZE_LOCALE(loc);
59 decimalpoint = localeconv_l(loc)->decimal_point;
60 decimalpointlen = strlen(decimalpoint);
61#else
62#define decimalpoint '.'
63#endif
64
65 if (!hexdig['0'])
66 hexdig_init_D2A();
67 havedig = 0;
68 s0 = *(CONST unsigned char **)sp + 2;
69 while(s0[havedig] == '0')
70 havedig++;
71 s0 += havedig;
72 s = s0;
73 decpt = 0;
74 zret = 0;
75 e = 0;
76 if (!hexdig[*s]) {
77 zret = 1;
78#ifdef USE_LOCALE
79 if (strncmp((char *)s, decimalpoint, decimalpointlen) != 0)
80#else /* USE_LOCALE */
81 if (*s != decimalpoint)
82#endif /* USE_LOCALE */
83 goto pcheck;
84#ifdef USE_LOCALE
85 decpt = (s += decimalpointlen);
86 decimalpointend = s - 1;
87#else /* USE_LOCALE */
88 decpt = ++s;
89#endif /* USE_LOCALE */
90 if (!hexdig[*s])
91 goto pcheck;
92 while(*s == '0')
93 s++;
94 if (hexdig[*s])
95 zret = 0;
96 havedig = 1;
97 s0 = s;
98 }
99 while(hexdig[*s])
100 s++;
101#ifdef USE_LOCALE
102 if (strncmp((char *)s, decimalpoint, decimalpointlen) == 0 && !decpt)
103#else /* USE_LOCALE */
104 if (*s == decimalpoint && !decpt)
105#endif /* USE_LOCALE */
106 {
107#ifdef USE_LOCALE
108 decpt = (s += decimalpointlen);
109 decimalpointend = s - 1;
110#else /* USE_LOCALE */
111 decpt = ++s;
112#endif /* USE_LOCALE */
113 while(hexdig[*s])
114 s++;
115 }
116 if (decpt)
117 e = -(((Long)(s-decpt)) << 2);
118 pcheck:
119 s1 = s;
120 switch(*s) {
121 case 'p':
122 case 'P':
123 esign = 0;
124 switch(*++s) {
125 case '-':
126 esign = 1;
127 /* no break */
128 case '+':
129 s++;
130 }
131 if ((n = hexdig[*s]) == 0 || n > 0x19) {
132 s = s1;
133 break;
134 }
135 e1 = n - 0x10;
136 while((n = hexdig[*++s]) !=0 && n <= 0x19)
137 e1 = 10*e1 + n - 0x10;
138 if (esign)
139 e1 = -e1;
140 e += e1;
141 }
142 *sp = (char*)s;
143 if (zret)
144 return havedig ? STRTOG_Zero : STRTOG_NoNumber;
145 n = s1 - s0 - 1;
146 for(k = 0; n > 7; n >>= 1)
147 k++;
148 b = Balloc(k);
149 x = b->x;
150 n = 0;
151 L = 0;
152 while(s1 > s0) {
153#ifdef USE_LOCALE
154 if (--s1 == decimalpointend) {
155 s1 -= decimalpointlen - 1;
156 continue;
157 }
158#else /* USE_LOCALE */
159 if (*--s1 == decimalpoint)
160 continue;
161#endif /* USE_LOCALE */
162 if (n == 32) {
163 *x++ = L;
164 L = 0;
165 n = 0;
166 }
167 L |= (hexdig[*s1] & 0x0f) << n;
168 n += 4;
169 }
170 *x++ = L;
171 b->wds = n = x - b->x;
172 n = 32*n - hi0bits(L);
173 nbits = fpi->nbits;
174 lostbits = 0;
175 x = b->x;
176 if (n > nbits) {
177 n -= nbits;
178 if (any_on(b,n)) {
179 lostbits = 1;
180 k = n - 1;
181 if (x[k>>kshift] & 1 << (k & kmask)) {
182 lostbits = 2;
183 if (k > 1 && any_on(b,k-1))
184 lostbits = 3;
185 }
186 }
187 rshift(b, n);
188 e += n;
189 }
190 else if (n < nbits) {
191 n = nbits - n;
192 b = lshift(b, n);
193 e -= n;
194 x = b->x;
195 }
196 if (e > fpi->emax) {
197 ovfl:
198 Bfree(b);
199 *bp = 0;
200 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
201 }
202 irv = STRTOG_Normal;
203 if (e < fpi->emin) {
204 irv = STRTOG_Denormal;
205 n = fpi->emin - e;
206 if (n >= nbits) {
207 switch (fpi->rounding) {
208 case FPI_Round_near:
209 if (n == nbits && (n < 2 || any_on(b,n-1)))
210 goto one_bit;
211 break;
212 case FPI_Round_up:
213 if (!sign)
214 goto one_bit;
215 break;
216 case FPI_Round_down:
217 if (sign) {
218 one_bit:
219 *exp = fpi->emin;
220 x[0] = b->wds = 1;
221 *bp = b;
222 return STRTOG_Denormal | STRTOG_Inexhi
223 | STRTOG_Underflow;
224 }
225 }
226 Bfree(b);
227 *bp = 0;
228 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
229 }
230 k = n - 1;
231 if (lostbits)
232 lostbits = 1;
233 else if (k > 0)
234 lostbits = any_on(b,k);
235 if (x[k>>kshift] & 1 << (k & kmask))
236 lostbits |= 2;
237 nbits -= n;
238 rshift(b,n);
239 e = fpi->emin;
240 }
241 if (lostbits) {
242 up = 0;
243 switch(fpi->rounding) {
244 case FPI_Round_zero:
245 break;
246 case FPI_Round_near:
247 if (lostbits & 2
248 && (lostbits & 1) | x[0] & 1)
249 up = 1;
250 break;
251 case FPI_Round_up:
252 up = 1 - sign;
253 break;
254 case FPI_Round_down:
255 up = sign;
256 }
257 if (up) {
258 k = b->wds;
259 b = increment(b);
260 x = b->x;
261 if (irv == STRTOG_Denormal) {
262 if (nbits == fpi->nbits - 1
263 && x[nbits >> kshift] & 1 << (nbits & kmask))
264 irv = STRTOG_Normal;
265 }
266 else if (b->wds > k
267 || (n = nbits & kmask) !=0
268 && hi0bits(x[k-1]) < 32-n) {
269 rshift(b,1);
270 if (++e > fpi->emax)
271 goto ovfl;
272 }
273 irv |= STRTOG_Inexhi;
274 }
275 else
276 irv |= STRTOG_Inexlo;
277 }
278 *bp = b;
279 *exp = e;
280 return irv;
281 }