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