From bd25c6f476ca2c7c05557a3ad64cf09549e47572 Mon Sep 17 00:00:00 2001 From: "Tim J. Robbins" Date: Thu, 17 Oct 2002 12:02:36 +0000 Subject: The field width for single-byte string conversions (%c, %s, %[) is the maximum number of bytes that may be stored in the array, not the maximum number of wide characters to read. The wording of the standard unfortunately does not make this clear. --- lib/libc/stdio/vfwscanf.c | 121 +++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 33 deletions(-) diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c index 2b26da9e50b8..d148aeb4cf9c 100644 --- a/lib/libc/stdio/vfwscanf.c +++ b/lib/libc/stdio/vfwscanf.c @@ -149,6 +149,7 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) char *mbp; /* multibyte string pointer for %c %s %[ */ size_t nconv; /* number of bytes in mb. conversion */ mbstate_t mbs; /* multibyte state */ + char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */ /* `basefix' is used to avoid `if' tests in the integer scanner */ static short basefix[17] = @@ -364,38 +365,56 @@ literal: /* scan arbitrary characters (sets NOSKIP) */ if (width == 0) width = 1; - if (flags & SUPPRESS) { - while (width-- != 0 && - (wi = __fgetwc(fp)) != WEOF) - nread++; - } else if (flags & LONG) { - p = va_arg(ap, wchar_t *); + if (flags & LONG) { + if (!(flags & SUPPRESS)) + p = va_arg(ap, wchar_t *); n = 0; while (width-- != 0 && (wi = __fgetwc(fp)) != WEOF) { - *p++ = (wchar_t)wi; + if (!(flags & SUPPRESS)) + *p++ = (wchar_t)wi; n++; } if (n == 0) goto input_failure; nread += n; - nassigned++; + if (!(flags & SUPPRESS)) + nassigned++; } else { - mbp = va_arg(ap, char *); + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); n = 0; memset(&mbs, 0, sizeof(mbs)); - while (width-- != 0 && + while (width != 0 && (wi = __fgetwc(fp)) != WEOF) { - nconv = wcrtomb(mbp, wi, &mbs); - if (nconv == (size_t)-1) - goto input_failure; - mbp += nconv; + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) { + __ungetwc(wi, fp); + break; + } + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; n++; } if (n == 0) goto input_failure; nread += n; - nassigned++; + if (!(flags & SUPPRESS)) + nassigned++; } nconversions++; break; @@ -405,7 +424,7 @@ literal: if (width == 0) width = (size_t)~0; /* `infinity' */ /* take only those things in the class */ - if (flags & SUPPRESS) { + if ((flags & SUPPRESS) && (flags & LONG)) { n = 0; while ((wi = __fgetwc(fp)) != WEOF && width-- != 0 && INCCL(wi)) @@ -427,21 +446,39 @@ literal: *p = 0; nassigned++; } else { - mbp = va_arg(ap, char *); + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); n = 0; memset(&mbs, 0, sizeof(mbs)); while ((wi = __fgetwc(fp)) != WEOF && - width-- != 0 && INCCL(wi)) { - nconv = wcrtomb(mbp, wi, &mbs); - if (nconv == (size_t)-1) - goto input_failure; - mbp += nconv; + width != 0 && INCCL(wi)) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; n++; } if (wi != WEOF) __ungetwc(wi, fp); - *mbp = 0; - nassigned++; + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } } nread += n; nconversions++; @@ -451,7 +488,7 @@ literal: /* like CCL, but zero-length string OK, & no NOSKIP */ if (width == 0) width = (size_t)~0; - if (flags & SUPPRESS) { + if ((flags & SUPPRESS) && (flags & LONG)) { while ((wi = __fgetwc(fp)) != WEOF && width-- != 0 && !iswspace(wi)) @@ -471,21 +508,39 @@ literal: *p = '\0'; nassigned++; } else { - mbp = va_arg(ap, char *); + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); memset(&mbs, 0, sizeof(mbs)); while ((wi = __fgetwc(fp)) != WEOF && - width-- != 0 && + width != 0 && !iswspace(wi)) { - nconv = wcrtomb(mbp, wi, &mbs); - if (nconv == (size_t)-1) - goto input_failure; - mbp += nconv; + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; nread++; } if (wi != WEOF) __ungetwc(wi, fp); - *mbp = 0; - nassigned++; + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } } nconversions++; continue; -- cgit v1.3