summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2002-10-17 12:02:36 +0000
committertjr <tjr@FreeBSD.org>2002-10-17 12:02:36 +0000
commit235c4480d371a766f57bdeb52c90b856089e4e55 (patch)
treec8303e175878476ab2b6862e719019ca15f8beaf /lib/libc
parent4bc30afc1ef6688ba2d68597de8e84a2a9cdfe1e (diff)
downloadFreeBSD-src-235c4480d371a766f57bdeb52c90b856089e4e55.zip
FreeBSD-src-235c4480d371a766f57bdeb52c90b856089e4e55.tar.gz
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.
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdio/vfwscanf.c121
1 files changed, 88 insertions, 33 deletions
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
index 2b26da9..d148aeb 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;
OpenPOWER on IntegriCloud