libc/newlib/libc/machine/powerpc/strtosfix16.c

182 lines
4.8 KiB
C

/*
FUNCTION
<<strtosfix16>>, <<strtosfix32>>, <<strtosfix64>>---string to signed fixed point
INDEX
strtosfix16
INDEX
strtosfix32
INDEX
strtosfix64
INDEX
_strtosfix16_r
INDEX
_strtosfix32_r
INDEX
_strtosfix64_r
SYNOPSIS
#include <stdlib.h>
__int16 strtosfix16 (const char *<[s]>, char **<[ptr]>);
__int32 strtosfix32 (const char *<[s]>, char **<[ptr]>);
__int64 strtosfix64 (const char *<[s]>, char **<[ptr]>);
__int16 _strtosfix16_r (void *<[reent]>,
const char *<[s]>, char **<[ptr]>);
__int32 _strtosfix32_r (void *<[reent]>,
const char *<[s]>, char **<[ptr]>);
__int64 _strtosfix64_r (void *<[reent]>,
const char *<[s]>, char **<[ptr]>);
DESCRIPTION
The function <<strtosfix16>> converts the string <<*<[s]>>> to
a fixed-point sign + 15-bits fraction representation. The function
follows the same rules as <<strtod>>.
The substring converted is the longest initial
subsequence of <[s]>, beginning with the first
non-whitespace character, that has the format:
.[+|-]<[digits]>[.][<[digits]>][(e|E)[+|-]<[digits]>]
The substring contains no characters if <[s]> is empty, consists
entirely of whitespace, or if the first non-whitespace
character is something other than <<+>>, <<->>, <<.>>, or a
digit. If the substring is empty, no conversion is done, and
the value of <[s]> is stored in <<*<[ptr]>>>. Otherwise,
the substring is converted, and a pointer to the final string
(which will contain at least the terminating null character of
<[s]>) is stored in <<*<[ptr]>>>. If you want no
assignment to <<*<[ptr]>>>, pass a null pointer as <[ptr]>.
<<strtosfix32>> is identical to <<strtosfix16>> except that it
converts to fixed-point sign + 31-bits fraction representation.
<<strtosfix64>> is also similar, except that it converts
to fixed-point sign + 63-bit fraction format.
The alternate functions <<_strtosfix16_r>>, <<_strtosfix32_r>>,
and <<_strtosfix64_r>> are reentrant versions.
The extra argument <[reent]> is a pointer to a reentrancy structure.
RETURNS
The functions return the converted substring value, if any. If
no conversion can be performed, then 0 is returned. If the converted
value is a NaN, 0 is returned and errno is set to <<EDOM>>.
If the converted value exceeds the maximum positive fixed-point value,
the output value is saturated to the maximum value and <<ERANGE>> is stored in
errno. If the converted value is less than the minimum fixed-point negative
value, then the output is saturated to the minimum value and <<ERANGE>> is stored
in errno. Otherwise, the converted value is returned in the
specified fixed-point format.
PORTABILITY
<<strtosfix16>>, <<strtosfix32>>, and <<strtosfix64>> are non-standard.
The OS subroutines of <<strtod>> are required.
*/
#ifdef __SPE__
#include <_ansi.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <reent.h>
#include "vfieeefp.h"
/*
* Convert a string to a fixed-point (sign + 15-bits) value.
*
* Ignores `locale' stuff.
*/
__int16_t
_DEFUN (_strtosfix16_r, (rptr, nptr, endptr),
struct _reent *rptr,
const char *nptr,
char **endptr)
{
union double_union dbl;
unsigned long tmp, tmp2;
int exp, negexp, sign;
__int16_t result;
dbl.d = _strtod_r (rptr, nptr, endptr);
/* treat NAN as domain error, +/- infinity as saturation */
if (!finite(dbl.d))
{
if (isnan (dbl.d))
{
rptr->_errno = EDOM;
return 0;
}
rptr->_errno = ERANGE;
if (word0(dbl) & Sign_bit)
return SHRT_MIN;
return SHRT_MAX;
}
/* check for normal saturation */
if (dbl.d >= 1.0)
{
rptr->_errno = ERANGE;
return SHRT_MAX;
}
else if (dbl.d < -1.0)
{
rptr->_errno = ERANGE;
return SHRT_MIN;
}
/* otherwise we have normal number in range */
/* strip off sign and exponent */
sign = word0(dbl) & Sign_bit;
exp = ((word0(dbl) & Exp_mask) >> Exp_shift) - Bias;
negexp = -exp;
if (negexp > 15)
return 0;
/* add in implicit normalized bit */
tmp = word0(dbl) | Exp_msk1;
/* remove exponent and sign */
tmp <<= Ebits;
if (negexp != 0)
{
/* perform rounding */
tmp2 = tmp + (1 << (negexp - 1));
result = (short)(tmp2 >> (negexp + 16));
/* check if rounding caused carry bit which must be added into result */
if (tmp2 < tmp)
result |= (1 << (16 - negexp));
/* check if positive saturation has occurred because of rounding */
if (!sign && result < 0)
{
rptr->_errno = ERANGE;
return SHRT_MAX;
}
}
else
{
/* we have -1.0, no rounding necessary */
return SHRT_MIN;
}
return sign ? -result : result;
}
#ifndef _REENT_ONLY
__int16_t
_DEFUN (strtosfix16, (s, ptr, base),
const char *s,
char **ptr)
{
return _strtosfix16_r (_REENT, s, ptr);
}
#endif
#endif /* __SPE__ */