summaryrefslogtreecommitdiff
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;
+}