xref: /openbsd-src/lib/libc/gdtoa/gethex.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
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 			if (b == NULL)
173 				return (STRTOG_NoMemory);
174 			b->wds = 1;
175 			b->x[0] = 1;
176 			goto dret;
177 			}
178 		switch(fpi->rounding) {
179 		  case FPI_Round_near:
180 			goto ovfl1;
181 		  case FPI_Round_up:
182 			if (!sign)
183 				goto ovfl1;
184 			goto ret_big;
185 		  case FPI_Round_down:
186 			if (sign)
187 				goto ovfl1;
188 			goto ret_big;
189 		  }
190  ret_big:
191 		nbits = fpi->nbits;
192 		n0 = n = nbits >> kshift;
193 		if (nbits & kmask)
194 			++n;
195 		for(j = n, k = 0; j >>= 1; ++k);
196 		*bp = b = Balloc(k);
197 		if (b == NULL)
198 			return (STRTOG_NoMemory);
199 		b->wds = n;
200 		for(j = 0; j < n0; ++j)
201 			b->x[j] = ALL_ON;
202 		if (n > n0)
203 			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
204 		*exp = fpi->emin;
205 		return STRTOG_Normal | STRTOG_Inexlo;
206 		}
207 	n = s1 - s0 - 1;
208 	for(k = 0; n > 7; n >>= 1)
209 		k++;
210 	b = Balloc(k);
211 	if (b == NULL)
212 		return (STRTOG_NoMemory);
213 	x = b->x;
214 	n = 0;
215 	L = 0;
216 #ifdef USE_LOCALE
217 	for(i = 0; decimalpoint[i+1]; ++i);
218 #endif
219 	while(s1 > s0) {
220 #ifdef USE_LOCALE
221 		if (*--s1 == decimalpoint[i]) {
222 			s1 -= i;
223 			continue;
224 			}
225 #else
226 		if (*--s1 == '.')
227 			continue;
228 #endif
229 		if (n == 32) {
230 			*x++ = L;
231 			L = 0;
232 			n = 0;
233 			}
234 		L |= (hexdig[*s1] & 0x0f) << n;
235 		n += 4;
236 		}
237 	*x++ = L;
238 	b->wds = n = x - b->x;
239 	n = 32*n - hi0bits(L);
240 	nbits = fpi->nbits;
241 	lostbits = 0;
242 	x = b->x;
243 	if (n > nbits) {
244 		n -= nbits;
245 		if (any_on(b,n)) {
246 			lostbits = 1;
247 			k = n - 1;
248 			if (x[k>>kshift] & 1 << (k & kmask)) {
249 				lostbits = 2;
250 				if (k > 0 && any_on(b,k))
251 					lostbits = 3;
252 				}
253 			}
254 		rshift(b, n);
255 		e += n;
256 		}
257 	else if (n < nbits) {
258 		n = nbits - n;
259 		b = lshift(b, n);
260 		if (b == NULL)
261 			return (STRTOG_NoMemory);
262 		e -= n;
263 		x = b->x;
264 		}
265 	if (e > fpi->emax) {
266  ovfl:
267 		Bfree(b);
268  ovfl1:
269 #ifndef NO_ERRNO
270 		errno = ERANGE;
271 #endif
272 		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
273 		}
274 	irv = STRTOG_Normal;
275 	if (e < fpi->emin) {
276 		irv = STRTOG_Denormal;
277 		n = fpi->emin - e;
278 		if (n >= nbits) {
279 			switch (fpi->rounding) {
280 			  case FPI_Round_near:
281 				if (n == nbits && (n < 2 || any_on(b,n-1)))
282 					goto one_bit;
283 				break;
284 			  case FPI_Round_up:
285 				if (!sign)
286 					goto one_bit;
287 				break;
288 			  case FPI_Round_down:
289 				if (sign) {
290  one_bit:
291 					x[0] = b->wds = 1;
292  dret:
293 					*bp = b;
294 					*exp = fpi->emin;
295 #ifndef NO_ERRNO
296 					errno = ERANGE;
297 #endif
298 					return STRTOG_Denormal | STRTOG_Inexhi
299 						| STRTOG_Underflow;
300 					}
301 			  }
302 			Bfree(b);
303  retz:
304 #ifndef NO_ERRNO
305 			errno = ERANGE;
306 #endif
307 			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
308 			}
309 		k = n - 1;
310 		if (lostbits)
311 			lostbits = 1;
312 		else if (k > 0)
313 			lostbits = any_on(b,k);
314 		if (x[k>>kshift] & 1 << (k & kmask))
315 			lostbits |= 2;
316 		nbits -= n;
317 		rshift(b,n);
318 		e = fpi->emin;
319 		}
320 	if (lostbits) {
321 		up = 0;
322 		switch(fpi->rounding) {
323 		  case FPI_Round_zero:
324 			break;
325 		  case FPI_Round_near:
326 			if (lostbits & 2
327 			 && (lostbits & 1) | x[0] & 1)
328 				up = 1;
329 			break;
330 		  case FPI_Round_up:
331 			up = 1 - sign;
332 			break;
333 		  case FPI_Round_down:
334 			up = sign;
335 		  }
336 		if (up) {
337 			k = b->wds;
338 			b = increment(b);
339 			if (b == NULL)
340 				return (STRTOG_NoMemory);
341 			x = b->x;
342 			if (irv == STRTOG_Denormal) {
343 				if (nbits == fpi->nbits - 1
344 				 && x[nbits >> kshift] & 1 << (nbits & kmask))
345 					irv =  STRTOG_Normal;
346 				}
347 			else if (b->wds > k
348 			 || (n = nbits & kmask) !=0
349 			     && hi0bits(x[k-1]) < 32-n) {
350 				rshift(b,1);
351 				if (++e > fpi->emax)
352 					goto ovfl;
353 				}
354 			irv |= STRTOG_Inexhi;
355 			}
356 		else
357 			irv |= STRTOG_Inexlo;
358 		}
359 	*bp = b;
360 	*exp = e;
361 	return irv;
362 	}
363