* NEWS: Document this. * localtime.c (tzloadbody): Handle America/Anchorage after 2037, even though the sum of the abbreviations' sizes (42) plus the sum of the extended abbreviations' sizes (10) exceeds TZ_MAX_CHARS (50). Do this by reusing existing abbreviations. Thanks to Bradley White for reporting the bug. Perhaps we should also consider increasing TZ_MAX_CHARS from its currently-low value. --- NEWS | 8 +++++++ localtime.c | 71 +++++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/NEWS b/NEWS index b477250..ffe3fb2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,13 @@ News for the tz database +Unreleased, experimental changes + + Changes affecting code + + localtime no longer mishandles America/Anchorage after 2037. + (Thanks to Bradley White for reporting the bug.) + + Release 2015f - 2015-08-10 18:06:56 -0700 Changes affecting future time stamps diff --git a/localtime.c b/localtime.c index ded8f7b..ac34e5d 100644 --- a/localtime.c +++ b/localtime.c @@ -569,31 +569,52 @@ tzloadbody(char const *name, struct state *sp, bool doextend, up->buf[nread - 1] = '\0'; if (tzparse(&up->buf[1], ts, false) - && ts->typecnt == 2 - && sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) { - for (i = 0; i < 2; ++i) - ts->ttis[i].tt_abbrind += - sp->charcnt; - for (i = 0; i < ts->charcnt; ++i) - sp->chars[sp->charcnt++] = - ts->chars[i]; - i = 0; - while (i < ts->timecnt && - ts->ats[i] <= - sp->ats[sp->timecnt - 1]) - ++i; - while (i < ts->timecnt && - sp->timecnt < TZ_MAX_TIMES) { - sp->ats[sp->timecnt] = - ts->ats[i]; - sp->types[sp->timecnt] = - sp->typecnt + - ts->types[i]; - ++sp->timecnt; - ++i; - } - sp->ttis[sp->typecnt++] = ts->ttis[0]; - sp->ttis[sp->typecnt++] = ts->ttis[1]; + && ts->typecnt == 2) { + + /* Attempt to reuse existing abbreviations. + Without this, America/Anchorage would stop + working after 2037 when TZ_MAX_CHARS is 50, as + sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST + AHDT YST AKDT AKST) and ts->charcnt equals 10 + (for AKST AKDT). Reusing means sp->charcnt can + stay 42 in this example. */ + int gotabbr = 0; + int charcnt = sp->charcnt; + for (i = 0; i < 2; i++) { + char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind; + int j; + for (j = 0; j < charcnt; j++) + if (strcmp(sp->chars + j, tsabbr) == 0) { + ts->ttis[i].tt_abbrind = j; + gotabbr++; + break; + } + if (! (j < charcnt)) { + int tsabbrlen = strlen(tsabbr); + if (j + tsabbrlen < TZ_MAX_CHARS) { + strcpy(sp->chars + j, tsabbr); + charcnt = j + tsabbrlen + 1; + ts->ttis[i].tt_abbrind = j; + gotabbr++; + } + } + } + if (gotabbr == 2) { + sp->charcnt = charcnt; + for (i = 0; i < ts->timecnt; i++) + if (sp->ats[sp->timecnt - 1] < ts->ats[i]) + break; + while (i < ts->timecnt + && sp->timecnt < TZ_MAX_TIMES) { + sp->ats[sp->timecnt] = ts->ats[i]; + sp->types[sp->timecnt] = (sp->typecnt + + ts->types[i]); + sp->timecnt++; + i++; + } + sp->ttis[sp->typecnt++] = ts->ttis[0]; + sp->ttis[sp->typecnt++] = ts->ttis[1]; + } } } if (sp->timecnt > 1) { -- 2.1.4