Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libc/time PR/50380: Balazs Scheidler: strptime() returns...
details: https://anonhg.NetBSD.org/src/rev/d2a38c996806
branches: trunk
changeset: 811428:d2a38c996806
user: christos <christos%NetBSD.org@localhost>
date: Thu Oct 29 17:54:49 2015 +0000
description:
PR/50380: Balazs Scheidler: strptime() returns incorrect values in tm_gmtoff
- Always offset in seconds.
- Handle arbitrary timezones.
diffstat:
lib/libc/time/strptime.3 | 82 ++++++++++++++++++++++----------
lib/libc/time/strptime.c | 119 +++++++++++++++++++++++++++++++++++-----------
2 files changed, 145 insertions(+), 56 deletions(-)
diffs (truncated from 327 to 300 lines):
diff -r d55108f1809a -r d2a38c996806 lib/libc/time/strptime.3
--- a/lib/libc/time/strptime.3 Thu Oct 29 17:53:04 2015 +0000
+++ b/lib/libc/time/strptime.3 Thu Oct 29 17:54:49 2015 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: strptime.3,v 1.31 2015/04/06 14:38:22 ginsbach Exp $
+.\" $NetBSD: strptime.3,v 1.32 2015/10/29 17:54:49 christos Exp $
.\"
.\" Copyright (c) 1997, 1998, 2008 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -223,33 +223,56 @@
.It Cm \&%z
an ISO 8601 or RFC-2822 time zone specification.
This is one of the following:
-the offset from
-Coordinated Universal Time
+.Bl -dash -offset indent -compact
+.It
+The offset from Coordinated Universal Time
.Pq Ql UTC
specified as:
-.Dq [+-]hhmm ,
-.Dq [+-]hh:mm ,
-or
-.Dq [+-]hh ;
+.Bl -bullet -offset indent -compact
+.It
+[+-]hhmm
+.It
+[+-]hh:mm
+.It
+[+-]hh
+.El
+.It
.Ql UTC
specified as:
-.Dq GMT
-.Pq Ql Greenwich Mean Time ,
-.Dq UT
-.Pq Ql Universal Time ,
-or
-.Dq Z
-.Pq Ql Zulu Time ;
-a three character US time zone specified as:
-.Dq EDT ,
-.Dq EST ,
-.Dq CDT ,
-.Dq CST ,
-.Dq MDT ,
-.Dq MST ,
-.Dq PDT ,
-or
-.Dq PST ,
+.Bl -bullet -offset indent -compact
+.It
+UTC
+.Pq Ql Coordinated Universal time
+.It
+GMT
+.Pq Ql Greenwich Mean Time
+.It
+UT
+.Pq Ql Universal Time
+.It
+Z
+.Pq Ql Zulu Time
+.El
+.It
+A three character US time zone specified as:
+.Bl -bullet -offset indent -compact
+.It
+EDT
+.It
+EST
+.It
+CDT
+.It
+CST
+.It
+MDT
+.It
+MST
+.It
+PDT
+.It
+PST
+.El
with the first letter standing for
.Ql Eastern
.Pq Dq E ,
@@ -270,15 +293,22 @@
or
.Ql Standard
.Pq Dq S
-time;
+time
+.It
a single letter military time zone specified as:
+.Bl -bullet -offset indent -compact
+.It
.Dq A
through
.Dq I
-and
+.It
.Dq K
through
.Dq Y .
+.El
+.It
+An arbirtrary timezone name that can be loaded from the database.
+.El
.Po
A
.Nx
diff -r d55108f1809a -r d2a38c996806 lib/libc/time/strptime.c
--- a/lib/libc/time/strptime.c Thu Oct 29 17:53:04 2015 +0000
+++ b/lib/libc/time/strptime.c Thu Oct 29 17:54:49 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: strptime.c,v 1.49 2015/10/09 17:21:45 christos Exp $ */
+/* $NetBSD: strptime.c,v 1.50 2015/10/29 17:54:49 christos Exp $ */
/*-
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: strptime.c,v 1.49 2015/10/09 17:21:45 christos Exp $");
+__RCSID("$NetBSD: strptime.c,v 1.50 2015/10/29 17:54:49 christos Exp $");
#endif
#include "namespace.h"
@@ -114,6 +114,34 @@
(isleap(yr) ? 6 : 0) + 1) % 7;
}
+#define delim(p) ((p) == '\0' || isspace((unsigned char)(p)))
+
+static int
+fromzone(const unsigned char **bp, struct tm *tm)
+{
+ timezone_t tz;
+ char buf[512], *p;
+
+ for (p = buf; !delim(**bp) && p < &buf[sizeof(buf) - 1]; (*bp)++)
+ *p++ = **bp;
+ *p = '\0';
+
+ tz = tzalloc(buf);
+ if (tz == NULL)
+ return 0;
+
+ tm->tm_isdst = 0; /* XXX */
+#ifdef TM_GMTOFF
+ tm->TM_GMTOFF = tzgetgmtoff(tz, tm->tm_isdst);
+#endif
+#ifdef TM_ZONE
+ // Can't use tzgetname() here because we are going to free()
+ tm->TM_ZONE = utc; /* XXX */
+#endif
+ tzfree(tz);
+ return 1;
+}
+
char *
strptime(const char *buf, const char *fmt, struct tm *tm)
{
@@ -124,7 +152,7 @@
strptime_l(const char *buf, const char *fmt, struct tm *tm, locale_t loc)
{
unsigned char c;
- const unsigned char *bp, *ep;
+ const unsigned char *bp, *ep, *zname;
int alt_format, i, split_year = 0, neg = 0, state = 0,
day_offset = -1, week_offset = 0, offs;
const char *new_fmt;
@@ -439,13 +467,18 @@
if (ep != NULL) {
tm->tm_isdst = i;
#ifdef TM_GMTOFF
- tm->TM_GMTOFF = -(timezone);
+#ifdef USG_COMPAT
+ tm->TM_GMTOFF = -timezone;
+#else
+ tm->TM_GMTOFF = -timezone();
+#endif
#endif
#ifdef TM_ZONE
tm->TM_ZONE = tzname[i];
+ bp = ep;
#endif
- }
- bp = ep;
+ } else
+ (void)fromzone(&bp, tm);
}
continue;
@@ -470,16 +503,21 @@
while (isspace(*bp))
bp++;
+ zname = bp;
switch (*bp++) {
case 'G':
if (*bp++ != 'M')
- return NULL;
+ goto namedzone;
/*FALLTHROUGH*/
case 'U':
if (*bp++ != 'T')
- return NULL;
+ goto namedzone;
+ else if (!delim(*bp) && *bp++ != 'C')
+ goto namedzone;
/*FALLTHROUGH*/
case 'Z':
+ if (!delim(*bp))
+ goto namedzone;
tm->tm_isdst = 0;
#ifdef TM_GMTOFF
tm->TM_GMTOFF = 0;
@@ -495,11 +533,42 @@
neg = 1;
break;
default:
- --bp;
+namedzone:
+ bp = zname;
+
+ /* Military style */
+ if (delim(bp[1]) &&
+ ((*bp >= 'A' && *bp <= 'I') ||
+ (*bp >= 'L' && *bp <= 'Y'))) {
+#ifdef TM_GMTOFF
+ /* Argh! No 'J'! */
+ if (*bp >= 'A' && *bp <= 'I')
+ tm->TM_GMTOFF =
+ ('A' - 1) - (int)*bp;
+ else if (*bp >= 'L' && *bp <= 'M')
+ tm->TM_GMTOFF = 'A' - (int)*bp;
+ else if (*bp >= 'N' && *bp <= 'Y')
+ tm->TM_GMTOFF = (int)*bp - 'M';
+ tm->TM_GMTOFF *= 3600;
+#endif
+#ifdef TM_ZONE
+ tm->TM_ZONE = utc; /* XXX */
+#endif
+ bp++;
+ continue;
+ }
+
+ /*
+ * From our 3 letter hard-coded table
+ * XXX: Can be removed, handled by tzload()
+ */
+ if (delim(bp[0]) || delim(bp[1]) ||
+ delim(bp[2]) || !delim(bp[3]))
+ goto loadzone;
ep = find_string(bp, &i, nast, NULL, 4);
if (ep != NULL) {
#ifdef TM_GMTOFF
- tm->TM_GMTOFF = -5 - i;
+ tm->TM_GMTOFF = (-5 - i) * 3600;
#endif
#ifdef TM_ZONE
tm->TM_ZONE = __UNCONST(nast[i]);
@@ -511,7 +580,7 @@
if (ep != NULL) {
tm->tm_isdst = 1;
#ifdef TM_GMTOFF
- tm->TM_GMTOFF = -4 - i;
+ tm->TM_GMTOFF = (-4 - i) * 3600;
#endif
#ifdef TM_ZONE
tm->TM_ZONE = __UNCONST(nadt[i]);
@@ -520,24 +589,12 @@
continue;
}
- if ((*bp >= 'A' && *bp <= 'I') ||
- (*bp >= 'L' && *bp <= 'Y')) {
-#ifdef TM_GMTOFF
- /* Argh! No 'J'! */
- if (*bp >= 'A' && *bp <= 'I')
- tm->TM_GMTOFF =
- ('A' - 1) - (int)*bp;
- else if (*bp >= 'L' && *bp <= 'M')
- tm->TM_GMTOFF = 'A' - (int)*bp;
- else if (*bp >= 'N' && *bp <= 'Y')
- tm->TM_GMTOFF = (int)*bp - 'M';
-#endif
-#ifdef TM_ZONE
- tm->TM_ZONE = utc; /* XXX */
-#endif
- bp++;
+loadzone:
+ /*
+ * The hard way, load the zone!
+ */
Home |
Main Index |
Thread Index |
Old Index