X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com X-Authenticated: #27081556 X-Provags-ID: V01U2FsdGVkX19ch4w1KbNcK0aKkMg3ZGXqhk5knV31ilIZSEHTYy HvtPcpX3mRbn4b From: Juan Manuel Guerrero To: djgpp-workers AT delorie DOT com Subject: Hex float string conversion for strto[dfld] Date: Tue, 8 Apr 2008 22:32:26 +0200 User-Agent: KMail/1.9.5 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200804082232.28045.juan.guerrero@gmx.de> X-Y-GMX-Trusted: 0 Reply-To: djgpp-workers AT delorie DOT com 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: 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 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 #include +#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 -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 #include #include +#include #include #include #include #include +#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 -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 -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 #include +#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 -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