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