diff options
Diffstat (limited to 'stdio-common')
-rw-r--r-- | stdio-common/Makefile | 2 | ||||
-rw-r--r-- | stdio-common/bug10.c | 26 | ||||
-rw-r--r-- | stdio-common/bug8.c | 26 | ||||
-rw-r--r-- | stdio-common/bug9.c | 22 | ||||
-rw-r--r-- | stdio-common/tstdiomisc.c | 41 | ||||
-rw-r--r-- | stdio-common/vfscanf.c | 97 |
6 files changed, 156 insertions, 58 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 8ae8b48e1d..a718db6a2c 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -39,7 +39,7 @@ distribute := _itoa.h printf-parse.h tests := tst-printf tstscanf test_rdwr test-popen tstgetln test-fseek \ temptest tst-fileno test-fwrite \ xbug errnobug \ - bug1 bug2 bug3 bug4 bug5 bug6 bug7 \ + bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 \ tfformat tiformat tstdiomisc diff --git a/stdio-common/bug10.c b/stdio-common/bug10.c new file mode 100644 index 0000000000..3e1477dca1 --- /dev/null +++ b/stdio-common/bug10.c @@ -0,0 +1,26 @@ +#include <stdio.h> +int main(int arc, char *argv) +{ + int n, res; + unsigned int val; + char *s; + int result = 0; + + s = "111"; + + n = 0; + res = sscanf(s, "%u %n", &val, &n); + + printf("Result of sscanf = %d\n", res); + printf("Scanned format %%u = %u\n", val); + printf("Possibly scanned format %%n = %d\n", n); + result |= res != 1 || val != 111 || n != 3; + + + result |= sscanf ("", " %n", &n) == EOF; + + puts (result ? "Test failed" : "All tests passed"); + + return result; +} + diff --git a/stdio-common/bug8.c b/stdio-common/bug8.c new file mode 100644 index 0000000000..39a41855de --- /dev/null +++ b/stdio-common/bug8.c @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <string.h> + +main() +{ + char buf[100]; + int point, x, y; + int status = 0; + + sscanf("0x10 10", "%x %x", &x, &y); + sprintf(buf, "%d %d", x, y); + puts (buf); + status |= strcmp (buf, "16 16"); + sscanf("P012349876", "P%1d%4d%4d", &point, &x, &y); + sprintf(buf, "%d %d %d", point, x, y); + status |= strcmp (buf, "0 1234 9876"); + puts (buf); + sscanf("P112349876", "P%1d%4d%4d", &point, &x, &y); + sprintf(buf, "%d %d %d", point, x, y); + status |= strcmp (buf, "1 1234 9876"); + puts (buf); + + puts (status ? "Test failed" : "Test passed"); + + return status; +} diff --git a/stdio-common/bug9.c b/stdio-common/bug9.c new file mode 100644 index 0000000000..5a7166ce90 --- /dev/null +++ b/stdio-common/bug9.c @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <string.h> + +int +main() +{ + char buf[100]; + int a, b; + int status = 0; + + sscanf ("12ab", "%dab%n", &a, &b); + sprintf (buf, "%d, %d", a, b); + puts (buf); + status |= strcmp (buf, "12, 4"); + + sscanf ("12ab100", "%dab%n100", &a, &b); + sprintf (buf, "%d, %d", a, b); + puts (buf); + status |= strcmp (buf, "12, 4"); + + return status; +} diff --git a/stdio-common/tstdiomisc.c b/stdio-common/tstdiomisc.c index 0bd5515934..66e1fe3ec7 100644 --- a/stdio-common/tstdiomisc.c +++ b/stdio-common/tstdiomisc.c @@ -1,40 +1,49 @@ #include <stdio.h> -void +int t1 () { int n = -1; sscanf ("abc ", "abc %n", &n); printf ("t1: count=%d\n", n); + + return n != 5; } -void +int t2 () { + int result = 0; int n; long N; int retval; -#define SCAN(INPUT, FORMAT, VAR) \ +#define SCAN(INPUT, FORMAT, VAR, EXP_RES, EXP_VAL) \ VAR = -1; \ retval = sscanf (INPUT, FORMAT, &VAR); \ printf ("sscanf (\"%s\", \"%s\", &x) => %d, x = %ld\n", \ - INPUT, FORMAT, retval, VAR); - - SCAN ("12345", "%ld", N); - SCAN ("12345", "%llllld", N); - SCAN ("12345", "%LLLLLd", N); - SCAN ("test ", "%*s%n", n); - SCAN ("test ", "%2*s%n", n); - SCAN ("12 ", "%l2d", n); - SCAN ("12 ", "%2ld", N); + INPUT, FORMAT, retval, VAR); \ + result |= retval != EXP_RES || VAR != EXP_VAL + + SCAN ("12345", "%ld", N, 1, 12345); + SCAN ("12345", "%llllld", N, 0, -1); + SCAN ("12345", "%LLLLLd", N, 0, -1); + SCAN ("test ", "%*s%n", n, 0, 4); + SCAN ("test ", "%2*s%n", n, 0, -1); + SCAN ("12 ", "%l2d", n, 0, -1); + SCAN ("12 ", "%2ld", N, 1, 12); + + return result; } int main () { - t1 (); - t2 (); + int result = 0; + + result |= t1 (); + result |= t2 (); + + result |= fflush (stdout) == EOF; - fflush (stdout); - return 0; + return result; } diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 76c9936abe..df68260cdd 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -34,10 +34,6 @@ Cambridge, MA 02139, USA. */ #define LONGLONG long #endif -#ifdef USE_IN_LIBIO -# include <libioP.h> -# include <libio.h> - /* Those are flags in the conversion format. */ # define LONG 0x01 /* l: long or double */ # define LONGDBL 0x02 /* L: long long or long double */ @@ -48,11 +44,15 @@ Cambridge, MA 02139, USA. */ # define WIDTH 0x40 /* width */ +#ifdef USE_IN_LIBIO +# include <libioP.h> +# include <libio.h> + # define va_list _IO_va_list # define ungetc(c, s) _IO_ungetc (c, s) -# define inchar() ((c = _IO_getc(s)), ++read_in, c) +# define inchar() ((c = _IO_getc (s)), ++read_in, c) # define conv_error() return ((errp != NULL && (*errp |= 2)), \ - (c == EOF || _IO_ungetc(c, s)), done) + (c == EOF || _IO_ungetc (c, s)), done) # define input_error() return ((errp != NULL && (*errp |= 1)), \ done == 0 ? EOF : done) @@ -69,8 +69,8 @@ Cambridge, MA 02139, USA. */ } \ } while (0) #else -# define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c)) -# define conv_error() return (ungetc(c, s), done) +# define inchar() ((c = getc (s)), ++read_in, c) +# define conv_error() return (ungetc (c, s), done) # define input_error() return (done == 0 ? EOF : done) # define memory_error() return ((errno = ENOMEM), EOF) # define ARGCHECK(s, format) \ @@ -111,9 +111,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) register int do_assign; /* Whether to do an assignment. */ register int width; /* Maximum field width. */ int group_flag; /* %' modifier flag. */ -#ifdef USE_IN_LIBIO int flags; /* Trace flags for current format element. */ -#endif /* Type modifiers. */ int is_short, is_long, is_long_double; @@ -145,11 +143,15 @@ __vfscanf (FILE *s, const char *format, va_list argptr) /* Character-buffer pointer. */ register char *str, **strptr; size_t strsize; + /* We must not react on white spaces immediately because they can + possibly be matched even if in the input stream no character is + available anymore. */ + int skip_space = 0; /* Workspace. */ char *tw; /* Temporary pointer. */ char *wp = NULL; /* Workspace. */ - size_t wpsize = 0; /* Currently used bytes in workspace. */ size_t wpmax = 0; /* Maximal size of workspace. */ + size_t wpsize; /* Currently used bytes in workspace. */ #define ADDW(Ch) \ do \ { \ @@ -158,7 +160,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) char *old = wp; \ wpmax = 200 > 2 * wpmax ? 200 : 2 * wpmax; \ wp = (char *) alloca (wpmax); \ - if (wpsize > 0) \ + if (old != NULL) \ memcpy (wp, old, wpsize); \ } \ wp[wpsize++] = (Ch); \ @@ -220,27 +222,37 @@ __vfscanf (FILE *s, const char *format, va_list argptr) fc = *f++; if (fc != '%') { + /* Remember to skip spaces. */ + if (isspace (fc)) + { + skip_space = 1; + continue; + } + /* Characters other than format specs must just match. */ if (c == EOF) input_error (); - if (isspace (fc)) + + /* We saw an white space as the last character in the format + string. Now it's time to skip all leading white + spaces. */ + if (skip_space) { - /* Whitespace characters match any amount of whitespace. */ while (isspace (c)) - inchar (); - continue; + (void) inchar (); + skip_space = 0; } + else if (c == fc) (void) inchar (); else conv_error (); + continue; } -#ifdef USE_IN_LIBIO - /* That is the start of the coversion string. */ + /* This is the start of the conversion string. */ flags = 0; -#endif /* Initialize state of modifiers. */ argpos = 0; @@ -248,6 +260,9 @@ __vfscanf (FILE *s, const char *format, va_list argptr) group_flag = 0; is_short = is_long = is_long_double = malloc_string = 0; + /* Prepare temporary buffer. */ + wpsize = 0; + /* Check for a positional parameter specification. */ if (isdigit (*f)) { @@ -270,9 +285,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) switch (*f++) { case '*': -#ifdef USE_IN_LIBIO flags = SUPPRESS; -#endif do_assign = 0; break; case '\'': @@ -280,11 +293,9 @@ __vfscanf (FILE *s, const char *format, va_list argptr) break; } -#ifdef USE_IN_LIBIO /* We have seen width. */ if (isdigit (*f)) flags |= WIDTH; -#endif /* Find the maximum field width. */ width = 0; @@ -303,44 +314,36 @@ __vfscanf (FILE *s, const char *format, va_list argptr) { case 'h': /* int's are short int's. */ -#ifdef USE_IN_LIBIO if (flags & ~(SUPPRESS | WIDTH)) /* Signal illegal format element. */ conv_error (); flags |= SHORT; -#endif is_short = 1; break; case 'l': if (is_long) { /* A double `l' is equivalent to an `L'. */ -#ifdef USE_IN_LIBIO - if ((flags & ~(SUPPRESS | WIDTH)) && (flags & LONGDBL)) + if ((flags & ~(SUPPRESS | WIDTH))) conv_error (); flags &= ~LONG; flags |= LONGDBL; -#endif is_longlong = 1; } else { /* int's are long int's. */ -#ifdef USE_IN_LIBIO flags |= LONG; -#endif is_long = 1; } break; case 'q': case 'L': /* double's are long double's, and int's are long long int's. */ -#ifdef USE_IN_LIBIO if (flags & ~(SUPPRESS | WIDTH)) /* Signal illegal format element. */ conv_error (); flags |= LONGDBL; -#endif is_long_double = 1; break; case 'a': @@ -356,15 +359,20 @@ __vfscanf (FILE *s, const char *format, va_list argptr) /* Find the conversion specifier. */ fc = *f++; - if (fc != '[' && fc != 'c' && fc != 'n') - /* Eat whitespace. */ - while (isspace (c)) - (void) inchar (); + if (skip_space || (fc != '[' && fc != 'c' && fc != 'n')) + { + /* Eat whitespace. */ + while (isspace (c)) + (void) inchar (); + skip_space = 0; + } + switch (fc) { case '%': /* Must match a literal '%'. */ if (c != fc) conv_error (); + inchar (); break; case 'n': /* Answer number of assignments done. */ @@ -444,7 +452,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) { \ /* We lose. Oh well. \ Terminate the string and stop converting, \ - so at least we don't swallow any input. */ \ + so at least we don't skip any input. */ \ (*strptr)[strsize] = '\0'; \ ++done; \ conv_error (); \ @@ -513,7 +521,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) } /* Look for a leading indication of base. */ - if (c == '0') + if (width != 0 && c == '0') { if (width > 0) --width; @@ -521,7 +529,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) (void) inchar (); - if (tolower (c) == 'x') + if (width != 0 && tolower (c) == 'x') { if (base == 0) base = 16; @@ -540,7 +548,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) base = 10; /* Read the number into workspace. */ - do + while (c != EOF && width != 0) { if (base == 16 ? !isxdigit (c) : (!isdigit (c) || c - '0' >= base)) @@ -548,8 +556,9 @@ __vfscanf (FILE *s, const char *format, va_list argptr) ADDW (c); if (width > 0) --width; + + (void) inchar (); } - while (inchar () != EOF && width != 0); if (wpsize == 0 || (wpsize == 1 && (wp[0] == '+' || wp[0] == '-'))) @@ -739,6 +748,12 @@ __vfscanf (FILE *s, const char *format, va_list argptr) } } + /* The last thing we saw int the format string was a white space. + Consume the last white spaces. */ + if (skip_space) + while (isspace (c)) + (void) inchar (); + return ((c == EOF || ungetc (c, s)), done); } |