From 79281c3f8b98ca937633ffc0499c25a1160fdde5 Mon Sep 17 00:00:00 2001 From: corinna Date: Thu, 12 Mar 2009 10:27:10 +0000 Subject: [PATCH] * 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. --- newlib/ChangeLog | 16 ++++++ newlib/libc/stdio/sprintf.c | 49 +++++++++-------- newlib/libc/stdio/swprintf.c | 122 +++++++++++++++++++++++++++--------------- newlib/libc/stdio/vfwprintf.c | 35 ++++++------ newlib/libc/stdio/vswprintf.c | 20 +++++-- newlib/libc/time/strftime.c | 108 +++++++++++++++++++------------------ 6 files changed, 210 insertions(+), 140 deletions(-) diff --git a/newlib/ChangeLog b/newlib/ChangeLog index f7bc2ea958..9aeac02d3b 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,19 @@ +2009-03-09 Craig Howland + + * 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 * libc/include/wchar.h (wcscasecmp, wcsncasecmp): Declare. diff --git a/newlib/libc/stdio/sprintf.c b/newlib/libc/stdio/sprintf.c index 1d81ebdf97..072622e75a 100644 --- a/newlib/libc/stdio/sprintf.c +++ b/newlib/libc/stdio/sprintf.c @@ -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 <>, - <>, <>, <>, <>, <>, or <>, - 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 <>, + <>, <>, <>, <>, <>, or <>, 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 <>, <>, <>, <>, <>, <>, <>, <>, - <>, <>, <>, <>, or <>: leading + <>, <>, <>, <>, <>, or <>: 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 <>, <>, <>, <>, <>, or - <>, specifies that the argument is a - <> or <>. + <>, specifies that the argument is a <>. With <>, specifies that the argument is a - pointer to a <>. + pointer to a <>. o t With <>, <>, <>, <>, <>, 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 <> @@ -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 <>. 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 <>. 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 <>. 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 <> as digits beyond <<9>>); takes an <>. 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 <>, but uses <> as digits @@ -540,6 +542,9 @@ If an error occurs, the result of <>, <>, to ENOMEM if allocation fails, and for <>, <> 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 <>, <>, <>, and <>. <> and <> 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); } diff --git a/newlib/libc/stdio/swprintf.c b/newlib/libc/stdio/swprintf.c index 0d0e4d933b..63480176a2 100644 --- a/newlib/libc/stdio/swprintf.c +++ b/newlib/libc/stdio/swprintf.c @@ -33,25 +33,27 @@ INDEX _swprintf_r ANSI_SYNOPSIS - #include + #include 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]>, ...); + 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 <> accepts a series of arguments, applies to each a format specifier from <<*<[format]>>>, and writes the formatted data to <>, without a terminating NUL wide character. The behavior of <> is undefined if there - are not enough arguments for the format. <> 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. <> + 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 <>. <> is like <>, 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 - <>. As a special case, if <[size]> is 0, <[str]> can be NULL, - and <> merely calculates how many bytes would be printed. + to the buffer <[str]> with a terminating wide <>, and the + resulting string length is limited to at most <[size]> wide characters, + including the terminating <>. It is considered an error if the + output (including the terminating wide-<>) does not fit into + <[size]> wide characters. (This error behavior is not the same as for + <>, which <> is otherwise completely analogous to. + While <> allows the needed size to be known simply by giving + <[size]>=0, <> does not, giving an error instead.) For <> 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 <>, - <>, <>, <>, <>, <>, or <>, - 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 <>, + <>, <>, <>, <>, <>, or <>, 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 <>, <>, <>, <>, <>, <>, <>, <>, - <>, <>, <>, <>, or <>: leading + <>, <>, <>, <>, <>, or <>: 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 <>, <>, <>, <>, <>, or - <>, specifies that the argument is a - <> or <>. + <>, specifies that the argument is a <>. With <>, specifies that the argument is a - pointer to a <>. + pointer to a <>. o t With <>, <>, <>, <>, <>, 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 <> 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 <>. 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 <>. 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 <>. 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 <> as digits beyond <<9>>); takes an <>. 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 <>, but uses <> as digits @@ -503,12 +511,16 @@ the output string, except the concluding <> is not counted. If an error occurs, the result of <>, <>, and <> is a negative value. For <> and <>, -<> may be set according to <>. For <>, <> -may be set to EOVERFLOW if <[size]> or the output length exceeds -INT_MAX / sizeof (wchar_t). +<> may be set according to <>. For <>, <> +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 <>). + +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: <>, <>, <>, #include #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); } diff --git a/newlib/libc/stdio/vfwprintf.c b/newlib/libc/stdio/vfwprintf.c index 991a2d52fe..68e92a8a69 100644 --- a/newlib/libc/stdio/vfwprintf.c +++ b/newlib/libc/stdio/vfwprintf.c @@ -50,17 +50,18 @@ INDEX ANSI_SYNOPSIS #include #include + #include 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]>, - va_list <[list]>); + 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]>, - va_list <[list]>); + va_list <[list]>); int _vfwprintf_r(struct _reent *<[reent]>, FILE *<[fp]>, - const wchar_t *<[fmt]>, va_list <[list]>); + 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 <>, <> and <> 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: <>, <>, <>, <>, <>, <>, <>. + +SEEALSO +<>, <> and <>. */ /* @@ -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 diff --git a/newlib/libc/stdio/vswprintf.c b/newlib/libc/stdio/vswprintf.c index aebb20a002..2d9096c15f 100644 --- a/newlib/libc/stdio/vswprintf.c +++ b/newlib/libc/stdio/vswprintf.c @@ -27,6 +27,7 @@ static char sccsid[] = "%W% (Berkeley) %G%"; #include #include #include + #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; } diff --git a/newlib/libc/time/strftime.c b/newlib/libc/time/strftime.c index 88ccf46b5c..e9849ac9b4 100644 --- a/newlib/libc/time/strftime.c +++ b/newlib/libc/time/strftime.c @@ -251,6 +251,10 @@ This implementation does not support <> being NULL, nor overlapping <> and <>. <> requires no supporting OS subroutines. + +BUGS +<> ignores the LC_TIME category of the current locale, hard-coding +the "C" locale settings. */ #include @@ -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) }, -- 2.11.0