xref: /third_party/FreeBSD/contrib/gdtoa/gethex.c (revision f9f848fa)
1f9f848faSopenharmony_ci/****************************************************************
2f9f848faSopenharmony_ci
3f9f848faSopenharmony_ciThe author of this software is David M. Gay.
4f9f848faSopenharmony_ci
5f9f848faSopenharmony_ciCopyright (C) 1998 by Lucent Technologies
6f9f848faSopenharmony_ciAll Rights Reserved
7f9f848faSopenharmony_ci
8f9f848faSopenharmony_ciPermission to use, copy, modify, and distribute this software and
9f9f848faSopenharmony_ciits documentation for any purpose and without fee is hereby
10f9f848faSopenharmony_cigranted, provided that the above copyright notice appear in all
11f9f848faSopenharmony_cicopies and that both that the copyright notice and this
12f9f848faSopenharmony_cipermission notice and warranty disclaimer appear in supporting
13f9f848faSopenharmony_cidocumentation, and that the name of Lucent or any of its entities
14f9f848faSopenharmony_cinot be used in advertising or publicity pertaining to
15f9f848faSopenharmony_cidistribution of the software without specific, written prior
16f9f848faSopenharmony_cipermission.
17f9f848faSopenharmony_ci
18f9f848faSopenharmony_ciLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19f9f848faSopenharmony_ciINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20f9f848faSopenharmony_ciIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21f9f848faSopenharmony_ciSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22f9f848faSopenharmony_ciWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23f9f848faSopenharmony_ciIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24f9f848faSopenharmony_ciARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25f9f848faSopenharmony_ciTHIS SOFTWARE.
26f9f848faSopenharmony_ci
27f9f848faSopenharmony_ci****************************************************************/
28f9f848faSopenharmony_ci
29f9f848faSopenharmony_ci/* Please send bug reports to David M. Gay (dmg at acm dot org,
30f9f848faSopenharmony_ci * with " at " changed at "@" and " dot " changed to ".").	*/
31f9f848faSopenharmony_ci
32f9f848faSopenharmony_ci#include "gdtoaimp.h"
33f9f848faSopenharmony_ci
34f9f848faSopenharmony_ci#ifdef USE_LOCALE
35f9f848faSopenharmony_ci#include "locale.h"
36f9f848faSopenharmony_ci#endif
37f9f848faSopenharmony_ci
38f9f848faSopenharmony_ci int
39f9f848faSopenharmony_ci#ifdef KR_headers
40f9f848faSopenharmony_cigethex(sp, fpi, exp, bp, sign)
41f9f848faSopenharmony_ci	CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
42f9f848faSopenharmony_ci#else
43f9f848faSopenharmony_cigethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
44f9f848faSopenharmony_ci#endif
45f9f848faSopenharmony_ci{
46f9f848faSopenharmony_ci	Bigint *b;
47f9f848faSopenharmony_ci	CONST unsigned char *decpt, *s0, *s, *s1;
48f9f848faSopenharmony_ci	int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
49f9f848faSopenharmony_ci	ULong L, lostbits, *x;
50f9f848faSopenharmony_ci	Long e, e1;
51f9f848faSopenharmony_ci#ifdef USE_LOCALE
52f9f848faSopenharmony_ci	int i;
53f9f848faSopenharmony_ci#ifdef NO_LOCALE_CACHE
54f9f848faSopenharmony_ci	const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
55f9f848faSopenharmony_ci#else
56f9f848faSopenharmony_ci	const unsigned char *decimalpoint;
57f9f848faSopenharmony_ci	static unsigned char *decimalpoint_cache;
58f9f848faSopenharmony_ci	if (!(s0 = decimalpoint_cache)) {
59f9f848faSopenharmony_ci		s0 = (unsigned char*)localeconv()->decimal_point;
60f9f848faSopenharmony_ci		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
61f9f848faSopenharmony_ci			strcpy(decimalpoint_cache, s0);
62f9f848faSopenharmony_ci			s0 = decimalpoint_cache;
63f9f848faSopenharmony_ci			}
64f9f848faSopenharmony_ci		}
65f9f848faSopenharmony_ci	decimalpoint = s0;
66f9f848faSopenharmony_ci#endif
67f9f848faSopenharmony_ci#endif
68f9f848faSopenharmony_ci
69f9f848faSopenharmony_ci	if (!hexdig['0'])
70f9f848faSopenharmony_ci		hexdig_init_D2A();
71f9f848faSopenharmony_ci	*bp = 0;
72f9f848faSopenharmony_ci	havedig = 0;
73f9f848faSopenharmony_ci	s0 = *(CONST unsigned char **)sp + 2;
74f9f848faSopenharmony_ci	while(s0[havedig] == '0')
75f9f848faSopenharmony_ci		havedig++;
76f9f848faSopenharmony_ci	s0 += havedig;
77f9f848faSopenharmony_ci	s = s0;
78f9f848faSopenharmony_ci	decpt = 0;
79f9f848faSopenharmony_ci	zret = 0;
80f9f848faSopenharmony_ci	e = 0;
81f9f848faSopenharmony_ci	if (hexdig[*s])
82f9f848faSopenharmony_ci		havedig++;
83f9f848faSopenharmony_ci	else {
84f9f848faSopenharmony_ci		zret = 1;
85f9f848faSopenharmony_ci#ifdef USE_LOCALE
86f9f848faSopenharmony_ci		for(i = 0; decimalpoint[i]; ++i) {
87f9f848faSopenharmony_ci			if (s[i] != decimalpoint[i])
88f9f848faSopenharmony_ci				goto pcheck;
89f9f848faSopenharmony_ci			}
90f9f848faSopenharmony_ci		decpt = s += i;
91f9f848faSopenharmony_ci#else
92f9f848faSopenharmony_ci		if (*s != '.')
93f9f848faSopenharmony_ci			goto pcheck;
94f9f848faSopenharmony_ci		decpt = ++s;
95f9f848faSopenharmony_ci#endif
96f9f848faSopenharmony_ci		if (!hexdig[*s])
97f9f848faSopenharmony_ci			goto pcheck;
98f9f848faSopenharmony_ci		while(*s == '0')
99f9f848faSopenharmony_ci			s++;
100f9f848faSopenharmony_ci		if (hexdig[*s])
101f9f848faSopenharmony_ci			zret = 0;
102f9f848faSopenharmony_ci		havedig = 1;
103f9f848faSopenharmony_ci		s0 = s;
104f9f848faSopenharmony_ci		}
105f9f848faSopenharmony_ci	while(hexdig[*s])
106f9f848faSopenharmony_ci		s++;
107f9f848faSopenharmony_ci#ifdef USE_LOCALE
108f9f848faSopenharmony_ci	if (*s == *decimalpoint && !decpt) {
109f9f848faSopenharmony_ci		for(i = 1; decimalpoint[i]; ++i) {
110f9f848faSopenharmony_ci			if (s[i] != decimalpoint[i])
111f9f848faSopenharmony_ci				goto pcheck;
112f9f848faSopenharmony_ci			}
113f9f848faSopenharmony_ci		decpt = s += i;
114f9f848faSopenharmony_ci#else
115f9f848faSopenharmony_ci	if (*s == '.' && !decpt) {
116f9f848faSopenharmony_ci		decpt = ++s;
117f9f848faSopenharmony_ci#endif
118f9f848faSopenharmony_ci		while(hexdig[*s])
119f9f848faSopenharmony_ci			s++;
120f9f848faSopenharmony_ci		}/*}*/
121f9f848faSopenharmony_ci	if (decpt)
122f9f848faSopenharmony_ci		e = -(((Long)(s-decpt)) << 2);
123f9f848faSopenharmony_ci pcheck:
124f9f848faSopenharmony_ci	s1 = s;
125f9f848faSopenharmony_ci	big = esign = 0;
126f9f848faSopenharmony_ci	switch(*s) {
127f9f848faSopenharmony_ci	  case 'p':
128f9f848faSopenharmony_ci	  case 'P':
129f9f848faSopenharmony_ci		switch(*++s) {
130f9f848faSopenharmony_ci		  case '-':
131f9f848faSopenharmony_ci			esign = 1;
132f9f848faSopenharmony_ci			/* no break */
133f9f848faSopenharmony_ci		  case '+':
134f9f848faSopenharmony_ci			s++;
135f9f848faSopenharmony_ci		  }
136f9f848faSopenharmony_ci		if ((n = hexdig[*s]) == 0 || n > 0x19) {
137f9f848faSopenharmony_ci			s = s1;
138f9f848faSopenharmony_ci			break;
139f9f848faSopenharmony_ci			}
140f9f848faSopenharmony_ci		e1 = n - 0x10;
141f9f848faSopenharmony_ci		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
142f9f848faSopenharmony_ci			if (e1 & 0xf8000000)
143f9f848faSopenharmony_ci				big = 1;
144f9f848faSopenharmony_ci			e1 = 10*e1 + n - 0x10;
145f9f848faSopenharmony_ci			}
146f9f848faSopenharmony_ci		if (esign)
147f9f848faSopenharmony_ci			e1 = -e1;
148f9f848faSopenharmony_ci		e += e1;
149f9f848faSopenharmony_ci	  }
150f9f848faSopenharmony_ci	*sp = (char*)s;
151f9f848faSopenharmony_ci	if (!havedig)
152f9f848faSopenharmony_ci		*sp = (char*)s0 - 1;
153f9f848faSopenharmony_ci	if (zret)
154f9f848faSopenharmony_ci		return STRTOG_Zero;
155f9f848faSopenharmony_ci	if (big) {
156f9f848faSopenharmony_ci		if (esign) {
157f9f848faSopenharmony_ci			switch(fpi->rounding) {
158f9f848faSopenharmony_ci			  case FPI_Round_up:
159f9f848faSopenharmony_ci				if (sign)
160f9f848faSopenharmony_ci					break;
161f9f848faSopenharmony_ci				goto ret_tiny;
162f9f848faSopenharmony_ci			  case FPI_Round_down:
163f9f848faSopenharmony_ci				if (!sign)
164f9f848faSopenharmony_ci					break;
165f9f848faSopenharmony_ci				goto ret_tiny;
166f9f848faSopenharmony_ci			  }
167f9f848faSopenharmony_ci			goto retz;
168f9f848faSopenharmony_ci ret_tiny:
169f9f848faSopenharmony_ci			b = Balloc(0);
170f9f848faSopenharmony_ci			b->wds = 1;
171f9f848faSopenharmony_ci			b->x[0] = 1;
172f9f848faSopenharmony_ci			goto dret;
173f9f848faSopenharmony_ci			}
174f9f848faSopenharmony_ci		switch(fpi->rounding) {
175f9f848faSopenharmony_ci		  case FPI_Round_near:
176f9f848faSopenharmony_ci			goto ovfl1;
177f9f848faSopenharmony_ci		  case FPI_Round_up:
178f9f848faSopenharmony_ci			if (!sign)
179f9f848faSopenharmony_ci				goto ovfl1;
180f9f848faSopenharmony_ci			goto ret_big;
181f9f848faSopenharmony_ci		  case FPI_Round_down:
182f9f848faSopenharmony_ci			if (sign)
183f9f848faSopenharmony_ci				goto ovfl1;
184f9f848faSopenharmony_ci			goto ret_big;
185f9f848faSopenharmony_ci		  }
186f9f848faSopenharmony_ci ret_big:
187f9f848faSopenharmony_ci		nbits = fpi->nbits;
188f9f848faSopenharmony_ci		n0 = n = nbits >> kshift;
189f9f848faSopenharmony_ci		if (nbits & kmask)
190f9f848faSopenharmony_ci			++n;
191f9f848faSopenharmony_ci		for(j = n, k = 0; j >>= 1; ++k);
192f9f848faSopenharmony_ci		*bp = b = Balloc(k);
193f9f848faSopenharmony_ci		b->wds = n;
194f9f848faSopenharmony_ci		for(j = 0; j < n0; ++j)
195f9f848faSopenharmony_ci			b->x[j] = ALL_ON;
196f9f848faSopenharmony_ci		if (n > n0)
197f9f848faSopenharmony_ci			b->x[j] = ULbits >> (ULbits - (nbits & kmask));
198f9f848faSopenharmony_ci		*exp = fpi->emin;
199f9f848faSopenharmony_ci		return STRTOG_Normal | STRTOG_Inexlo;
200f9f848faSopenharmony_ci		}
201f9f848faSopenharmony_ci	n = s1 - s0 - 1;
202f9f848faSopenharmony_ci	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
203f9f848faSopenharmony_ci		k++;
204f9f848faSopenharmony_ci	b = Balloc(k);
205f9f848faSopenharmony_ci	x = b->x;
206f9f848faSopenharmony_ci	n = 0;
207f9f848faSopenharmony_ci	L = 0;
208f9f848faSopenharmony_ci#ifdef USE_LOCALE
209f9f848faSopenharmony_ci	for(i = 0; decimalpoint[i+1]; ++i);
210f9f848faSopenharmony_ci#endif
211f9f848faSopenharmony_ci	while(s1 > s0) {
212f9f848faSopenharmony_ci#ifdef USE_LOCALE
213f9f848faSopenharmony_ci		if (*--s1 == decimalpoint[i]) {
214f9f848faSopenharmony_ci			s1 -= i;
215f9f848faSopenharmony_ci			continue;
216f9f848faSopenharmony_ci			}
217f9f848faSopenharmony_ci#else
218f9f848faSopenharmony_ci		if (*--s1 == '.')
219f9f848faSopenharmony_ci			continue;
220f9f848faSopenharmony_ci#endif
221f9f848faSopenharmony_ci		if (n == ULbits) {
222f9f848faSopenharmony_ci			*x++ = L;
223f9f848faSopenharmony_ci			L = 0;
224f9f848faSopenharmony_ci			n = 0;
225f9f848faSopenharmony_ci			}
226f9f848faSopenharmony_ci		L |= (hexdig[*s1] & 0x0f) << n;
227f9f848faSopenharmony_ci		n += 4;
228f9f848faSopenharmony_ci		}
229f9f848faSopenharmony_ci	*x++ = L;
230f9f848faSopenharmony_ci	b->wds = n = x - b->x;
231f9f848faSopenharmony_ci	n = ULbits*n - hi0bits(L);
232f9f848faSopenharmony_ci	nbits = fpi->nbits;
233f9f848faSopenharmony_ci	lostbits = 0;
234f9f848faSopenharmony_ci	x = b->x;
235f9f848faSopenharmony_ci	if (n > nbits) {
236f9f848faSopenharmony_ci		n -= nbits;
237f9f848faSopenharmony_ci		if (any_on(b,n)) {
238f9f848faSopenharmony_ci			lostbits = 1;
239f9f848faSopenharmony_ci			k = n - 1;
240f9f848faSopenharmony_ci			if (x[k>>kshift] & 1 << (k & kmask)) {
241f9f848faSopenharmony_ci				lostbits = 2;
242f9f848faSopenharmony_ci				if (k > 0 && any_on(b,k))
243f9f848faSopenharmony_ci					lostbits = 3;
244f9f848faSopenharmony_ci				}
245f9f848faSopenharmony_ci			}
246f9f848faSopenharmony_ci		rshift(b, n);
247f9f848faSopenharmony_ci		e += n;
248f9f848faSopenharmony_ci		}
249f9f848faSopenharmony_ci	else if (n < nbits) {
250f9f848faSopenharmony_ci		n = nbits - n;
251f9f848faSopenharmony_ci		b = lshift(b, n);
252f9f848faSopenharmony_ci		e -= n;
253f9f848faSopenharmony_ci		x = b->x;
254f9f848faSopenharmony_ci		}
255f9f848faSopenharmony_ci	if (e > fpi->emax) {
256f9f848faSopenharmony_ci ovfl:
257f9f848faSopenharmony_ci		Bfree(b);
258f9f848faSopenharmony_ci ovfl1:
259f9f848faSopenharmony_ci#ifndef NO_ERRNO
260f9f848faSopenharmony_ci		errno = ERANGE;
261f9f848faSopenharmony_ci#endif
262f9f848faSopenharmony_ci		return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
263f9f848faSopenharmony_ci		}
264f9f848faSopenharmony_ci	irv = STRTOG_Normal;
265f9f848faSopenharmony_ci	if (e < fpi->emin) {
266f9f848faSopenharmony_ci		irv = STRTOG_Denormal;
267f9f848faSopenharmony_ci		n = fpi->emin - e;
268f9f848faSopenharmony_ci		if (n >= nbits) {
269f9f848faSopenharmony_ci			switch (fpi->rounding) {
270f9f848faSopenharmony_ci			  case FPI_Round_near:
271f9f848faSopenharmony_ci				if (n == nbits && (n < 2 || any_on(b,n-1)))
272f9f848faSopenharmony_ci					goto one_bit;
273f9f848faSopenharmony_ci				break;
274f9f848faSopenharmony_ci			  case FPI_Round_up:
275f9f848faSopenharmony_ci				if (!sign)
276f9f848faSopenharmony_ci					goto one_bit;
277f9f848faSopenharmony_ci				break;
278f9f848faSopenharmony_ci			  case FPI_Round_down:
279f9f848faSopenharmony_ci				if (sign) {
280f9f848faSopenharmony_ci one_bit:
281f9f848faSopenharmony_ci					x[0] = b->wds = 1;
282f9f848faSopenharmony_ci dret:
283f9f848faSopenharmony_ci					*bp = b;
284f9f848faSopenharmony_ci					*exp = fpi->emin;
285f9f848faSopenharmony_ci#ifndef NO_ERRNO
286f9f848faSopenharmony_ci					errno = ERANGE;
287f9f848faSopenharmony_ci#endif
288f9f848faSopenharmony_ci					return STRTOG_Denormal | STRTOG_Inexhi
289f9f848faSopenharmony_ci						| STRTOG_Underflow;
290f9f848faSopenharmony_ci					}
291f9f848faSopenharmony_ci			  }
292f9f848faSopenharmony_ci			Bfree(b);
293f9f848faSopenharmony_ci retz:
294f9f848faSopenharmony_ci#ifndef NO_ERRNO
295f9f848faSopenharmony_ci			errno = ERANGE;
296f9f848faSopenharmony_ci#endif
297f9f848faSopenharmony_ci			return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
298f9f848faSopenharmony_ci			}
299f9f848faSopenharmony_ci		k = n - 1;
300f9f848faSopenharmony_ci		if (lostbits)
301f9f848faSopenharmony_ci			lostbits = 1;
302f9f848faSopenharmony_ci		else if (k > 0)
303f9f848faSopenharmony_ci			lostbits = any_on(b,k);
304f9f848faSopenharmony_ci		if (x[k>>kshift] & 1 << (k & kmask))
305f9f848faSopenharmony_ci			lostbits |= 2;
306f9f848faSopenharmony_ci		nbits -= n;
307f9f848faSopenharmony_ci		rshift(b,n);
308f9f848faSopenharmony_ci		e = fpi->emin;
309f9f848faSopenharmony_ci		}
310f9f848faSopenharmony_ci	if (lostbits) {
311f9f848faSopenharmony_ci		up = 0;
312f9f848faSopenharmony_ci		switch(fpi->rounding) {
313f9f848faSopenharmony_ci		  case FPI_Round_zero:
314f9f848faSopenharmony_ci			break;
315f9f848faSopenharmony_ci		  case FPI_Round_near:
316f9f848faSopenharmony_ci			if (lostbits & 2
317f9f848faSopenharmony_ci			 && (lostbits | x[0]) & 1)
318f9f848faSopenharmony_ci				up = 1;
319f9f848faSopenharmony_ci			break;
320f9f848faSopenharmony_ci		  case FPI_Round_up:
321f9f848faSopenharmony_ci			up = 1 - sign;
322f9f848faSopenharmony_ci			break;
323f9f848faSopenharmony_ci		  case FPI_Round_down:
324f9f848faSopenharmony_ci			up = sign;
325f9f848faSopenharmony_ci		  }
326f9f848faSopenharmony_ci		if (up) {
327f9f848faSopenharmony_ci			k = b->wds;
328f9f848faSopenharmony_ci			b = increment(b);
329f9f848faSopenharmony_ci			x = b->x;
330f9f848faSopenharmony_ci			if (irv == STRTOG_Denormal) {
331f9f848faSopenharmony_ci				if (nbits == fpi->nbits - 1
332f9f848faSopenharmony_ci				 && x[nbits >> kshift] & 1 << (nbits & kmask))
333f9f848faSopenharmony_ci					irv =  STRTOG_Normal;
334f9f848faSopenharmony_ci				}
335f9f848faSopenharmony_ci			else if (b->wds > k
336f9f848faSopenharmony_ci			 || ((n = nbits & kmask) !=0
337f9f848faSopenharmony_ci			      && hi0bits(x[k-1]) < 32-n)) {
338f9f848faSopenharmony_ci				rshift(b,1);
339f9f848faSopenharmony_ci				if (++e > fpi->emax)
340f9f848faSopenharmony_ci					goto ovfl;
341f9f848faSopenharmony_ci				}
342f9f848faSopenharmony_ci			irv |= STRTOG_Inexhi;
343f9f848faSopenharmony_ci			}
344f9f848faSopenharmony_ci		else
345f9f848faSopenharmony_ci			irv |= STRTOG_Inexlo;
346f9f848faSopenharmony_ci		}
347f9f848faSopenharmony_ci	*bp = b;
348f9f848faSopenharmony_ci	*exp = e;
349f9f848faSopenharmony_ci	return irv;
350f9f848faSopenharmony_ci	}
351