From a33c43a5aefbbb2d1e00432ba034d256af0008ae Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 14 Oct 2007 20:56:52 +0000 Subject: Updated to fedora-glibc-20071014T1847 --- time/tzfile.c | 249 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 154 insertions(+), 95 deletions(-) (limited to 'time/tzfile.c') diff --git a/time/tzfile.c b/time/tzfile.c index 0d48c8ca0c..44d6614771 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1993,1995-2001,2003,2004,2006 +/* Copyright (C) 1991-1993,1995-2001,2003,2004,2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -50,7 +50,6 @@ struct leap long int change; /* Seconds of correction to apply. */ }; -static struct ttinfo *find_transition (time_t timer) internal_function; static void compute_tzname_max (size_t) internal_function; static size_t num_transitions; @@ -63,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 #include @@ -114,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 (); @@ -242,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; @@ -254,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]; @@ -357,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); @@ -531,111 +549,151 @@ __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; + register size_t i; - 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 if (timer >= transitions[num_transitions - 1]) - i = type_idxs[num_transitions - 1]; - else + if (use_localtime) { - /* 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) + __tzname[0] = NULL; + __tzname[1] = NULL; + + if (num_transitions == 0 || timer < transitions[0]) { - i = num_transitions - 1 - i; - if (timer < transitions[i]) + /* 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 (i < 10 || timer >= transitions[i - 10]) - { - /* Linear search. */ - while (timer < transitions[i - 1]) - --i; - goto found; - } - hi = i - 10; + if (__tzname[1] == NULL) + __tzname[1] = __tzstring (&zone_names[types[i].idx]); + + ++i; } - else + + if (i == num_types) + i = 0; + __tzname[0] = __tzstring (&zone_names[types[i].idx]); + if (__tzname[1] == NULL) { - if (i + 10 >= num_transitions || timer < transitions[i + 10]) - { - /* Linear search. */ - while (timer >= transitions[i]) - ++i; - goto found; - } - lo = i + 10; + size_t j = i; + while (j < num_types) + if (types[j].isdst) + { + __tzname[1] = __tzstring (&zone_names[types[j].idx]); + break; + } + else + ++j; } } - - /* Binary search. */ - /* assert (timer >= transitions[lo] && timer < transitions[hi]); */ - while (lo + 1 < hi) + else if (timer >= transitions[num_transitions - 1]) { - i = (lo + hi) / 2; - if (timer < transitions[i]) - hi = i; - else - lo = i; - } - i = hi; + if (tzspec == NULL) + { + use_last: + i = num_transitions - 1; + goto found; + } - found: - /* assert (timer >= transitions[i - 1] && timer < transitions[i]); */ - i = type_idxs[i - 1]; - } + /* Parse the POSIX TZ-style string. */ + __tzset_parse_tz (tzspec); - 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; + /* Convert to broken down structure. If this fails do not + use the string. */ + if (! __offtime (&timer, 0, tp)) + goto use_last; - if (use_localtime) - { - struct ttinfo *info = find_transition (timer); - __daylight = rule_stdoff != rule_dstoff; - __timezone = -rule_stdoff; - __tzname[0] = NULL; - __tzname[1] = NULL; - for (i = num_transitions; i > 0; ) + /* Use the rules from the TZ string to compute the change. */ + __tz_compute (timer, tp, 1); + + *leap_correct = 0L; + *leap_hit = 0; + return; + } + else { - int type = type_idxs[--i]; - int dst = types[type].isdst; - int idx = types[type].idx; + /* 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) + { + i = num_transitions - 1 - i; + if (timer < transitions[i]) + { + if (i < 10 || timer >= transitions[i - 10]) + { + /* Linear search. */ + while (timer < transitions[i - 1]) + --i; + goto found; + } + hi = i - 10; + } + else + { + if (i + 10 >= num_transitions || timer < transitions[i + 10]) + { + /* Linear search. */ + while (timer >= transitions[i]) + ++i; + goto found; + } + lo = i + 10; + } + } - if (__tzname[dst] == NULL) + /* 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) { - __tzname[dst] = __tzstring (&zone_names[idx]); + int type = type_idxs[j]; + int dst = types[type].isdst; + int idx = types[type].idx; + + if (__tzname[dst] == NULL) + { + __tzname[dst] = __tzstring (&zone_names[idx]); + + if (__tzname[1 - dst] != NULL) + break; + } - if (__tzname[1 - dst] != NULL) - break; + ++j; } + + i = type_idxs[i - 1]; } + + struct ttinfo *info = &types[i]; + __daylight = rule_stdoff != rule_dstoff; + __timezone = -rule_stdoff; + if (__tzname[0] == NULL) { /* This should only happen if there are no transition rules. @@ -647,7 +705,8 @@ __tzfile_compute (time_t timer, int use_localtime, /* There is no daylight saving time. */ __tzname[1] = __tzname[0]; tp->tm_isdst = info->isdst; - tp->tm_zone = __tzstring (&zone_names[info->idx]); + assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0); + tp->tm_zone = __tzname[tp->tm_isdst]; tp->tm_gmtoff = info->offset; } -- cgit v1.2.3