about summary refs log tree commit diff
path: root/time/mktime.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
committerJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
commit0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch)
tree2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /time/mktime.c
parent7d58530341304d403a6626d7f7a1913165fe2f32 (diff)
downloadglibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz
glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.xz
glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.zip
2.5-18.1
Diffstat (limited to 'time/mktime.c')
-rw-r--r--time/mktime.c73
1 files changed, 48 insertions, 25 deletions
diff --git a/time/mktime.c b/time/mktime.c
index c6ae56ee60..8f00c72e09 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -1,7 +1,7 @@
 /* Convert a `struct tm' to a time_t value.
-   Copyright (C) 1993-1999, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1993-1999, 2002-2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Paul Eggert (eggert@twinsun.com).
+   Contributed by Paul Eggert <eggert@twinsun.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -38,10 +38,11 @@
 
 #include <limits.h>
 
+#include <string.h>		/* For the real memcpy prototype.  */
+
 #if DEBUG
 # include <stdio.h>
 # include <stdlib.h>
-# include <string.h>
 /* Make it work even if the system's libc has its own mktime routine.  */
 # define mktime my_mktime
 #endif /* DEBUG */
@@ -61,13 +62,38 @@
    ? (a) >> (b)		\
    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
 
-/* The extra casts work around common compiler bugs.  */
+/* The extra casts in the following macros work around compiler bugs,
+   e.g., in Cray C 5.0.3.0.  */
+
+/* True if the arithmetic type T is an integer type.  bool counts as
+   an integer.  */
+#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
+
+/* True if negative values of the signed integer type T use two's
+   complement, ones' complement, or signed magnitude representation,
+   respectively.  Much GNU code assumes two's complement, but some
+   people like to be portable to all possible C hosts.  */
+#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
+#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
+#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
+
+/* True if the arithmetic type T is signed.  */
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
-   It is necessary at least when t == time_t.  */
-#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
-			      ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
-#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+
+/* The maximum and minimum values for the integer type T.  These
+   macros have undefined behavior if T is signed and has padding bits.
+   If this is a problem for you, please let us know how to fix it for
+   your host.  */
+#define TYPE_MINIMUM(t) \
+  ((t) (! TYPE_SIGNED (t) \
+	? (t) 0 \
+	: TYPE_SIGNED_MAGNITUDE (t) \
+	? ~ (t) 0 \
+	: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+#define TYPE_MAXIMUM(t) \
+  ((t) (! TYPE_SIGNED (t) \
+	? (t) -1 \
+	: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
 
 #ifndef TIME_T_MIN
 # define TIME_T_MIN TYPE_MINIMUM (time_t)
@@ -80,8 +106,8 @@
 /* Verify a requirement at compile-time (unlike assert, which is runtime).  */
 #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
 
-verify (time_t_is_integer, (time_t) 0.5 == 0);
-verify (twos_complement_arithmetic, -1 == ~1 + 1);
+verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
+verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
 /* The code also assumes that signed integer overflow silently wraps
    around, but this assumption can't be stated without causing a
    diagnostic on some hosts.  */
@@ -190,10 +216,11 @@ guess_time_tm (long int year, long int yday, int hour, int min, int sec,
   /* Overflow occurred one way or another.  Return the nearest result
      that is actually in range, except don't report a zero difference
      if the actual difference is nonzero, as that would cause a false
-     match.  */
+     match; and don't oscillate between two values, as that would
+     confuse the spring-forward gap detector.  */
   return (*t < TIME_T_MIDPOINT
-	  ? TIME_T_MIN + (*t == TIME_T_MIN)
-	  : TIME_T_MAX - (*t == TIME_T_MAX));
+	  ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
+	  : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
 }
 
 /* Use CONVERT to convert *T to a broken down time in *TP.
@@ -203,13 +230,12 @@ static struct tm *
 ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
 		time_t *t, struct tm *tp)
 {
-  struct tm *r;
+  struct tm *r = convert (t, tp);
 
-  if (! (r = (*convert) (t, tp)) && *t)
+  if (!r && *t)
     {
       time_t bad = *t;
       time_t ok = 0;
-      struct tm tm;
 
       /* BAD is a known unconvertible time_t, and OK is a known good one.
 	 Use binary search to narrow the range between BAD and OK until
@@ -219,11 +245,9 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
 	  time_t mid = *t = (bad < 0
 			     ? bad + ((ok - bad) >> 1)
 			     : ok + ((bad - ok) >> 1));
-	  if ((r = (*convert) (t, tp)))
-	    {
-	      tm = *r;
-	      ok = mid;
-	    }
+	  r = convert (t, tp);
+	  if (r)
+	    ok = mid;
 	  else
 	    bad = mid;
 	}
@@ -233,8 +257,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
 	  /* The last conversion attempt failed;
 	     revert to the most recent successful attempt.  */
 	  *t = ok;
-	  *tp = tm;
-	  r = tp;
+	  r = convert (t, tp);
 	}
     }
 
@@ -463,7 +486,7 @@ __mktime_internal (struct tm *tp,
       t2 = t1 + sec_adjustment;
       if (((t1 < t) != (sec_requested < 0))
 	  | ((t2 < t1) != (sec_adjustment < 0))
-	  | ! (*convert) (&t2, &tm))
+	  | ! convert (&t2, &tm))
 	return -1;
       t = t2;
     }