diff --git a/tz/Makefile b/tz/Makefile index 34cec49..afb9d53 100644 --- a/tz/Makefile +++ b/tz/Makefile @@ -196,6 +196,7 @@ PACKRATLIST= UTF8_LOCALE= en_US.utf8 # Non-default libraries needed to link. +# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0. LDLIBS= # Add the following to the end of the "CFLAGS=" line as needed to override @@ -208,14 +209,18 @@ LDLIBS= # For example, N is 252460800 on AmigaOS. # -DHAVE_DECL_ASCTIME_R=0 if does not declare asctime_r # -DHAVE_DECL_ENVIRON if declares 'environ' +# -DHAVE_DECL_TIMEGM=0 if does not declare timegm # -DHAVE_DIRECT_H if mkdir needs (MS-Windows) -# -DHAVE_GENERIC=0 if _Generic does not work -# -DHAVE_GETRANDOM if getgrandom works (e.g., GNU/Linux)* -# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)* +# -DHAVE_GENERIC=0 if _Generic does not work* +# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux), +# -DHAVE_GETRANDOM=0 to avoid using getrandom +# -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris), +# where LDLIBS also needs to contain -lintl on some hosts; +# -DHAVE_GETTEXT=0 to avoid using gettext # -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares # ctime_r and asctime_r incompatibly with the POSIX standard # (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined). -# -DHAVE_INTTYPES_H if you have a non-C99 compiler with +# -DHAVE_INTTYPES_H=0 if does not work* # -DHAVE_LINK=0 if your system lacks a link function # -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function # -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz @@ -225,15 +230,17 @@ LDLIBS= # functions like 'link' or variables like 'tzname' required by POSIX # -DHAVE_SETENV=0 if your system lacks the setenv function # -DHAVE_SNPRINTF=0 if your system lacks the snprintf function -# -DHAVE_STDINT_H if you have a non-C99 compiler with * +# -DHAVE_STDCKDINT_H=0 if neither nor substitutes like +# __builtin_add_overflow work* +# -DHAVE_STDINT_H=0 if does not work* # -DHAVE_STRFTIME_L if declares locale_t and strftime_l # -DHAVE_STRDUP=0 if your system lacks the strdup function # -DHAVE_STRTOLL=0 if your system lacks the strtoll function # -DHAVE_SYMLINK=0 if your system lacks the symlink function -# -DHAVE_SYS_STAT_H=0 if your compiler lacks a * +# -DHAVE_SYS_STAT_H=0 if does not work* # -DHAVE_TZSET=0 if your system lacks a tzset function -# -DHAVE_UNISTD_H=0 if your compiler lacks a * -# -DHAVE_UTMPX_H=0 if your compiler lacks a * +# -DHAVE_UNISTD_H=0 if does not work* +# -DHAVE_UTMPX_H=0 if does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. @@ -280,7 +287,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ -Wdeclaration-after-statement -Wdouble-promotion \ -Wduplicated-branches -Wduplicated-cond \ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ - -Winit-self -Wlogical-op \ + -Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wnull-dereference \ -Wold-style-definition -Woverlength-strings -Wpointer-arith \ @@ -293,7 +300,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ -Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ -Wno-address -Wno-format-nonliteral -Wno-sign-compare \ - -Wno-type-limits -Wno-unused-parameter + -Wno-type-limits # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), @@ -340,14 +347,11 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # If you want functions that were inspired by early versions of X3J11's work, # add # -DSTD_INSPIRED -# to the end of the "CFLAGS=" line. This arranges for the functions -# "offtime", "timelocal", "timegm", "timeoff", -# "posix2time", and "time2posix" to be added to the time conversion library. +# to the end of the "CFLAGS=" line. This arranges for the following +# functions to be added to the time conversion library. # "offtime" is like "gmtime" except that it accepts a second (long) argument # that gives an offset to add to the time_t when converting it. # "timelocal" is equivalent to "mktime". -# "timegm" is like "timelocal" except that it turns a struct tm into -# a time_t using UT (rather than local time as "timelocal" does). # "timeoff" is like "timegm" except that it accepts a second (long) argument # that gives an offset to use when converting to a time_t. # "posix2time" and "time2posix" are described in an included manual page. @@ -495,6 +499,11 @@ TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \ # Flags to give 'gzip' when making a distribution. GZIPFLAGS= -9n +# When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported. +# This makes it easier to see which Zone has been affected. +DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \ + || echo ' -F^TZ=') + ############################################################################### #MAKE= make @@ -773,7 +782,8 @@ tzselect: tzselect.ksh version chmod +x $@.out mv $@.out $@ -check: check_character_set check_white_space check_links \ +check: check_back check_mild +check_mild: check_character_set check_white_space check_links \ check_name_lengths check_slashed_abbrs check_sorted \ check_tables check_web check_ziguard check_zishrink check_tzs @@ -824,16 +834,19 @@ check_slashed_abbrs: $(TDATA_TO_CHECK) CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; } check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab - $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} /^$$/ {g++}' \ + $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \ backward | LC_ALL=C sort -cu $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu touch $@ -check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi +check_back: checklinks.awk $(TDATA_TO_CHECK) $(AWK) \ -v DATAFORM=$(DATAFORM) \ -v backcheck=backward \ -f checklinks.awk $(TDATA_TO_CHECK) + touch $@ + +check_links: checklinks.awk tzdata.zi $(AWK) \ -v DATAFORM=$(DATAFORM) \ -f checklinks.awk tzdata.zi @@ -849,7 +862,7 @@ check_tables: checktab.awk $(YDATA) backward $(ZONETABLES) check_tzs: $(TZS) $(TZS_NEW) if test -s $(TZS); then \ - diff -u $(TZS) $(TZS_NEW); \ + $(DIFF_TZS) $(TZS) $(TZS_NEW); \ else \ cp $(TZS_NEW) $(TZS); \ fi @@ -1050,7 +1063,7 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS) TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \ D=$$wd/$@.dir \ to$$range.tzs) && \ - diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \ + $(DIFF_TZS) $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \ $@.dir/to$$range.tzs && \ if diff -q Makefile Makefile 2>/dev/null; then \ quiet_option='-q'; \ @@ -1220,7 +1233,7 @@ zdump.o: version.h zic.o: private.h tzfile.h version.h .PHONY: ALL INSTALL all -.PHONY: check check_time_t_alternatives +.PHONY: check check_mild check_time_t_alternatives .PHONY: check_web check_zishrink .PHONY: clean clean_misc dummy.zd force_tzs .PHONY: install install_data maintainer-clean names diff --git a/tz/NEWS b/tz/NEWS index 0861510..701e490 100644 --- a/tz/NEWS +++ b/tz/NEWS @@ -1,5 +1,91 @@ News for the tz database +Release 2022g - 2022-11-29 08:58:31 -0800 + + Briefly: + The northern edge of Chihuahua changes to US timekeeping. + Much of Greenland stops changing clocks after March 2023. + Fix some pre-1996 timestamps in northern Canada. + C89 is now deprecated; please use C99 or later. + Portability fixes for AIX, libintl, MS-Windows, musl, z/OS + In C code, use more C23 features if available. + C23 timegm now supported by default + Fixes for unlikely integer overflows + + Changes to future timestamps + + In the Mexican state of Chihuahua, the border strip near the US + will change to agree with nearby US locations on 2022-11-30. + The strip's western part, represented by Ciudad Juárez, switches + from -06 all year to -07/-06 with US DST rules, like El Paso, TX. + The eastern part, represented by Ojinaga, will observe US DST next + year, like Presidio, TX. (Thanks to Heitor David Pinto.) + A new Zone America/Ciudad_Juarez splits from America/Ojinaga. + + Much of Greenland, represented by America/Nuuk, stops observing + winter time after March 2023, so its daylight saving time becomes + standard time. (Thanks to Jonas Nyrup and Jürgen Appel.) + + Changes to past timestamps + + Changes for pre-1996 northern Canada (thanks to Chris Walton): + + Merge America/Iqaluit and America/Pangnirtung into the former, + with a backward compatibility link for the latter name. + There is no good evidence the two locations differ since 1970. + This change affects pre-1996 America/Pangnirtung timestamps. + + Cambridge Bay, Inuvik, Iqaluit, Rankin Inlet, Resolute and + Yellowknife did not observe DST in 1965, and did observe DST + from 1972 through 1979. + + Whitehorse moved from -09 to -08 on 1966-02-27, not 1967-05-28. + + Colombia's 1993 fallback was 02-06 24:00, not 04-04 00:00. + (Thanks to Alois Treindl.) + + Singapore's 1981-12-31 change was at 16:00 UTC (23:30 local time), + not 24:00 local time. (Thanks to Geoff Clare via Robert Elz.) + + Changes to code + + Although tzcode still works with C89, bugs found in recent routine + maintenance indicate that bitrot has set in and that in practice + C89 is no longer used to build tzcode. As it is a maintenance + burden, support for C89 is planned to be removed soon. Instead, + please use compilers compatible with C99, C11, C17, or C23. + + timegm, which tzcode implemented in 1989, will finally be + standardized 34 years later as part of C23, so timegm is now + supported even if STD_INSPIRED is not defined. + + Fix bug in zdump's tzalloc emulation on hosts that lack tm_zone. + (Problem reported by Đoàn Trần Công Danh.) + + Fix bug in zic on hosts where malloc(0) yields NULL on success. + (Problem reported by Tim McBrayer for AIX 6.1.) + + Fix zic configuration to avoid linkage failures on some platforms. + (Problems reported by Gilmore Davidson and Igor Ivanov.) + + Work around MS-Windows nmake incompatibility with POSIX. + (Problem reported by Manuela Friedrich.) + + Port mktime and strftime to debugging platforms where accessing + uninitialized data has undefined behavior (strftime problem + reported by Robert Elz). + + Check more carefully for unlikely integer overflows, preferring + C23 to overflow checking by hand, as the latter has + had obscure bugs. + + Changes to build procedure + + New Makefile rule check_mild that skips checking whether Link + lines are in the file 'backward'. (Inspired by a suggestion from + Stephen Colebourne.) + + Release 2022f - 2022-10-28 18:04:57 -0700 Briefly: @@ -16,7 +102,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700 In C code, use some C23 features if available. Remove no-longer-needed workaround for Qt bug 53071. - Changes to future timestamps. + Changes to future timestamps Mexico will no longer observe DST after 2022, except for areas near the US border that continue to observe US DST rules. @@ -24,6 +110,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700 from -07 (-06 with DST) to year-round -06, thus not changing its clocks that day. The new law states that Chihuahua near the US border no longer observes US DST. + (Thanks to gera for the heads-up about Chihuahua.) Fiji will not observe DST in 2022/3. (Thanks to Shalvin Narayan.) For now, assume DST is suspended indefinitely. diff --git a/tz/africa b/tz/africa index 92a6125..cfb9283 100644 --- a/tz/africa +++ b/tz/africa @@ -588,6 +588,10 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # Agalega Is, Rodriguez # no information; probably like Indian/Mauritius + +# Morocco +# See Africa/Ceuta for Spanish Morocco. + # From Alex Krivenyshev (2008-05-09): # Here is an article that Morocco plan to introduce Daylight Saving Time between # 1 June, 2008 and 27 September, 2008. diff --git a/tz/asia b/tz/asia index 6e8ad28..199e6ad 100644 --- a/tz/asia +++ b/tz/asia @@ -3585,7 +3585,7 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 7:20 - +0720 1941 Sep 1 7:30 - +0730 1942 Feb 16 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1982 Jan 1 + 7:30 - +0730 1981 Dec 31 16:00u 8:00 - +08 # Spratly Is diff --git a/tz/backward b/tz/backward index 4c1c5d5..0ae5d74 100644 --- a/tz/backward +++ b/tz/backward @@ -267,6 +267,7 @@ Link America/Tijuana America/Ensenada Link America/Indiana/Indianapolis America/Fort_Wayne Link America/Toronto America/Montreal Link America/Toronto America/Nipigon +Link America/Iqaluit America/Pangnirtung Link America/Rio_Branco America/Porto_Acre Link America/Winnipeg America/Rainy_River Link America/Argentina/Cordoba America/Rosario diff --git a/tz/backzone b/tz/backzone index b4ebd2e..7803c57 100644 --- a/tz/backzone +++ b/tz/backzone @@ -7,6 +7,10 @@ # tz@iana.org for general use in the future). For more, please see # the file CONTRIBUTING in the tz distribution. +# When proposing changes to this file, please use 'git format-patch' +# format, either by attaching the resulting .patch file to your email, +# or by using 'git send-email'. This will help maintainers save time. + # From Paul Eggert (2014-10-31): @@ -750,6 +754,55 @@ Zone America/Nipigon -5:53:04 - LMT 1895 -5:00 1:00 EDT 1942 Feb 9 2:00s -5:00 Canada E%sT +# From Rives McDow (1999-11-08): +# On October 31, when the rest of Nunavut went to Central time, +# Pangnirtung wobbled. Here is the result of their wobble: +# +# The following businesses and organizations in Pangnirtung use Central Time: +# +# First Air, Power Corp, Nunavut Construction, Health Center, RCMP, +# Eastern Arctic National Parks, A & D Specialist +# +# The following businesses and organizations in Pangnirtung use Eastern Time: +# +# Hamlet office, All other businesses, Both schools, Airport operator +# +# This has made for an interesting situation there, which warranted the news. +# No one there that I spoke with seems concerned, or has plans to +# change the local methods of keeping time, as it evidently does not +# really interfere with any activities or make things difficult locally. +# They plan to celebrate New Year's turn-over twice, one hour apart, +# so it appears that the situation will last at least that long. +# The Nunavut Intergovernmental Affairs hopes that they will "come to +# their senses", but the locals evidently don't see any problem with +# the current state of affairs. + +# From Michaela Rodrigue, writing in the +# Nunatsiaq News (1999-11-19): +# http://www.nunatsiaqonline.ca/archives/nunavut991130/nvt91119_17.html +# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones, +# central - or Nunavut time - for government offices, and eastern time +# for municipal offices and schools.... Igloolik [was similar but then] +# made the switch to central time on Saturday, Nov. 6. + +# From Chris Walton (2022-11-06): +# The implication is that Pangnirtung and Qikiqtarjuaq have observed Eastern +# Time as far back as 1984 (and likely even further back than that). +# It is possible that these communities never actually observed Atlantic +# Time, but that would be difficult to prove. +# From Paul Eggert (2022-11-06): +# This is in 'backzone' as we have no good evidence that Pangnirtung differs +# from America/Iqaluit since 1970. A Google Books snippet view of +# volume 2, page 186 of "Pilot of Arctic Canada", published 1959 by +# the Canadian Hydrographic Service, suggests (though does not state) +# that Pangnirtung observed EST then. +# +# aka Panniqtuuq +Zone America/Pangnirtung 0 - -00 1921 # trading post est. + -5:00 NT_YK E%sT 1999 Oct 31 2:00 + -6:00 Canada C%sT 2000 Oct 29 2:00 + -5:00 Canada E%sT + # United States # # From Paul Eggert (2018-03-18): @@ -1043,7 +1096,7 @@ Zone Asia/Kuala_Lumpur 6:46:46 - LMT 1901 Jan 1 7:20 - +0720 1941 Sep 1 7:30 - +0730 1942 Feb 16 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1982 Jan 1 + 7:30 - +0730 1981 Dec 31 16:00u 8:00 - +08 # Kuwait diff --git a/tz/date.1 b/tz/date.1 index 1ecd63a..043e568 100644 --- a/tz/date.1 +++ b/tz/date.1 @@ -1,10 +1,12 @@ -.TH DATE 1 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH date 1 .SH NAME date \- show and set date and time .SH SYNOPSIS .if n .nh .if n .na -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B date [ @@ -163,5 +165,3 @@ If is absent, UTC leap seconds are loaded from .BR /usr/share/zoneinfo/posixrules . -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/date.c b/tz/date.c index 4e4b355..11c5e5f 100644 --- a/tz/date.c +++ b/tz/date.c @@ -42,7 +42,7 @@ static void display(const char *, time_t); static void dogmt(void); static void errensure(void); static void timeout(FILE *, const char *, const struct tm *); -static _Noreturn void usage(void); +static ATTRIBUTE_NORETURN void usage(void); int main(const int argc, char *argv[]) @@ -117,14 +117,19 @@ dogmt(void) static char ** fakeenv; if (fakeenv == NULL) { - register int from; - register int to; - register int n; static char tzeutc0[] = "TZ=UTC0"; + ptrdiff_t from, to, n; for (n = 0; environ[n] != NULL; ++n) continue; - fakeenv = malloc((n + 2) * sizeof *fakeenv); +#if defined ckd_add && defined ckd_mul + if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv) + && n <= SIZE_MAX) + fakeenv = malloc(n); +#else + if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2) + fakeenv = malloc((n + 2) * sizeof *fakeenv); +#endif if (fakeenv == NULL) { fprintf(stderr, _("date: Memory exhausted\n")); errensure(); @@ -183,33 +188,28 @@ display(char const *format, time_t now) static void timeout(FILE *fp, char const *format, struct tm const *tmp) { - char * cp; - size_t result; - size_t size; - struct tm tm; - int INCR = 1024; + char *cp = NULL; + ptrdiff_t result; + ptrdiff_t size = 1024 / 2; - if (!tmp) { - fprintf(stderr, _("date: error: time out of range\n")); - errensure(); - return; - } - tm = *tmp; - tmp = &tm; - size = INCR; - cp = malloc(size); for ( ; ; ) { - if (cp == NULL) { +#ifdef ckd_mul + bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX; +#else + bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2 + && (size *= 2, true)); +#endif + char *newcp = bigger ? realloc(cp, size) : NULL; + if (!newcp) { fprintf(stderr, _("date: error: can't get memory\n")); errensure(); exit(retval); } + cp = newcp; result = strftime(cp, size, format, tmp); if (result != 0) break; - size += INCR; - cp = realloc(cp, size); } fwrite(cp + 1, 1, result - 1, fp); free(cp); diff --git a/tz/europe b/tz/europe index 6ac41e7..a3547b4 100644 --- a/tz/europe +++ b/tz/europe @@ -1103,7 +1103,30 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # "National Park" by Executive Order: # http://naalakkersuisut.gl/~/media/Nanoq/Files/Attached%20Files/Engelske-tekster/Legislation/Executive%20Order%20National%20Park.rtf # It is their only National Park. -# + +# From Jonas Nyrup (2022-11-24): +# On last Saturday in October 2023 when DST ends America/Nuuk will switch +# from -03/-02 to -02/-01 +# https://sermitsiaq.ag/forslagtidsforskel-danmark-mindskes-sommertid-beholdes +# ... +# https://sermitsiaq.ag/groenland-skifte-tidszone-trods-bekymringer +# +# From Jürgen Appel (2022-11-25): +# https://ina.gl/samlinger/oversigt-over-samlinger/samling/dagsordener/dagsorden.aspx?lang=da&day=24-11-2022 +# If I understand this correctly, from the next planned switch to +# summer time, Greenland will permanently stay at that time, i.e. no +# switch back to winter time in 2023 will occur. +# +# From Paul Eggert (2022-11-28): +# The official document in Danish +# https://naalakkersuisut.gl/-/media/naalakkersuisut/filer/kundgoerelser/2022/11/2511/31_da_inatsisartutlov-om-tidens-bestemmelse.pdf?la=da&hash=A33597D8A38CC7038465241119EF34F3 +# says standard time for Greenland is -02, that Naalakkersuisut can lay down +# rules for DST and can require some areas to use a different time zone, +# and that this all takes effect 2023-03-25 22:00. The abovementioned +# "bekymringer" URL says the intent is no transition March 25, that +# Greenland will not go back to winter time in fall 2023, and that +# only America/Nuuk is affected (though further changes may occur). + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D Rule Thule 1991 1992 - Sep lastSun 2:00 0 S @@ -1126,7 +1149,8 @@ Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -1:00 EU -01/+00 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 + -3:00 EU -03/-02 2023 Mar 25 22:00 + -2:00 - -02 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT diff --git a/tz/iso3166.tab b/tz/iso3166.tab index a4ff61a..911af5e 100644 --- a/tz/iso3166.tab +++ b/tz/iso3166.tab @@ -3,13 +3,13 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2015-05-02): +# From Paul Eggert (2022-11-18): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 +# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 # https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. @@ -238,7 +238,7 @@ SY Syria SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad -TF French Southern & Antarctic Lands +TF French Southern Territories TG Togo TH Thailand TJ Tajikistan diff --git a/tz/localtime.c b/tz/localtime.c index c556531..1d22d35 100644 --- a/tz/localtime.c +++ b/tz/localtime.c @@ -425,8 +425,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, #endif if (!doaccess) { char const *dot; - size_t namelen = strlen(name); - if (sizeof lsp->fullname - sizeof tzdirslash <= namelen) + if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) return ENAMETOOLONG; /* Create a string "TZDIR/NAME". Using sprintf here @@ -839,7 +838,7 @@ is_digit(char c) ** Return a pointer to that character. */ -static ATTRIBUTE_PURE const char * +static ATTRIBUTE_REPRODUCIBLE const char * getzname(register const char *strp) { register char c; @@ -860,7 +859,7 @@ getzname(register const char *strp) ** We don't do any checking here; checking is done later in common-case code. */ -static ATTRIBUTE_PURE const char * +static ATTRIBUTE_REPRODUCIBLE const char * getqzname(register const char *strp, const int delim) { register int c; @@ -1120,13 +1119,11 @@ tzparse(const char *name, struct state *sp, struct state *basep) { const char * stdname; const char * dstname; - size_t stdlen; - size_t dstlen; - size_t charcnt; int_fast32_t stdoffset; int_fast32_t dstoffset; register char * cp; register bool load_ok; + ptrdiff_t stdlen, dstlen, charcnt; time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN; stdname = name; @@ -1568,6 +1565,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return NULL; /* "cannot happen" */ result = localsub(sp, &newt, setname, tmp); if (result) { +#if defined ckd_add && defined ckd_sub + if (t < sp->ats[0] + ? ckd_sub(&result->tm_year, + result->tm_year, years) + : ckd_add(&result->tm_year, + result->tm_year, years)) + return NULL; +#else register int_fast64_t newy; newy = result->tm_year; @@ -1577,6 +1582,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, if (! (INT_MIN <= newy && newy <= INT_MAX)) return NULL; result->tm_year = newy; +#endif } return result; } @@ -1656,8 +1662,8 @@ localtime_r(const time_t *timep, struct tm *tmp) */ static struct tm * -gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset, - struct tm *tmp) +gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, + int_fast32_t offset, struct tm *tmp) { register struct tm * result; @@ -1786,6 +1792,12 @@ timesub(const time_t *timep, int_fast32_t offset, y = newy; } +#ifdef ckd_add + if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) { + errno = EOVERFLOW; + return NULL; + } +#else if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) { int signed_y = y; tmp->tm_year = signed_y - TM_YEAR_BASE; @@ -1796,6 +1808,7 @@ timesub(const time_t *timep, int_fast32_t offset, errno = EOVERFLOW; return NULL; } +#endif tmp->tm_yday = idays; /* ** The "extra" mods below avoid overflow problems. @@ -1870,6 +1883,9 @@ ctime_r(const time_t *timep, char *buf) static bool increment_overflow(int *ip, int j) { +#ifdef ckd_add + return ckd_add(ip, *ip, j); +#else register int const i = *ip; /* @@ -1882,22 +1898,30 @@ increment_overflow(int *ip, int j) return true; *ip += j; return false; +#endif } static bool increment_overflow32(int_fast32_t *const lp, int const m) { +#ifdef ckd_add + return ckd_add(lp, *lp, m); +#else register int_fast32_t const l = *lp; if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) return true; *lp += m; return false; +#endif } static bool increment_overflow_time(time_t *tp, int_fast32_t j) { +#ifdef ckd_add + return ckd_add(tp, *tp, j); +#else /* ** This is like ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...', @@ -1909,6 +1933,7 @@ increment_overflow_time(time_t *tp, int_fast32_t j) return true; *tp += j; return false; +#endif } static bool @@ -1951,6 +1976,23 @@ tmcomp(register const struct tm *const atmp, return result; } +/* Copy to *DEST from *SRC. Copy only the members needed for mktime, + as other members might not be initialized. */ +static void +mktmcpy(struct tm *dest, struct tm const *src) +{ + dest->tm_sec = src->tm_sec; + dest->tm_min = src->tm_min; + dest->tm_hour = src->tm_hour; + dest->tm_mday = src->tm_mday; + dest->tm_mon = src->tm_mon; + dest->tm_year = src->tm_year; + dest->tm_isdst = src->tm_isdst; +#if defined TM_GMTOFF && ! UNINIT_TRAP + dest->TM_GMTOFF = src->TM_GMTOFF; +#endif +} + static time_t time2sub(struct tm *const tmp, struct tm *(*funcp)(struct state const *, time_t const *, @@ -1972,7 +2014,8 @@ time2sub(struct tm *const tmp, struct tm yourtm, mytm; *okayp = false; - yourtm = *tmp; + mktmcpy(&yourtm, tmp); + if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) @@ -2014,14 +2057,19 @@ time2sub(struct tm *const tmp, return WRONG; } } +#ifdef ckd_add + if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) + return WRONG; +#else if (increment_overflow32(&y, -TM_YEAR_BASE)) return WRONG; if (! (INT_MIN <= y && y <= INT_MAX)) return WRONG; yourtm.tm_year = y; +#endif if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; - else if (y + TM_YEAR_BASE < EPOCH_YEAR) { + else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. @@ -2278,7 +2326,6 @@ mktime(struct tm *tmp) } #ifdef STD_INSPIRED - time_t timelocal(struct tm *tmp) { @@ -2286,13 +2333,9 @@ timelocal(struct tm *tmp) tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } - -time_t -timegm(struct tm *tmp) -{ - return timeoff(tmp, 0); -} - +#else +static +#endif time_t timeoff(struct tm *tmp, long offset) { @@ -2302,7 +2345,18 @@ timeoff(struct tm *tmp, long offset) return time1(tmp, gmtsub, gmtptr, offset); } -#endif /* defined STD_INSPIRED */ +time_t +timegm(struct tm *tmp) +{ + time_t t; + struct tm tmcpy; + mktmcpy(&tmcpy, tmp); + tmcpy.tm_wday = -1; + t = timeoff(&tmcpy, 0); + if (0 <= tmcpy.tm_wday) + *tmp = tmcpy; + return t; +} static int_fast32_t leapcorr(struct state const *sp, time_t t) diff --git a/tz/newctime.3 b/tz/newctime.3 index 8661549..e25d841 100644 --- a/tz/newctime.3 +++ b/tz/newctime.3 @@ -1,9 +1,11 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH NEWCTIME 3 .SH NAME asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -340,5 +342,3 @@ restricted to years in the range 1900 through 2099. To avoid this portability mess, new programs should use .B strftime instead. -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/newstrftime.3 b/tz/newstrftime.3 index d68bc33..d5d8ee1 100644 --- a/tz/newstrftime.3 +++ b/tz/newstrftime.3 @@ -40,7 +40,7 @@ strftime \- format date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -55,7 +55,7 @@ strftime \- format date and time .ie '\(rq'' .ds rq \&"\" .el .ds rq \(rq\" .de c -.ie \n(.g \f(CW\\$1\fP\\$2 +.ie \n(.g \f(CR\\$1\fP\\$2 .el \\$1\\$2 .. .de q diff --git a/tz/newtzset.3 b/tz/newtzset.3 index 8aaa0ff..1e75acf 100644 --- a/tz/newtzset.3 +++ b/tz/newtzset.3 @@ -1,9 +1,11 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH NEWTZSET 3 .SH NAME tzset \- initialize time conversion information .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -331,7 +333,7 @@ from the rest of the specification. .br /usr/share/zoneinfo/localtime local timezone file .br -/usr/share/zoneinfo/posixrules used with POSIX-style TZ's +/usr/share/zoneinfo/posixrules used with POSIX-style TZ .br /usr/share/zoneinfo/GMT for UTC leap seconds .sp @@ -346,5 +348,3 @@ newctime(3), newstrftime(3), time(2), tzfile(5) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/northamerica b/tz/northamerica index df19543..d50581d 100644 --- a/tz/northamerica +++ b/tz/northamerica @@ -1969,6 +1969,37 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # Northwest Territories, Nunavut, Yukon +# From Chris Walton (2022-11-06): +# Whitehorse Star - Thursday April 22, 1965 - page 1 +# title: DST Starts Monday ... +# https://www.newspapers.com/image/578587481/ +# The title of this first article is wrong and/or misleading. +# Also, the start time shown in the article is vague; it simply says "after +# midnight" when it probably should have stated 2:00a.m.... +# +# Whitehorse Star - Monday October 25, 1965 - page 15 ... +# https://www.newspapers.com/image/578589147/ +# The 1965 Yukon Council minutes can be found here: +# http://assets.yukonarchives.ca/PER_YG_06_1965_C20_S02_v1.pdf +# ... I do not currently believe that NWT touched any of its clocks in 1965.... +# +# Whitehorse Star - Thursday Feb 24,1966 - page 2 +# title: It's Time for YDT ... +# https://www.newspapers.com/image/578575979/ ... +# America/Whitehorse as a permanent change from UTC-9(YST) to +# UTC-8(PST) at 00:00 on Sunday February 27, 1966.... +# +# Whitehorse Star - Friday April 28,1972 - page 6 +# title: Daylight Saving Time for N.W.T.... +# https://www.newspapers.com/image/578701610/ ... +# Nunavut and NWT zones ... DST starting in 1972.... Start and End ... +# should be the same as the rest of Canada +# +# +# From Paul Eggert (2022-11-06): +# For now, assume Yukon's 1965-04-22 spring forward was 00:00 -> 02:00, as this +# seems likely than 02:00 -> 04:00 and matches "after midnight". + # From Paul Eggert (2006-03-22): # Dawson switched to PST in 1973. Inuvik switched to MST in 1979. # Mathew Englander (1996-10-07) gives the following refs: @@ -2083,6 +2114,13 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # * Interpretation Act, RSY 2002, c 125 # https://www.canlii.org/en/yk/laws/stat/rsy-2002-c-125/latest/rsy-2002-c-125.html +# From Chris Walton (2022-11-06): +# The 5th edition of the Atlas of Canada contains a time zone map that +# shows both legislated and observed time zone boundaries. +# All communities on Baffin Island are shown to be observing Eastern time. +# The date on the map is 1984. +# https://ftp.maps.canada.ca/pub/nrcan_rncan/raster/atlas_5_ed/eng/other/referencemaps/mcr4056.pdf + # From Rives McDow (1999-09-04): # Nunavut ... moved ... to incorporate the whole territory into one time zone. # Nunavut moves to single time zone Oct. 31 @@ -2095,40 +2133,7 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # From Paul Eggert (1999-09-20): # Basic Facts: The New Territory # http://www.nunavut.com/basicfacts/english/basicfacts_1territory.html -# (1999) reports that Pangnirtung operates on eastern time, -# and that Coral Harbour does not observe DST. We don't know when -# Pangnirtung switched to eastern time; we'll guess 1995. - -# From Rives McDow (1999-11-08): -# On October 31, when the rest of Nunavut went to Central time, -# Pangnirtung wobbled. Here is the result of their wobble: -# -# The following businesses and organizations in Pangnirtung use Central Time: -# -# First Air, Power Corp, Nunavut Construction, Health Center, RCMP, -# Eastern Arctic National Parks, A & D Specialist -# -# The following businesses and organizations in Pangnirtung use Eastern Time: -# -# Hamlet office, All other businesses, Both schools, Airport operator -# -# This has made for an interesting situation there, which warranted the news. -# No one there that I spoke with seems concerned, or has plans to -# change the local methods of keeping time, as it evidently does not -# really interfere with any activities or make things difficult locally. -# They plan to celebrate New Year's turn-over twice, one hour apart, -# so it appears that the situation will last at least that long. -# The Nunavut Intergovernmental Affairs hopes that they will "come to -# their senses", but the locals evidently don't see any problem with -# the current state of affairs. - -# From Michaela Rodrigue, writing in the -# Nunatsiaq News (1999-11-19): -# http://www.nunatsiaqonline.ca/archives/nunavut991130/nvt91119_17.html -# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones, -# central - or Nunavut time - for government offices, and eastern time -# for municipal offices and schools.... Igloolik [was similar but then] -# made the switch to central time on Saturday, Nov. 6. +# (1999) reports that ... Coral Harbour does not observe DST. # From Paul Eggert (2000-10-02): # Matthews and Vincent (1998) say the following, but we lack histories @@ -2287,18 +2292,12 @@ Rule NT_YK 1919 only - Nov 1 0:00 0 S Rule NT_YK 1942 only - Feb 9 2:00 1:00 W # War Rule NT_YK 1945 only - Aug 14 23:00u 1:00 P # Peace Rule NT_YK 1945 only - Sep 30 2:00 0 S -Rule NT_YK 1965 only - Apr lastSun 0:00 2:00 DD -Rule NT_YK 1965 only - Oct lastSun 2:00 0 S -Rule NT_YK 1980 1986 - Apr lastSun 2:00 1:00 D -Rule NT_YK 1980 2006 - Oct lastSun 2:00 0 S +Rule NT_YK 1972 1986 - Apr lastSun 2:00 1:00 D +Rule NT_YK 1972 2006 - Oct lastSun 2:00 0 S Rule NT_YK 1987 2006 - Apr Sun>=1 2:00 1:00 D +Rule Yukon 1965 only - Apr lastSun 0:00 2:00 DD +Rule Yukon 1965 only - Oct lastSun 2:00 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] -# aka Panniqtuuq -Zone America/Pangnirtung 0 - -00 1921 # trading post est. - -4:00 NT_YK A%sT 1995 Apr Sun>=1 2:00 - -5:00 Canada E%sT 1999 Oct 31 2:00 - -6:00 Canada C%sT 2000 Oct 29 2:00 - -5:00 Canada E%sT # formerly Frobisher Bay Zone America/Iqaluit 0 - -00 1942 Aug # Frobisher Bay est. -5:00 NT_YK E%sT 1999 Oct 31 2:00 @@ -2331,13 +2330,15 @@ Zone America/Inuvik 0 - -00 1953 # Inuvik founded -7:00 NT_YK M%sT 1980 -7:00 Canada M%sT Zone America/Whitehorse -9:00:12 - LMT 1900 Aug 20 - -9:00 NT_YK Y%sT 1967 May 28 0:00 - -8:00 NT_YK P%sT 1980 + -9:00 NT_YK Y%sT 1965 + -9:00 Yukon Y%sT 1966 Feb 27 0:00 + -8:00 - PST 1980 -8:00 Canada P%sT 2020 Nov 1 -7:00 - MST Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 - -9:00 NT_YK Y%sT 1973 Oct 28 0:00 - -8:00 NT_YK P%sT 1980 + -9:00 NT_YK Y%sT 1965 + -9:00 Yukon Y%sT 1973 Oct 28 0:00 + -8:00 - PST 1980 -8:00 Canada P%sT 2020 Nov 1 -7:00 - MST @@ -2559,6 +2560,14 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # This abolishes DST except where US DST rules are observed, # and in addition changes all of Chihuahua to -06 with no DST. +# From Heitor David Pinto (2022-11-28): +# Now the northern municipalities want to have the same time zone as the +# respective neighboring cities in the US, for example Juárez in UTC-7 with +# DST, matching El Paso, and Ojinaga in UTC-6 with DST, matching Presidio.... +# the president authorized the publication of the decree for November 29, +# so the time change would occur on November 30 at 0:00. +# http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Mexico 1931 only - May 1 23:00 1:00 D Rule Mexico 1931 only - Oct 1 0:00 0 S @@ -2590,14 +2599,12 @@ Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u -6:00 Mexico C%sT # Coahuila, Nuevo León, Tamaulipas (near US border) # This includes the following municipalities: -# in Coahuila: Ocampo, Acuña, Zaragoza, Jiménez, Piedras Negras, Nava, -# Guerrero, Hidalgo. -# in Nuevo León: Anáhuac, Los Aldama. +# in Coahuila: Acuña, Allende, Guerrero, Hidalgo, Jiménez, Morelos, Nava, +# Ocampo, Piedras Negras, Villa Unión, Zaragoza +# in Nuevo León: Anáhuac # in Tamaulipas: Nuevo Laredo, Guerrero, Mier, Miguel Alemán, Camargo, # Gustavo Díaz Ordaz, Reynosa, Río Bravo, Valle Hermoso, Matamoros. -# See: Inicia mañana Horario de Verano en zona fronteriza, El Universal, -# 2016-03-12 -# http://www.eluniversal.com.mx/articulo/estados/2016/03/12/inicia-manana-horario-de-verano-en-zona-fronteriza +# https://www.dof.gob.mx/nota_detalle.php?codigo=5670045&fecha=28/10/2022 Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u -6:00 - CST 1988 -6:00 US C%sT 1989 @@ -2616,10 +2623,24 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u -6:00 Mexico C%sT 2001 Sep 30 2:00 -6:00 - CST 2002 Feb 20 -6:00 Mexico C%sT -# Chihuahua (near US border) +# Chihuahua (near US border - western side) # This includes the municipalities of Janos, Ascensión, Juárez, Guadalupe, -# Práxedis G Guerrero, Coyame del Sotol, Ojinaga, and Manuel Benavides. -# (See the 2016-03-12 El Universal source mentioned above.) +# and Práxedis G Guerrero. +# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf +Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 + -7:00 US M%sT 2022 Oct 30 2:00 + -6:00 - CST 2022 Nov 30 0:00 + -7:00 US M%sT +# Chihuahua (near US border - eastern side) +# The municipalities of Coyame del Sotol, Ojinaga, and Manuel Benavides. +# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 @@ -2629,7 +2650,8 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -6:00 - CST 1998 Apr Sun>=1 3:00 -7:00 Mexico M%sT 2010 -7:00 US M%sT 2022 Oct 30 2:00 - -6:00 - CST + -6:00 - CST 2022 Nov 30 0:00 + -6:00 US C%sT # Chihuahua (away from US border) Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 @@ -2651,6 +2673,18 @@ Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u -7:00 Mexico M%sT 1999 -7:00 - MST +# Baja California Sur, Nayarit (except Bahía de Banderas), Sinaloa +Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT + +# Bahía de Banderas + # From Alexander Krivenyshev (2010-04-21): # According to news, Bahía de Banderas (Mexican state of Nayarit) # changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to @@ -2678,17 +2712,6 @@ Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u # From Arthur David Olson (2010-05-01): # Use "Bahia_Banderas" to keep the name to fourteen characters. -# Mazatlán -Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 - -6:00 - CST 1930 Nov 15 - -7:00 Mexico M%sT 1932 Apr 1 - -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 - -7:00 Mexico M%sT - -# Bahía de Banderas Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 diff --git a/tz/private.h b/tz/private.h index 18f6a05..7a73eff 100644 --- a/tz/private.h +++ b/tz/private.h @@ -17,6 +17,10 @@ ** Thank you! */ +#ifndef __STDC_VERSION__ +# define __STDC_VERSION__ 0 +#endif + /* Define true, false and bool if they don't work out of the box. */ #if __STDC_VERSION__ < 199901 # define true 1 @@ -56,24 +60,13 @@ # endif #endif /* _Generic is buggy in pre-4.9 GCC. */ -#if !defined HAVE_GENERIC && defined __GNUC__ +#if !defined HAVE_GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__ # define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__)) #endif #ifndef HAVE_GENERIC # define HAVE_GENERIC (201112 <= __STDC_VERSION__) #endif -#if !defined HAVE_GETRANDOM && defined __has_include -# if __has_include() -# define HAVE_GETRANDOM true -# else -# define HAVE_GETRANDOM false -# endif -#endif -#ifndef HAVE_GETRANDOM -# define HAVE_GETRANDOM (2 < __GLIBC__ + (25 <= __GLIBC_MINOR__)) -#endif - #if !defined HAVE_GETTEXT && defined __has_include # if __has_include() # define HAVE_GETTEXT true @@ -289,36 +282,36 @@ #endif /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ -#ifdef __LONG_LONG_MAX__ +#if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__ # ifndef LLONG_MAX # define LLONG_MAX __LONG_LONG_MAX__ # endif # ifndef LLONG_MIN # define LLONG_MIN (-1 - LLONG_MAX) # endif +# ifndef ULLONG_MAX +# define ULLONG_MAX (LLONG_MAX * 2ull + 1) +# endif #endif #ifndef INT_FAST64_MAX -# ifdef LLONG_MAX -typedef long long int_fast64_t; -# define INT_FAST64_MIN LLONG_MIN -# define INT_FAST64_MAX LLONG_MAX -# else -# if LONG_MAX >> 31 < 0xffffffff -Please use a compiler that supports a 64-bit integer type (or wider); -you may need to compile with "-DHAVE_STDINT_H". -# endif -typedef long int_fast64_t; +# if 1 <= LONG_MAX >> 31 >> 31 +typedef long int_fast64_t; # define INT_FAST64_MIN LONG_MIN # define INT_FAST64_MAX LONG_MAX +# else +/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ +typedef long long int_fast64_t; +# define INT_FAST64_MIN LLONG_MIN +# define INT_FAST64_MAX LLONG_MAX # endif #endif #ifndef PRIdFAST64 -# if INT_FAST64_MAX == LLONG_MAX -# define PRIdFAST64 "lld" -# else +# if INT_FAST64_MAX == LONG_MAX # define PRIdFAST64 "ld" +# else +# define PRIdFAST64 "lld" # endif #endif @@ -364,24 +357,27 @@ typedef long intmax_t; # endif #endif +#ifndef PTRDIFF_MAX +# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)) +#endif + #ifndef UINT_FAST32_MAX typedef unsigned long uint_fast32_t; #endif #ifndef UINT_FAST64_MAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ -typedef unsigned long long uint_fast64_t; +# if 3 <= ULONG_MAX >> 31 >> 31 +typedef unsigned long uint_fast64_t; +# define UINT_FAST64_MAX ULONG_MAX # else -# if ULONG_MAX >> 31 >> 1 < 0xffffffff -Please use a compiler that supports a 64-bit integer type (or wider); -you may need to compile with "-DHAVE_STDINT_H". -# endif -typedef unsigned long uint_fast64_t; +/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ +typedef unsigned long long uint_fast64_t; +# define UINT_FAST64_MAX ULLONG_MAX # endif #endif #ifndef UINTMAX_MAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ +# ifdef ULLONG_MAX typedef unsigned long long uintmax_t; # else typedef unsigned long uintmax_t; @@ -389,7 +385,7 @@ typedef unsigned long uintmax_t; #endif #ifndef PRIuMAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ +# ifdef ULLONG_MAX # define PRIuMAX "llu" # else # define PRIuMAX "lu" @@ -400,23 +396,114 @@ typedef unsigned long uintmax_t; # define SIZE_MAX ((size_t) -1) #endif +/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like + hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */ +#if !defined HAVE_STDCKDINT_H && defined __has_include +# if __has_include() +# define HAVE_STDCKDINT_H true +# endif +#endif +#ifdef HAVE_STDCKDINT_H +# if HAVE_STDCKDINT_H +# include +# endif +#elif defined __EDG__ +/* Do nothing, to work around EDG bug . */ +#elif defined __has_builtin +# if __has_builtin(__builtin_add_overflow) +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_sub_overflow) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_mul_overflow) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +# endif +#elif 7 <= __GNUC__ +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +#endif + #if 3 <= __GNUC__ -# define ATTRIBUTE_CONST __attribute__((const)) -# define ATTRIBUTE_MALLOC __attribute__((__malloc__)) -# define ATTRIBUTE_PURE __attribute__((__pure__)) -# define ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec)) +# define ATTRIBUTE_MALLOC __attribute__((malloc)) +# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) #else -# define ATTRIBUTE_CONST /* empty */ # define ATTRIBUTE_MALLOC /* empty */ -# define ATTRIBUTE_PURE /* empty */ # define ATTRIBUTE_FORMAT(spec) /* empty */ #endif -#if !defined _Noreturn && __STDC_VERSION__ < 201112 -# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) -# define _Noreturn __attribute__((__noreturn__)) +#if (defined __has_c_attribute \ + && (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__)) +# define HAVE_HAS_C_ATTRIBUTE true +#else +# define HAVE_HAS_C_ATTRIBUTE false +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(fallthrough) +# define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +# endif +#endif +#ifndef ATTRIBUTE_FALLTHROUGH +# if 7 <= __GNUC__ +# define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define ATTRIBUTE_FALLTHROUGH ((void) 0) +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(maybe_unused) +# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]] +# endif +#endif +#ifndef ATTRIBUTE_MAYBE_UNUSED +# if 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define ATTRIBUTE_MAYBE_UNUSED __attribute__((unused)) +# else +# define ATTRIBUTE_MAYBE_UNUSED /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(noreturn) +# define ATTRIBUTE_NORETURN [[noreturn]] +# endif +#endif +#ifndef ATTRIBUTE_NORETURN +# if 201112 <= __STDC_VERSION__ +# define ATTRIBUTE_NORETURN _Noreturn +# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define ATTRIBUTE_NORETURN __attribute__((noreturn)) # else -# define _Noreturn +# define ATTRIBUTE_NORETURN /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(reproducible) +# define ATTRIBUTE_REPRODUCIBLE [[reproducible]] +# endif +#endif +#ifndef ATTRIBUTE_REPRODUCIBLE +# if 3 <= __GNUC__ +# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure)) +# else +# define ATTRIBUTE_REPRODUCIBLE /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(unsequenced) +# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] +# endif +#endif +#ifndef ATTRIBUTE_UNSEQUENCED +# if 3 <= __GNUC__ +# define ATTRIBUTE_UNSEQUENCED __attribute__((const)) +# else +# define ATTRIBUTE_UNSEQUENCED /* empty */ # endif #endif @@ -541,7 +628,7 @@ char *asctime(struct tm const *); char *asctime_r(struct tm const *restrict, char *restrict); char *ctime(time_t const *); char *ctime_r(time_t const *, char *); -double difftime(time_t, time_t) ATTRIBUTE_CONST; +double difftime(time_t, time_t) ATTRIBUTE_UNSEQUENCED; size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); # if HAVE_STRFTIME_L @@ -554,9 +641,24 @@ struct tm *localtime(time_t const *); struct tm *localtime_r(time_t const *restrict, struct tm *restrict); time_t mktime(struct tm *); time_t time(time_t *); +time_t timegm(struct tm *); void tzset(void); #endif +#ifndef HAVE_DECL_TIMEGM +# if (202311 <= __STDC_VERSION__ \ + || defined __GLIBC__ || defined __tm_zone /* musl */ \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# define HAVE_DECL_TIMEGM true +# else +# define HAVE_DECL_TIMEGM false +# endif +#endif +#if !HAVE_DECL_TIMEGM && !defined timegm +time_t timegm(struct tm *); +#endif + #if !HAVE_DECL_ASCTIME_R && !defined asctime_r extern char *asctime_r(struct tm const *restrict, char *restrict); #endif @@ -593,9 +695,6 @@ extern long altzone; # if TZ_TIME_T || !defined offtime struct tm *offtime(time_t const *, long); # endif -# if TZ_TIME_T || !defined timegm -time_t timegm(struct tm *); -# endif # if TZ_TIME_T || !defined timelocal time_t timelocal(struct tm *); # endif @@ -613,6 +712,7 @@ time_t posix2time(time_t); /* Infer TM_ZONE on systems where this information is known, but suppress guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */ #if (defined __GLIBC__ \ + || defined __tm_zone /* musl */ \ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ || (defined __APPLE__ && defined __MACH__)) # if !defined TM_GMTOFF && !defined NO_TM_GMTOFF @@ -640,10 +740,10 @@ timezone_t tzalloc(char const *); void tzfree(timezone_t); # ifdef STD_INSPIRED # if TZ_TIME_T || !defined posix2time_z -time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_PURE; +time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE; # endif # if TZ_TIME_T || !defined time2posix_z -time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE; +time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE; # endif # endif #endif diff --git a/tz/southamerica b/tz/southamerica index 13cc65e..87b71d5 100644 --- a/tz/southamerica +++ b/tz/southamerica @@ -1418,9 +1418,14 @@ Zone Antarctica/Palmer 0 - -00 1965 # Milne gives 4:56:16.4 for Bogotá time in 1899. He writes, # "A variation of fifteen minutes in the public clocks of Bogota is not rare." +# From Alois Treindl (2022-11-10): +# End of time change in Colombia 1993 ... should be 6 February 24h ... +# DECRETO 267 DE 1993 +# https://www.suin-juriscol.gov.co/viewDocument.asp?ruta=Decretos/1061335 + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule CO 1992 only - May 3 0:00 1:00 - -Rule CO 1993 only - Apr 4 0:00 0 - +Rule CO 1992 only - May 3 0:00 1:00 - +Rule CO 1993 only - Feb 6 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF -4:56:16.4 Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 diff --git a/tz/strftime.c b/tz/strftime.c index deba2b5..b23b610 100644 --- a/tz/strftime.c +++ b/tz/strftime.c @@ -117,7 +117,7 @@ static char * _yconv(int, int, bool, bool, char *, char const *); #if HAVE_STRFTIME_L size_t strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t, - locale_t locale) + ATTRIBUTE_MAYBE_UNUSED locale_t locale) { /* Just call strftime, as only the C locale is supported. */ return strftime(s, maxsize, format, t); @@ -319,12 +319,21 @@ _fmt(const char *format, const struct tm *t, char *pt, time_t) + 1]; time_t mkt; - tm = *t; + tm.tm_sec = t->tm_sec; + tm.tm_min = t->tm_min; + tm.tm_hour = t->tm_hour; + tm.tm_mday = t->tm_mday; + tm.tm_mon = t->tm_mon; + tm.tm_year = t->tm_year; + tm.tm_isdst = t->tm_isdst; +#if defined TM_GMTOFF && ! UNINIT_TRAP + tm.TM_GMTOFF = t->TM_GMTOFF; +#endif mkt = mktime(&tm); - /* There is no portable, definitive - test for whether whether mktime - succeeded, so treat (time_t) -1 as - the success that it might be. */ + /* If mktime fails, %s expands to the + value of (time_t) -1 as a failure + marker; this is better in practice + than strftime failing. */ if (TYPE_SIGNED(time_t)) { intmax_t n = mkt; sprintf(buf, "%"PRIdMAX, n); diff --git a/tz/theory.html b/tz/theory.html index 298db86..75e347f 100644 --- a/tz/theory.html +++ b/tz/theory.html @@ -60,7 +60,6 @@

Scope of the tz database

American mountain time zone can choose from the timezones America/Denver which observes US-style daylight saving time (DST), -America/Mazatlan which observes Mexican-style DST, and America/Phoenix which does not observe DST. Applications that also deal with past timestamps in the mountain time zone can choose from over a dozen timezones, such as diff --git a/tz/time2posix.3 b/tz/time2posix.3 index 1fcdf9e..e13c431 100644 --- a/tz/time2posix.3 +++ b/tz/time2posix.3 @@ -1,9 +1,11 @@ -.TH TIME2POSIX 3 +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. +.TH time2posix 3 .SH NAME time2posix, posix2time \- convert seconds since the Epoch .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -58,7 +60,7 @@ expression for directly computing a time_t value from a given date/time, and the same relationship is assumed by some (usually older) applications. -Any programs creating/dissecting time_t's +Any programs creating/dissecting time_t values using such a relationship will typically not handle intervals over leap seconds correctly. .PP @@ -93,7 +95,7 @@ Both of these are good indicators of the inferiority of the POSIX representation. .PP The following table summarizes the relationship between a time -T and it's conversion to, +T and its conversion to, and back from, the POSIX representation over the leap second inserted at the end of June, 1993. @@ -117,8 +119,8 @@ DATE TIME T X=time2posix(T) posix2time(X) .fi .PP If leap-second support is not enabled, -local time_t's and -POSIX time_t's are equivalent, +local time_t and +POSIX time_t values are equivalent, and both .B time2posix and @@ -129,5 +131,3 @@ difftime(3), localtime(3), mktime(3), time(2) -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/tz/tzfile.5 b/tz/tzfile.5 index 280e8d8..c3e86c6 100644 --- a/tz/tzfile.5 +++ b/tz/tzfile.5 @@ -1,3 +1,5 @@ +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. .TH TZFILE 5 .SH NAME tzfile \- timezone information @@ -9,7 +11,7 @@ tzfile \- timezone information .de q \\$3\*(lq\\$1\*(rq\\$2 .. -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- The timezone information files used by .BR tzset (3) @@ -492,5 +494,3 @@ Internet RFC 8536 .UR https://\:doi.org/\:10.17487/\:RFC8536 doi:10.17487/RFC8536 .UE . -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/tz/tzselect.8 b/tz/tzselect.8 index 1a5ce11..846b867 100644 --- a/tz/tzselect.8 +++ b/tz/tzselect.8 @@ -1,8 +1,10 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH TZSELECT 8 .SH NAME tzselect \- select a timezone .SH SYNOPSIS -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .ds d " degrees .ds m " minutes @@ -121,5 +123,3 @@ newctime(3), tzfile(5), zdump(8), zic(8) Applications should not assume that .BR tzselect 's output matches the user's political preferences. -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/zdump.8 b/tz/zdump.8 index 131a6cb..170e18d 100644 --- a/tz/zdump.8 +++ b/tz/zdump.8 @@ -1,4 +1,6 @@ -.TH ZDUMP 8 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zdump 8 .SH NAME zdump \- timezone dumper .SH SYNOPSIS @@ -16,7 +18,7 @@ zdump \- timezone dumper .de q \\$3\*(lq\\$1\*(rq\\$2 .. -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- The .B zdump @@ -149,7 +151,7 @@ Here is an example of the output, with the leading empty line omitted. tabbed columns line up.) .nf .sp -.if \n(.g .ft CW +.if \n(.g .ft CR .if t .in +.5i .if n .in +2 .nr w \w'1896-01-13 'u+\n(.i @@ -182,7 +184,7 @@ UT, a standard time abbreviated HST. Here are excerpts from another example: .nf .sp -.if \n(.g .ft CW +.if \n(.g .ft CR .if t .in +.5i .if n .in +2 TZ="Europe/Astrakhan" @@ -227,5 +229,3 @@ introduction of UTC is problematic. .SH SEE ALSO .BR tzfile (5), .BR zic (8) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/zdump.c b/tz/zdump.c index ffb321a..7acb3e2 100644 --- a/tz/zdump.c +++ b/tz/zdump.c @@ -84,20 +84,20 @@ static time_t const absolute_max_time = ? (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift)) : -1); static int longest; -static char * progname; +static char const *progname; static bool warned; static bool errout; static char const *abbr(struct tm const *); -static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE; +static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_REPRODUCIBLE; static void dumptime(struct tm const *); -static time_t hunt(timezone_t, char *, time_t, time_t, bool); +static time_t hunt(timezone_t, time_t, time_t, bool); static void show(timezone_t, char *, time_t, bool); static void showextrema(timezone_t, char *, time_t, struct tm *, time_t); static void showtrans(char const *, struct tm const *, time_t, char const *, char const *); static const char *tformat(void); -static time_t yeartot(intmax_t) ATTRIBUTE_PURE; +static time_t yeartot(intmax_t) ATTRIBUTE_REPRODUCIBLE; /* Is C an ASCII digit? */ static bool @@ -125,16 +125,28 @@ is_alpha(char a) } } -/* Return A + B, exiting if the result would overflow. */ -static size_t +static ATTRIBUTE_NORETURN void +size_overflow(void) +{ + fprintf(stderr, _("%s: size overflow\n"), progname); + exit(EXIT_FAILURE); +} + +/* Return A + B, exiting if the result would overflow either ptrdiff_t + or size_t. */ +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t sumsize(size_t a, size_t b) { - size_t sum = a + b; - if (sum < a) { - fprintf(stderr, _("%s: size overflow\n"), progname); - exit(EXIT_FAILURE); - } - return sum; +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX) + return sum; +#else + ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX); + if (a <= sum_max && b <= sum_max - a) + return a + b; +#endif + size_overflow(); } /* Return a pointer to a newly allocated buffer of size SIZE, exiting @@ -234,22 +246,30 @@ tzalloc(char const *val) exit(EXIT_FAILURE); } tzset(); - return NULL; + return &optarg; /* Any valid non-null char ** will do. */ # else enum { TZeqlen = 3 }; static char const TZeq[TZeqlen] = "TZ="; static char **fakeenv; - static size_t fakeenv0size; + static ptrdiff_t fakeenv0size; void *freeable = NULL; char **env = fakeenv, **initial_environ; size_t valsize = strlen(val) + 1; if (fakeenv0size < valsize) { char **e = environ, **to; - ptrdiff_t initial_nenvptrs; /* Counting the trailing NULL pointer. */ - - while (*e++) - continue; - initial_nenvptrs = e - environ; + ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ + + while (*e++) { +# ifdef ckd_add + if (ckd_add(&initial_nenvptrs, initial_envptrs, 1) + || SIZE_MAX < initial_envptrs) + size_overflow(); +# else + if (initial_nenvptrs == min(PTRDIFF_MAX, SIZE_MAX) / sizeof *environ) + size_overflow(); + initial_nenvptrs++; +# endif + } fakeenv0size = sumsize(valsize, valsize); fakeenv0size = max(fakeenv0size, 64); freeable = env; @@ -385,7 +405,7 @@ abbrok(const char *const abbrp, const char *const zone) return the abbreviation. Get the abbreviation from TMP. Exit on memory allocation failure. */ static char const * -saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp) +saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) { char const *ab = abbr(tmp); if (HAVE_LOCALTIME_RZ) @@ -442,7 +462,7 @@ main(int argc, char *argv[]) { /* These are static so that they're initially zero. */ static char * abbrev; - static size_t abbrevsize; + static ptrdiff_t abbrevsize; register int i; register bool vflag; @@ -463,7 +483,7 @@ main(int argc, char *argv[]) # endif /* defined TEXTDOMAINDIR */ textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ - progname = argv[0]; + progname = argv[0] ? argv[0] : "zdump"; for (i = 1; i < argc; ++i) if (strcmp(argv[i], "--version") == 0) { printf("zdump %s%s\n", PKGVERSION, TZVERSION); @@ -483,7 +503,7 @@ main(int argc, char *argv[]) case -1: if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) goto arg_processing_done; - /* Fall through. */ + ATTRIBUTE_FALLTHROUGH; default: usage(stderr, EXIT_FAILURE); } @@ -607,7 +627,7 @@ main(int argc, char *argv[]) || (ab && (delta(&newtm, &tm) != newt - t || newtm.tm_isdst != tm.tm_isdst || strcmp(abbr(&newtm), ab) != 0))) { - newt = hunt(tz, argv[i], t, newt, false); + newt = hunt(tz, t, newt, false); newtmp = localtime_rz(tz, &newt, &newtm); newtm_ok = newtmp != NULL; if (iflag) @@ -687,7 +707,7 @@ yeartot(intmax_t y) return t; } -/* Search for a discontinuity in timezone TZ with name NAME, in the +/* Search for a discontinuity in timezone TZ, in the timestamps ranging from LOT through HIT. LOT and HIT disagree about some aspect of timezone. If ONLY_OK, search only for definedness changes, i.e., localtime succeeds on one side of the @@ -695,10 +715,10 @@ yeartot(intmax_t y) before the transition from LOT's settings. */ static time_t -hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok) +hunt(timezone_t tz, time_t lot, time_t hit, bool only_ok) { static char * loab; - static size_t loabsize; + static ptrdiff_t loabsize; struct tm lotm; struct tm tm; @@ -787,7 +807,8 @@ adjusted_yday(struct tm const *a, struct tm const *b) my_gmtime_r and use its result instead of B. Otherwise, B is the possibly nonnull result of an earlier call to my_gmtime_r. */ static long -gmtoff(struct tm const *a, time_t *t, struct tm const *b) +gmtoff(struct tm const *a, ATTRIBUTE_MAYBE_UNUSED time_t *t, + ATTRIBUTE_MAYBE_UNUSED struct tm const *b) { #ifdef TM_GMTOFF return a->TM_GMTOFF; @@ -858,7 +879,7 @@ static void showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) { struct tm localtm[2], gmtm[2]; - time_t t, boundary = hunt(tz, zone, lo, hi, true); + time_t t, boundary = hunt(tz, lo, hi, true); bool old = false; hi = (SECSPERDAY < hi - boundary ? boundary + SECSPERDAY @@ -937,7 +958,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) fit, return the length that the string would have been if it had fit; do not overrun the output buffer. */ static int -format_local_time(char *buf, size_t size, struct tm const *tm) +format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) { int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; return (ss @@ -960,7 +981,7 @@ format_local_time(char *buf, size_t size, struct tm const *tm) the length that the string would have been if it had fit; do not overrun the output buffer. */ static int -format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t) +format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) { long off = gmtoff(tm, &t, NULL); char sign = ((off < 0 @@ -989,11 +1010,11 @@ format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t) If the representation's length is less than SIZE, return the length; the representation is not null terminated. Otherwise return SIZE, to indicate that BUF is too small. */ -static size_t -format_quoted_string(char *buf, size_t size, char const *p) +static ptrdiff_t +format_quoted_string(char *buf, ptrdiff_t size, char const *p) { char *b = buf; - size_t s = size; + ptrdiff_t s = size; if (!s) return size; *b++ = '"', s--; @@ -1031,11 +1052,11 @@ format_quoted_string(char *buf, size_t size, char const *p) and omit any trailing tabs. */ static bool -istrftime(char *buf, size_t size, char const *time_fmt, +istrftime(char *buf, ptrdiff_t size, char const *time_fmt, struct tm const *tm, time_t t, char const *ab, char const *zone_name) { char *b = buf; - size_t s = size; + ptrdiff_t s = size; char const *f = time_fmt, *p; for (p = f; ; p++) @@ -1044,9 +1065,9 @@ istrftime(char *buf, size_t size, char const *time_fmt, else if (!*p || (*p == '%' && (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) { - size_t formatted_len; - size_t f_prefix_len = p - f; - size_t f_prefix_copy_size = p - f + 2; + ptrdiff_t formatted_len; + ptrdiff_t f_prefix_len = p - f; + ptrdiff_t f_prefix_copy_size = sumsize(f_prefix_len, 2); char fbuf[100]; bool oversized = sizeof fbuf <= f_prefix_copy_size; char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf; @@ -1078,7 +1099,7 @@ istrftime(char *buf, size_t size, char const *time_fmt, b += offlen, s -= offlen; if (show_abbr) { char const *abp; - size_t len; + ptrdiff_t len; if (s <= 1) return false; *b++ = '\t', s--; @@ -1117,7 +1138,7 @@ showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab, putchar('\n'); } else { char stackbuf[1000]; - size_t size = sizeof stackbuf; + ptrdiff_t size = sizeof stackbuf; char *buf = stackbuf; char *bufalloc = NULL; while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) { diff --git a/tz/zic.8 b/tz/zic.8 index f79148f..019a289 100644 --- a/tz/zic.8 +++ b/tz/zic.8 @@ -1,4 +1,6 @@ -.TH ZIC 8 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zic 8 .SH NAME zic \- timezone compiler .SH SYNOPSIS @@ -22,7 +24,7 @@ zic \- timezone compiler .el .ds > \(ra .ie \n(.g \{\ . ds : \: -. ds - \f(CW-\fP +. ds - \f(CR-\fP .\} .el \{\ . ds : @@ -347,7 +349,9 @@ nor .q + . To allow for future extensions, an unquoted name should not contain characters from the set -.q !$%&'()*,/:;<=>?@[\e]^`{|}~ . +.ie \n(.g .q \f(CR!$%&\(aq()*,/:;<=>?@[\e]\(ha\(ga{|}\(ti\fP . +.el .ie t .q \f(CW!$%&'()*,/:;<=>?@[\e]^\(ga{|}~\fP . +.el .q !$%&'()*,/:;<=>?@[\e]^`{|}~ . .TP .B FROM Gives the first year in which the rule applies. @@ -894,5 +898,3 @@ specifying transition instants using universal time. .SH SEE ALSO .BR tzfile (5), .BR zdump (8) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/tz/zic.c b/tz/zic.c index 501718f..892414a 100644 --- a/tz/zic.c +++ b/tz/zic.c @@ -34,6 +34,9 @@ static zic_t const # define ZIC_MAX_ABBR_LEN_WO_WARN 6 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ +/* An upper bound on how much a format might grow due to concatenation. */ +enum { FORMAT_LEN_GROWTH_BOUND = 5 }; + #ifdef HAVE_DIRECT_H # include # include @@ -41,7 +44,16 @@ static zic_t const # define mkdir(name, mode) _mkdir(name) #endif -#if HAVE_GETRANDOM +#ifndef HAVE_GETRANDOM +# ifdef __has_include +# if __has_include() +# include +# endif +# elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__) +# include +# endif +# define HAVE_GETRANDOM GRND_RANDOM +#elif HAVE_GETRANDOM # include #endif @@ -54,11 +66,6 @@ static zic_t const # define MKDIR_UMASK 0755 #endif -/* The maximum ptrdiff_t value, for pre-C99 platforms. */ -#ifndef PTRDIFF_MAX -static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)); -#endif - /* The minimum alignment of a type, for pre-C23 platforms. */ #if __STDC_VERSION__ < 201112 # define alignof(type) offsetof(struct { char a; type b; }, b) @@ -452,29 +459,54 @@ static char roll[TZ_MAX_LEAPS]; ** Memory allocation. */ -static _Noreturn void +static ATTRIBUTE_NORETURN void memory_exhausted(const char *msg) { fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); exit(EXIT_FAILURE); } -static ATTRIBUTE_PURE size_t -size_product(size_t nitems, size_t itemsize) +static ATTRIBUTE_NORETURN void +size_overflow(void) +{ + memory_exhausted(_("size overflow")); +} + +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +size_sum(size_t a, size_t b) +{ +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX) + return sum; +#else + ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX); + if (a <= sum_max && b <= sum_max - a) + return a + b; +#endif + size_overflow(); +} + +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +size_product(ptrdiff_t nitems, ptrdiff_t itemsize) { - if (SIZE_MAX / itemsize < nitems) - memory_exhausted(_("size overflow")); - return nitems * itemsize; +#ifdef ckd_mul + ptrdiff_t product; + if (!ckd_mul(&product, nitems, itemsize) && product <= SIZE_MAX) + return product; +#else + ptrdiff_t nitems_max = min(PTRDIFF_MAX, SIZE_MAX) / itemsize; + if (nitems <= nitems_max) + return nitems * itemsize; +#endif + size_overflow(); } -static ATTRIBUTE_PURE size_t -align_to(size_t size, size_t alignment) +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +align_to(ptrdiff_t size, ptrdiff_t alignment) { - size_t aligned_size = size + alignment - 1; - aligned_size -= aligned_size % alignment; - if (aligned_size < size) - memory_exhausted(_("alignment overflow")); - return aligned_size; + ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); + return sum & ~lo_bits; } #if !HAVE_STRDUP @@ -507,23 +539,37 @@ erealloc(void *ptr, size_t size) } static char * ATTRIBUTE_MALLOC -ecpyalloc(char const *str) +estrdup(char const *str) { return memcheck(strdup(str)); } +static ptrdiff_t +grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) +{ + ptrdiff_t addend = (*nitems_alloc >> 1) + 1; +#if defined ckd_add && defined ckd_mul + ptrdiff_t product; + if (!ckd_add(nitems_alloc, *nitems_alloc, addend) + && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= SIZE_MAX) + return product; +#else + ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX); + if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) { + *nitems_alloc += addend; + return *nitems_alloc * itemsize; + } +#endif + memory_exhausted(_("integer overflow")); +} + static void * -growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc) +growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, + ptrdiff_t *nitems_alloc) { - if (nitems < *nitems_alloc) - return ptr; - else { - ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX); - if ((amax - 1) / 3 * 2 < *nitems_alloc) - memory_exhausted(_("integer overflow")); - *nitems_alloc += (*nitems_alloc >> 1) + 1; - return erealloc(ptr, size_product(*nitems_alloc, itemsize)); - } + return (nitems < *nitems_alloc + ? ptr + : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); } /* @@ -620,7 +666,7 @@ close_file(FILE *stream, char const *dir, char const *name, } } -static _Noreturn void +static ATTRIBUTE_NORETURN void usage(FILE *stream, int status) { fprintf(stream, @@ -943,7 +989,7 @@ main(int argc, char **argv) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ main_argv = argv; - progname = argv[0]; + progname = argv[0] ? argv[0] : "zic"; if (TYPE_BIT(zic_t) < 64) { fprintf(stderr, "%s: %s\n", progname, _("wild compilation-time specification of zic_t")); @@ -1201,21 +1247,12 @@ get_rand_u64(void) #endif /* getrandom didn't work, so fall back on portable code that is - not the best because the seed doesn't necessarily have enough bits, - the seed isn't cryptographically random on platforms lacking - getrandom, and 'rand' might not be cryptographically secure. */ + not the best because the seed isn't cryptographically random and + 'rand' might not be cryptographically secure. */ { static bool initialized; if (!initialized) { - unsigned seed; -#ifdef CLOCK_REALTIME - struct timespec now; - clock_gettime (CLOCK_REALTIME, &now); - seed = now.tv_sec ^ now.tv_nsec; -#else - seed = time(NULL); -#endif - srand(seed); + srand(time(NULL)); initialized = true; } } @@ -1224,13 +1261,21 @@ get_rand_u64(void) the typical case where RAND_MAX is one less than a power of two. In other cases this code yields a sort-of-random number. */ { - uint_fast64_t - rand_max = RAND_MAX, - multiplier = rand_max + 1, /* It's OK if this overflows to 0. */ + uint_fast64_t rand_max = RAND_MAX, + nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0, + rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1, r = 0, rmax = 0; + do { - uint_fast64_t rmax1 = rmax * multiplier + rand_max; - r = r * multiplier + rand(); + uint_fast64_t rmax1 = rmax; + if (rmod) { + /* Avoid signed integer overflow on theoretical platforms + where uint_fast64_t promotes to int. */ + rmax1 %= rmod; + r %= rmod; + } + rmax1 = nrand * rmax1 + rand_max; + r = nrand * r + rand(); rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX; } while (rmax < UINT_FAST64_MAX); @@ -1272,7 +1317,7 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = emalloc(dirlen + prefixlen + suffixlen + 1); + dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); memcpy(dst, src, dirlen); memcpy(dst + dirlen, prefix, prefixlen); dst[dirlen + prefixlen + suffixlen] = '\0'; @@ -1351,19 +1396,20 @@ rename_dest(char *tempname, char const *name) static char * relname(char const *target, char const *linkname) { - size_t i, taillen, dotdotetcsize; - size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; + size_t i, taillen, dir_len = 0, dotdots = 0; + ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX); char const *f = target; char *result = NULL; if (*linkname == '/') { /* Make F absolute too. */ size_t len = strlen(directory); - bool needslash = len && directory[len - 1] != '/'; - linksize = len + needslash + strlen(target) + 1; + size_t lenslash = len + (len && directory[len - 1] != '/'); + size_t targetsize = strlen(target) + 1; + linksize = size_sum(lenslash, targetsize); f = result = emalloc(linksize); - strcpy(result, directory); + memcpy(result, directory, len); result[len] = '/'; - strcpy(result + len + needslash, target); + memcpy(result + lenslash, target, targetsize); } for (i = 0; f[i] && f[i] == linkname[i]; i++) if (f[i] == '/') @@ -1371,7 +1417,7 @@ relname(char const *target, char const *linkname) for (; linkname[i]; i++) dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; taillen = strlen(f + dir_len); - dotdotetcsize = 3 * dotdots + taillen + 1; + dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { if (!result) result = emalloc(dotdotetcsize); @@ -1575,10 +1621,9 @@ associate(void) /* Read a text line from FP into BUF, which is of size BUFSIZE. Terminate it with a NUL byte instead of a newline. - Return the line's length, not counting the NUL byte. - On EOF, return a negative number. + Return true if successful, false if EOF. On error, report the error and exit. */ -static ptrdiff_t +static bool inputline(FILE *fp, char *buf, ptrdiff_t bufsize) { ptrdiff_t linelen = 0, ch; @@ -1589,7 +1634,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize) exit(EXIT_FAILURE); } if (linelen == 0) - return -1; + return false; error(_("unterminated line")); exit(EXIT_FAILURE); } @@ -1604,7 +1649,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize) } } buf[linelen] = '\0'; - return linelen; + return true; } static void @@ -1626,13 +1671,14 @@ infile(int fnum, char const *name) } wantcont = false; for (num = 1; ; ++num) { - ptrdiff_t linelen; - char buf[_POSIX2_LINE_MAX]; + enum { bufsize_bound + = (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX)) + / FORMAT_LEN_GROWTH_BOUND) }; + char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; int nfields; char *fields[MAX_FIELDS]; eat(fnum, num); - linelen = inputline(fp, buf, sizeof buf); - if (linelen < 0) + if (!inputline(fp, buf, sizeof buf)) break; nfields = getfields(buf, fields, sizeof fields / sizeof *fields); @@ -1704,15 +1750,15 @@ gethms(char const *string, char const *errstring) default: ok = false; break; case 8: ok = '0' <= xr && xr <= '9'; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 7: ok &= ssx == '.'; if (ok && noise) warning(_("fractional seconds rejected by" " pre-2018 versions of zic")); - /* fallthrough */ - case 5: ok &= mmx == ':'; /* fallthrough */ - case 3: ok &= hhx == ':'; /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; + case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH; + case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH; case 1: break; } if (!ok) { @@ -1742,7 +1788,7 @@ getsave(char *field, bool *isdst) { int dst = -1; zic_t save; - size_t fieldlen = strlen(field); + ptrdiff_t fieldlen = strlen(field); if (fieldlen != 0) { char *ep = field + fieldlen - 1; switch (*ep) { @@ -1780,8 +1826,8 @@ inrule(char **fields, int nfields) fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD])) return; - r.r_name = ecpyalloc(fields[RF_NAME]); - r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); + r.r_name = estrdup(fields[RF_NAME]); + r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); if (max_abbrvar_len < strlen(r.r_abbrvar)) max_abbrvar_len = strlen(r.r_abbrvar); rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); @@ -1838,7 +1884,7 @@ inzsub(char **fields, int nfields, bool iscont) register char * cp; char * cp1; struct zone z; - size_t format_len; + int format_len; register int i_stdoff, i_rule, i_format; register int i_untilyear, i_untilmonth; register int i_untilday, i_untiltime; @@ -1905,9 +1951,9 @@ inzsub(char **fields, int nfields, bool iscont) return false; } } - z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]); - z.z_rule = ecpyalloc(fields[i_rule]); - z.z_format = cp1 = ecpyalloc(fields[i_format]); + z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); + z.z_rule = estrdup(fields[i_rule]); + z.z_format = cp1 = estrdup(fields[i_format]); if (z.z_format_specifier == 'z') { cp1[cp - fields[i_format]] = 's'; if (noise) @@ -1924,7 +1970,7 @@ inzsub(char **fields, int nfields, bool iscont) } static zic_t -getleapdatetime(char **fields, int nfields, bool expire_line) +getleapdatetime(char **fields, bool expire_line) { register const char * cp; register const struct lookup * lp; @@ -2002,7 +2048,7 @@ inleap(char **fields, int nfields) if (nfields != LEAP_FIELDS) error(_("wrong number of fields on Leap line")); else { - zic_t t = getleapdatetime(fields, nfields, false); + zic_t t = getleapdatetime(fields, false); if (0 <= t) { struct lookup const *lp = byword(fields[LP_ROLL], leap_types); if (!lp) @@ -2030,7 +2076,7 @@ inexpires(char **fields, int nfields) else if (0 <= leapexpires) error(_("multiple Expires lines")); else - leapexpires = getleapdatetime(fields, nfields, true); + leapexpires = getleapdatetime(fields, true); } static void @@ -2050,8 +2096,8 @@ inlink(char **fields, int nfields) return; l.l_filenum = filenum; l.l_linenum = linenum; - l.l_target = ecpyalloc(fields[LF_TARGET]); - l.l_linkname = ecpyalloc(fields[LF_LINKNAME]); + l.l_target = estrdup(fields[LF_TARGET]); + l.l_linkname = estrdup(fields[LF_LINKNAME]); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } @@ -2074,7 +2120,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, rp->r_month = lp->l_value; rp->r_todisstd = false; rp->r_todisut = false; - dp = ecpyalloc(timep); + dp = estrdup(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { @@ -2153,7 +2199,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ** Sun<=20 ** Sun>=7 */ - dp = ecpyalloc(dayp); + dp = estrdup(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; @@ -2216,7 +2262,7 @@ convert64(uint_fast64_t val, char *buf) } static void -puttzcode(const int_fast32_t val, FILE *const fp) +puttzcode(zic_t val, FILE *fp) { char buf[4]; @@ -2305,8 +2351,10 @@ writezone(const char *const name, const char *const string, char version, char const *outname = name; /* Allocate the ATS and TYPES arrays via a single malloc, - as this is a bit faster. */ - zic_t *ats = emalloc(align_to(size_product(timecnt, sizeof *ats + 1), + as this is a bit faster. Do not malloc(0) if !timecnt, + as that might return NULL even on success. */ + zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + sizeof *ats + 1), alignof(zic_t))); void *typesptr = ats + timecnt; unsigned char *types = typesptr; @@ -2739,13 +2787,13 @@ abbroffset(char *buf, zic_t offset) static char const disable_percent_s[] = ""; -static size_t +static ptrdiff_t doabbr(char *abbr, struct zone const *zp, char const *letters, bool isdst, zic_t save, bool doquotes) { register char * cp; register char * slashp; - register size_t len; + ptrdiff_t len; char const *format = zp->z_format; slashp = strchr(format, '/'); @@ -2911,9 +2959,9 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) register ptrdiff_t i; register int compat = 0; register int c; - size_t len; int offsetlen; struct rule stdr, dstr; + ptrdiff_t len; int dstcmp; struct rule *lastrp[2] = { NULL, NULL }; struct zone zstr[2]; @@ -3046,8 +3094,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) check_for_signal(); + /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */ max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; + startbuf = emalloc(max_abbr_len + 1); ab = emalloc(max_abbr_len + 1); envvar = emalloc(max_envvar_len + 1); @@ -3547,7 +3597,7 @@ lowerit(char a) } /* case-insensitive equality */ -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool ciequal(register const char *ap, register const char *bp) { while (lowerit(*ap) == lowerit(*bp++)) @@ -3556,7 +3606,7 @@ ciequal(register const char *ap, register const char *bp) return false; } -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool itsabbr(register const char *abbr, register const char *word) { if (lowerit(*abbr) != lowerit(*word)) @@ -3572,7 +3622,7 @@ itsabbr(register const char *abbr, register const char *word) /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool ciprefix(char const *abbr, char const *word) { do @@ -3675,38 +3725,41 @@ getfields(char *cp, char **array, int arrayelts) return nsubs; } -static _Noreturn void +static ATTRIBUTE_NORETURN void time_overflow(void) { error(_("time overflow")); exit(EXIT_FAILURE); } -static ATTRIBUTE_PURE zic_t +static ATTRIBUTE_REPRODUCIBLE zic_t oadd(zic_t t1, zic_t t2) { - if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) - time_overflow(); - return t1 + t2; +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2)) + return sum; +#else + if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) + return t1 + t2; +#endif + time_overflow(); } -static ATTRIBUTE_PURE zic_t +static ATTRIBUTE_REPRODUCIBLE zic_t tadd(zic_t t1, zic_t t2) { - if (t1 < 0) { - if (t2 < min_time - t1) { - if (t1 != min_time) - time_overflow(); - return min_time; - } - } else { - if (max_time - t1 < t2) { - if (t1 != max_time) - time_overflow(); - return max_time; - } - } - return t1 + t2; +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) + return sum; +#else + if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) + return t1 + t2; +#endif + if (t1 == min_time || t1 == max_time) + return t1; + time_overflow(); } /* @@ -3830,10 +3883,8 @@ mp = _("time zone abbreviation differs from POSIX standard"); static void mkdirs(char const *argname, bool ancestors) { - register char * name; - register char * cp; - - cp = name = ecpyalloc(argname); + char *name = estrdup(argname); + char *cp = name; /* On MS-Windows systems, do not worry about drive letters or backslashes, as this should suffice in practice. Time zone diff --git a/tz/zone.tab b/tz/zone.tab index 2636e21..6e5adb9 100644 --- a/tz/zone.tab +++ b/tz/zone.tab @@ -114,8 +114,7 @@ CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) @@ -277,17 +276,18 @@ MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV +0410+07330 Indian/Maldives MW -1547+03500 Africa/Blantyre -MX +1924-09909 America/Mexico_City Central Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatan -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatan +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo Leon, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahia de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) MY +0133+11020 Asia/Kuching Sabah, Sarawak MZ -2558+03235 Africa/Maputo diff --git a/tz/zone1970.tab b/tz/zone1970.tab index 75372e3..a9b36d3 100644 --- a/tz/zone1970.tab +++ b/tz/zone1970.tab @@ -102,8 +102,7 @@ CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA,BS +4339-07923 America/Toronto Eastern - ON, QC (most areas), Bahamas -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) @@ -214,17 +213,18 @@ MQ +1436-06105 America/Martinique MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV,TF +0410+07330 Indian/Maldives Maldives, Kerguelen, St Paul I, Amsterdam I -MX +1924-09909 America/Mexico_City Central Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatán -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo León, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahía de Banderas +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatán +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo León, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo León, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahía de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California MY,BN +0133+11020 Asia/Kuching Sabah, Sarawak, Brunei MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time NA -2234+01706 Africa/Windhoek