* libc/stdio/swprintf.c (_swprintf_r, swprintf):

correct how terminating L'\0' is added;
	change return to match standard for when output does not fit;
	some corrections and enhancements to the docs.
	* libc/stdio/vswprintf.c (_vswprintf_r):  ditto, except for docs.
	* libc/stdio/vfwprintf.c:  some corrections to the docs and some
	enhancements to comments.  (No code changes.)
	* libc/time/strftime.c:  Correct some problems that made wcsftime()
	not work correctly:  work properly with swprintf returns that are
	different from snprintf returns, correct test vector lengths for
	when sizeof(wchar_t) > 1.
	* libc/stdio/sprintf.c:  Some documentation and comment corrections and
	enhancements to match those done to swprintf.c.
This commit is contained in:
Corinna Vinschen 2009-03-12 10:27:10 +00:00
parent cab0758eb2
commit 4a825d4145
6 changed files with 210 additions and 140 deletions

View File

@ -1,3 +1,19 @@
2009-03-09 Craig Howland <howland@LGSInnovations.com>
* libc/stdio/swprintf.c (_swprintf_r, swprintf):
correct how terminating L'\0' is added;
change return to match standard for when output does not fit;
some corrections and enhancements to the docs.
* libc/stdio/vswprintf.c (_vswprintf_r): ditto, except for docs.
* libc/stdio/vfwprintf.c: some corrections to the docs and some
enhancements to comments. (No code changes.)
* libc/time/strftime.c: Correct some problems that made wcsftime()
not work correctly: work properly with swprintf returns that are
different from snprintf returns, correct test vector lengths for
when sizeof(wchar_t) > 1.
* libc/stdio/sprintf.c: Some documentation and comment corrections and
enhancements to match those done to swprintf.c.
2009-03-11 Corinna Vinschen <corinna@vinschen.de>
* libc/include/wchar.h (wcscasecmp, wcsncasecmp): Declare.

View File

@ -134,6 +134,8 @@ DESCRIPTION
arguments must be requested somewhere within <[format]>. If
positional parameters are used, then all conversion
specifications except for <<%%>> must specify a position.
This positional parameters method is a POSIX extension to the C
standard definition for the functions.
o <[flags]>
@ -147,12 +149,13 @@ DESCRIPTION
o+
o '
Since newlib only supports the C locale, this
flag has no effect in this implementation.
But in other locales, when <[type]> is <<i>>,
<<d>>, <<u>>, <<f>>, <<F>>, <<g>>, or <<G>>,
the locale-dependent thousand's separator is
inserted prior to zero padding.
A POSIX extension to the C standard. However, this
implementation presently treats it as a no-op, which
is the default behavior for the C locale, anyway. (If
it did what it is supposed to, when <[type]> were <<i>>,
<<d>>, <<u>>, <<f>>, <<F>>, <<g>>, or <<G>>, the
integer portion of the conversion would be formatted
with thousands' grouping wide characters.)
o -
The result of the conversion is left
@ -180,7 +183,7 @@ DESCRIPTION
o 0
If the <[type]> character is <<d>>, <<i>>,
<<o>>, <<u>>, <<x>>, <<X>>, <<a>>, <<A>>,
<<e>>, <<E>>, <<f>>, <<g>>, or <<G>>: leading
<<e>>, <<E>>, <<f>>, <<F>>, <<g>>, or <<G>>: leading
zeros are used to pad the field width
(following any indication of sign or base); no
spaces are used for padding. If the zero
@ -353,11 +356,10 @@ DESCRIPTION
o z
With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
<<X>>, specifies that the argument is a
<<ssize_t>> or <<size_t>>.
<<X>>, specifies that the argument is a <<size_t>>.
With <<n>>, specifies that the argument is a
pointer to a <<ssize_t>>.
pointer to a <<size_t>>.
o t
With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
@ -389,7 +391,7 @@ DESCRIPTION
character is printed.
o C
Short for <<%lc>>.
Short for <<%lc>>. A POSIX extension to the C standard.
o s
Prints the elements of a pointer to <<char>>
@ -400,13 +402,13 @@ DESCRIPTION
multibyte characters before printing.
o S
Short for <<%ls>>.
Short for <<%ls>>. A POSIX extension to the C standard.
o d or i
Prints a signed decimal integer; takes an
<<int>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o D
Newlib extension, short for <<%ld>>.
@ -414,8 +416,8 @@ DESCRIPTION
o o
Prints an unsigned octal integer; takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o O
Newlib extension, short for <<%lo>>.
@ -423,8 +425,8 @@ DESCRIPTION
o u
Prints an unsigned decimal integer; takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o U
Newlib extension, short for <<%lu>>.
@ -433,8 +435,8 @@ DESCRIPTION
Prints an unsigned hexadecimal integer (using
<<abcdef>> as digits beyond <<9>>); takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o X
Like <<x>>, but uses <<ABCDEF>> as digits
@ -540,6 +542,9 @@ If an error occurs, the result of <<printf>>, <<fprintf>>,
to ENOMEM if allocation fails, and for <<snprintf>>, <<errno>> may be
set to EOVERFLOW if <[size]> or the output length exceeds INT_MAX.
BUGS
The ``''' (quote) flag does not work when locale's thousands_sep is not empty.
PORTABILITY
ANSI C requires <<printf>>, <<fprintf>>, <<sprintf>>, and
<<snprintf>>. <<asprintf>> and <<asnprintf>> are newlib extensions.
@ -595,7 +600,7 @@ _sprintf_r(ptr, str, fmt, va_alist)
#endif
ret = _svfprintf_r (ptr, &f, fmt, ap);
va_end (ap);
*f._p = 0;
*f._p = '\0'; /* terminate the string */
return (ret);
}
@ -628,7 +633,7 @@ sprintf(str, fmt, va_alist)
#endif
ret = _svfprintf_r (_REENT, &f, fmt, ap);
va_end (ap);
*f._p = 0;
*f._p = '\0'; /* terminate the string */
return (ret);
}

View File

@ -33,25 +33,27 @@ INDEX
_swprintf_r
ANSI_SYNOPSIS
#include <stdio.h>
#include <wchar.h>
int wprintf(const wchar_t *<[format]>, ...);
int fwprintf(FILE *<[fd]>, const wchar_t *<[format]>, ...);
int swprintf(wchar_t *<[str]>, const wchar_t *<[format]>, ...);
int swprintf(wchar_t *<[str]>, size_t <[size]>,
const wchar_t *<[format]>, ...);
int _wprintf_r(struct _reent *<[ptr]>, const wchar_t *<[format]>, ...);
int _fwprintf_r(struct _reent *<[ptr]>, FILE *<[fd]>,
const wchar_t *<[format]>, ...);
int _swprintf_r(struct _reent *<[ptr]>, wchar_t *<[str]>,
const wchar_t *<[format]>, ...);
size_t <[size]>, const wchar_t *<[format]>, ...);
DESCRIPTION
<<wprintf>> accepts a series of arguments, applies to each a
format specifier from <<*<[format]>>>, and writes the
formatted data to <<stdout>>, without a terminating NUL
wide character. The behavior of <<wprintf>> is undefined if there
are not enough arguments for the format. <<wprintf>> returns
when it reaches the end of the format string. If there are
are not enough arguments for the format or if any argument is not the
right type for the corresponding conversion specifier. <<wprintf>>
returns when it reaches the end of the format string. If there are
more arguments than the format requires, excess arguments are
ignored.
@ -59,10 +61,14 @@ DESCRIPTION
to the stream <[fd]> rather than <<stdout>>.
<<swprintf>> is like <<wprintf>>, except that output is directed
to the buffer <[str]>, and the resulting string length is limited
to at most <[size]> wide characters, including the terminating
<<NUL>>. As a special case, if <[size]> is 0, <[str]> can be NULL,
and <<swprintf>> merely calculates how many bytes would be printed.
to the buffer <[str]> with a terminating wide <<NUL>>, and the
resulting string length is limited to at most <[size]> wide characters,
including the terminating <<NUL>>. It is considered an error if the
output (including the terminating wide-<<NULL>>) does not fit into
<[size]> wide characters. (This error behavior is not the same as for
<<snprintf>>, which <<swprintf>> is otherwise completely analogous to.
While <<snprintf>> allows the needed size to be known simply by giving
<[size]>=0, <<swprintf>> does not, giving an error instead.)
For <<swprintf>> the behavior is undefined if the output
<<*<[str]>>> overlaps with one of the arguments. Behavior is also
@ -95,6 +101,8 @@ DESCRIPTION
arguments must be requested somewhere within <[format]>. If
positional parameters are used, then all conversion
specifications except for <<%%>> must specify a position.
This positional parameters method is a POSIX extension to the C
standard definition for the functions.
o <[flags]>
@ -108,12 +116,13 @@ DESCRIPTION
o+
o '
Since newlib only supports the C locale, this
flag has no effect in this implementation.
But in other locales, when <[type]> is <<i>>,
<<d>>, <<u>>, <<f>>, <<F>>, <<g>>, or <<G>>,
the locale-dependent thousand's separator is
inserted prior to zero padding.
A POSIX extension to the C standard. However, this
implementation presently treats it as a no-op, which
is the default behavior for the C locale, anyway. (If
it did what it is supposed to, when <[type]> were <<i>>,
<<d>>, <<u>>, <<f>>, <<F>>, <<g>>, or <<G>>, the
integer portion of the conversion would be formatted
with thousands' grouping wide characters.)
o -
The result of the conversion is left
@ -141,7 +150,7 @@ DESCRIPTION
o 0
If the <[type]> character is <<d>>, <<i>>,
<<o>>, <<u>>, <<x>>, <<X>>, <<a>>, <<A>>,
<<e>>, <<E>>, <<f>>, <<g>>, or <<G>>: leading
<<e>>, <<E>>, <<f>>, <<F>>, <<g>>, or <<G>>: leading
zeros are used to pad the field width
(following any indication of sign or base); no
spaces are used for padding. If the zero
@ -314,11 +323,10 @@ DESCRIPTION
o z
With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
<<X>>, specifies that the argument is a
<<ssize_t>> or <<size_t>>.
<<X>>, specifies that the argument is a <<size_t>>.
With <<n>>, specifies that the argument is a
pointer to a <<ssize_t>>.
pointer to a <<size_t>>.
o t
With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
@ -352,7 +360,7 @@ DESCRIPTION
shall be converted to wchar_t, and written.
o C
Short for <<%lc>>.
Short for <<%lc>>. A POSIX extension to the C standard.
o s
If no <<l>> qualifier is present, the application
@ -383,32 +391,32 @@ DESCRIPTION
written.
o S
Short for <<%ls>>.
Short for <<%ls>>. A POSIX extension to the C standard.
o d or i
Prints a signed decimal integer; takes an
<<int>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o o
Prints an unsigned octal integer; takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o u
Prints an unsigned decimal integer; takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o x
Prints an unsigned hexadecimal integer (using
<<abcdef>> as digits beyond <<9>>); takes an
<<unsigned>>. Leading zeros are inserted as
necessary to reach the precision. A precision
of 0 produces an empty string.
necessary to reach the precision. A value of 0 with
a precision of 0 produces an empty string.
o X
Like <<x>>, but uses <<ABCDEF>> as digits
@ -503,12 +511,16 @@ the output string, except the concluding <<NUL>> is not counted.
If an error occurs, the result of <<wprintf>>, <<fwprintf>>, and
<<swprintf>> is a negative value. For <<wprintf>> and <<fwprintf>>,
<<errno>> may be set according to <<fputwc>>. For <<snwprintf>>, <<errno>>
may be set to EOVERFLOW if <[size]> or the output length exceeds
INT_MAX / sizeof (wchar_t).
<<errno>> may be set according to <<fputwc>>. For <<swprintf>>, <<errno>>
may be set to EOVERFLOW if <[size]> is greater than INT_MAX / sizeof (wchar_t),
or when the output does not fit into <[size]> wide characters (including the
terminating wide <<NULL>>).
BUGS
The ``''' (quote) flag does not work when locale's thousands_sep is not empty.
PORTABILITY
POSIX-1.2008
POSIX-1.2008 with extensions; C99 (compliant except for POSIX extensions).
Depending on how newlib was configured, not all format specifiers are
supported.
@ -527,6 +539,10 @@ Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
#include <errno.h>
#include "local.h"
/* NOTE: _swprintf_r() should be identical to swprintf() except for the
* former having ptr as a parameter and the latter needing to declare it as
* a variable set to _REENT. */
int
_DEFUN(_swprintf_r, (ptr, str, size, fmt),
struct _reent *ptr _AND
@ -540,7 +556,7 @@ _DEFUN(_swprintf_r, (ptr, str, size, fmt),
if (size > INT_MAX / sizeof (wchar_t))
{
ptr->_errno = EOVERFLOW;
ptr->_errno = EOVERFLOW; /* POSIX extension */
return EOF;
}
f._flags = __SWR | __SSTR;
@ -550,10 +566,19 @@ _DEFUN(_swprintf_r, (ptr, str, size, fmt),
va_start (ap, fmt);
ret = _svfwprintf_r (ptr, &f, fmt, ap);
va_end (ap);
if (ret < EOF)
ptr->_errno = EOVERFLOW;
if (size > 0)
*f._p = 0;
/* _svfwprintf_r() does not put in a terminating NUL, so add one if
* appropriate, which is whenever size is > 0. _svfwprintf_r() stops
* after n-1, so always just put at the end. */
if (size > 0) {
*(wchar_t *)f._p = L'\0'; /* terminate the string */
}
if(ret >= size) {
/* _svfwprintf_r() returns how many wide characters it would have printed
* if there were enough space. Return an error if too big to fit in str,
* unlike snprintf, which returns the size needed. */
ptr->_errno = EOVERFLOW; /* POSIX extension */
ret = -1;
}
return (ret);
}
@ -572,7 +597,7 @@ _DEFUN(swprintf, (str, size, fmt),
if (size > INT_MAX / sizeof (wchar_t))
{
ptr->_errno = EOVERFLOW;
ptr->_errno = EOVERFLOW; /* POSIX extension */
return EOF;
}
f._flags = __SWR | __SSTR;
@ -582,10 +607,19 @@ _DEFUN(swprintf, (str, size, fmt),
va_start (ap, fmt);
ret = _svfwprintf_r (ptr, &f, fmt, ap);
va_end (ap);
if (ret < EOF)
ptr->_errno = EOVERFLOW;
if (size > 0)
*f._p = 0;
/* _svfwprintf_r() does not put in a terminating NUL, so add one if
* appropriate, which is whenever size is > 0. _svfwprintf_r() stops
* after n-1, so always just put at the end. */
if (size > 0) {
*(wchar_t *)f._p = L'\0'; /* terminate the string */
}
if(ret >= size) {
/* _svfwprintf_r() returns how many wide characters it would have printed
* if there were enough space. Return an error if too big to fit in str,
* unlike snprintf, which returns the size needed. */
ptr->_errno = EOVERFLOW; /* POSIX extension */
ret = -1;
}
return (ret);
}

View File

@ -50,9 +50,10 @@ INDEX
ANSI_SYNOPSIS
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
int vwprintf(const wchar_t *<[fmt]>, va_list <[list]>);
int vfwprintf(FILE *<[fp]>, const wchar_t *<[fmt]>, va_list <[list]>);
int vswprintf(wchar_t *<[str]>, const wchar_t *<[fmt]>,
int vswprintf(wchar_t *<[str]>, size_t <[size]>, const wchar_t *<[fmt]>,
va_list <[list]>);
int _vwprintf_r(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
@ -60,7 +61,7 @@ ANSI_SYNOPSIS
int _vfwprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
const wchar_t *<[fmt]>, va_list <[list]>);
int _vswprintf_r(struct _reent *<[reent]>, wchar_t *<[str]>,
const wchar_t *<[fmt]>, va_list <[list]>);
size_t <[size]>, const wchar_t *<[fmt]>, va_list <[list]>);
DESCRIPTION
<<vwprintf>>, <<vfwprintf>> and <<vswprintf>> are (respectively) variants
@ -76,10 +77,13 @@ RETURNS
The return values are consistent with the corresponding functions.
PORTABILITY
POSIX-1.2008
POSIX-1.2008 with extensions; C99 (compliant except for POSIX extensions).
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
SEEALSO
<<wprintf>>, <<fwprintf>> and <<swprintf>>.
*/
/*
@ -244,7 +248,7 @@ static int wexponent(wchar_t *, int, int);
mantissa, this would be 29 characters). %e, %f, and %g use
reentrant storage shared with mprec. All other formats that use
buf get by with fewer characters. Making BUF slightly bigger
reduces the need for malloc in %.*a and %S, when large precision or
reduces the need for malloc in %.*a and %ls/%S, when large precision or
long strings are processed. */
#define BUF 40
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF
@ -396,7 +400,7 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
#define NIOV 8
struct __suio uio; /* output information: summary */
struct __siov iov[NIOV];/* ... and individual io vectors */
wchar_t buf[BUF]; /* space for %c, %S, %[diouxX], %[aA] */
wchar_t buf[BUF]; /* space for %c, %ls/%S, %[diouxX], %[aA] */
wchar_t ox[2]; /* space for 0x hex-prefix */
wchar_t *malloc_buf = NULL;/* handy pointer for malloced buffers */
@ -576,10 +580,7 @@ reswitch: switch (ch) {
#ifdef _WANT_IO_C99_FORMATS
case L'\'':
/* The ' flag is required by POSIX, but not C99.
In the C locale, LC_NUMERIC requires
thousands_sep to be the empty string. And since
no other locales are supported (yet), this flag
is currently a no-op. */
FIXME: this flag is currently a no-op. */
goto rflag;
#endif
case L' ':
@ -742,7 +743,7 @@ reswitch: switch (ch) {
#endif
flags |= LONGINT;
goto rflag;
case L'q': /* extension */
case L'q': /* GNU extension */
flags |= QUADINT;
goto rflag;
#ifdef _WANT_IO_C99_FORMATS
@ -783,7 +784,7 @@ reswitch: switch (ch) {
have ptrdiff_t as wide as long long. */
flags |= QUADINT;
goto rflag;
case L'C':
case L'C': /* POSIX extension */
#endif /* _WANT_IO_C99_FORMATS */
case L'c':
cp = buf;
@ -1001,7 +1002,7 @@ reswitch: switch (ch) {
goto nosign;
case L's':
#ifdef _WANT_IO_C99_FORMATS
case L'S':
case L'S': /* POSIX extension */
#endif
sign = '\0';
cp = GET_ARG (N, ap, wchar_ptr_t);
@ -1640,7 +1641,7 @@ _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
break;
case L's':
# ifdef _WANT_IO_C99_FORMATS
case L'S':
case L'S': /* POSIX extension */
# endif
case L'p':
case L'n':
@ -1655,7 +1656,7 @@ _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
spec_type = INT;
break;
# ifdef _WANT_IO_C99_FORMATS
case L'C':
case L'C': /* POSIX extension */
spec_type = WIDE_CHAR;
break;
# endif

View File

@ -27,6 +27,7 @@ static char sccsid[] = "%W% (Berkeley) %G%";
#include <limits.h>
#include <stdarg.h>
#include <errno.h>
#include "local.h"
int
@ -42,7 +43,7 @@ _DEFUN(_vswprintf_r, (ptr, str, size, fmt, ap),
if (size > INT_MAX / sizeof (wchar_t))
{
ptr->_errno = EOVERFLOW;
ptr->_errno = EOVERFLOW; /* POSIX extension */
return EOF;
}
f._flags = __SWR | __SSTR;
@ -50,10 +51,19 @@ _DEFUN(_vswprintf_r, (ptr, str, size, fmt, ap),
f._bf._size = f._w = (size > 0 ? (size - 1) * sizeof (wchar_t) : 0);
f._file = -1; /* No file. */
ret = _svfwprintf_r (ptr, &f, fmt, ap);
if (ret < EOF)
ptr->_errno = EOVERFLOW;
if (size > 0)
*f._p = 0;
/* _svfwprintf_r() does not put in a terminating NUL, so add one if
* appropriate, which is whenever size is > 0. _svfwprintf_r() stops
* after n-1, so always just put at the end. */
if (size > 0) {
*(wchar_t *)f._p = L'\0'; /* terminate the string */
}
if(ret >= size) {
/* _svfwprintf_r() returns how many wide characters it would have printed
* if there were enough space. Return an error if too big to fit in str,
* unlike snprintf, which returns the size needed. */
ptr->_errno = EOVERFLOW; /* POSIX extension */
ret = -1;
}
return ret;
}

View File

@ -251,6 +251,10 @@ This implementation does not support <<s>> being NULL, nor overlapping
<<s>> and <<format>>.
<<strftime>> requires no supporting OS subroutines.
BUGS
<<strftime>> ignores the LC_TIME category of the current locale, hard-coding
the "C" locale settings.
*/
#include <stddef.h>
@ -356,7 +360,7 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
_CONST struct tm *tim_p)
{
size_t count = 0;
int i;
int i, len;
for (;;)
{
@ -455,28 +459,27 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
int century = tim_p->tm_year >= 0
? tim_p->tm_year / 100 + YEAR_BASE / 100
: abs (tim_p->tm_year + YEAR_BASE) / 100;
count += snprintf (&s[count], maxsize - count, CQ("%s%.*d"),
len = snprintf (&s[count], maxsize - count, CQ("%s%.*d"),
neg ? CQ("-") : CQ(""), 2 - neg, century);
if (count >= maxsize)
return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('d'):
case CQ('e'):
count += snprintf (&s[count], maxsize - count,
len = snprintf (&s[count], maxsize - count,
*format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
tim_p->tm_mday);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('D'):
case CQ('x'):
/* %m/%d/%y */
count += snprintf (&s[count], maxsize - count,
len = snprintf (&s[count], maxsize - count,
CQ("%.2d/%.2d/%.2d"),
tim_p->tm_mon + 1, tim_p->tm_mday,
tim_p->tm_year >= 0 ? tim_p->tm_year % 100
: abs (tim_p->tm_year + YEAR_BASE) % 100);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('F'):
{ /* %F is equivalent to "%Y-%m-%d" */
@ -500,9 +503,9 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
adjust = 1;
else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
adjust = -1;
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
((year + adjust) % 100 + 100) % 100);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('G'):
@ -532,18 +535,18 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
year = 0;
++century;
}
count += snprintf (&s[count], maxsize - count, CQ("%s%.*d%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%s%.*d%.2d"),
neg ? CQ("-") : CQ(""), 2 - neg, century, year);
if (count >= maxsize)
if (len < 0 || (count+=len) >= maxsize)
return 0;
}
break;
case CQ('H'):
case CQ('k'): /* newlib extension */
count += snprintf (&s[count], maxsize - count,
len = snprintf (&s[count], maxsize - count,
*format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
tim_p->tm_hour);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('I'):
case CQ('l'): /* newlib extension */
@ -551,26 +554,26 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
register int h12;
h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12) ?
12 : tim_p->tm_hour % 12;
count += snprintf (&s[count], maxsize - count,
len = snprintf (&s[count], maxsize - count,
*format == CQ('I') ? CQ("%.2d") : CQ("%2d"),
h12);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('j'):
count += snprintf (&s[count], maxsize - count, CQ("%.3d"),
len = snprintf (&s[count], maxsize - count, CQ("%.3d"),
tim_p->tm_yday + 1);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('m'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
tim_p->tm_mon + 1);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('M'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
tim_p->tm_min);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('n'):
if (count < maxsize - 1)
@ -598,24 +601,24 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
register int h12;
h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12) ?
12 : tim_p->tm_hour % 12;
count += snprintf (&s[count], maxsize - count,
len = snprintf (&s[count], maxsize - count,
CQ("%.2d:%.2d:%.2d %cM"),
h12,
tim_p->tm_min,
tim_p->tm_sec,
(tim_p->tm_hour < 12) ? CQ('A') : CQ('P'));
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('R'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
tim_p->tm_hour, tim_p->tm_min);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('S'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
tim_p->tm_sec);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('t'):
if (count < maxsize - 1)
@ -625,9 +628,9 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
break;
case CQ('T'):
case CQ('X'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('u'):
if (count < maxsize - 1)
@ -641,10 +644,10 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
return 0;
break;
case CQ('U'):
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
(tim_p->tm_yday + 7 -
tim_p->tm_wday) / 7);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('V'):
{
@ -662,8 +665,8 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
+ (YEAR_BASE - 1
- (tim_p->tm_year < 0
? 0 : 2000)))));
count += snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
if (count >= maxsize) return 0;
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('w'):
@ -675,9 +678,9 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
case CQ('W'):
{
int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
count += snprintf (&s[count], maxsize - count, CQ("%.2d"),
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
(tim_p->tm_yday + 7 - wday) / 7);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('y'):
@ -686,8 +689,8 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
the asymmetric range of years. */
int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
: abs (tim_p->tm_year + YEAR_BASE) % 100;
count += snprintf (&s[count], maxsize - count, CQ("%.2d"), year);
if (count >= maxsize) return 0;
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), year);
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('Y'):
@ -695,17 +698,17 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
* gives at least 4 digits, with leading zeros as needed. */
if(tim_p->tm_year <= INT_MAX-YEAR_BASE) {
/* For normal, non-overflow case. */
count += snprintf (&s[count], maxsize - count, CQ("%04d"),
len = snprintf (&s[count], maxsize - count, CQ("%04d"),
tim_p->tm_year + YEAR_BASE);
}
else {
/* int would overflow, so use unsigned instead. */
register unsigned year;
year = (unsigned) tim_p->tm_year + (unsigned) YEAR_BASE;
count += snprintf (&s[count], maxsize - count, CQ("%04u"),
len = snprintf (&s[count], maxsize - count, CQ("%04u"),
tim_p->tm_year + YEAR_BASE);
}
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
break;
case CQ('z'):
if (tim_p->tm_isdst >= 0)
@ -718,10 +721,10 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
but have to use __tzrule for daylight savings. */
offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
TZ_UNLOCK;
count += snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
len = snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
offset / SECSPERHOUR,
labs (offset / SECSPERMIN) % 60L);
if (count >= maxsize) return 0;
if (len < 0 || (count+=len) >= maxsize) return 0;
}
break;
case CQ('Z'):
@ -803,7 +806,7 @@ const struct test Vec0[] = {
/* Testing fields one at a time, expecting to pass, using exact
* allowed length as what is needed. */
/* Using tm0 for time: */
#define EXP(s) sizeof(s)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%a"), 3+1, EXP(CQ("Tue")) },
{ CQ("%A"), 7+1, EXP(CQ("Tuesday")) },
{ CQ("%b"), 3+1, EXP(CQ("Dec")) },
@ -862,8 +865,8 @@ const struct tm tm1 = {
const struct test Vec1[] = {
/* Testing fields one at a time, expecting to pass, using exact
* allowed length as what is needed. */
/* Using tm0 for time: */
#define EXP(s) sizeof(s)-1, s
/* Using tm1 for time: */
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%a"), 3+1, EXP(CQ("Wed")) },
{ CQ("%A"), 9+1, EXP(CQ("Wednesday")) },
{ CQ("%b"), 3+1, EXP(CQ("Jul")) },
@ -904,10 +907,11 @@ const struct test Vec1[] = {
{ CQ("%Z"), 3+1, EXP(CQ("EDT")) },
{ CQ("%%"), 1+1, EXP(CQ("%")) },
#undef EXP
#define VEC(s) s, sizeof(s), sizeof(s)-1, s
#define EXP(s) sizeof(s), sizeof(s)-1, s
#define VEC(s) s, sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
{ VEC(CQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) },
{ CQ("0123456789%%%h:`~"), EXP(CQ("0123456789%Jul:`~")) },
{ CQ("%R%h:`~ %x %w"), EXP(CQ("23:01Jul:`~ 07/02/08 3")) },
#undef VEC
#undef EXP
};
@ -949,7 +953,7 @@ const struct test Vecyr0[] = {
/* Testing fields one at a time, expecting to pass, using a larger
* allowed length than what is needed. */
/* Using tmyr0 for time: */
#define EXP(s) sizeof(s)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%C"), OUTSIZE, EXP(CENT) },
{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul 2 23:01:13 ")YEAR) },
{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
@ -995,7 +999,7 @@ const struct test Vecyr1[] = {
/* Testing fields one at a time, expecting to pass, using a larger
* allowed length than what is needed. */
/* Using tmyr1 for time: */
#define EXP(s) sizeof(s)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%C"), OUTSIZE, EXP(CENT) },
{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul 2 23:01:13 ")YEAR) },
{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
@ -1032,7 +1036,7 @@ const struct test Vecyrzp[] = {
/* Testing fields one at a time, expecting to pass, using a larger
* allowed length than what is needed. */
/* Using tmyrzp for time: */
#define EXP(s) sizeof(s)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%C"), OUTSIZE, EXP(CENT) },
{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul 2 23:01:60 ")YEAR) },
{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
@ -1067,7 +1071,7 @@ const struct test Vecyrzn[] = {
/* Testing fields one at a time, expecting to pass, using a larger
* allowed length than what is needed. */
/* Using tmyrzn for time: */
#define EXP(s) sizeof(s)-1, s
#define EXP(s) sizeof(s)/sizeof(CHAR)-1, s
{ CQ("%C"), OUTSIZE, EXP(CENT) },
{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul 2 23:01:00 ")YEAR) },
{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },