134 lines
3.7 KiB
Diff
134 lines
3.7 KiB
Diff
From 8b238ec54c09556eb2aa405c1741eedfd12c4a87 Mon Sep 17 00:00:00 2001
|
||
From: Paul Eggert <eggert@cs.ucla.edu>
|
||
Date: Sat, 8 Aug 2020 12:19:28 -0700
|
||
Subject: [PATCH 24/47] strftime: conform better to POSIX+
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
The latest POSIX draft specifies errno values for some strftime
|
||
errors. Implement those, plus one other one: a reliable way
|
||
to determine whether 0 represents failure or buffer exhaustion
|
||
(I’ll propose this to POSIX).
|
||
* newstrftime.3 (RETURN VALUE): Document this.
|
||
* strftime.c (strftime): Set errno according to current draft of
|
||
POSIX. Also, set errno to ERANGE on overflow, and preserve errno
|
||
if there is no error.
|
||
(_fmt): Return NULL if %s would be out of range. Callers changed.
|
||
---
|
||
newstrftime.3 | 34 +++++++++++++++++++++++++++-------
|
||
strftime.c | 24 +++++++++++++++++++++++-
|
||
2 files changed, 50 insertions(+), 8 deletions(-)
|
||
|
||
diff --git a/newstrftime.3 b/newstrftime.3
|
||
index 63842c7..887aba5 100644
|
||
--- a/newstrftime.3
|
||
+++ b/newstrftime.3
|
||
@@ -82,13 +82,6 @@ and one other character.
|
||
No more than
|
||
.I maxsize
|
||
bytes are placed into the array.
|
||
-If the total number of resulting bytes, including the terminating
|
||
-NUL character, is not more than
|
||
-.IR maxsize ,
|
||
-.B strftime
|
||
-returns the number of bytes placed into the array, not counting the
|
||
-terminating NUL.
|
||
-Otherwise, zero is returned and the array contents are unspecified.
|
||
.PP
|
||
Each conversion specification is replaced by the characters as
|
||
follows which are then copied into the array.
|
||
@@ -259,6 +252,33 @@ is replaced by a single %.
|
||
is replaced by the locale's date and time in
|
||
.BR date (1)
|
||
format.
|
||
+.SH "RETURN VALUE"
|
||
+If the conversion is successful,
|
||
+.B strftime
|
||
+returns the number of bytes placed into the array, not counting the
|
||
+terminating NUL;
|
||
+.B errno
|
||
+is unchanged if the returned value is zero.
|
||
+Otherwise,
|
||
+.B errno
|
||
+is set to indicate the error, zero is returned,
|
||
+and the array contents are unspecified.
|
||
+.SH ERRORS
|
||
+This function fails if:
|
||
+.TP
|
||
+[ERANGE]
|
||
+The total number of resulting bytes, including the terminating
|
||
+NUL character, is more than
|
||
+.IR maxsize .
|
||
+.PP
|
||
+This function may fail if:
|
||
+.TP
|
||
+[EOVERFLOW]
|
||
+The format includes an
|
||
+.c %s
|
||
+conversion and the number of seconds since the Epoch cannot be represented
|
||
+in a
|
||
+.c time_t .
|
||
.SH SEE ALSO
|
||
date(1),
|
||
getenv(3),
|
||
diff --git a/strftime.c b/strftime.c
|
||
index 14cbc9a..4f871cd 100644
|
||
--- a/strftime.c
|
||
+++ b/strftime.c
|
||
@@ -130,10 +130,15 @@ size_t
|
||
strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
|
||
{
|
||
char * p;
|
||
+ int saved_errno = errno;
|
||
enum warn warn = IN_NONE;
|
||
|
||
tzset();
|
||
p = _fmt(format, t, s, s + maxsize, &warn);
|
||
+ if (!p) {
|
||
+ errno = EOVERFLOW;
|
||
+ return 0;
|
||
+ }
|
||
if (DEPRECATE_TWO_DIGIT_YEARS
|
||
&& warn != IN_NONE && getenv(YEAR_2000_NAME)) {
|
||
fprintf(stderr, "\n");
|
||
@@ -146,9 +151,12 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
|
||
else fprintf(stderr, "all locales");
|
||
fprintf(stderr, "\n");
|
||
}
|
||
- if (p == s + maxsize)
|
||
+ if (p == s + maxsize) {
|
||
+ errno = ERANGE;
|
||
return 0;
|
||
+ }
|
||
*p = '\0';
|
||
+ errno = saved_errno;
|
||
return p - s;
|
||
}
|
||
|
||
@@ -312,7 +320,21 @@ label:
|
||
time_t mkt;
|
||
|
||
tm = *t;
|
||
+ tm.tm_yday = -1;
|
||
mkt = mktime(&tm);
|
||
+ if (mkt == (time_t) -1) {
|
||
+ /* Fail unless this -1 represents
|
||
+ a valid time. */
|
||
+ struct tm tm_1;
|
||
+ if (!localtime_r(&mkt, &tm_1))
|
||
+ return NULL;
|
||
+ if (!(tm.tm_year == tm_1.tm_year
|
||
+ && tm.tm_yday == tm_1.tm_yday
|
||
+ && tm.tm_hour == tm_1.tm_hour
|
||
+ && tm.tm_min == tm_1.tm_min
|
||
+ && tm.tm_sec == tm_1.tm_sec))
|
||
+ return NULL;
|
||
+ }
|
||
if (TYPE_SIGNED(time_t))
|
||
sprintf(buf, "%"PRIdMAX,
|
||
(intmax_t) mkt);
|
||
--
|
||
1.8.3.1
|
||
|