about summary refs log tree commit diff
path: root/time/tzset.c
diff options
context:
space:
mode:
Diffstat (limited to 'time/tzset.c')
-rw-r--r--time/tzset.c109
1 files changed, 89 insertions, 20 deletions
diff --git a/time/tzset.c b/time/tzset.c
index 49935c04d3..6c16091ef5 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -17,6 +17,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <ctype.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -26,15 +28,19 @@
 /* Defined in mktime.c.  */
 extern const unsigned short int __mon_yday[2][13];
 
+/* Defined in localtime.c.  */
+extern struct tm _tmbuf;
+
 #define NOID
 #include "tzfile.h"
 
 extern int __use_tzfile;
 extern void __tzfile_read __P ((const char *file));
+extern int __tzfile_compute __P ((time_t timer, int use_localtime,
+				  long int *leap_correct, int *leap_hit));
 extern void __tzfile_default __P ((const char *std, const char *dst,
 				   long int stdoff, long int dstoff));
 extern char * __tzstring __P ((const char *string));
-extern int __tz_compute __P ((time_t timer, const struct tm *tm));
 
 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
 int __daylight = 0;
@@ -44,6 +50,9 @@ weak_alias (__tzname, tzname)
 weak_alias (__daylight, daylight)
 weak_alias (__timezone, timezone)
 
+/* This locks all the state variables in tzfile.c and this file.  */
+__libc_lock_define (static, tzset_lock)
+
 
 #define	min(a, b)	((a) < (b) ? (a) : (b))
 #define	max(a, b)	((a) > (b) ? (a) : (b))
@@ -74,6 +83,8 @@ static tz_rule tz_rules[2];
 
 
 static int compute_change __P ((tz_rule *rule, int year));
+static int tz_compute __P ((time_t timer, const struct tm *tm));
+static void tzset_internal __P ((int always));
 
 /* Header for a list of buffers containing time zone strings.  */
 struct tzstring_head
@@ -139,9 +150,8 @@ __tzstring (string)
 static char *old_tz = NULL;
 
 /* Interpret the TZ envariable.  */
-void __tzset_internal __P ((int always));
-void
-__tzset_internal (always)
+static void
+tzset_internal (always)
      int always;
 {
   static int is_initialized = 0;
@@ -426,7 +436,11 @@ size_t __tzname_cur_max;
 long int
 __tzname_max ()
 {
-  __tzset_internal (0);
+  __libc_lock_lock (tzset_lock);
+
+  tzset_internal (0);
+
+  __libc_lock_unlock (tzset_lock);
 
   return __tzname_cur_max;
 }
@@ -473,8 +487,9 @@ compute_change (rule, year)
     case M:
       /* Mm.n.d - Nth "Dth day" of month M.  */
       {
-	register int i, d, m1, yy0, yy1, yy2, dow;
-	register const unsigned short int *myday =
+	unsigned int i;
+	int d, m1, yy0, yy1, yy2, dow;
+	const unsigned short int *myday =
 	  &__mon_yday[__isleap (year)][rule->m];
 
 	/* First add SECSPERDAY for each day in months before M.  */
@@ -496,7 +511,7 @@ compute_change (rule, year)
 	  d += 7;
 	for (i = 1; i < rule->n; ++i)
 	  {
-	    if (d + 7 >= myday[0] - myday[-1])
+	    if (d + 7 >= (int) myday[0] - myday[-1])
 	      break;
 	    d += 7;
 	  }
@@ -519,13 +534,11 @@ compute_change (rule, year)
 /* Figure out the correct timezone for *TIMER and TM (which must be the same)
    and set `__tzname', `__timezone', and `__daylight' accordingly.
    Return nonzero on success, zero on failure.  */
-int
-__tz_compute (timer, tm)
+static int
+tz_compute (timer, tm)
      time_t timer;
      const struct tm *tm;
 {
-  __tzset_internal (0);
-
   if (! compute_change (&tz_rules[0], 1900 + tm->tm_year) ||
       ! compute_change (&tz_rules[1], 1900 + tm->tm_year))
     return 0;
@@ -548,20 +561,15 @@ __tz_compute (timer, tm)
   return 1;
 }
 
-#include <bits/libc-lock.h>
-
-/* This locks all the state variables in tzfile.c and this file.  */
-__libc_lock_define (, __tzset_lock)
-
 /* Reinterpret the TZ environment variable and set `tzname'.  */
 #undef tzset
 
 void
 __tzset (void)
 {
-  __libc_lock_lock (__tzset_lock);
+  __libc_lock_lock (tzset_lock);
 
-  __tzset_internal (1);
+  tzset_internal (1);
 
   if (!__use_tzfile)
     {
@@ -570,6 +578,67 @@ __tzset (void)
       __tzname[1] = (char *) tz_rules[1].name;
     }
 
-  __libc_lock_unlock (__tzset_lock);
+  __libc_lock_unlock (tzset_lock);
 }
 weak_alias (__tzset, tzset)
+
+/* Return the `struct tm' representation of *TIMER in the local timezone.
+   Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
+struct tm *
+__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
+{
+  long int leap_correction;
+  int leap_extra_secs;
+
+  if (timer == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  __libc_lock_lock (tzset_lock);
+
+  /* Update internal database according to current TZ setting.
+     POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
+     This is a good idea since this allows at least a bit more parallelism.
+     By analogy we apply the same rule to gmtime_r.  */
+  tzset_internal (tp == &_tmbuf);
+
+  if (__use_tzfile)
+    {
+      if (! __tzfile_compute (*timer, use_localtime,
+			      &leap_correction, &leap_extra_secs))
+	tp = NULL;
+    }
+  else
+    {
+      __offtime (timer, 0, tp);
+      if (! tz_compute (*timer, tp))
+	tp = NULL;
+      leap_correction = 0L;
+      leap_extra_secs = 0;
+    }
+
+  if (tp)
+    {
+      if (use_localtime)
+	{
+	  tp->tm_isdst = __daylight;
+	  tp->tm_zone = __tzname[__daylight];
+	  tp->tm_gmtoff = __timezone;
+	}
+      else
+	{
+	  tp->tm_isdst = 0;
+	  tp->tm_zone = "GMT";
+	  tp->tm_gmtoff = 0L;
+	}
+
+      __offtime (timer, tp->tm_gmtoff - leap_correction, tp);
+      tp->tm_sec += leap_extra_secs;
+    }
+
+  __libc_lock_unlock (tzset_lock);
+
+  return tp;
+}