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
|
|||
|
|
|