Formerly ../time/tzfile.c.~14~
[kopensolaris-gnu/glibc.git] / time / tzfile.c
index 2f4a51b..c3889cf 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991 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;
@@ -108,27 +114,32 @@ DEFUN(__tzfile_read, (file), CONST char *file)
   num_types = (size_t) uc2ul(tzhead.tzh_typecnt);
   chars = (size_t) uc2ul(tzhead.tzh_charcnt);
   num_leaps = (size_t) uc2ul(tzhead.tzh_leapcnt);
-#if 0
   num_isstd = (size_t) uc2ul(tzhead.tzh_ttisstdcnt);
-#else
-  num_isstd = 0;
-#endif
 
-  transitions = (time_t *) malloc(num_transitions * sizeof(time_t));
-  if (transitions == NULL)
-    goto lose;
-  type_idxs = (unsigned char *) malloc(num_transitions);
-  if (type_idxs == NULL)
-    goto lose;
-  types = (struct ttinfo *) malloc(num_types * sizeof(struct ttinfo));
-  if (types == NULL)
-    goto lose;
-  zone_names = (char *) malloc(chars);
-  if (zone_names == NULL)
-    goto lose;
-  if (num_leaps != 0)
+  if (num_transitions > 0)
+    {
+      transitions = (time_t *) malloc (num_transitions * sizeof(time_t));
+      if (transitions == NULL)
+       goto lose;
+      type_idxs = (unsigned char *) malloc (num_transitions);
+      if (type_idxs == NULL)
+       goto lose;
+    }
+  if (num_types > 0)
+    {
+      types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
+      if (types == NULL)
+       goto lose;
+    }
+  if (chars > 0)
     {
-      leaps = (struct leap *) malloc(num_leaps * sizeof(struct leap));
+      zone_names = (char *) malloc (chars);
+      if (zone_names == NULL)
+       goto lose;
+    }
+  if (num_leaps > 0)
+    {
+      leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
       if (leaps == NULL)
        goto lose;
     }
@@ -138,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];
@@ -179,33 +193,115 @@ 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;
 
-  i = 0;
-  while (i < num_transitions &&
-        (timer >= transitions[i] && timer < transitions[i + 1]))
-    ++i;
-  if (i == num_transitions)
-    i = 0;
+  if (num_transitions == 0 || timer < transitions[0])
+    {
+      /* TIMER is before any transition (or there are no transitions).
+        Choose the first non-DST type
+        (or the first if they're all DST types).  */
+      i = 0;
+      while (i < num_types && types[i].isdst)
+       ++i;
+      if (i == num_types)
+       i = 0;
+    }
+  else
+    {
+      /* 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]];
-  __daylight = info->isdst != 0;
+  info = &types[i];
+  __daylight = info->isdst;
   __timezone = info->offset;
-  __tzname[0] = &zone_names[types[0].idx];
-  if (num_types > 0)
-    __tzname[1] = &zone_names[types[1].idx];
+  for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
+       ++i)
+    __tzname[types[i].isdst] = &zone_names[types[i].idx];
+  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;
 }