From: Message-Id: <200303142003.h2EK3NH09554@speedy.ludd.luth.se> Subject: strto{d,f,ld}, inf and nan patch To: DJGPP-WORKERS Date: Fri, 14 Mar 2003 21:03:23 +0100 (CET) X-Mailer: ELM [version 2.4ME+ PL78 (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII X-MailScanner: Found to be clean Reply-To: djgpp-workers AT delorie DOT com Hello. Ok, this is what I have for inf and nan support for strto{d,f,ld}. Now all three of them are done. Many added test cases for strtof(). Somebody else might want to add some in the endptr category. No test cases at all for strtold(). Sorry. There weren't any before either. I'm unsure if my markup in wc204.txi is good. Comments? Right, MartinS Index: djgpp/include/math.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/math.h,v retrieving revision 1.7 diff -p -u -r1.7 math.h --- djgpp/include/math.h 20 Feb 2003 19:04:02 -0000 1.7 +++ djgpp/include/math.h 14 Mar 2003 19:53:52 -0000 @@ -51,6 +51,11 @@ extern long double __dj_huge_vall; #define HUGE_VALF __dj_huge_valf #define HUGE_VALL __dj_huge_vall +#define INFINITY HUGE_VALF + +extern float __dj_nan; +#define NAN __dj_nan + #endif /* (__STDC_VERSION__ >= 199901L) || !__STRICT_ANSI__ */ #ifndef __STRICT_ANSI__ Index: djgpp/src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.149 diff -p -u -r1.149 wc204.txi --- djgpp/src/docs/kb/wc204.txi 14 Mar 2003 19:11:31 -0000 1.149 +++ djgpp/src/docs/kb/wc204.txi 14 Mar 2003 19:54:00 -0000 @@ -917,3 +917,10 @@ The functions @code{readv} and @code{wri @findex pwrite The function @code{pwrite} was added. + +@findex strtod AT r{, inf and nan in input} +@findex strtof AT r{, inf and nan in input} +@findex strtold AT r{, inf and nan in input} +The functions @code{strtod}, @code{strtof} and @code{strtold} now +understand ``inf'', ``infinity'', ``nan'' and ``nan()'' in the +input string. Index: djgpp/src/libc/ansi/stdlib/strtod.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtod.c,v retrieving revision 1.5 diff -p -u -r1.5 strtod.c --- djgpp/src/libc/ansi/stdlib/strtod.c 17 Oct 2002 23:00:24 -0000 1.5 +++ djgpp/src/libc/ansi/stdlib/strtod.c 14 Mar 2003 19:54:01 -0000 @@ -1,13 +1,16 @@ +/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ +#include #include #include #include #include #include +#include #include double @@ -32,6 +35,7 @@ strtod(const char *s, char **sret) while (isspace((unsigned char) *s)) s++; + /* Handle leading sign. */ if (*s == '+') s++; else if (*s == '-') @@ -40,6 +44,66 @@ strtod(const char *s, char **sret) s++; } + /* Handle INF and INFINITY. */ + if ( ! strnicmp( "INF", s, 3 ) ) + { + if( sret ) + { + if ( ! strnicmp( "INITY", &s[3], 5 ) ) + { + *sret = unconst((&s[8]), char *); + } + else + { + *sret = unconst((&s[3]), char *); + } + } + + if( 0 <= sign ) + { + return INFINITY; + } + else + { + return -INFINITY; + } + } + + /* Handle NAN and NAN(). */ + if ( ! strnicmp( "NAN", s, 3 ) ) + { + if( s[3] == '(' ) + { + int end_of_n_char_sequence = 4; + + while( s[end_of_n_char_sequence] != 0 && + s[end_of_n_char_sequence] != ')' ) + { + end_of_n_char_sequence++; + } + if( s[end_of_n_char_sequence] == ')' ) + { + /* If we are going to support "nan(0x1234) for setting specific bits, + * that code goes here. Something like "bits = strtoul( &s[4], &end_p, + * 0);". + */ + if( sret ) + { + *sret = unconst((&s[end_of_n_char_sequence+1]), char *); + } + return NAN; + } + /* The subject sequence didn't match NAN(), so match only NAN. */ + } + + if( sret ) + { + *sret = unconst((&s[3]), char *); + } + return NAN; + } + + /* Handle ordinary numbers. */ while ((*s >= '0') && (*s <= '9')) { flags |= 1; Index: djgpp/src/libc/ansi/stdlib/strtold.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtold.c,v retrieving revision 1.4 diff -p -u -r1.4 strtold.c --- djgpp/src/libc/ansi/stdlib/strtold.c 6 Dec 2002 09:32:23 -0000 1.4 +++ djgpp/src/libc/ansi/stdlib/strtold.c 14 Mar 2003 19:54:01 -0000 @@ -1,9 +1,12 @@ +/* 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 */ /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ #include #include #include +#include +#include #include static long double powten[] = @@ -38,6 +41,66 @@ strtold(const char *s, char **sret) s++; } + /* Handle INF and INFINITY. */ + if ( ! strnicmp( "INF", s, 3 ) ) + { + if( sret ) + { + if ( ! strnicmp( "INITY", &s[3], 5 ) ) + { + *sret = unconst((&s[8]), char *); + } + else + { + *sret = unconst((&s[3]), char *); + } + } + + if( 0 <= sign ) + { + return INFINITY; + } + else + { + return -INFINITY; + } + } + + /* Handle NAN and NAN(). */ + if ( ! strnicmp( "NAN", s, 3 ) ) + { + if( s[3] == '(' ) + { + int end_of_n_char_sequence = 4; + + while( s[end_of_n_char_sequence] != 0 && + s[end_of_n_char_sequence] != ')' ) + { + end_of_n_char_sequence++; + } + if( s[end_of_n_char_sequence] == ')' ) + { + /* If we are going to support "nan(0x1234) for setting specific bits, + * that code goes here. Something like "bits = strtoul( &s[4], &end_p, + * 0);". + */ + if( sret ) + { + *sret = unconst((&s[end_of_n_char_sequence+1]), char *); + } + return NAN; + } + /* The subject sequence didn't match NAN(), so match only NAN. */ + } + + if( sret ) + { + *sret = unconst((&s[3]), char *); + } + return NAN; + } + + /* Handle ordinary numbers. */ while ((*s >= '0') && (*s <= '9')) { flags |= 1; Index: djgpp/src/libc/c99/math/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/c99/math/makefile,v retrieving revision 1.1 diff -p -u -r1.1 makefile --- djgpp/src/libc/c99/math/makefile 23 Jan 2003 19:50:51 -0000 1.1 +++ djgpp/src/libc/c99/math/makefile 14 Mar 2003 19:54:01 -0000 @@ -3,5 +3,6 @@ TOP=../.. SRC += hugevalf.c SRC += hugevall.c +SRC += nan.c include $(TOP)/../makefile.inc Index: djgpp/src/libc/c99/stdlib/strtof.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/c99/stdlib/strtof.c,v retrieving revision 1.2 diff -p -u -r1.2 strtof.c --- djgpp/src/libc/c99/stdlib/strtof.c 23 Jan 2003 19:53:02 -0000 1.2 +++ djgpp/src/libc/c99/stdlib/strtof.c 14 Mar 2003 19:54:01 -0000 @@ -5,11 +5,13 @@ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ +#include #include #include #include #include #include +#include #include float @@ -43,6 +45,66 @@ strtof(const char *s, char **sret) s++; } + /* Handle INF and INFINITY. */ + if ( ! strnicmp( "INF", s, 3 ) ) + { + if( sret ) + { + if ( ! strnicmp( "INITY", &s[3], 5 ) ) + { + *sret = unconst((&s[8]), char *); + } + else + { + *sret = unconst((&s[3]), char *); + } + } + + if( 0 <= sign ) + { + return INFINITY; + } + else + { + return -INFINITY; + } + } + + /* Handle NAN and NAN(). */ + if ( ! strnicmp( "NAN", s, 3 ) ) + { + if( s[3] == '(' ) + { + int end_of_n_char_sequence = 4; + + while( s[end_of_n_char_sequence] != 0 && + s[end_of_n_char_sequence] != ')' ) + { + end_of_n_char_sequence++; + } + if( s[end_of_n_char_sequence] == ')' ) + { + /* If we are going to support "nan(0x1234) for setting specific bits, + * that code goes here. Something like "bits = strtoul( &s[4], &end_p, + * 0);". + */ + if( sret ) + { + *sret = unconst((&s[end_of_n_char_sequence+1]), char *); + } + return NAN; + } + /* The subject sequence didn't match NAN(), so match only NAN. */ + } + + if( sret ) + { + *sret = unconst((&s[3]), char *); + } + return NAN; + } + + /* Handle ordinary numbers. */ while ((*s >= '0') && (*s <= '9')) { flags |= 1; Index: djgpp/tests/libc/ansi/stdlib/strtod.c =================================================================== RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/stdlib/strtod.c,v retrieving revision 1.1 diff -p -u -r1.1 strtod.c --- djgpp/tests/libc/ansi/stdlib/strtod.c 1 Jan 1998 21:45:46 -0000 1.1 +++ djgpp/tests/libc/ansi/stdlib/strtod.c 14 Mar 2003 19:54:05 -0000 @@ -9,6 +9,10 @@ static const char *testnum[] = { "1e6000000000", /* overflow */ "1e400", /* ditto */ "1e-400", /* underflow */ + "InF", /* infinity */ + "-inFinitY", /* infinity */ + "nAn", /* nan */ + "-Nan()", /* nan */ 0 }; Index: djgpp/tests/libc/c99/stdlib/t-strtof.c =================================================================== RCS file: /cvs/djgpp/djgpp/tests/libc/c99/stdlib/t-strtof.c,v retrieving revision 1.2 diff -p -u -r1.2 t-strtof.c --- djgpp/tests/libc/c99/stdlib/t-strtof.c 23 Jan 2003 19:53:57 -0000 1.2 +++ djgpp/tests/libc/c99/stdlib/t-strtof.c 14 Mar 2003 19:54:05 -0000 @@ -51,6 +51,50 @@ static const test3_t tests3[] = { static const size_t n_tests3 = sizeof(tests3) / sizeof(tests3[0]); +typedef struct { + const char * const str; /* String to run strtof() on. */ + const int diff; /* For endptr tests. How many characters from string start + endptr should be offset. */ + const int inf; /* 0 -> not inf, 1 -> +inf, -1 -> -inf. */ + const int nan; /* 0 -> not nan, 1 -> nan. */ +} test4_t; + +static const test4_t tests4[] = { + { "nAn", 3, 0, 1 }, + { "-nAn", 4, 0, 1 }, + { "nanny", 3, 0, 1 }, + { "-nanny", 4, 0, 1 }, + { "NAN()", 5, 0, 1 }, + { "-NAN()", 6, 0, 1 }, + { "nan(whatever)", 13, 0, 1 }, + { "-nan(someMOREever)", 18, 0, 1 }, + { "nan(!#%&/=?`)", 13, 0, 1 }, + { "-nan(((()", 9, 0, 1 }, + { "nan(-0x12)", 10, 0, 1 }, + { "-nan(-nan)", 10, 0, 1 }, + { "nan(-42)", 8, 0, 1 }, + { "-nan(0xaa7d7aa74)", 17, 0, 1 }, + { "nan()()", 5, 0, 1 }, + { "-nan(smurf)()", 11, 0, 1 }, + { "NAN()nan", 5, 0, 1 }, + { "-nan(NAN)nanNAN", 9, 0, 1 }, + { "inF", 3, 1, 0 }, + { "-INf", 4, -1, 0 }, + { "infi", 3, 1, 0 }, + { "-infi", 4, -1, 0 }, + { "infinit", 3, 1, 0 }, + { "-infinit", 4, -1, 0 }, + { "INfINITY", 8, 1, 0 }, + { "-InfInIty", 9, -1, 0 }, + { "infinity0", 8, 1, 0 }, + { "-infinity5", 9, -1, 0 }, + { "infinity-1", 8, 1, 0 }, + { "-infinity-6", 9, -1, 0 }, +}; + +static const size_t n_tests4 = sizeof(tests4) / sizeof(tests4[0]); + + static void inline result (const size_t n, const float f_in, const float f_out) { @@ -104,6 +148,62 @@ main (void) puts("Yes - FAIL"); else puts("No - OK"); + } + } + + puts("Infinity tests:"); + for (i = 0; i < n_tests4; i++) { + float_t float_bits; + + if (tests4[i].inf) { + f_res = strtof(tests4[i].str, NULL); + + printf("strtof(\"%s\", NULL) -> %f - ", tests4[i].str, f_res); + + /* Need to to the inf detection ourselves. */ + float_bits = *(float_t *)(&f_res); + if (float_bits.exponent == 0xff && float_bits.mantissa == 0 && + ( (float_bits.sign && f_res < 0) || + (!float_bits.sign && 0 < f_res) )) { + puts("OK"); + } else { + puts("FAIL"); + } + } + } + + puts("Nan tests:"); + for (i = 0; i < n_tests4; i++) { + float_t float_bits; + + if (tests4[i].nan) { + f_res = strtof(tests4[i].str, NULL); + + printf("strtof(\"%s\", NULL) -> %f - ", tests4[i].str, f_res); + + /* Need to to the nandetection ourselves. */ + float_bits = *(float_t *)(&f_res); + if (float_bits.exponent == 0xff && float_bits.mantissa != 0) { + puts("OK"); + } else { + puts("FAIL"); + } + } + } + + puts("endptr tests:"); + for (i = 0; i < n_tests4; i++) { + char *endptr; + + f_res = strtof(tests4[i].str, &endptr); + + printf("strtof(\"%s\", endptr) -> endptr - (start_of_string) == %ld - ", + tests4[i].str, endptr - tests4[i].str); + + if (endptr-tests4[i].str == tests4[i].diff) { + puts("OK"); + } else { + puts("FAIL"); } }