From 7890be6e7d2658fd14c793c77be4d91a461abce8 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Fri, 15 Jul 2011 17:20:16 +0000 Subject: 2011-07-15 Yufeng Zhang * libc/stdio/vfwprintf.c (wcvt): Add a new parameter len of type int. *length is set to the value of (rev - digits) regardless of whether _MB_CAPABLE is defined or not. Replace BUF with len in calling _mbsnrtowcs_r and also in the loop where _MB_CAPABLE is not defined. (_VFWPRINTF_R): Call wcvt with an extra argument. Call wcvt again with allocated new buffer if buf is not large enough for the conversion. * testsuite/newlib.stdio/stdio.exp: New. * testsuite/newlib.stdio/swprintf.c: Likewise. --- newlib/ChangeLog | 13 +++++++++++ newlib/libc/stdio/vfwprintf.c | 39 ++++++++++++++++++++++++-------- newlib/testsuite/newlib.stdio/stdio.exp | 12 ++++++++++ newlib/testsuite/newlib.stdio/swprintf.c | 30 ++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 newlib/testsuite/newlib.stdio/stdio.exp create mode 100644 newlib/testsuite/newlib.stdio/swprintf.c (limited to 'newlib') diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 6cfa9fb27..383b42aa1 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,16 @@ +2011-07-15 Yufeng Zhang + + * libc/stdio/vfwprintf.c (wcvt): Add a new parameter len of type + int. *length is set to the value of (rev - digits) regardless + of whether _MB_CAPABLE is defined or not. Replace BUF with len + in calling _mbsnrtowcs_r and also in the loop where _MB_CAPABLE + is not defined. + (_VFWPRINTF_R): Call wcvt with an extra argument. Call wcvt + again with allocated new buffer if buf is not large enough for + the conversion. + * testsuite/newlib.stdio/stdio.exp: New. + * testsuite/newlib.stdio/swprintf.c: Likewise. + 2011-07-15 Matt Johnson * libc/stdio/fscanf.c (fscanf): Call _vfscanf_r instead of __svfscanf_r diff --git a/newlib/libc/stdio/vfwprintf.c b/newlib/libc/stdio/vfwprintf.c index 7c58d123c..79020f386 100644 --- a/newlib/libc/stdio/vfwprintf.c +++ b/newlib/libc/stdio/vfwprintf.c @@ -240,7 +240,7 @@ extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *)); # endif /* !_NO_LONGDBL */ static wchar_t *wcvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, wchar_t *, - int *, int, int *, wchar_t *); + int *, int, int *, wchar_t *, int); static int wexponent(wchar_t *, int, int); @@ -996,7 +996,23 @@ reswitch: switch (ch) { flags |= FPT; cp = wcvt (data, _fpvalue, prec, flags, &softsign, - &expt, ch, &ndig, cp); + &expt, ch, &ndig, cp, BUF); + + /* If buf is not large enough for the converted wchar_t + sequence, call wcvt again with a malloced new buffer. + This should happen fairly rarely. + */ + if (cp == buf && ndig > BUF && malloc_buf == NULL) { + if ((malloc_buf = + (wchar_t *)_malloc_r (data, ndig * sizeof (wchar_t))) + == NULL) + { + fp->_flags |= __SERR; + goto error; + } + cp = wcvt (data, _fpvalue, prec, flags, &softsign, + &expt, ch, &ndig, malloc_buf, ndig); + } if (ch == L'g' || ch == L'G') { if (expt <= -4 || expt > prec) @@ -1450,11 +1466,15 @@ error: to whether trailing zeros must be included. Set *SIGN to nonzero if VALUE was negative. Set *DECPT to the exponent plus one. Set *LENGTH to the length of the returned string. CH must be one of - [aAeEfFgG]; if it is [aA], then the return string lives in BUF, - otherwise the return value shares the mprec reentrant storage. */ + [aAeEfFgG]; different from vfprintf.c:cvt(), the return string + lives in BUF regardless of CH. LEN is the length of BUF, except + when CH is [aA], in which case LEN is not in use. If BUF is not + large enough for the converted string, only the first LEN number + of characters will be returned in BUF, but *LENGTH will be set to + the full length of the string before the truncation. */ static wchar_t * wcvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags, - wchar_t *sign, int *decpt, int ch, int *length, wchar_t *buf) + wchar_t *sign, int *decpt, int ch, int *length, wchar_t *buf, int len) { int mode, dsgn; # ifdef _NO_LONGDBL @@ -1548,12 +1568,13 @@ wcvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags, while (rve < bp) *rve++ = '0'; } + + *length = rve - digits; /* full length of the string */ #ifdef _MB_CAPABLE - *length = _mbsnrtowcs_r (data, buf, (const char **) &digits, - rve - digits, BUF, NULL); + _mbsnrtowcs_r (data, buf, (const char **) &digits, *length, + len, NULL); #else - *length = rve - digits; - for (i = 0; i < *length && i < BUF; ++i) + for (i = 0; i < *length && i < len; ++i) buf[i] = (wchar_t) digits[i]; #endif return buf; diff --git a/newlib/testsuite/newlib.stdio/stdio.exp b/newlib/testsuite/newlib.stdio/stdio.exp new file mode 100644 index 000000000..164cbf353 --- /dev/null +++ b/newlib/testsuite/newlib.stdio/stdio.exp @@ -0,0 +1,12 @@ +# Copyright (C) 2011 by ARM Ltd. All rights reserved. +# +# Permission to use, copy, modify, and distribute this software +# is freely granted, provided that this notice is preserved. +# + +load_lib passfail.exp + +set exclude_list { +} + +newlib_pass_fail_all -x $exclude_list diff --git a/newlib/testsuite/newlib.stdio/swprintf.c b/newlib/testsuite/newlib.stdio/swprintf.c new file mode 100644 index 000000000..b925da487 --- /dev/null +++ b/newlib/testsuite/newlib.stdio/swprintf.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 by ARM Ltd. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ + +#include +#include +#include +#include +#include "check.h" + +int main() +{ +#if defined(INTEGER_ONLY) || defined(NO_FLOATING_POINT) + +#else + char cbuf[512]; + wchar_t wcbuf[512], wcbuf2[512]; + double val = 1E+308; + snprintf(cbuf, 512, "%.*f", 3, val); + swprintf(wcbuf, 512, L"%.*f", 3, val); + mbstowcs(wcbuf2, cbuf, 512); + + CHECK (wcscmp(wcbuf, wcbuf2) == 0); +#endif + + exit (0); +} -- cgit v1.2.3