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