[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] nstrftime: be more predictable about errno
From: |
Paul Eggert |
Subject: |
[PATCH] nstrftime: be more predictable about errno |
Date: |
Sat, 15 Aug 2020 16:06:45 -0700 |
This aligns nstrftime better with draft POSIX 202x strftime.
* lib/nstrftime.c: Include errno.h.
(width_add, __strftime_internal): Set errno on failure,
and preserve it on success. Check for mktime_z failure.
* modules/nstrftime (Depends-on): Add errno.
* modules/nstrftime-tests (Depends-on): Add atoll, intprops.
* tests/test-nstrftime.c: Include intprops.h, limits.h.
(errno_test): New test function.
(main): Call it.
---
ChangeLog | 13 +++++++
lib/nstrftime.c | 14 +++++++-
lib/strftime.h | 7 +++-
modules/nstrftime | 1 +
modules/nstrftime-tests | 2 ++
tests/test-nstrftime.c | 79 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 86b512991..eb80aba80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2020-08-15 Paul Eggert <eggert@cs.ucla.edu>
+
+ nstrftime: be more predictable about errno
+ This aligns nstrftime better with draft POSIX 202x strftime.
+ * lib/nstrftime.c: Include errno.h.
+ (width_add, __strftime_internal): Set errno on failure,
+ and preserve it on success. Check for mktime_z failure.
+ * modules/nstrftime (Depends-on): Add errno.
+ * modules/nstrftime-tests (Depends-on): Add atoll, intprops.
+ * tests/test-nstrftime.c: Include intprops.h, limits.h.
+ (errno_test): New test function.
+ (main): Call it.
+
2020-08-15 Bruno Haible <bruno@clisp.org>
canonicalize: Fix a problem of the autoconf test on MSVC/clang.
diff --git a/lib/nstrftime.c b/lib/nstrftime.c
index 35b65bbbd..28bc42fd6 100644
--- a/lib/nstrftime.c
+++ b/lib/nstrftime.c
@@ -33,6 +33,7 @@
#endif
#include <ctype.h>
+#include <errno.h>
#include <time.h>
#if HAVE_TZNAME && !HAVE_DECL_TZNAME
@@ -162,7 +163,10 @@ extern char *tzname[];
size_t _w = pad == L_('-') || width < 0 ? 0 : width; \
size_t _incr = _n < _w ? _w : _n; \
if (_incr >= maxsize - i) \
- return 0; \
+ { \
+ errno = ERANGE; \
+ return 0; \
+ } \
if (p) \
{ \
if (_n < _w) \
@@ -447,6 +451,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG
(size_t maxsize)
size_t maxsize = (size_t) -1;
#endif
+ int saved_errno = errno;
int hour12 = tp->tm_hour;
#ifdef _NL_CURRENT
/* We cannot make the following values variables since we must delay
@@ -1186,7 +1191,13 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG
(size_t maxsize)
time_t t;
ltm = *tp;
+ ltm.tm_yday = -1;
t = mktime_z (tz, <m);
+ if (ltm.tm_yday < 0)
+ {
+ errno = EOVERFLOW;
+ return 0;
+ }
/* Generate string value for T using time_t arithmetic;
this works even if sizeof (long) < sizeof (time_t). */
@@ -1484,5 +1495,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG
(size_t maxsize)
*p = L_('\0');
#endif
+ errno = saved_errno;
return i;
}
diff --git a/lib/strftime.h b/lib/strftime.h
index e85016315..fe0c4195a 100644
--- a/lib/strftime.h
+++ b/lib/strftime.h
@@ -24,7 +24,12 @@ extern "C" {
/* Just like strftime, but with two more arguments:
POSIX requires that strftime use the local timezone information.
Use the timezone __TZ instead. Use __NS as the number of
- nanoseconds in the %N directive. */
+ nanoseconds in the %N directive.
+
+ On error, set errno and return 0. Otherwise, return the number of
+ bytes generated (not counting the trailing NUL), preserving errno
+ if the number is 0. This errno behavior is in draft POSIX 202x
+ plus some requested changes to POSIX. */
size_t nstrftime (char *restrict, size_t, char const *, struct tm const *,
timezone_t __tz, int __ns);
diff --git a/modules/nstrftime b/modules/nstrftime
index 7ff82896b..9db0c7521 100644
--- a/modules/nstrftime
+++ b/modules/nstrftime
@@ -9,6 +9,7 @@ m4/nstrftime.m4
Depends-on:
attribute
+errno
extensions
intprops
stdbool
diff --git a/modules/nstrftime-tests b/modules/nstrftime-tests
index 708b510d2..4089771e0 100644
--- a/modules/nstrftime-tests
+++ b/modules/nstrftime-tests
@@ -3,6 +3,8 @@ tests/test-nstrftime.c
tests/macros.h
Depends-on:
+atoll
+intprops
strerror
configure.ac:
diff --git a/tests/test-nstrftime.c b/tests/test-nstrftime.c
index cb9e2d6ad..63864fc83 100644
--- a/tests/test-nstrftime.c
+++ b/tests/test-nstrftime.c
@@ -20,7 +20,10 @@
#include "strftime.h"
+#include "intprops.h"
+
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
@@ -247,6 +250,81 @@ quarter_test (void)
return result;
}
+static int
+errno_test (void)
+{
+ int fail = 0;
+ struct tm tm = { .tm_year = 2020 - 1900, .tm_mday = 1 };
+ char buf[INT_BUFSIZE_BOUND (time_t)];
+ size_t n;
+ int bigyear = LLONG_MAX - 1900 < INT_MAX ? LLONG_MAX - 1900 : INT_MAX;
+
+ errno = 0;
+ n = nstrftime (buf, 0, "%m", &tm, 0, 0);
+ if (! (n == 0 && errno == ERANGE))
+ {
+ fail = 1;
+ printf ("nstrftime failed to set errno = ERANGE\n");
+ }
+
+ errno = 0;
+ n = nstrftime (buf, sizeof buf, "", &tm, 0, 0);
+ if (! (n == 0 && errno == 0))
+ {
+ fail = 1;
+ printf ("nstrftime failed to leave errno alone\n");
+ }
+
+
+ tm.tm_year = bigyear;
+ errno = 0;
+ n = nstrftime (buf, sizeof buf, "%s", &tm, 0, 0);
+ if (n == 0)
+ {
+ if (errno != EOVERFLOW)
+ {
+ fail = 1;
+ printf ("nstrftime failed to set errno = EOVERFLOW\n");
+ }
+
+ if (mktime_z (0, &tm) != (time_t) -1)
+ {
+ fail = 1;
+ printf ("nstrftime %%s failed but mktime_z worked for tm_year=%d\n",
+ bigyear);
+ }
+ }
+ else
+ {
+ long long int text_seconds = atoll (buf);
+ if (text_seconds <= (LLONG_MAX - 1 < TYPE_MAXIMUM (time_t)
+ ? LLONG_MAX - 1 : TYPE_MAXIMUM (time_t)))
+ {
+ time_t bigtime = text_seconds;
+ struct tm *tmp = gmtime (&bigtime);
+ if (!tmp)
+ {
+ fail = 1;
+ printf ("gmtime failed on nstrftime result\n");
+ }
+ else
+ {
+ char buf1[sizeof buf];
+ size_t n1 = nstrftime (buf1, sizeof buf1, "%s", tmp, 0, 0);
+ buf1[n1] = '\0';
+ if (! STREQ (buf, buf1))
+ {
+ fail = 1;
+ printf ("nstrftime %%s first returned '%s', then '%s'\n",
+ buf, buf1);
+ }
+ }
+ }
+ }
+
+ return fail;
+}
+
int
main (void)
{
@@ -254,6 +332,7 @@ main (void)
fail |= posixtm_test ();
fail |= tzalloc_test ();
fail |= quarter_test ();
+ fail |= errno_test ();
return fail;
}
--
2.17.1
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] nstrftime: be more predictable about errno,
Paul Eggert <=