X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f Date: Sun, 09 Nov 2003 22:51:54 +0000 From: "Richard Dawe" Sender: rich AT phekda DOT freeserve DOT co DOT uk To: djgpp-workers AT delorie DOT com X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6 Subject: Problems with sscanf & suppressions [PATCH] Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is a patch that fixes the bugs MartinS (or whoever originally) reported in sscanf. Changes related to this bug: * _instr was always succeeding, when we were suppressing assignment. This was wrong. It should fail and set the EOF indicator variable. * We should always increase the value of nmatch, whether or not we stored a value. See the code handling _innum's return in _doscan_low. Other changes: * Return EOF instead of -1. (Actually the same value, but it's symbolically clearer to return EOF.) * Add some braces in _getccl() to make it more readable. I added some new test cases - sscanf3. I've run all the test cases in tests/libc/ansi/stdio that use *scanf. They all pass. I've run the Cygnus test suite - no regressions there, although I guess that tests only numerical formats. Any ideas on good scanf tests? OK to commit? Bye, Rich =] Index: src/libc/ansi/stdio/doscan.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/doscan.c,v retrieving revision 1.14 diff -p -u -3 -r1.14 doscan.c --- src/libc/ansi/stdio/doscan.c 8 Nov 2003 12:19:40 -0000 1.14 +++ src/libc/ansi/stdio/doscan.c 9 Nov 2003 22:34:52 -0000 @@ -144,7 +144,7 @@ _doscan_low(FILE *iop, int (*scan_getc)( } } if (ch == '\0') - return(-1); + return(EOF); if (ch == 'n') { @@ -166,13 +166,12 @@ _doscan_low(FILE *iop, int (*scan_getc)( if (_innum(ptr, ch, len, size, iop, scan_getc, scan_ungetc, &fileended)) { - if (ptr) - nmatch++; + nmatch++; } else { - if (fileended && nmatch==0) - return(-1); + if (fileended) + return(EOF); return(nmatch); } break; @@ -198,7 +197,7 @@ _doscan_low(FILE *iop, int (*scan_getc)( if (ch1 != EOF) nchars++; if (ch1 != ch) { if (ch1==EOF) - return(nmatch? nmatch: -1); + return(nmatch? nmatch: EOF); scan_ungetc(ch1, iop); nchars--; return(nmatch); @@ -351,11 +350,10 @@ _instr(char *ptr, int type, int len, FIL int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr) { register int ch; - register char *optr; int ignstp; + int matched = 0; *eofptr = 0; - optr = ptr; if (type=='c' && len==30000) len = 1; ignstp = 0; @@ -369,6 +367,7 @@ _instr(char *ptr, int type, int len, FIL else if (type=='[') ignstp = STP; while (ch!=EOF && (_sctab[ch & 0xff]&ignstp)==0) { + matched = 1; if (ptr) *ptr++ = ch; if (--len <= 0) @@ -388,10 +387,8 @@ _instr(char *ptr, int type, int len, FIL nchars--; *eofptr = 1; } - if (!ptr) - return(1); - if (ptr!=optr) { - if (type!='c') + if (matched) { + if (ptr && type!='c') *ptr++ = '\0'; return(1); } @@ -409,11 +406,12 @@ _getccl(const unsigned char *s) t++; s++; } - for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++) + for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++) { if (t) _sctab[c] &= ~STP; else _sctab[c] |= STP; + } if ((c = *s) == ']' || c == '-') { /* first char is special */ if (t) _sctab[c] |= STP; Index: tests/libc/ansi/stdio/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/stdio/makefile,v retrieving revision 1.10 diff -p -u -3 -r1.10 makefile --- tests/libc/ansi/stdio/makefile 8 Nov 2003 12:19:40 -0000 1.10 +++ tests/libc/ansi/stdio/makefile 9 Nov 2003 22:34:52 -0000 @@ -18,6 +18,7 @@ SRC += printf.c SRC += printf2.c SRC += sscanf.c SRC += sscanf2.c +SRC += sscanf3.c SRC += tmpnam.c SRC += tremove.c SRC += tscanf.c Index: src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.162 diff -p -u -3 -r1.162 wc204.txi --- src/docs/kb/wc204.txi 8 Nov 2003 12:19:40 -0000 1.162 +++ src/docs/kb/wc204.txi 9 Nov 2003 22:34:59 -0000 @@ -1032,3 +1032,9 @@ from the current locale. @code{strftime} now uses the date format (for @code{%x}) and time format (for @code{%X}) from the current locale. This means that @code{%T} and @code{%X} are no longer equivalent. + +@findex scanf AT r{, and assignment suppression} +A bug was fixed in the @code{scanf} family of functions, +when suppressing assignment of conversions to variables. +Previously the @code{scanf} family of functions could return +a match failure at EOF instead of @code{EOF}. --- /dev/null 2003-11-09 22:46:33.000000000 +0000 +++ tests/libc/ansi/stdio/sscanf3.c 2003-11-09 22:45:12.000000000 +0000 @@ -0,0 +1,92 @@ +#include +#include +#include + +typedef struct { + const char *input; + const char *fmt; + + const int expected; + const char expected_c[2]; + const char expected_c2[2]; + + char c[2]; + char c2[2]; +} sscanf_testcase_t; + +sscanf_testcase_t sscanf_testcases[] = { + /* No assignment */ + { "", "%*[0123456789]%*c", EOF, "", "" }, + { "X", "%*[0123456789]%*c", 0, "", "" }, + { "1", "%*[0123456789]%*c", EOF, "", "" }, + { "1X2", "%*[0123456789]%*[0123456789]", 1, "", "" }, + { "1,2", "%*[0123456789],%*[0123456789]", 2, "", "" }, + + /* Assign first */ + { "", "%[0123456789]%*c", EOF, "", "" }, + { "X", "%[0123456789]%*c", 0, "", "" }, + { "1", "%[0123456789]%*c", EOF, "1", "" }, + { "1X2", "%[0123456789]%*[0123456789]", 1, "1", "" }, + { "1,2", "%[0123456789],%*[0123456789]", 2, "1", "" }, + + /* Assign second */ + { "", "%*[0123456789]%c", EOF, "", "" }, + { "X", "%*[0123456789]%c", 0, "", "" }, + { "1", "%*[0123456789]%c", EOF, "", "" }, + { "1X2", "%*[0123456789]%[0123456789]", 1, "", "" }, + { "1,2", "%*[0123456789],%[0123456789]", 2, "2", "" }, + + /* Assign both */ + { "", "%[0123456789]%c", EOF, "", "" }, + { "X", "%[0123456789]%c", 0, "", "" }, + { "1", "%[0123456789]%c", EOF, "1", "" }, + { "1X2", "%[0123456789]%[0123456789]", 1, "1", "" }, + { "1,2", "%[0123456789],%[0123456789]", 2, "1", "2" }, + + /* Terminator */ + { NULL, NULL, 0 } +}; + +int +main (void) +{ + int ok = 1; + int ret; + int i; + + for (i = 0; sscanf_testcases[i].input != NULL; i++) + { + sscanf_testcases[i].c[0] + = sscanf_testcases[i].c2[0] + = 0; + ret = sscanf(sscanf_testcases[i].input, + sscanf_testcases[i].fmt, + sscanf_testcases[i].c, + sscanf_testcases[i].c2); + if ( (ret != sscanf_testcases[i].expected) + || (strcmp(sscanf_testcases[i].c, sscanf_testcases[i].expected_c)) + || (strcmp(sscanf_testcases[i].c2, sscanf_testcases[i].expected_c2))) + { + printf("Test %d: FAIL: (\"%s\", \"%s\");\n" + "\texpected %d;\n" + "\texpected c1 '%s';\n" + "\texpected c2 '%s';\n" + "\tgot %d;\n" + "\tc == '%s'\n" + "\tc2 == '%s'\n", + i + 1, + sscanf_testcases[i].input, + sscanf_testcases[i].fmt, + sscanf_testcases[i].expected, + sscanf_testcases[i].expected_c, + sscanf_testcases[i].expected_c2, + ret, + sscanf_testcases[i].c, + sscanf_testcases[i].c2); + ok = 0; + } + } + + puts(ok ? "PASS" : "FAIL"); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +}