Mail Archives: djgpp-workers/2003/11/09/17:40:36
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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;
+}
- Raw text -