Don't override previously installed signal handlers.
[gnulib.git] / lib / mktime.c
index fa65e01..f9e7b60 100644 (file)
@@ -1,8 +1,7 @@
 /* Convert a `struct tm' to a time_t value.
-   Copyright (C) 1993-1999, 2002, 2003, 2004, 2005 Free Software Foundation,
-   Inc.
+   Copyright (C) 1993-1999, 2002-2005, 2006, 2007 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>.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
 
 /* Define this to have a standalone program to test this implementation of
    mktime.  */
 /* #define DEBUG 1 */
 
-#ifdef HAVE_CONFIG_H
+#ifndef _LIBC
 # include <config.h>
 #endif
 
 # define LEAP_SECONDS_POSSIBLE 1
 #endif
 
-#include <sys/types.h>         /* Some systems define `time_t' here.  */
 #include <time.h>
 
 #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 */
@@ -141,11 +140,10 @@ const unsigned short int __mon_yday[2][13] =
 
 
 #ifndef _LIBC
-/* Portable standalone applications should supply a "time_r.h" that
+/* Portable standalone applications should supply a <time.h> that
    declares a POSIX-compliant localtime_r, for the benefit of older
    implementations that lack localtime_r or have a nonstandard one.
    See the gnulib time_r module for one way to implement this.  */
-# include "time_r.h"
 # undef __localtime_r
 # define __localtime_r localtime_r
 # define __mktime_internal mktime_internal
@@ -215,10 +213,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.
@@ -228,13 +227,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
@@ -244,11 +242,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;
        }
@@ -258,8 +254,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);
        }
     }
 
@@ -295,7 +290,9 @@ __mktime_internal (struct tm *tp,
   int mday = tp->tm_mday;
   int mon = tp->tm_mon;
   int year_requested = tp->tm_year;
-  int isdst = tp->tm_isdst;
+  /* Normalize the value.  */
+  int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1))
+              | (tp->tm_isdst != 0));
 
   /* 1 if the previous probe was DST.  */
   int dst2;
@@ -488,7 +485,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;
     }