strptime %z support

Tony Finch <[email protected]>
Newsgroups gmane.os.freebsd.devel.audit
Message-ID <[email protected]>
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 <[email protected]> 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 [email protected]
with "unsubscribe freebsd-audit" in the body of the message
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.