Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 May 2002 19:51:07 +0100
From:      Tony Finch <dot@dotat.at>
To:        freebsd-audit@freebsd.org
Subject:   strptime %z support
Message-ID:  <20020521195107.A4260@chiark.greenend.org.uk>

next in thread | raw e-mail | index | archive | help
This is a work-in-progress patch against -STABLE. The reason I'm posting
here is because I have a feeling I'm barking up the wrong tree -- I'm
not sure how to get it to return a struct tm with the right timezone
filled in so it currently falls back to GMT. It also replaces a pthreads
lock with re-entrant code.

Any comments would be welcome.

Tony.
-- 
f.a.n.finch <dot@dotat.at> http://dotat.at/
SOUTHEAST ICELAND: SOUTHEASTERLY 6 TO GALE 8, BACKING EAST OR NORTHEAST 4 OR
5. SHOWERS. MODERATE.

Index: strptime.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdtime/strptime.c,v
retrieving revision 1.17.2.3
diff -u -r1.17.2.3 strptime.c
--- strptime.c	12 Mar 2002 17:24:54 -0000	1.17.2.3
+++ strptime.c	21 May 2002 18:39:23 -0000
@@ -75,18 +75,17 @@
 #endif
 #include "timelocal.h"
 
-static char * _strptime(const char *, const char *, struct tm *);
+static char * _strptime(const char *, const char *, struct tm *, int *);
 
-#ifdef	_THREAD_SAFE
-static struct pthread_mutex	_gotgmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
-static pthread_mutex_t		gotgmt_mutex   = &_gotgmt_mutexd;
-#endif
-static int got_GMT;
+enum {
+	NORMALIZE_GMT = 1,
+	NORMALIZE_LOCAL = 2
+};
 
 #define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
 
 static char *
-_strptime(const char *buf, const char *fmt, struct tm *tm)
+_strptime(const char *buf, const char *fmt, struct tm *tm, int *flagp)
 {
 	char	c;
 	const char *ptr;
@@ -123,7 +122,7 @@
 			break;
 
 		case '+':
-			buf = _strptime(buf, tptr->date_fmt, tm);
+			buf = _strptime(buf, tptr->date_fmt, tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
@@ -146,13 +145,13 @@
 			break;
 
 		case 'c':
-			buf = _strptime(buf, tptr->c_fmt, tm);
+			buf = _strptime(buf, tptr->c_fmt, tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'D':
-			buf = _strptime(buf, "%m/%d/%y", tm);
+			buf = _strptime(buf, "%m/%d/%y", tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
@@ -170,37 +169,37 @@
 			goto label;
 
 		case 'F':
-			buf = _strptime(buf, "%Y-%m-%d", tm);
+			buf = _strptime(buf, "%Y-%m-%d", tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'R':
-			buf = _strptime(buf, "%H:%M", tm);
+			buf = _strptime(buf, "%H:%M", tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'r':
-			buf = _strptime(buf, tptr->ampm_fmt, tm);
+			buf = _strptime(buf, tptr->ampm_fmt, tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'T':
-			buf = _strptime(buf, "%H:%M:%S", tm);
+			buf = _strptime(buf, "%H:%M:%S", tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'X':
-			buf = _strptime(buf, tptr->X_fmt, tm);
+			buf = _strptime(buf, tptr->X_fmt, tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'x':
-			buf = _strptime(buf, tptr->x_fmt, tm);
+			buf = _strptime(buf, tptr->x_fmt, tm, flagp);
 			if (buf == 0)
 				return 0;
 			break;
@@ -460,7 +459,7 @@
 				return 0;
 			buf = cp;
 			gmtime_r(&t, tm);
-			got_GMT = 1;
+			*flagp |= NORMALIZE_GMT;
 			}
 			break;
 
@@ -504,7 +503,7 @@
 				zonestr[cp - buf] = '\0';
 				tzset();
 				if (0 == strcmp(zonestr, "GMT")) {
-				    got_GMT = 1;
+				    *flagp |= NORMALIZE_GMT;
 				} else if (0 == strcmp(zonestr, tzname[0])) {
 				    tm->tm_isdst = 0;
 				} else if (0 == strcmp(zonestr, tzname[1])) {
@@ -516,6 +515,31 @@
 			}
 			}
 			break;
+		case 'z':
+			{
+			long off;
+			char *end;
+
+			off = strtol(buf + 1, &end, 10);
+			if (end != buf + 5)
+				return 0;
+			if (off % 100 > 59)
+				return 0;
+			/* convert from 4 decimal digits to hours + minutes */
+			off = (off / 100) * 60 + off % 100;
+			if (*buf == '-')
+				off = -off;
+			else if (*buf == '+')
+				off = +off;
+			else
+				return 0;
+			tm->tm_gmtoff = off * 60;
+			tm->tm_isdst = -1;
+			tm->tm_zone = NULL;
+			*flagp |= NORMALIZE_LOCAL;
+			buf = end;
+			}
+			break;
 		}
 	}
 	return (char *)buf;
@@ -526,22 +550,20 @@
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
 	char *ret;
+	int flags;
 
-#ifdef	_THREAD_SAFE
-	pthread_mutex_lock(&gotgmt_mutex);
-#endif
-
-	got_GMT = 0;
-	ret = _strptime(buf, fmt, tm);
-	if (ret && got_GMT) {
+	ret = _strptime(buf, fmt, tm, &flags);
+	if (ret == NULL)
+		return NULL;
+	if (flags & NORMALIZE_LOCAL) {
+		tm->tm_hour -= tm->tm_gmtoff / 3600;
+		tm->tm_min -= (tm->tm_min / 60) % 60;
+		flags |= NORMALIZE_GMT;
+	}
+	if (flags & NORMALIZE_GMT) {
 		time_t t = timegm(tm);
-	    localtime_r(&t, tm);
-		got_GMT = 0;
+		localtime_r(&t, tm);
 	}
-
-#ifdef	_THREAD_SAFE
-	pthread_mutex_unlock(&gotgmt_mutex);
-#endif
 
 	return ret;
 }

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020521195107.A4260>