Module Name:    src
Committed By:   kre
Date:           Tue Sep 17 11:30:11 UTC 2024

Modified Files:
        src/bin/date: date.c

Log Message:
PR lib/58674 (and I suspect, several others)

Stop expecting strptime(3) in the tools build, it is an XSI
function, and the tools builds do not set up the environment
to expect XSI functions to be available.

This means dropping support for the -f option in the tools date
(which shouldn't matter, -f sets the format for the string used
to set the time, which the tools date does not support), and
open coding parsing for the -d option in the tools build.

There should be no changes to the date(1) that is installed in /bin

As a (minor) benefit, the tools -d support has become somewhat
more flexible than the previous simple strptime() implementation
allowed, and also does better error checking (no more Feb 30 etc).

Note: no change to the usage message, if -f is passed to the tools
date it will elicit a usage which says that -f is supported...
(that's just laziness...)


To generate a diff of this commit:
cvs rdiff -u -r1.67 -r1.68 src/bin/date/date.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/date/date.c
diff -u src/bin/date/date.c:1.67 src/bin/date/date.c:1.68
--- src/bin/date/date.c:1.67	Tue Sep 17 09:55:38 2024
+++ src/bin/date/date.c	Tue Sep 17 11:30:11 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: date.c,v 1.67 2024/09/17 09:55:38 kre Exp $ */
+/* $NetBSD: date.c,v 1.68 2024/09/17 11:30:11 kre Exp $ */
 
 /*
  * Copyright (c) 1985, 1987, 1988, 1993
@@ -44,7 +44,7 @@ __COPYRIGHT(
 #if 0
 static char sccsid[] = "@(#)date.c	8.2 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: date.c,v 1.67 2024/09/17 09:55:38 kre Exp $");
+__RCSID("$NetBSD: date.c,v 1.68 2024/09/17 11:30:11 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -72,12 +72,17 @@ __RCSID("$NetBSD: date.c,v 1.67 2024/09/
 
 static time_t tval;
 static int Rflag, aflag, jflag, rflag, nflag;
-static char *fmt;
 
 __dead static void badcanotime(const char *, const char *, size_t);
 static void setthetime(const char *);
 __dead static void usage(void);
 
+#if HAVE_NBTOOL_CONFIG_H
+static int parse_iso_datetime(time_t *, const char *);
+#else
+static char *fmt;
+#endif
+
 #if !defined(isleap)
 # define isleap(y)   (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
 #endif
@@ -103,33 +108,24 @@ main(int argc, char *argv[])
 			break;
 		case 'd':
 			rflag = 1;
-#ifndef HAVE_NBTOOL_CONFIG_H
+#ifdef HAVE_NBTOOL_CONFIG_H
+			if (parse_iso_datetime(&tval, optarg))
+				break;
+			errx(EXIT_FAILURE,
+			    "-d only supports ISO format in the tool version");
+			break;
+#else
+			errno = 0;
 			tval = parsedate(optarg, NULL, NULL);
-			if (tval == -1) {
+			if (tval == -1 && errno != 0) {
 				errx(EXIT_FAILURE,
 				    "%s: Unrecognized date format", optarg);
 			}
 			break;
-#else
-			/* handle YYYYMMDD, or fail */
-			{
-				struct tm tm;
-				char *p;
-				memset(&tm, 0, sizeof(tm));
-				p = strptime(optarg, "%Y%m%d", &tm);
-				if (*p == '\0'
-				    && tm.tm_year >= 0 && tm.tm_year < 1000
-				    && tm.tm_mon >= 0 && tm.tm_mon <= 11
-				    && tm.tm_mday >= 1 && tm.tm_mday <= 31
-				    && (tval = mktime(&tm)) != -1)
-					break;
-			}
-			errx(EXIT_FAILURE,
-			    "-d not supported in the tool version");
-#endif
 		case 'f':
 			fmt = optarg;
 			break;
+#endif
 		case 'j':		/* don't set time */
 			jflag = 1;
 			break;
@@ -182,8 +178,11 @@ main(int argc, char *argv[])
 	if (*argv) {
 		setthetime(*argv);
 		++argv;
-	} else if (fmt)
+#ifndef HAVE_NBTOOL_CONFIG_H
+	} else if (fmt) {
 		usage();
+#endif
+	}
 
 	if (*argv && **argv == '+')
 		format = *argv;
@@ -216,6 +215,122 @@ badcanotime(const char *msg, const char 
 
 #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
 
+#if HAVE_NBTOOL_CONFIG_H
+
+inline static int
+digitstring(const char *s, int len)
+{
+	while (--len > 0) {
+		if (!isdigit(*(unsigned char *)s))
+			return 0;
+		s++;
+	}
+	return 1;
+}
+
+static int
+parse_iso_datetime(time_t * res, const char * string)
+{
+	struct tm tm;
+	time_t t;
+
+	memset(&tm, 0, sizeof tm);
+
+	if (!digitstring(string, 4))
+		return 0;
+	tm.tm_year = ATOI2(string) * 100;
+	tm.tm_year += ATOI2(string);
+	tm.tm_year -= 1900;
+
+	if (*string == '-')
+		string++;
+
+	if (!digitstring(string, 2))
+		return 0;
+
+	tm.tm_mon = ATOI2(string);
+	if (tm.tm_mon < 1 || tm.tm_mon > 12)
+		return 0;
+	tm.tm_mon--;
+
+	if (*string == '-')
+		string++;
+
+	if (!digitstring(string, 2))
+		return 0;
+
+	tm.tm_mday = ATOI2(string);
+	if (tm.tm_mday < 1)
+		return 0;
+	switch (tm.tm_mon) {
+	case 0: case 2: case 4: case 6: case 7: case 9: case 11:
+		if (tm.tm_mday > 31)
+			return 0;
+		break;
+	case 3: case 5: case 8: case 10:
+		if (tm.tm_mday > 30)
+			return 0;
+		break;
+	case 1:
+		if (tm.tm_mday > 28 + isleap(tm.tm_year + 1900))
+			return 0;
+		break;
+	default:
+		abort();
+	}
+
+	do {
+		if (*string == '\0')
+			break;
+		if (*string == 'T' || *string == 't' || *string == ' ' ||
+		    *string == '-')
+			string++;
+
+		if (!digitstring(string, 2))
+			return 0;
+		tm.tm_hour = ATOI2(string);
+		if (tm.tm_hour > 23)
+			return 0;
+
+		if (*string == '\0')
+			break;
+		if (*string == ':')
+			string++;
+
+		if (!digitstring(string, 2))
+			return 0;
+		tm.tm_min = ATOI2(string);
+		if (tm.tm_min >= 60)
+			return 0;
+
+		if (*string == '\0')
+			break;
+		if (*string == ':')
+			string++;
+
+		if (!digitstring(string, 2))
+			return 0;
+		tm.tm_sec = ATOI2(string);
+		if (tm.tm_sec >= 60)
+			return 0;
+	} while (0);
+
+	if (*string != '\0')
+		return 0;
+
+	tm.tm_isdst = -1;
+	tm.tm_wday = -1;
+
+	t = mktime(&tm);
+	if (tm.tm_wday == -1)
+		return 0;
+
+	*res = t;
+	return 1;
+}
+
+#endif	/*NBTOOL*/
+
 static void
 setthetime(const char *p)
 {
@@ -231,6 +346,7 @@ setthetime(const char *p)
 
 	lt->tm_isdst = -1;			/* Divine correct DST */
 
+#ifndef HAVE_NBTOOL_CONFIG_H
 	if (fmt) {
 		t = strptime(p, fmt, lt);
 		if (t == NULL) {
@@ -242,6 +358,7 @@ setthetime(const char *p)
 				strlen(t), t);
 		goto setit;
 	}
+#endif
 	for (t = p, dot = NULL; *t; ++t) {
 		if (*t == '.') {
 			if (dot == NULL) {

Reply via email to