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