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