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