Index | Thread | Search

From:
Nicolas Samberger <nicolas_samberger@genua.de>
Subject:
newsyslog: refactor date parsing
To:
<tech@openbsd.org>
Date:
Mon, 20 Apr 2026 14:44:35 +0200

Download raw body.

Thread
  • Nicolas Samberger:

    newsyslog: refactor date parsing

Hi all,

analogue to rev1.118 [1], I refactored parseDWM() in newsyslog(8) for date parsing. 
I replaced the manual parsing with strtol(3) by strptime(3).

Best regards

Nico

[1]: https://cvsweb.openbsd.org/log/src/usr.bin/newsyslog/newsyslog.c,v?sort=File#rev1.118

Index: newsyslog.c
===================================================================
RCS file: /cvs/src/usr.bin/newsyslog/newsyslog.c,v
diff -u -p -r1.120 newsyslog.c
--- newsyslog.c	2 Apr 2026 18:22:24 -0000	1.120
+++ newsyslog.c	20 Apr 2026 13:17:33 -0000
@@ -1239,10 +1239,10 @@ time_t
 parseDWM(char *s)
 {
 	static int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-	int WMseen = 0, Dseen = 0, nd;
-	struct tm tm;
-	char *t;
-	long l;
+	int nd;
+	char format[7] = { 0 };
+	struct tm tm, now;
+	char *d, *w, *m;
 
 	if (localtime_r(&timenow, &tm) == NULL)
 		return -1;
@@ -1259,79 +1259,49 @@ parseDWM(char *s)
 		}
 	}
 	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+	memcpy(&now, &tm, sizeof tm);
 
-	for (;;) {
-		switch (*s) {
-		case 'D':
-			if (Dseen)
-				return (-1);
-			Dseen++;
-			s++;
-			l = strtol(s, &t, 10);
-			if (l < 0 || l > 23)
-				return (-1);
-			tm.tm_hour = l;
-			break;
-
-		case 'W':
-			if (WMseen)
-				return (-1);
-			WMseen++;
-			s++;
-			l = strtol(s, &t, 10);
-			if (l < 0 || l > 6)
-				return (-1);
-			if (l != tm.tm_wday) {
-				int save;
-
-				if (l < tm.tm_wday) {
-					save = 6 - tm.tm_wday;
-					save += (l + 1);
-				} else {
-					save = l - tm.tm_wday;
-				}
-
-				tm.tm_mday += save;
-
-				if (tm.tm_mday > nd) {
-					tm.tm_mon++;
-					tm.tm_mday = tm.tm_mday - nd;
-				}
-			}
-			break;
-
-		case 'M':
-			if (WMseen)
-				return (-1);
-			WMseen++;
-			s++;
-			if (tolower((unsigned char)*s) == 'l') {
-				tm.tm_mday = nd;
-				s++;
-				t = s;
-			} else {
-				l = strtol(s, &t, 10);
-				if (l < 1 || l > 31)
-					return (-1);
-
-				if (l > nd)
-					return (-1);
-				if (l < tm.tm_mday)
-					tm.tm_mon++;
-				tm.tm_mday = l;
-			}
-			break;
-
-		default:
-			return (-1);
-			break;
-		}
+	m = strchr(s, 'M');
+	w = strchr(s, 'W');
+	d = strchr(s, 'D');
+
+	if (m != NULL && w != NULL)
+		return -1;
 
-		if (*t == '\0' || isspace((unsigned char)*t))
-			break;
+	if ((m != NULL && w == NULL) && s == m) {
+		if (tolower(m[1]) == 'l') {
+			tm.tm_mday = nd;
+			snprintf(format, sizeof format, "M%c", m[1]);
+			s = d;
+		} else {
+			strlcat(format, "M%e", sizeof format);
+		}
+	} else if ((w != NULL && m == NULL) && s == w) {
+		strlcat(format, "W%w", sizeof format);
+	} else if (d != s)
+		return (-1);
+
+	if (d != NULL)
+		strlcat(format, "D%H", sizeof format);
+
+	if (strptime(s, format, &tm) == NULL)
+		return (-1);
+
+	if (tm.tm_wday != now.tm_wday) {
+		if (now.tm_wday > tm.tm_wday)
+			tm.tm_mday += 7 - (now.tm_wday - tm.tm_wday);
 		else
-			s = t;
+			tm.tm_mday += tm.tm_wday - now.tm_wday;
+
+		if (tm.tm_mday > nd) {
+			tm.tm_mday -= nd;
+			tm.tm_mon++;
+		}
 	}
+
+	if (now.tm_mday > tm.tm_mday)
+		tm.tm_mon++;
+
 	return (mktime(&tm));
 }