1cc36ccd1SDavid Schultz /****************************************************************
2cc36ccd1SDavid Schultz
3cc36ccd1SDavid Schultz The author of this software is David M. Gay.
4cc36ccd1SDavid Schultz
5cc36ccd1SDavid Schultz Copyright (C) 1998 by Lucent Technologies
6cc36ccd1SDavid Schultz All Rights Reserved
7cc36ccd1SDavid Schultz
8cc36ccd1SDavid Schultz Permission to use, copy, modify, and distribute this software and
9cc36ccd1SDavid Schultz its documentation for any purpose and without fee is hereby
10cc36ccd1SDavid Schultz granted, provided that the above copyright notice appear in all
11cc36ccd1SDavid Schultz copies and that both that the copyright notice and this
12cc36ccd1SDavid Schultz permission notice and warranty disclaimer appear in supporting
13cc36ccd1SDavid Schultz documentation, and that the name of Lucent or any of its entities
14cc36ccd1SDavid Schultz not be used in advertising or publicity pertaining to
15cc36ccd1SDavid Schultz distribution of the software without specific, written prior
16cc36ccd1SDavid Schultz permission.
17cc36ccd1SDavid Schultz
18cc36ccd1SDavid Schultz LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19cc36ccd1SDavid Schultz INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20cc36ccd1SDavid Schultz IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21cc36ccd1SDavid Schultz SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22cc36ccd1SDavid Schultz WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23cc36ccd1SDavid Schultz IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24cc36ccd1SDavid Schultz ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25cc36ccd1SDavid Schultz THIS SOFTWARE.
26cc36ccd1SDavid Schultz
27cc36ccd1SDavid Schultz ****************************************************************/
28cc36ccd1SDavid Schultz
29c88250a5SDavid Schultz /* Please send bug reports to David M. Gay (dmg at acm dot org,
30c88250a5SDavid Schultz * with " at " changed at "@" and " dot " changed to "."). */
31cc36ccd1SDavid Schultz
32cc36ccd1SDavid Schultz #include "gdtoaimp.h"
33cc36ccd1SDavid Schultz
348f7c2af4SDavid Schultz #ifdef USE_LOCALE
358f7c2af4SDavid Schultz #include "locale.h"
368f7c2af4SDavid Schultz #endif
378f7c2af4SDavid Schultz
38cc36ccd1SDavid Schultz int
39cc36ccd1SDavid Schultz #ifdef KR_headers
gethex(sp,fpi,exp,bp,sign)40cc36ccd1SDavid Schultz gethex(sp, fpi, exp, bp, sign)
41cc36ccd1SDavid Schultz CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
42cc36ccd1SDavid Schultz #else
43cc36ccd1SDavid Schultz gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
44cc36ccd1SDavid Schultz #endif
45cc36ccd1SDavid Schultz {
46cc36ccd1SDavid Schultz Bigint *b;
47cc36ccd1SDavid Schultz CONST unsigned char *decpt, *s0, *s, *s1;
48ae2cbf4cSDavid Schultz int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
49cc36ccd1SDavid Schultz ULong L, lostbits, *x;
50cc36ccd1SDavid Schultz Long e, e1;
518f7c2af4SDavid Schultz #ifdef USE_LOCALE
524848dd08SDavid Schultz int i;
534848dd08SDavid Schultz #ifdef NO_LOCALE_CACHE
544848dd08SDavid Schultz const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
558f7c2af4SDavid Schultz #else
564848dd08SDavid Schultz const unsigned char *decimalpoint;
574848dd08SDavid Schultz static unsigned char *decimalpoint_cache;
584848dd08SDavid Schultz if (!(s0 = decimalpoint_cache)) {
594848dd08SDavid Schultz s0 = (unsigned char*)localeconv()->decimal_point;
60*50dad48bSDavid Schultz if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
614848dd08SDavid Schultz strcpy(decimalpoint_cache, s0);
624848dd08SDavid Schultz s0 = decimalpoint_cache;
634848dd08SDavid Schultz }
644848dd08SDavid Schultz }
654848dd08SDavid Schultz decimalpoint = s0;
664848dd08SDavid Schultz #endif
678f7c2af4SDavid Schultz #endif
68cc36ccd1SDavid Schultz
69cc36ccd1SDavid Schultz if (!hexdig['0'])
70cc36ccd1SDavid Schultz hexdig_init_D2A();
71ae2cbf4cSDavid Schultz *bp = 0;
72cc36ccd1SDavid Schultz havedig = 0;
73cc36ccd1SDavid Schultz s0 = *(CONST unsigned char **)sp + 2;
74cc36ccd1SDavid Schultz while(s0[havedig] == '0')
75cc36ccd1SDavid Schultz havedig++;
76cc36ccd1SDavid Schultz s0 += havedig;
77cc36ccd1SDavid Schultz s = s0;
78cc36ccd1SDavid Schultz decpt = 0;
79c88250a5SDavid Schultz zret = 0;
80c88250a5SDavid Schultz e = 0;
814848dd08SDavid Schultz if (hexdig[*s])
824848dd08SDavid Schultz havedig++;
834848dd08SDavid Schultz else {
84c88250a5SDavid Schultz zret = 1;
854848dd08SDavid Schultz #ifdef USE_LOCALE
864848dd08SDavid Schultz for(i = 0; decimalpoint[i]; ++i) {
874848dd08SDavid Schultz if (s[i] != decimalpoint[i])
884848dd08SDavid Schultz goto pcheck;
894848dd08SDavid Schultz }
904848dd08SDavid Schultz decpt = s += i;
914848dd08SDavid Schultz #else
924848dd08SDavid Schultz if (*s != '.')
93c88250a5SDavid Schultz goto pcheck;
94cc36ccd1SDavid Schultz decpt = ++s;
954848dd08SDavid Schultz #endif
96cc36ccd1SDavid Schultz if (!hexdig[*s])
97c88250a5SDavid Schultz goto pcheck;
98cc36ccd1SDavid Schultz while(*s == '0')
99cc36ccd1SDavid Schultz s++;
100c88250a5SDavid Schultz if (hexdig[*s])
101c88250a5SDavid Schultz zret = 0;
102cc36ccd1SDavid Schultz havedig = 1;
103cc36ccd1SDavid Schultz s0 = s;
104cc36ccd1SDavid Schultz }
105cc36ccd1SDavid Schultz while(hexdig[*s])
106cc36ccd1SDavid Schultz s++;
1074848dd08SDavid Schultz #ifdef USE_LOCALE
1084848dd08SDavid Schultz if (*s == *decimalpoint && !decpt) {
1094848dd08SDavid Schultz for(i = 1; decimalpoint[i]; ++i) {
1104848dd08SDavid Schultz if (s[i] != decimalpoint[i])
1114848dd08SDavid Schultz goto pcheck;
1124848dd08SDavid Schultz }
1134848dd08SDavid Schultz decpt = s += i;
1144848dd08SDavid Schultz #else
1154848dd08SDavid Schultz if (*s == '.' && !decpt) {
116cc36ccd1SDavid Schultz decpt = ++s;
1174848dd08SDavid Schultz #endif
118cc36ccd1SDavid Schultz while(hexdig[*s])
119cc36ccd1SDavid Schultz s++;
1204848dd08SDavid Schultz }/*}*/
121cc36ccd1SDavid Schultz if (decpt)
122cc36ccd1SDavid Schultz e = -(((Long)(s-decpt)) << 2);
123c88250a5SDavid Schultz pcheck:
124cc36ccd1SDavid Schultz s1 = s;
125ae2cbf4cSDavid Schultz big = esign = 0;
126cc36ccd1SDavid Schultz switch(*s) {
127cc36ccd1SDavid Schultz case 'p':
128cc36ccd1SDavid Schultz case 'P':
129cc36ccd1SDavid Schultz switch(*++s) {
130cc36ccd1SDavid Schultz case '-':
131cc36ccd1SDavid Schultz esign = 1;
132cc36ccd1SDavid Schultz /* no break */
133cc36ccd1SDavid Schultz case '+':
134cc36ccd1SDavid Schultz s++;
135cc36ccd1SDavid Schultz }
136cc36ccd1SDavid Schultz if ((n = hexdig[*s]) == 0 || n > 0x19) {
137cc36ccd1SDavid Schultz s = s1;
138cc36ccd1SDavid Schultz break;
139cc36ccd1SDavid Schultz }
140cc36ccd1SDavid Schultz e1 = n - 0x10;
141ae2cbf4cSDavid Schultz while((n = hexdig[*++s]) !=0 && n <= 0x19) {
142ae2cbf4cSDavid Schultz if (e1 & 0xf8000000)
143ae2cbf4cSDavid Schultz big = 1;
144cc36ccd1SDavid Schultz e1 = 10*e1 + n - 0x10;
145ae2cbf4cSDavid Schultz }
146cc36ccd1SDavid Schultz if (esign)
147cc36ccd1SDavid Schultz e1 = -e1;
148cc36ccd1SDavid Schultz e += e1;
149cc36ccd1SDavid Schultz }
150cc36ccd1SDavid Schultz *sp = (char*)s;
151c713eaa6SDavid Schultz if (!havedig)
1524848dd08SDavid Schultz *sp = (char*)s0 - 1;
153ae2cbf4cSDavid Schultz if (zret)
154c713eaa6SDavid Schultz return STRTOG_Zero;
155ae2cbf4cSDavid Schultz if (big) {
156ae2cbf4cSDavid Schultz if (esign) {
157ae2cbf4cSDavid Schultz switch(fpi->rounding) {
158ae2cbf4cSDavid Schultz case FPI_Round_up:
159ae2cbf4cSDavid Schultz if (sign)
160ae2cbf4cSDavid Schultz break;
161ae2cbf4cSDavid Schultz goto ret_tiny;
162ae2cbf4cSDavid Schultz case FPI_Round_down:
163ae2cbf4cSDavid Schultz if (!sign)
164ae2cbf4cSDavid Schultz break;
165ae2cbf4cSDavid Schultz goto ret_tiny;
166ae2cbf4cSDavid Schultz }
167ae2cbf4cSDavid Schultz goto retz;
168ae2cbf4cSDavid Schultz ret_tiny:
169ae2cbf4cSDavid Schultz b = Balloc(0);
170ae2cbf4cSDavid Schultz b->wds = 1;
171ae2cbf4cSDavid Schultz b->x[0] = 1;
172ae2cbf4cSDavid Schultz goto dret;
173ae2cbf4cSDavid Schultz }
174ae2cbf4cSDavid Schultz switch(fpi->rounding) {
175ae2cbf4cSDavid Schultz case FPI_Round_near:
176ae2cbf4cSDavid Schultz goto ovfl1;
177ae2cbf4cSDavid Schultz case FPI_Round_up:
178ae2cbf4cSDavid Schultz if (!sign)
179ae2cbf4cSDavid Schultz goto ovfl1;
180ae2cbf4cSDavid Schultz goto ret_big;
181ae2cbf4cSDavid Schultz case FPI_Round_down:
182ae2cbf4cSDavid Schultz if (sign)
183ae2cbf4cSDavid Schultz goto ovfl1;
184ae2cbf4cSDavid Schultz goto ret_big;
185ae2cbf4cSDavid Schultz }
186ae2cbf4cSDavid Schultz ret_big:
187ae2cbf4cSDavid Schultz nbits = fpi->nbits;
188ae2cbf4cSDavid Schultz n0 = n = nbits >> kshift;
189ae2cbf4cSDavid Schultz if (nbits & kmask)
190ae2cbf4cSDavid Schultz ++n;
191ae2cbf4cSDavid Schultz for(j = n, k = 0; j >>= 1; ++k);
192ae2cbf4cSDavid Schultz *bp = b = Balloc(k);
193ae2cbf4cSDavid Schultz b->wds = n;
194ae2cbf4cSDavid Schultz for(j = 0; j < n0; ++j)
195ae2cbf4cSDavid Schultz b->x[j] = ALL_ON;
196ae2cbf4cSDavid Schultz if (n > n0)
197ae2cbf4cSDavid Schultz b->x[j] = ULbits >> (ULbits - (nbits & kmask));
198ae2cbf4cSDavid Schultz *exp = fpi->emin;
199ae2cbf4cSDavid Schultz return STRTOG_Normal | STRTOG_Inexlo;
200c713eaa6SDavid Schultz }
201cc36ccd1SDavid Schultz n = s1 - s0 - 1;
202*50dad48bSDavid Schultz for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
203cc36ccd1SDavid Schultz k++;
204cc36ccd1SDavid Schultz b = Balloc(k);
205cc36ccd1SDavid Schultz x = b->x;
206cc36ccd1SDavid Schultz n = 0;
207cc36ccd1SDavid Schultz L = 0;
2084848dd08SDavid Schultz #ifdef USE_LOCALE
2094848dd08SDavid Schultz for(i = 0; decimalpoint[i+1]; ++i);
2104848dd08SDavid Schultz #endif
211cc36ccd1SDavid Schultz while(s1 > s0) {
2124848dd08SDavid Schultz #ifdef USE_LOCALE
2134848dd08SDavid Schultz if (*--s1 == decimalpoint[i]) {
2144848dd08SDavid Schultz s1 -= i;
215cc36ccd1SDavid Schultz continue;
2164848dd08SDavid Schultz }
2174848dd08SDavid Schultz #else
2184848dd08SDavid Schultz if (*--s1 == '.')
2194848dd08SDavid Schultz continue;
2204848dd08SDavid Schultz #endif
2214848dd08SDavid Schultz if (n == ULbits) {
222cc36ccd1SDavid Schultz *x++ = L;
223cc36ccd1SDavid Schultz L = 0;
224cc36ccd1SDavid Schultz n = 0;
225cc36ccd1SDavid Schultz }
226cc36ccd1SDavid Schultz L |= (hexdig[*s1] & 0x0f) << n;
227cc36ccd1SDavid Schultz n += 4;
228cc36ccd1SDavid Schultz }
229cc36ccd1SDavid Schultz *x++ = L;
230cc36ccd1SDavid Schultz b->wds = n = x - b->x;
2314848dd08SDavid Schultz n = ULbits*n - hi0bits(L);
232cc36ccd1SDavid Schultz nbits = fpi->nbits;
233cc36ccd1SDavid Schultz lostbits = 0;
234cc36ccd1SDavid Schultz x = b->x;
235cc36ccd1SDavid Schultz if (n > nbits) {
236cc36ccd1SDavid Schultz n -= nbits;
237cc36ccd1SDavid Schultz if (any_on(b,n)) {
238cc36ccd1SDavid Schultz lostbits = 1;
239cc36ccd1SDavid Schultz k = n - 1;
240cc36ccd1SDavid Schultz if (x[k>>kshift] & 1 << (k & kmask)) {
241cc36ccd1SDavid Schultz lostbits = 2;
242ae2cbf4cSDavid Schultz if (k > 0 && any_on(b,k))
243cc36ccd1SDavid Schultz lostbits = 3;
244cc36ccd1SDavid Schultz }
245cc36ccd1SDavid Schultz }
246cc36ccd1SDavid Schultz rshift(b, n);
247cc36ccd1SDavid Schultz e += n;
248cc36ccd1SDavid Schultz }
249cc36ccd1SDavid Schultz else if (n < nbits) {
250cc36ccd1SDavid Schultz n = nbits - n;
251cc36ccd1SDavid Schultz b = lshift(b, n);
252cc36ccd1SDavid Schultz e -= n;
253cc36ccd1SDavid Schultz x = b->x;
254cc36ccd1SDavid Schultz }
255cc36ccd1SDavid Schultz if (e > fpi->emax) {
256cc36ccd1SDavid Schultz ovfl:
257cc36ccd1SDavid Schultz Bfree(b);
258ae2cbf4cSDavid Schultz ovfl1:
259ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
260ae2cbf4cSDavid Schultz errno = ERANGE;
261ae2cbf4cSDavid Schultz #endif
262cc36ccd1SDavid Schultz return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
263cc36ccd1SDavid Schultz }
264cc36ccd1SDavid Schultz irv = STRTOG_Normal;
265cc36ccd1SDavid Schultz if (e < fpi->emin) {
266cc36ccd1SDavid Schultz irv = STRTOG_Denormal;
267cc36ccd1SDavid Schultz n = fpi->emin - e;
268cc36ccd1SDavid Schultz if (n >= nbits) {
269cc36ccd1SDavid Schultz switch (fpi->rounding) {
270cc36ccd1SDavid Schultz case FPI_Round_near:
27119927830SDavid Schultz if (n == nbits && (n < 2 || any_on(b,n-1)))
272cc36ccd1SDavid Schultz goto one_bit;
273cc36ccd1SDavid Schultz break;
274cc36ccd1SDavid Schultz case FPI_Round_up:
275cc36ccd1SDavid Schultz if (!sign)
276cc36ccd1SDavid Schultz goto one_bit;
277cc36ccd1SDavid Schultz break;
278cc36ccd1SDavid Schultz case FPI_Round_down:
279cc36ccd1SDavid Schultz if (sign) {
280cc36ccd1SDavid Schultz one_bit:
281cc36ccd1SDavid Schultz x[0] = b->wds = 1;
282ae2cbf4cSDavid Schultz dret:
283cc36ccd1SDavid Schultz *bp = b;
284ae2cbf4cSDavid Schultz *exp = fpi->emin;
285ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
286ae2cbf4cSDavid Schultz errno = ERANGE;
287ae2cbf4cSDavid Schultz #endif
288cc36ccd1SDavid Schultz return STRTOG_Denormal | STRTOG_Inexhi
289cc36ccd1SDavid Schultz | STRTOG_Underflow;
290cc36ccd1SDavid Schultz }
291cc36ccd1SDavid Schultz }
292cc36ccd1SDavid Schultz Bfree(b);
293ae2cbf4cSDavid Schultz retz:
294ae2cbf4cSDavid Schultz #ifndef NO_ERRNO
295ae2cbf4cSDavid Schultz errno = ERANGE;
296ae2cbf4cSDavid Schultz #endif
297cc36ccd1SDavid Schultz return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
298cc36ccd1SDavid Schultz }
299cc36ccd1SDavid Schultz k = n - 1;
300cc36ccd1SDavid Schultz if (lostbits)
301cc36ccd1SDavid Schultz lostbits = 1;
302cc36ccd1SDavid Schultz else if (k > 0)
303cc36ccd1SDavid Schultz lostbits = any_on(b,k);
304cc36ccd1SDavid Schultz if (x[k>>kshift] & 1 << (k & kmask))
305cc36ccd1SDavid Schultz lostbits |= 2;
306cc36ccd1SDavid Schultz nbits -= n;
307cc36ccd1SDavid Schultz rshift(b,n);
308cc36ccd1SDavid Schultz e = fpi->emin;
309cc36ccd1SDavid Schultz }
310cc36ccd1SDavid Schultz if (lostbits) {
311cc36ccd1SDavid Schultz up = 0;
312cc36ccd1SDavid Schultz switch(fpi->rounding) {
313cc36ccd1SDavid Schultz case FPI_Round_zero:
314cc36ccd1SDavid Schultz break;
315cc36ccd1SDavid Schultz case FPI_Round_near:
316cc36ccd1SDavid Schultz if (lostbits & 2
317*50dad48bSDavid Schultz && (lostbits | x[0]) & 1)
318cc36ccd1SDavid Schultz up = 1;
319cc36ccd1SDavid Schultz break;
320cc36ccd1SDavid Schultz case FPI_Round_up:
321cc36ccd1SDavid Schultz up = 1 - sign;
322cc36ccd1SDavid Schultz break;
323cc36ccd1SDavid Schultz case FPI_Round_down:
324cc36ccd1SDavid Schultz up = sign;
325cc36ccd1SDavid Schultz }
326cc36ccd1SDavid Schultz if (up) {
327cc36ccd1SDavid Schultz k = b->wds;
328cc36ccd1SDavid Schultz b = increment(b);
329cc36ccd1SDavid Schultz x = b->x;
33019927830SDavid Schultz if (irv == STRTOG_Denormal) {
33119927830SDavid Schultz if (nbits == fpi->nbits - 1
33219927830SDavid Schultz && x[nbits >> kshift] & 1 << (nbits & kmask))
33319927830SDavid Schultz irv = STRTOG_Normal;
33419927830SDavid Schultz }
33519927830SDavid Schultz else if (b->wds > k
336*50dad48bSDavid Schultz || ((n = nbits & kmask) !=0
337*50dad48bSDavid Schultz && hi0bits(x[k-1]) < 32-n)) {
338cc36ccd1SDavid Schultz rshift(b,1);
339cc36ccd1SDavid Schultz if (++e > fpi->emax)
340cc36ccd1SDavid Schultz goto ovfl;
341cc36ccd1SDavid Schultz }
342cc36ccd1SDavid Schultz irv |= STRTOG_Inexhi;
343cc36ccd1SDavid Schultz }
344cc36ccd1SDavid Schultz else
345cc36ccd1SDavid Schultz irv |= STRTOG_Inexlo;
346cc36ccd1SDavid Schultz }
347cc36ccd1SDavid Schultz *bp = b;
348cc36ccd1SDavid Schultz *exp = e;
349cc36ccd1SDavid Schultz return irv;
350cc36ccd1SDavid Schultz }
351