Formerly ../time/tzfile.c.~14~
[kopensolaris-gnu/glibc.git] / time / tzfile.c
index d6c49e7..c3889cf 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993 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
@@ -26,6 +26,12 @@ Cambridge, MA 02139, USA.  */
 #define        NOID
 #include <tzfile.h>
 
+#ifndef        HAVE_GNU_LD
+#define        __tzname        tzname
+#define        __daylight      daylight
+#define        __timezone      timezone
+#endif
+
 int __use_tzfile = 0;
 
 struct ttinfo
@@ -33,13 +39,13 @@ struct ttinfo
     long int offset;           /* Seconds east of GMT.  */
     unsigned char isdst;       /* Used to set tm_isdst.  */
     unsigned char idx;         /* Index into `zone_names'.  */
-    unsigned int isstd:1;      /* Transition times are standard time.  */
+    unsigned char isstd;       /* Transition times are standard time.  */
   };
 
 struct leap
   {
-    time_t transition;
-    long int change;
+    time_t transition;         /* Time the transition takes effect.  */
+    long int change;           /* Seconds of correction to apply.  */
   };
 
 static size_t num_transitions;
@@ -143,6 +149,9 @@ DEFUN(__tzfile_read, (file), CONST char *file)
       fread((PTR) type_idxs, 1, num_transitions, f) != num_transitions)
     goto lose;
 
+  for (i = 0; i < num_transitions; ++i)
+    transitions[i] = uc2ul (&transitions[i]);
+
   for (i = 0; i < num_types; ++i)
     {
       unsigned char x[4];
@@ -184,10 +193,55 @@ DEFUN(__tzfile_read, (file), CONST char *file)
  lose:;
   (void) fclose(f);
 }
+\f
+void
+DEFUN(__tzfile_default, (std, dst, stdoff, dstoff),
+      char *std AND char *dst AND
+      long int stdoff AND long int dstoff)
+{
+  size_t stdlen, dstlen, i;
 
+  __tzfile_read (TZDEFRULES);
+  if (!__use_tzfile)
+    return;
 
+  if (num_types < 2)
+    {
+      __use_tzfile = 0;
+      return;
+    }
+
+  free (zone_names);
+
+  stdlen = strlen (std) + 1;
+  dstlen = strlen (dst) + 1;
+  zone_names = malloc (stdlen + dstlen);
+  if (zone_names == NULL)
+    {
+      __use_tzfile = 0;
+      return;
+    }
+  memcpy (zone_names, std, stdlen);
+  memcpy (&zone_names[stdlen], dst, dstlen);
+
+  for (i = 0; i < num_types; ++i)
+    if (types[i].isdst)
+      {
+       types[i].idx = stdlen;
+       if (dst[0] != '\0')
+         types[i].offset = dstoff;
+      }
+    else
+      {
+       types[i].idx = 0;
+       if (dst[0] != '\0')
+         types[i].offset = stdoff;
+      }
+}
+\f
 int
-DEFUN(__tzfile_compute, (timer, tm), time_t timer AND struct tm tm)
+DEFUN(__tzfile_compute, (timer, leap_correct, leap_hit),
+      time_t timer AND long int *leap_correct AND int *leap_hit)
 {
   struct ttinfo *info;
   register size_t i;
@@ -205,14 +259,15 @@ DEFUN(__tzfile_compute, (timer, tm), time_t timer AND struct tm tm)
     }
   else
     {
-      /* Find the first transition after TIMER, and then go back one.  */
-      i = 1;
-      while (i < num_transitions && transitions[i] < timer)
-       ++i;
-      --i;
+      /* Find the first transition after TIMER, and
+        then pick the type of the transition before it.  */
+      for (i = 1; i < num_transitions; ++i)
+       if (timer < transitions[i])
+         break;
+      i = type_idxs[i - 1];
     }
 
-  info = &types[type_idxs[i]];
+  info = &types[i];
   __daylight = info->isdst;
   __timezone = info->offset;
   for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
@@ -221,11 +276,32 @@ DEFUN(__tzfile_compute, (timer, tm), time_t timer AND struct tm tm)
   if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
     __tzname[info->isdst] = &zone_names[info->idx];
 
+  *leap_correct = 0L;
+  *leap_hit = 0;
+
+  /* Find the last leap second correction transition time before TIMER.  */
   i = num_leaps;
   do
     if (i-- == 0)
       return 1;
   while (timer < leaps[i].transition);
-  __timezone += leaps[i].change;
+
+  /* Apply its correction.  */
+  *leap_correct = leaps[i].change;
+
+  if (timer == leaps[i].transition && /* Exactly at the transition time.  */
+      ((i == 0 && leaps[i].change > 0) ||
+       leaps[i].change > leaps[i - 1].change))
+    {
+      *leap_hit = 1;
+      while (i > 0 &&
+            leaps[i].transition == leaps[i - 1].transition + 1 &&
+            leaps[i].change == leaps[i - 1].change + 1)
+       {
+         ++*leap_hit;
+         --i;
+       }
+    }
+
   return 1;
 }