xref: /freebsd/contrib/gdtoa/gethex.c (revision 2f6a179eb910129fb812c1ad1bdc300da1203dc0)
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
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 esign, havedig, irv, k, n, nbits, up, zret;
49 	ULong L, lostbits, *x;
50 	Long e, e1;
51 #ifdef USE_LOCALE
52 	unsigned char decimalpoint = *localeconv()->decimal_point;
53 #else
54 #define decimalpoint '.'
55 #endif
56 
57 	if (!hexdig['0'])
58 		hexdig_init_D2A();
59 	havedig = 0;
60 	s0 = *(CONST unsigned char **)sp + 2;
61 	while(s0[havedig] == '0')
62 		havedig++;
63 	s0 += havedig;
64 	s = s0;
65 	decpt = 0;
66 	zret = 0;
67 	e = 0;
68 	if (!hexdig[*s]) {
69 		zret = 1;
70 		if (*s != decimalpoint)
71 			goto pcheck;
72 		decpt = ++s;
73 		if (!hexdig[*s])
74 			goto pcheck;
75 		while(*s == '0')
76 			s++;
77 		if (hexdig[*s])
78 			zret = 0;
79 		havedig = 1;
80 		s0 = s;
81 		}
82 	while(hexdig[*s])
83 		s++;
84 	if (*s == decimalpoint && !decpt) {
85 		decpt = ++s;
86 		while(hexdig[*s])
87 			s++;
88 		}
89 	if (decpt)
90 		e = -(((Long)(s-decpt)) << 2);
91  pcheck:
92 	s1 = s;
93 	switch(*s) {
94 	  case 'p':
95 	  case 'P':
96 		esign = 0;
97 		switch(*++s) {
98 		  case '-':
99 			esign = 1;
100 			/* no break */
101 		  case '+':
102 			s++;
103 		  }
104 		if ((n = hexdig[*s]) == 0 || n > 0x19) {
105 			s = s1;
106 			break;
107 			}
108 		e1 = n - 0x10;
109 		while((n = hexdig[*++s]) !=0 && n <= 0x19)
110 			e1 = 10*e1 + n - 0x10;
111 		if (esign)
112 			e1 = -e1;
113 		e += e1;
114 	  }
115 	*sp = (char*)s;
116 	if (zret) {
117 		if (!havedig)
118 			*sp = s0 - 1;
119 		return STRTOG_Zero;
120 		}
121 	n = s1 - s0 - 1;
122 	for(k = 0; n > 7; n >>= 1)
123 		k++;
124 	b = Balloc(k);
125 	x = b->x;
126 	n = 0;
127 	L = 0;
128 	while(s1 > s0) {
129 		if (*--s1 == decimalpoint)
130 			continue;
131 		if (n == 32) {
132 			*x++ = L;
133 			L = 0;
134 			n = 0;
135 			}
136 		L |= (hexdig[*s1] & 0x0f) << n;
137 		n += 4;
138 		}
139 	*x++ = L;
140 	b->wds = n = x - b->x;
141 	n = 32*n - hi0bits(L);
142 	nbits = fpi->nbits;
143 	lostbits = 0;
144 	x = b->x;
145 	if (n > nbits) {
146 		n -= nbits;
147 		if (any_on(b,n)) {
148 			lostbits = 1;
149 			k = n - 1;
150 			if (x[k>>kshift] & 1 << (k & kmask)) {
151 				lostbits = 2;
152 				if (k > 1 && any_on(b,k-1))
153 					lostbits = 3;
154 				}
155 			}
156 		rshift(b, n);
157 		e += n;
158 		}
159 	else if (n < nbits) {
160 		n = nbits - n;
161 		b = lshift(b, n);
162 		e -= n;
163 		x = b->x;
164 		}
165 	if (e > fpi->emax) {
166  ovfl:
167 		Bfree(b);
168 		*bp = 0;
169 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
170 		}
171 	irv = STRTOG_Normal;
172 	if (e < fpi->emin) {
173 		irv = STRTOG_Denormal;
174 		n = fpi->emin - e;
175 		if (n >= nbits) {
176 			switch (fpi->rounding) {
177 			  case FPI_Round_near:
178 				if (n == nbits && (n < 2 || any_on(b,n-1)))
179 					goto one_bit;
180 				break;
181 			  case FPI_Round_up:
182 				if (!sign)
183 					goto one_bit;
184 				break;
185 			  case FPI_Round_down:
186 				if (sign) {
187  one_bit:
188 					*exp = fpi->emin;
189 					x[0] = b->wds = 1;
190 					*bp = b;
191 					return STRTOG_Denormal | STRTOG_Inexhi
192 						| STRTOG_Underflow;
193 					}
194 			  }
195 			Bfree(b);
196 			*bp = 0;
197 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
198 			}
199 		k = n - 1;
200 		if (lostbits)
201 			lostbits = 1;
202 		else if (k > 0)
203 			lostbits = any_on(b,k);
204 		if (x[k>>kshift] & 1 << (k & kmask))
205 			lostbits |= 2;
206 		nbits -= n;
207 		rshift(b,n);
208 		e = fpi->emin;
209 		}
210 	if (lostbits) {
211 		up = 0;
212 		switch(fpi->rounding) {
213 		  case FPI_Round_zero:
214 			break;
215 		  case FPI_Round_near:
216 			if (lostbits & 2
217 			 && (lostbits & 1) | x[0] & 1)
218 				up = 1;
219 			break;
220 		  case FPI_Round_up:
221 			up = 1 - sign;
222 			break;
223 		  case FPI_Round_down:
224 			up = sign;
225 		  }
226 		if (up) {
227 			k = b->wds;
228 			b = increment(b);
229 			x = b->x;
230 			if (irv == STRTOG_Denormal) {
231 				if (nbits == fpi->nbits - 1
232 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
233 					irv =  STRTOG_Normal;
234 				}
235 			else if (b->wds > k
236 			 || (n = nbits & kmask) !=0
237 			     && hi0bits(x[k-1]) < 32-n) {
238 				rshift(b,1);
239 				if (++e > fpi->emax)
240 					goto ovfl;
241 				}
242 			irv |= STRTOG_Inexhi;
243 			}
244 		else
245 			irv |= STRTOG_Inexlo;
246 		}
247 	*bp = b;
248 	*exp = e;
249 	return irv;
250 	}
251