+2021-07-17 Paul Eggert <eggert@cs.ucla.edu>
+
+ posixtm: pacify latest GCC
+ Also, modernize while I’m at it.
+ * lib/posixtm.c: Include c-ctype.h, idx.h, intprops.h, verify.h
+ instead of stdlib.h.
+ (ISDIGIT): Remove. All uses replaced by c_isdigit.
+ (year, posix_time_parse): Prefer idx_t to size_t. Use assume
+ instead of abort.
+ (posixtime): Do not parse twice; once is enough. That way, we
+ needn’t worry about a bogus warning about strcpy overrunning a
+ buffer from GCC 11.1.1 20210531 (Red Hat 11.1.1-3) x86-64
+ when coreutils is configured with --enable-gcc-warnings.
+ * modules/posixtm (Depends-on): Add c-ctype, intprops, verify.
+ Remove stpcpy.
+
2021-07-17 Bruno Haible <bruno@clisp.org>
Don't use '#pragma weak' for thread functions in Linux/glibc>=2.34.
#include "posixtm.h"
-#include <stdlib.h>
-#include <string.h>
+#include "c-ctype.h"
+#include "idx.h"
+#include "intprops.h"
+#include "verify.h"
-/* ISDIGIT differs from isdigit, as follows:
- - Its arg may be any int or unsigned int; it need not be an unsigned char
- or EOF.
- - It's typically faster.
- POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
- isdigit unless it's important to use the locale's definition
- of "digit" even when the host does not conform to POSIX. */
-#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+#include <string.h>
/*
POSIX requires:
*/
static bool
-year (struct tm *tm, const int *digit_pair, size_t n, unsigned int syntax_bits)
+year (struct tm *tm, const int *digit_pair, idx_t n, unsigned int syntax_bits)
{
switch (n)
{
case 0:
{
- time_t now;
- struct tm *tmp;
-
/* Use current year. */
- time (&now);
- tmp = localtime (&now);
+ time_t now = time (NULL);
+ struct tm *tmp = localtime (&now);
if (! tmp)
return false;
tm->tm_year = tmp->tm_year;
break;
default:
- abort ();
+ assume (false);
}
return true;
{
const char *dot = NULL;
int pair[6];
- int *p;
- size_t i;
- size_t s_len = strlen (s);
- size_t len = s_len;
+ idx_t s_len = strlen (s);
+ idx_t len = s_len;
if (syntax_bits & PDS_SECONDS)
{
if (! (8 <= len && len <= 12 && len % 2 == 0))
return false;
- for (i = 0; i < len; i++)
- if (!ISDIGIT (s[i]))
+ for (idx_t i = 0; i < len; i++)
+ if (!c_isdigit (s[i]))
return false;
len /= 2;
- for (i = 0; i < len; i++)
+ for (idx_t i = 0; i < len; i++)
pair[i] = 10 * (s[2*i] - '0') + s[2*i + 1] - '0';
- p = pair;
+ int *p = pair;
if (! (syntax_bits & PDS_TRAILING_YEAR))
{
if (! year (tm, p, len - 4, syntax_bits))
/* Handle seconds. */
if (!dot)
tm->tm_sec = 0;
- else if (ISDIGIT (dot[1]) && ISDIGIT (dot[2]))
+ else if (c_isdigit (dot[1]) && c_isdigit (dot[2]))
tm->tm_sec = 10 * (dot[1] - '0') + dot[2] - '0';
else
return false;
posixtime (time_t *p, const char *s, unsigned int syntax_bits)
{
struct tm tm0;
- struct tm tm1;
- time_t t;
+ bool leapsec = false;
if (! posix_time_parse (&tm0, s, syntax_bits))
return false;
- tm1.tm_sec = tm0.tm_sec;
- tm1.tm_min = tm0.tm_min;
- tm1.tm_hour = tm0.tm_hour;
- tm1.tm_mday = tm0.tm_mday;
- tm1.tm_mon = tm0.tm_mon;
- tm1.tm_year = tm0.tm_year;
- tm1.tm_wday = -1;
- tm1.tm_isdst = -1;
- t = mktime (&tm1);
-
- if (tm1.tm_wday < 0)
- return false;
-
- /* Reject dates like "September 31" and times like "25:61".
- However, allow a seconds count of 60 even in time zones that do
- not support leap seconds, treating it as the following second;
- POSIX requires this. */
- if ((tm0.tm_year ^ tm1.tm_year)
- | (tm0.tm_mon ^ tm1.tm_mon)
- | (tm0.tm_mday ^ tm1.tm_mday)
- | (tm0.tm_hour ^ tm1.tm_hour)
- | (tm0.tm_min ^ tm1.tm_min)
- | (tm0.tm_sec ^ tm1.tm_sec))
+ while (true)
{
+ struct tm tm1;
+ tm1.tm_sec = tm0.tm_sec;
+ tm1.tm_min = tm0.tm_min;
+ tm1.tm_hour = tm0.tm_hour;
+ tm1.tm_mday = tm0.tm_mday;
+ tm1.tm_mon = tm0.tm_mon;
+ tm1.tm_year = tm0.tm_year;
+ tm1.tm_wday = -1;
+ tm1.tm_isdst = -1;
+ time_t t = mktime (&tm1);
+
+ if (tm1.tm_wday < 0)
+ return false;
+
+ /* Reject dates like "September 31" and times like "25:61".
+ However, allow a seconds count of 60 even in time zones that do
+ not support leap seconds, treating it as the following second;
+ POSIX requires this. */
+ if (! ((tm0.tm_year ^ tm1.tm_year)
+ | (tm0.tm_mon ^ tm1.tm_mon)
+ | (tm0.tm_mday ^ tm1.tm_mday)
+ | (tm0.tm_hour ^ tm1.tm_hour)
+ | (tm0.tm_min ^ tm1.tm_min)
+ | (tm0.tm_sec ^ tm1.tm_sec)))
+ {
+ if (INT_ADD_WRAPV (t, leapsec, &t))
+ return false;
+ *p = t;
+ return true;
+ }
+
/* Any mismatch without 60 in the tm_sec field is invalid. */
if (tm0.tm_sec != 60)
return false;
- {
- /* Allow times like 01:35:60 or 23:59:60. */
- time_t dummy;
- char buf[16];
- char *b = stpcpy (buf, s);
- strcpy (b - 2, "59");
- if (!posixtime (&dummy, buf, syntax_bits))
- return false;
- }
+ /* Allow times like 01:35:60 or 23:59:60. */
+ tm0.tm_sec = 59;
+ leapsec = true;
}
-
- *p = t;
- return true;
}