about summary refs log tree commit diff
path: root/time
diff options
context:
space:
mode:
Diffstat (limited to 'time')
-rw-r--r--time/Makefile5
-rw-r--r--time/strptime_l.c11
-rw-r--r--time/tst-strptime3.c55
-rw-r--r--time/tzfile.c114
4 files changed, 88 insertions, 97 deletions
diff --git a/time/Makefile b/time/Makefile
index 8ce34e4565..d93b84bb2f 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+# Copyright (C) 1991-2003, 2004, 2005 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -35,8 +35,7 @@ distribute := datemsk
 
 tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
 	   tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
-	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
-	   tst-strptime3
+	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1
 
 include ../Rules
 
diff --git a/time/strptime_l.c b/time/strptime_l.c
index 443a6fa88e..dc0cc686fd 100644
--- a/time/strptime_l.c
+++ b/time/strptime_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -400,7 +400,6 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
 	    /* Does not match a month name.  */
 	    return NULL;
 	  tm->tm_mon = cnt;
-	  have_mon = 1;
 	  want_xday = 1;
 	  break;
 	case 'c':
@@ -1086,15 +1085,11 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
 	      tm->tm_mday =
 		(tm->tm_yday
 		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
-	  have_mon = 1;
-	  have_mday = 1;
 	}
-      /* Don't crash in day_of_the_week if tm_mon is uninitialized.  */
-      if (have_mon || (unsigned) tm->tm_mon <= 11)
-	day_of_the_week (tm);
+      day_of_the_week (tm);
     }
 
-  if (want_xday && !have_yday && (have_mon || (unsigned) tm->tm_mon <= 11))
+  if (want_xday && !have_yday)
     day_of_the_year (tm);
 
   if ((have_uweek || have_wweek) && have_wday)
diff --git a/time/tst-strptime3.c b/time/tst-strptime3.c
deleted file mode 100644
index 9a8c6485e7..0000000000
--- a/time/tst-strptime3.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-
-int
-main (void)
-{
-  int result = 0;
-  struct tm tm;
-
-  memset (&tm, 0xaa, sizeof (tm));
-
-  /* Test we don't crash on uninitialized struct tm.
-     Some fields might contain bogus values until everything
-     needed is initialized, but we shouldn't crash.  */
-  if (strptime ("2007", "%Y", &tm) == NULL
-      || strptime ("12", "%d", &tm) == NULL
-      || strptime ("Feb", "%b", &tm) == NULL
-      || strptime ("13", "%M", &tm) == NULL
-      || strptime ("21", "%S", &tm) == NULL
-      || strptime ("16", "%H", &tm) == NULL)
-    {
-      puts ("strptimes failed");
-      result = 1;
-    }
-
-  if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
-      || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
-      || tm.tm_wday != 1 || tm.tm_yday != 42)
-    {
-      puts ("unexpected tm content");
-      result = 1;
-    }
-
-  if (strptime ("8", "%d", &tm) == NULL)
-    {
-      puts ("strptime failed");
-      result = 1;
-    }
-
-  if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
-      || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
-      || tm.tm_wday != 4 || tm.tm_yday != 38)
-    {
-      puts ("unexpected tm content");
-      result = 1;
-    }
-
-  if (result == 0)
-    puts ("all OK");
-
-  return 0;
-}
diff --git a/time/tzfile.c b/time/tzfile.c
index e95fd55f36..ea2d7cae4c 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-1993,1995-2001,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1993,1995-2001,2003,2004,2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -71,24 +72,34 @@ static inline int
 __attribute ((always_inline))
 decode (const void *ptr)
 {
-  if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
+  if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
     return *(const int *) ptr;
-  else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
+  if (sizeof (int) == 4)
     return bswap_32 (*(const int *) ptr);
-  else
-    {
-      const unsigned char *p = ptr;
-      int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
 
-      result = (result << 8) | *p++;
-      result = (result << 8) | *p++;
-      result = (result << 8) | *p++;
-      result = (result << 8) | *p++;
+  const unsigned char *p = ptr;
+  int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
 
-      return result;
-    }
+  result = (result << 8) | *p++;
+  result = (result << 8) | *p++;
+  result = (result << 8) | *p++;
+  result = (result << 8) | *p++;
+
+  return result;
 }
 
+
+static inline int64_t
+__attribute ((always_inline))
+decode64 (const void *ptr)
+{
+  if ((BYTE_ORDER == BIG_ENDIAN))
+    return *(const int64_t *) ptr;
+
+  return bswap_64 (*(const int64_t *) ptr);
+}
+
+
 void
 __tzfile_read (const char *file, size_t extra, char **extrap)
 {
@@ -102,6 +113,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   size_t types_idx;
   size_t leaps_idx;
   int was_using_tzfile = __use_tzfile;
+  int trans_width = 4;
+
+  if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
+    abort ();
 
   __use_tzfile = 0;
 
@@ -185,8 +200,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   /* No threads reading this stream.  */
   __fsetlocking (f, FSETLOCKING_BYCALLER);
 
+ read_again:
   if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
-					1, f) != 1, 0))
+					1, f) != 1, 0)
+      || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
     goto lose;
 
   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
@@ -196,6 +213,26 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
 
+  /* For platforms with 64-bit time_t we use the new format if available.  */
+  if (sizeof (time_t) == 8 && trans_width == 4
+      && tzhead.tzh_version[0] != '\0')
+    {
+      /* We use the 8-byte format.  */
+      trans_width = 8;
+
+      /* Position the stream before the second header.  */
+      size_t to_skip = (num_transitions * (4 + 1)
+			+ num_types * 6
+			+ chars
+			+ num_leaps * 8
+			+ num_isstd
+			+ num_isgmt);
+      if (fseek (f, to_skip, SEEK_CUR) != 0)
+	goto lose;
+
+      goto read_again;
+    }
+
   total_size = num_transitions * (sizeof (time_t) + 1);
   total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
 		& ~(__alignof__ (struct ttinfo) - 1));
@@ -205,10 +242,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
 		& ~(__alignof__ (struct leap) - 1));
   leaps_idx = total_size;
   total_size += num_leaps * sizeof (struct leap);
-  /* This is for the extra memory required by the caller.  */
-  total_size += extra;
 
-  transitions = (time_t *) malloc (total_size);
+  /* Allocate enough memory including the extra block requested by the
+     caller.  */
+  transitions = (time_t *) malloc (total_size + extra);
   if (transitions == NULL)
     goto lose;
 
@@ -220,14 +257,11 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   if (extra > 0)
     *extrap = (char *) &leaps[num_leaps];
 
-  if (sizeof (time_t) < 4)
-    abort ();
-
-  if (sizeof (time_t) == 4)
+  if (sizeof (time_t) == 4 || trans_width == 8)
     {
-      if (__builtin_expect (fread_unlocked (transitions, 1,
-					    (4 + 1) * num_transitions, f)
-			    != (4 + 1) * num_transitions, 0))
+      if (__builtin_expect (fread_unlocked (transitions, trans_width + 1,
+					    num_transitions, f)
+			    != num_transitions, 0))
 	goto lose;
     }
   else
@@ -245,7 +279,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
     if (__builtin_expect (type_idxs[i] >= num_types, 0))
       goto lose;
 
-  if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
+  if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4))
+      || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8
+	  && trans_width == 4))
     {
       /* Decode the transition times, stored as 4-byte integers in
 	 network (big-endian) byte order.  We work from the end of
@@ -255,6 +291,13 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
       while (i-- > 0)
 	transitions[i] = decode ((char *) transitions + i * 4);
     }
+  else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
+    {
+      /* Decode the transition times, stored as 8-byte integers in
+	 network (big-endian) byte order.  */
+      for (i = 0; i < num_transitions; ++i)
+	transitions[i] = decode64 ((char *) transitions + i * 8);
+    }
 
   for (i = 0; i < num_types; ++i)
     {
@@ -280,13 +323,16 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
 
   for (i = 0; i < num_leaps; ++i)
     {
-      unsigned char x[4];
-      if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
-			    0))
+      unsigned char x[8];
+      if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
+			    != trans_width, 0))
 	goto lose;
-      leaps[i].transition = (time_t) decode (x);
-      if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
-			    0))
+      if (sizeof (time_t) == 4 || trans_width == 4)
+	leaps[i].transition = (time_t) decode (x);
+      else
+	leaps[i].transition = (time_t) decode64 (x);
+
+      if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
 	goto lose;
       leaps[i].change = (long int) decode (x);
     }
@@ -311,6 +357,12 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   while (i < num_types)
     types[i++].isgmt = 0;
 
+  /* XXX When a version 2 file is available it can contain a POSIX TZ-style
+     formatted string which specifies how times past the last one specified
+     are supposed to be handled.  We might want to handle this at some
+     point.  But it might be overhead since most/all? files have an
+     open-ended last entry.  */
+
   fclose (f);
 
   /* First "register" all timezone names.  */