Mail Archives: djgpp-workers/2008/04/08/16:33:07
While I was trying to port m4-1.4.11 I got a new suprise.
Now they have started to use a version of strtod that according to:
<http://www.opengroup.org/onlinepubs/000095399/functions/strtod.html>
must be able to convert hex floating strings like this "0x123.abcP-123".
The patch submitted implements this functionality for the strto[dfld]
family of functions.
Suggestions, objections, comments are welcome.
Regards,
Juan M. Guerrero
2008-04-08 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
Diffs against djgpp CVS head of 2008-04-08.
* src/libc/ansi/stdlib/strtold.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/ansi/stdlib/strtold.txh: Info about hex floating point
string conversion added.
* src/libc/ansi/stdlib/strtod.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/ansi/stdlib/strtod.txh: Info about hex floating point
string conversion added.
* src/libc/c99/stdlib/strtof.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/c99/stdlib/strtof.txh: Info about hex floating point
string conversion added.
Index: src/libc/ansi/stdlib/strtod.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtod.c,v
retrieving revision 1.10
diff -p -U3 -r1.10 strtod.c
--- src/libc/ansi/stdlib/strtod.c 8 Apr 2008 17:55:48 -0000 1.10
+++ src/libc/ansi/stdlib/strtod.c 8 Apr 2008 20:26:51 -0000
@@ -15,6 +15,16 @@
#include <libc/unconst.h>
#include <libc/ieee.h>
+#define HEX_DIGIT_SIZE (4)
+#define DOUBLE_BIAS (0x3FFU)
+#define MAX_BIN_EXPONENT (1023) /* Max. and min. binary exponent (inclusive) as */
+#define MIN_BIN_EXPONENT (-1022) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
+#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
+ (((x) >= 'a') && ((x) <= 'f')) || \
+ IS_DEC_DIGIT(x))
+
+
double
strtod(const char *s, char **sret)
{
@@ -113,8 +123,145 @@ strtod(const char *s, char **sret)
return (t.d);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ int exponent;
+ unsigned long long int mantissa;
+ _double_union_t d_value;
+
+
+ /*
+ * Mantissa.
+ * 13 hex digits fit into the fraction part.
+ */
+ digits = integer_digits = 0;
+ mantissa = 0x00ULL;
+ s += 2;
+ while (integer_digits < 13 && IS_HEX_DIGIT(*s))
+ {
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16 ** integer_digits. */
+ s++;
+ }
+
+ if (*s == decimal)
+ {
+ s++;
+ digits = integer_digits;
+ while (digits < 13 && IS_HEX_DIGIT(*s))
+ {
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ s++;
+ }
+ }
+
+ if (!digits && !integer_digits)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0;
+ }
+
+ /*
+ * Normalize mantissa and adjust exponent accordingly.
+ * A maximum of four left shifts will be done to shift
+ * the most significant binary 1 from the fraction into
+ * the integer part of the mantissa.
+ * If there is still a valid hex character in the string
+ * its bits will be inserted in the LSB of the mantissa,
+ * else zeros will be inserted.
+ */
+ for (digits = 0; !(mantissa & 0x0010000000000000ULL); digits++)
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ if (IS_HEX_DIGIT(*s))
+ {
+ unsigned long long bits = IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+
+ switch (digits)
+ {
+ case 1:
+ mantissa |= (0x01ULL & bits >> 3);
+ break;
+ case 2:
+ mantissa |= (0x03ULL & bits >> 2);
+ break;
+ case 3:
+ mantissa |= (0x07ULL & bits >> 1);
+ break;
+ case 4:
+ mantissa |= (0x0FULL & bits);
+ break;
+ }
+ }
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extracting of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ exponent = 0U;
+ if (*s == 'P' || *s == 'p')
+ {
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while (exponent < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ }
+ exponent = esign * exponent + integer_digits * HEX_DIGIT_SIZE - 1; /* 2 ** exponent. */
+
+
+ if (exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VAL;
+ }
+ else if(exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0;
+ }
+ d_value.dt.sign = (sign == 1) ? 0 : 1;
+ d_value.dt.exponent = 0x07FFU & (exponent + DOUBLE_BIAS);
+ d_value.dt.mantissah = 0x000FFFFFUL & (mantissa >> 32);
+ d_value.dt.mantissal = 0xFFFFFFFFUL & mantissa;
+
+ if (sret)
+ *sret = unconst(s, char *);
+
+ return d_value.d;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0;
@@ -151,7 +298,7 @@ strtod(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
Index: src/libc/ansi/stdlib/strtod.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtod.txh,v
retrieving revision 1.5
diff -p -U3 -r1.5 strtod.txh
--- src/libc/ansi/stdlib/strtod.txh 25 Oct 2003 11:15:59 -0000 1.5
+++ src/libc/ansi/stdlib/strtod.txh 8 Apr 2008 20:26:51 -0000
@@ -5,19 +5,19 @@
@example
#include <stdlib.h>
-double strtod(const char *s, char **endp);
+double strtod(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
-This function converts as many characters of @var{s} as look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+This function converts as many characters of @var{s} that look like a
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -66,6 +66,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+123 foobar";
char *bp;
double x, x2, x3, x4;
@@ -73,5 +74,6 @@ x = strtod(buf, &bp);
x2 = strtod(buf2, &bp);
x3 = strtod(buf3, &bp);
x4 = strtod(buf4, &bp);
+x5 = strtod(buf5, &bp);
@end example
Index: src/libc/ansi/stdlib/strtold.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtold.c,v
retrieving revision 1.10
diff -p -U3 -r1.10 strtold.c
--- src/libc/ansi/stdlib/strtold.c 8 Nov 2003 12:19:40 -0000 1.10
+++ src/libc/ansi/stdlib/strtold.c 8 Apr 2008 20:26:52 -0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
@@ -6,11 +7,21 @@
#include <locale.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include <math.h>
#include <string.h>
#include <libc/unconst.h>
#include <libc/ieee.h>
+#define HEX_DIGIT_SIZE (4)
+#define LONG_DOUBLE_BIAS (0x3FFFU)
+#define MAX_BIN_EXPONENT (16383) /* Max. and min. binary exponent (inclusive) as */
+#define MIN_BIN_EXPONENT (-16382) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
+#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
+ (((x) >= 'a') && ((x) <= 'f')) || \
+ IS_DEC_DIGIT(x))
+
static long double powten[] =
{
1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
@@ -116,8 +127,143 @@ strtold(const char *s, char **sret)
return (t.ld);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ long long int exponent;
+ unsigned long long mantissa;
+ _longdouble_union_t ld_value;
+
+
+ /*
+ * Mantissa.
+ * 16 hex digits fit into the mantissa
+ * including the explicit integer bit.
+ */
+ digits = integer_digits = 0;
+ mantissa = 0x00ULL;
+ s += 2;
+ while (integer_digits < 16 && IS_HEX_DIGIT(*s))
+ {
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16 ** integer_digits. */
+ s++;
+ }
+
+ if (*s == decimal)
+ {
+ s++;
+ digits = integer_digits;
+ while (digits < 16 && IS_HEX_DIGIT(*s))
+ {
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ s++;
+ }
+ }
+
+ if (!digits && !integer_digits)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0L;
+ }
+
+ /*
+ * Normalize mantissa and adjust exponent accordingly.
+ * A maximum of three left shifts will be done to shift
+ * the most significant binary 1 from the fraction into
+ * the integer part of the mantissa.
+ * If there is still a valid hex character in the string
+ * its bits will be inserted in the LSB of the mantissa,
+ * else zeros will be inserted.
+ */
+ for (digits = 0; !(mantissa & 0x8000000000000000ULL); digits++)
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ if (IS_HEX_DIGIT(*s))
+ {
+ unsigned long long bits = IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+
+ switch (digits)
+ {
+ case 1:
+ mantissa |= (0x01ULL & bits >> 3);
+ break;
+ case 2:
+ mantissa |= (0x03ULL & bits >> 2);
+ break;
+ case 3:
+ mantissa |= (0x07ULL & bits >> 1);
+ break;
+ }
+ }
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extracting of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ exponent = 0ULL;
+ if (*s == 'P' || *s == 'p')
+ {
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while (exponent < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ }
+ exponent = esign * exponent + integer_digits * HEX_DIGIT_SIZE - 1; /* 2 ** exponent. */
+
+
+ if (exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VALL;
+ }
+ else if(exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0L;
+ }
+ ld_value.ldt.sign = (sign == 1) ? 0 : 1;
+ ld_value.ldt.exponent = 0x7FFFU & (exponent + LONG_DOUBLE_BIAS);
+ ld_value.ldt.mantissah = 0xFFFFFFFFUL & (mantissa >> 32);
+ ld_value.ldt.mantissal = 0xFFFFFFFFUL & mantissa;
+
+ if (sret)
+ *sret = unconst(s, char *);
+
+ return ld_value.ld;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0L;
@@ -128,7 +274,7 @@ strtold(const char *s, char **sret)
if (*s == decimal)
{
s++;
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 2;
r *= 10.0L;
@@ -141,6 +287,7 @@ strtold(const char *s, char **sret)
{
if (sret)
*sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
return 0.0L;
}
@@ -154,7 +301,7 @@ strtold(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
Index: src/libc/ansi/stdlib/strtold.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtold.txh,v
retrieving revision 1.6
diff -p -U3 -r1.6 strtold.txh
--- src/libc/ansi/stdlib/strtold.txh 25 Oct 2003 11:15:59 -0000 1.6
+++ src/libc/ansi/stdlib/strtold.txh 8 Apr 2008 20:26:52 -0000
@@ -5,26 +5,26 @@
@example
#include <stdlib.h>
-long double _strtold(const char *s, char **endp);
+long double _strtold(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
This function converts as many characters of @var{s} that look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
There is also a standardised version of this function:
@code{strtold} (@pxref{strtold}).
@subheading Return Value
-The value representedby @var{s}.
+The value represented by @var{s}.
If @var{s} is ``Inf'' or ``Infinity'', with any variations of case and
optionally prefixed with ``+'' or ``-'', the return value is
@@ -63,6 +63,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+1234 foobar";
char *bp;
long double x, x2, x3, x4;
@@ -70,6 +71,7 @@ x = _strtold(buf, &bp);
x2 = _strtold(buf2, &bp);
x3 = _strtold(buf3, &bp);
x4 = _strtold(buf4, &bp);
+x5 = _strtold(buf5, &bp);
@end example
@node strtold, string
@@ -79,19 +81,19 @@ x4 = _strtold(buf4, &bp);
@example
#include <stdlib.h>
-long double strtold(const char *s, char **endp);
+long double strtold(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
This function converts as many characters of @var{s} that look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number}),
-``NaN(@var{optional octal-number})
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -137,6 +139,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89abcdefP+1234 foobar";
char *bp;
long double x, x2, x3, x4;
@@ -144,4 +147,5 @@ x = strtold(buf, &bp);
x2 = strtold(buf2, &bp);
x3 = strtold(buf3, &bp);
x4 = strtold(buf4, &bp);
+x5 = strtold(buf5, &bp);
@end example
Index: src/libc/c99/stdlib/strtof.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/c99/stdlib/strtof.c,v
retrieving revision 1.8
diff -p -U3 -r1.8 strtof.c
--- src/libc/c99/stdlib/strtof.c 8 Apr 2008 18:50:31 -0000 1.8
+++ src/libc/c99/stdlib/strtof.c 8 Apr 2008 20:26:54 -0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
@@ -16,6 +17,16 @@
#include <libc/unconst.h>
#include <libc/ieee.h>
+#define HEX_DIGIT_SIZE (4)
+#define FLOAT_BIAS (0x7FU)
+#define MAX_BIN_EXPONENT (127) /* Max. and min. binary exponent (inclusive) as */
+#define MIN_BIN_EXPONENT (-126) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
+#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
+ (((x) >= 'a') && ((x) <= 'f')) || \
+ IS_DEC_DIGIT(x))
+
+
float
strtof(const char *s, char **sret)
{
@@ -113,8 +124,142 @@ strtof(const char *s, char **sret)
return (t.f);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ int exponent;
+ unsigned int mantissa;
+ _float_union_t f_value;
+
+
+ /*
+ * Mantissa.
+ * 6 hex digits fit into the mantissa
+ * including the implicit integer bit.
+ */
+ digits = integer_digits = 0;
+ mantissa = 0x00U;
+ s += 2;
+ while (integer_digits < 6 && IS_HEX_DIGIT(*s))
+ {
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16 ** integer_digits. */
+ s++;
+ }
+
+ if (*s == decimal)
+ {
+ s++;
+ digits = integer_digits;
+ while (digits < 6 && IS_HEX_DIGIT(*s))
+ {
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ s++;
+ }
+ }
+
+ if (!digits && !integer_digits)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0;
+ }
+
+ /*
+ * Normalize mantissa and adjust exponent accordingly.
+ * A maximum of three left shifts will be done to shift
+ * the most significant binary 1 from the fraction into
+ * the integer part of the mantissa.
+ * If there is still a valid hex character in the string
+ * its bits will be inserted in the LSB of the mantissa,
+ * else zeros will be inserted.
+ */
+ for (digits = 0; !(mantissa & 0x00800000U); digits++)
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ if (IS_HEX_DIGIT(*s))
+ {
+ unsigned int bits = IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+
+ switch (digits)
+ {
+ case 1:
+ mantissa |= (0x01U & bits >> 3);
+ break;
+ case 2:
+ mantissa |= (0x03U & bits >> 2);
+ break;
+ case 3:
+ mantissa |= (0x07U & bits >> 1);
+ break;
+ }
+ }
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extracting of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ exponent = 0U;
+ if (*s == 'P' || *s == 'p')
+ {
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while (exponent < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ }
+ exponent = esign * exponent + integer_digits * HEX_DIGIT_SIZE - 1; /* 2 ** exponent. */
+
+
+ if (exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VALF;
+ }
+ else if(exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0;
+ }
+ f_value.ft.sign = (sign == 1) ? 0 : 1;
+ f_value.ft.exponent = 0x07FFU & (exponent + FLOAT_BIAS);
+ f_value.ft.mantissa = 0x007FFFFFU & mantissa;
+
+ if (sret)
+ *sret = unconst(s, char *);
+
+ return f_value.f;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0;
@@ -151,7 +296,7 @@ strtof(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
Index: src/libc/c99/stdlib/strtof.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/c99/stdlib/strtof.txh,v
retrieving revision 1.6
diff -p -U3 -r1.6 strtof.txh
--- src/libc/c99/stdlib/strtof.txh 25 Oct 2003 11:16:20 -0000 1.6
+++ src/libc/c99/stdlib/strtof.txh 8 Apr 2008 20:26:54 -0000
@@ -5,19 +5,19 @@
@example
#include <stdlib.h>
-float strtof(const char *s, char **endp);
+float strtof(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
-This function converts as many characters of @var{s} as look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+This function converts as many characters of @var{s} that look like a
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -65,6 +65,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+12 foobar";
char *bp;
float x, x2, x3, x4;
@@ -72,4 +73,5 @@ x = strtof(buf, &bp);
x2 = strtof(buf2, &bp);
x3 = strtof(buf3, &bp);
x4 = strtof(buf4, &bp);
+x5 = strtod(buf5, &bp);
@end example
- Raw text -