delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/11/09/17:40:36

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" <rich AT phekda DOT freeserve DOT co DOT uk>
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: <E1AIyEJ-0000ka-00@phekda.freeserve.co.uk>
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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019