aboutsummaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-10-14 09:15:45 +0000
committerUlrich Drepper <drepper@redhat.com>2007-10-14 09:15:45 +0000
commitfa76dde2cf59865481793b9f233df74aa5c7d4c1 (patch)
tree909e9a417ad03e800b5be3a11a2a59e571b5722d /time
parent89dc9d4c5b50c4e6397d0d74d0570e88f09fca99 (diff)
downloadglibc-fa76dde2cf59865481793b9f233df74aa5c7d4c1.tar
glibc-fa76dde2cf59865481793b9f233df74aa5c7d4c1.tar.gz
glibc-fa76dde2cf59865481793b9f233df74aa5c7d4c1.tar.bz2
glibc-fa76dde2cf59865481793b9f233df74aa5c7d4c1.zip
* include/time.h: Declare __tzset_parse_tz and __tzset_compute.
* time/tzset.c (tzset_internal): Break TZ string parsing out into __tzset_parse_tz and updating of daylight, timezone, tzname into update_vars. (__tz_compute): Renamed from tz_compute. Take additional parameters. (__tz_convert): Updating of tm_isdst, tm_zone, and tm_gmtoff now happens in __tz_compute. * time/tzfile.c (__tzfile_read): Also read TZ string. (find_transition): Fold into __tzfile_compute. (__tzfile_compute): For times beyond the last transition try to use the TZ string. * timezone/tst-timezone.c: Information in daylight and tzname does change for Asia/Tokyo timezone with more concrete information. Remove the test. * include/stdio.h: Add libc_hidden_proto for ftello. * libio/ftello.c: Add libc_hidden_def.
Diffstat (limited to 'time')
-rw-r--r--time/tzfile.c259
-rw-r--r--time/tzset.c230
2 files changed, 266 insertions, 223 deletions
diff --git a/time/tzfile.c b/time/tzfile.c
index a872e283a2..44d6614771 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -62,6 +62,7 @@ static long int rule_stdoff;
static long int rule_dstoff;
static size_t num_leaps;
static struct leap *leaps;
+static char *tzspec;
#include <endian.h>
#include <byteswap.h>
@@ -113,6 +114,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
size_t leaps_idx;
int was_using_tzfile = __use_tzfile;
int trans_width = 4;
+ size_t tzspec_len;
if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
abort ();
@@ -241,10 +243,18 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
& ~(__alignof__ (struct leap) - 1));
leaps_idx = total_size;
total_size += num_leaps * sizeof (struct leap);
+ tzspec_len = (trans_width == 8
+ ? st.st_size - (ftello (f)
+ + num_transitions * (8 + 1)
+ + num_types * 6
+ + chars
+ + num_leaps * 8
+ + num_isstd
+ + num_isgmt) - 1 : 0);
/* Allocate enough memory including the extra block requested by the
caller. */
- transitions = (time_t *) malloc (total_size + extra);
+ transitions = (time_t *) malloc (total_size + tzspec_len + extra);
if (transitions == NULL)
goto lose;
@@ -253,6 +263,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
types = (struct ttinfo *) ((char *) transitions + types_idx);
zone_names = (char *) types + num_types * sizeof (struct ttinfo);
leaps = (struct leap *) ((char *) transitions + leaps_idx);
+ if (trans_width == 8)
+ tzspec = (char *) leaps + num_leaps * sizeof (struct leap);
+ else
+ tzspec = NULL;
if (extra > 0)
*extrap = (char *) &leaps[num_leaps];
@@ -356,11 +370,16 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
while (i < num_types)
types[i++].isgmt = 0;
- /* XXX When a version 2 file is available it can contain a POSIX TZ-style
- formatted string which specifies how times past the last one specified
- are supposed to be handled. We might want to handle this at some
- point. But it might be overhead since most/all? files have an
- open-ended last entry. */
+ /* Read the POSIX TZ-style information if possible. */
+ if (tzspec != NULL)
+ {
+ /* Skip over the newline first. */
+ if (getc_unlocked (f) != '\n'
+ || fread_unlocked (tzspec, 1, tzspec_len - 1, f) != tzspec_len - 1)
+ tzspec = NULL;
+ else
+ tzspec[tzspec_len - 1] = '\0';
+ }
fclose (f);
@@ -530,138 +549,148 @@ __tzfile_default (const char *std, const char *dst,
compute_tzname_max (stdlen + dstlen);
}
-static struct ttinfo *
-internal_function
-find_transition (time_t timer)
+void
+__tzfile_compute (time_t timer, int use_localtime,
+ long int *leap_correct, int *leap_hit,
+ struct tm *tp)
{
- size_t i;
-
- __tzname[0] = NULL;
- __tzname[1] = NULL;
+ register size_t i;
- if (num_transitions == 0 || timer < transitions[0])
+ if (use_localtime)
{
- /* 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)
+ __tzname[0] = NULL;
+ __tzname[1] = NULL;
+
+ if (num_transitions == 0 || timer < transitions[0])
{
- if (__tzname[1] == NULL)
- __tzname[1] = __tzstring (&zone_names[types[i].idx]);
+ /* 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)
+ {
+ if (__tzname[1] == NULL)
+ __tzname[1] = __tzstring (&zone_names[types[i].idx]);
- ++i;
- }
+ ++i;
+ }
- if (i == num_types)
- i = 0;
- __tzname[0] = __tzstring (&zone_names[types[i].idx]);
- if (__tzname[1] == NULL)
+ if (i == num_types)
+ i = 0;
+ __tzname[0] = __tzstring (&zone_names[types[i].idx]);
+ if (__tzname[1] == NULL)
+ {
+ size_t j = i;
+ while (j < num_types)
+ if (types[j].isdst)
+ {
+ __tzname[1] = __tzstring (&zone_names[types[j].idx]);
+ break;
+ }
+ else
+ ++j;
+ }
+ }
+ else if (timer >= transitions[num_transitions - 1])
{
- size_t j = i;
- while (j < num_types)
- if (types[j].isdst)
- {
- __tzname[1] = __tzstring (&zone_names[types[j].idx]);
- break;
- }
- else
- ++j;
+ if (tzspec == NULL)
+ {
+ use_last:
+ i = num_transitions - 1;
+ goto found;
+ }
+
+ /* Parse the POSIX TZ-style string. */
+ __tzset_parse_tz (tzspec);
+
+ /* Convert to broken down structure. If this fails do not
+ use the string. */
+ if (! __offtime (&timer, 0, tp))
+ goto use_last;
+
+ /* Use the rules from the TZ string to compute the change. */
+ __tz_compute (timer, tp, 1);
+
+ *leap_correct = 0L;
+ *leap_hit = 0;
+ return;
}
- }
- else if (timer >= transitions[num_transitions - 1])
- {
- i = num_transitions - 1;
- goto found;
- }
- else
- {
- /* Find the first transition after TIMER, and
- then pick the type of the transition before it. */
- size_t lo = 0;
- size_t hi = num_transitions - 1;
- /* Assume that DST is changing twice a year and guess initial
- search spot from it.
- Half of a gregorian year has on average 365.2425 * 86400 / 2
- = 15778476 seconds. */
- i = (transitions[num_transitions - 1] - timer) / 15778476;
- if (i < num_transitions)
+ else
{
- i = num_transitions - 1 - i;
- if (timer < transitions[i])
+ /* Find the first transition after TIMER, and
+ then pick the type of the transition before it. */
+ size_t lo = 0;
+ size_t hi = num_transitions - 1;
+ /* Assume that DST is changing twice a year and guess initial
+ search spot from it.
+ Half of a gregorian year has on average 365.2425 * 86400 / 2
+ = 15778476 seconds. */
+ i = (transitions[num_transitions - 1] - timer) / 15778476;
+ if (i < num_transitions)
{
- if (i < 10 || timer >= transitions[i - 10])
+ i = num_transitions - 1 - i;
+ if (timer < transitions[i])
{
- /* Linear search. */
- while (timer < transitions[i - 1])
- --i;
- goto found;
+ if (i < 10 || timer >= transitions[i - 10])
+ {
+ /* Linear search. */
+ while (timer < transitions[i - 1])
+ --i;
+ goto found;
+ }
+ hi = i - 10;
}
- hi = i - 10;
- }
- else
- {
- if (i + 10 >= num_transitions || timer < transitions[i + 10])
+ else
{
- /* Linear search. */
- while (timer >= transitions[i])
- ++i;
- goto found;
+ if (i + 10 >= num_transitions || timer < transitions[i + 10])
+ {
+ /* Linear search. */
+ while (timer >= transitions[i])
+ ++i;
+ goto found;
+ }
+ lo = i + 10;
}
- lo = i + 10;
}
- }
- /* Binary search. */
- /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
- while (lo + 1 < hi)
- {
- i = (lo + hi) / 2;
- if (timer < transitions[i])
- hi = i;
- else
- lo = i;
- }
- i = hi;
-
- found:
- /* assert (timer >= transitions[i - 1] && timer < transitions[i]); */
- __tzname[types[type_idxs[i - 1]].isdst]
- = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
- size_t j = i;
- while (j < num_transitions)
- {
- int type = type_idxs[j];
- int dst = types[type].isdst;
- int idx = types[type].idx;
+ /* Binary search. */
+ /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
+ while (lo + 1 < hi)
+ {
+ i = (lo + hi) / 2;
+ if (timer < transitions[i])
+ hi = i;
+ else
+ lo = i;
+ }
+ i = hi;
- if (__tzname[dst] == NULL)
+ found:
+ /* assert (timer >= transitions[i - 1] && timer < transitions[i]); */
+ __tzname[types[type_idxs[i - 1]].isdst]
+ = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
+ size_t j = i;
+ while (j < num_transitions)
{
- __tzname[dst] = __tzstring (&zone_names[idx]);
+ int type = type_idxs[j];
+ int dst = types[type].isdst;
+ int idx = types[type].idx;
- if (__tzname[1 - dst] != NULL)
- break;
- }
+ if (__tzname[dst] == NULL)
+ {
+ __tzname[dst] = __tzstring (&zone_names[idx]);
- ++j;
- }
+ if (__tzname[1 - dst] != NULL)
+ break;
+ }
- i = type_idxs[i - 1];
- }
+ ++j;
+ }
- return &types[i];
-}
-
-void
-__tzfile_compute (time_t timer, int use_localtime,
- long int *leap_correct, int *leap_hit,
- struct tm *tp)
-{
- register size_t i;
+ i = type_idxs[i - 1];
+ }
- if (use_localtime)
- {
- struct ttinfo *info = find_transition (timer);
+ struct ttinfo *info = &types[i];
__daylight = rule_stdoff != rule_dstoff;
__timezone = -rule_stdoff;
diff --git a/time/tzset.c b/time/tzset.c
index 0479abb38a..27efef0f7a 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2002,2003,2004,2007 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
@@ -70,7 +70,6 @@ static tz_rule tz_rules[2];
static void compute_change (tz_rule *rule, int year) __THROW internal_function;
-static void tz_compute (const struct tm *tm) __THROW internal_function;
static void tzset_internal (int always, int explicit)
__THROW internal_function;
@@ -92,7 +91,7 @@ __tzstring (const char *s)
{
char *p;
struct tzstring_l *t, *u, *new;
- size_t len = strlen(s);
+ size_t len = strlen (s);
/* Walk the list and look for a match. If this string is the same
as the end of an already-allocated string, it can share space. */
@@ -140,80 +139,34 @@ __tzname_max ()
static char *old_tz;
-/* Interpret the TZ envariable. */
static void
internal_function
-tzset_internal (always, explicit)
- int always;
- int explicit;
+update_vars (void)
+{
+ __daylight = tz_rules[0].offset != tz_rules[1].offset;
+ __timezone = -tz_rules[0].offset;
+ __tzname[0] = (char *) tz_rules[0].name;
+ __tzname[1] = (char *) tz_rules[1].name;
+
+ /* Keep __tzname_cur_max up to date. */
+ size_t len0 = strlen (__tzname[0]);
+ size_t len1 = strlen (__tzname[1]);
+ if (len0 > __tzname_cur_max)
+ __tzname_cur_max = len0;
+ if (len1 > __tzname_cur_max)
+ __tzname_cur_max = len1;
+}
+
+/* Parse the POSIX TZ-style string. */
+void
+__tzset_parse_tz (tz)
+ const char *tz;
{
- static int is_initialized;
- register const char *tz;
register size_t l;
char *tzbuf;
unsigned short int hh, mm, ss;
unsigned short int whichrule;
- if (is_initialized && !always)
- return;
- is_initialized = 1;
-
- /* Examine the TZ environment variable. */
- tz = getenv ("TZ");
- if (tz == NULL && !explicit)
- /* Use the site-wide default. This is a file name which means we
- would not see changes to the file if we compare only the file
- name for change. We want to notice file changes if tzset() has
- been called explicitly. Leave TZ as NULL in this case. */
- tz = TZDEFAULT;
- if (tz && *tz == '\0')
- /* User specified the empty string; use UTC explicitly. */
- tz = "Universal";
-
- /* A leading colon means "implementation defined syntax".
- We ignore the colon and always use the same algorithm:
- try a data file, and if none exists parse the 1003.1 syntax. */
- if (tz && *tz == ':')
- ++tz;
-
- /* Check whether the value changes since the last run. */
- if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
- /* No change, simply return. */
- return;
-
- if (tz == NULL)
- /* No user specification; use the site-wide default. */
- tz = TZDEFAULT;
-
- tz_rules[0].name = NULL;
- tz_rules[1].name = NULL;
-
- /* Save the value of `tz'. */
- if (old_tz != NULL)
- free (old_tz);
- old_tz = tz ? __strdup (tz) : NULL;
-
- /* Try to read a data file. */
- __tzfile_read (tz, 0, NULL);
- if (__use_tzfile)
- return;
-
- /* No data file found. Default to UTC if nothing specified. */
-
- if (tz == NULL || *tz == '\0'
- || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
- {
- tz_rules[0].name = tz_rules[1].name = "UTC";
- tz_rules[0].type = tz_rules[1].type = J0;
- tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
- tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
- tz_rules[0].secs = tz_rules[1].secs = 0;
- tz_rules[0].offset = tz_rules[1].offset = 0L;
- tz_rules[0].change = tz_rules[1].change = (time_t) -1;
- tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
- goto out;
- }
-
/* Clear out old state and reset to unnamed UTC. */
memset (tz_rules, 0, sizeof tz_rules);
tz_rules[0].name = tz_rules[1].name = "";
@@ -413,20 +366,81 @@ tzset_internal (always, explicit)
}
out:
- __daylight = tz_rules[0].offset != tz_rules[1].offset;
- __timezone = -tz_rules[0].offset;
- __tzname[0] = (char *) tz_rules[0].name;
- __tzname[1] = (char *) tz_rules[1].name;
+ update_vars ();
+}
- {
- /* Keep __tzname_cur_max up to date. */
- size_t len0 = strlen (__tzname[0]);
- size_t len1 = strlen (__tzname[1]);
- if (len0 > __tzname_cur_max)
- __tzname_cur_max = len0;
- if (len1 > __tzname_cur_max)
- __tzname_cur_max = len1;
- }
+/* Interpret the TZ envariable. */
+static void
+internal_function
+tzset_internal (always, explicit)
+ int always;
+ int explicit;
+{
+ static int is_initialized;
+ register const char *tz;
+
+ if (is_initialized && !always)
+ return;
+ is_initialized = 1;
+
+ /* Examine the TZ environment variable. */
+ tz = getenv ("TZ");
+ if (tz == NULL && !explicit)
+ /* Use the site-wide default. This is a file name which means we
+ would not see changes to the file if we compare only the file
+ name for change. We want to notice file changes if tzset() has
+ been called explicitly. Leave TZ as NULL in this case. */
+ tz = TZDEFAULT;
+ if (tz && *tz == '\0')
+ /* User specified the empty string; use UTC explicitly. */
+ tz = "Universal";
+
+ /* A leading colon means "implementation defined syntax".
+ We ignore the colon and always use the same algorithm:
+ try a data file, and if none exists parse the 1003.1 syntax. */
+ if (tz && *tz == ':')
+ ++tz;
+
+ /* Check whether the value changes since the last run. */
+ if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
+ /* No change, simply return. */
+ return;
+
+ if (tz == NULL)
+ /* No user specification; use the site-wide default. */
+ tz = TZDEFAULT;
+
+ tz_rules[0].name = NULL;
+ tz_rules[1].name = NULL;
+
+ /* Save the value of `tz'. */
+ if (old_tz != NULL)
+ free (old_tz);
+ old_tz = tz ? __strdup (tz) : NULL;
+
+ /* Try to read a data file. */
+ __tzfile_read (tz, 0, NULL);
+ if (__use_tzfile)
+ return;
+
+ /* No data file found. Default to UTC if nothing specified. */
+
+ if (tz == NULL || *tz == '\0'
+ || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
+ {
+ tz_rules[0].name = tz_rules[1].name = "UTC";
+ tz_rules[0].type = tz_rules[1].type = J0;
+ tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
+ tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
+ tz_rules[0].secs = tz_rules[1].secs = 0;
+ tz_rules[0].offset = tz_rules[1].offset = 0L;
+ tz_rules[0].change = tz_rules[1].change = (time_t) -1;
+ tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
+ update_vars ();
+ return;
+ }
+
+ __tzset_parse_tz (tz);
}
/* Figure out the exact time (as a time_t) in YEAR
@@ -523,13 +537,34 @@ compute_change (rule, year)
/* Figure out the correct timezone for TM and set `__tzname',
`__timezone', and `__daylight' accordingly. */
-static void
+void
internal_function
-tz_compute (tm)
- const struct tm *tm;
+__tz_compute (timer, tm, use_localtime)
+ time_t timer;
+ struct tm *tm;
+ int use_localtime;
{
compute_change (&tz_rules[0], 1900 + tm->tm_year);
compute_change (&tz_rules[1], 1900 + tm->tm_year);
+
+ if (use_localtime)
+ {
+ int isdst;
+
+ /* We have to distinguish between northern and southern
+ hemisphere. For the latter the daylight saving time
+ ends in the next year. */
+ if (__builtin_expect (tz_rules[0].change
+ > tz_rules[1].change, 0))
+ isdst = (timer < tz_rules[1].change
+ || timer >= tz_rules[0].change);
+ else
+ isdst = (timer >= tz_rules[0].change
+ && timer < tz_rules[1].change);
+ tm->tm_isdst = isdst;
+ tm->tm_zone = __tzname[isdst];
+ tm->tm_gmtoff = tz_rules[isdst].offset;
+ }
}
/* Reinterpret the TZ environment variable and set `tzname'. */
@@ -583,35 +618,14 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
if (! __offtime (timer, 0, tp))
tp = NULL;
else
- tz_compute (tp);
+ __tz_compute (*timer, tp, use_localtime);
leap_correction = 0L;
leap_extra_secs = 0;
}
if (tp)
{
- if (use_localtime)
- {
- if (!__use_tzfile)
- {
- int isdst;
-
- /* We have to distinguish between northern and southern
- hemisphere. For the latter the daylight saving time
- ends in the next year. */
- if (__builtin_expect (tz_rules[0].change
- > tz_rules[1].change, 0))
- isdst = (*timer < tz_rules[1].change
- || *timer >= tz_rules[0].change);
- else
- isdst = (*timer >= tz_rules[0].change
- && *timer < tz_rules[1].change);
- tp->tm_isdst = isdst;
- tp->tm_zone = __tzname[isdst];
- tp->tm_gmtoff = tz_rules[isdst].offset;
- }
- }
- else
+ if (! use_localtime)
{
tp->tm_isdst = 0;
tp->tm_zone = "GMT";