From 0f920ee55a4e8a61d354c82ff0210ddf11e7a715 Mon Sep 17 00:00:00 2001 From: Serge Vakulenko Date: Mon, 19 Oct 2015 23:40:54 -0700 Subject: [PATCH] Add zoneinfo sources. --- src/share/zoneinfo/Makefile | 68 ++ src/share/zoneinfo/README | 41 + src/share/zoneinfo/Theory | 130 +++ src/share/zoneinfo/asia | 5 + src/share/zoneinfo/australasia | 59 ++ src/share/zoneinfo/etcetera | 40 + src/share/zoneinfo/europe | 125 +++ src/share/zoneinfo/ialloc.c | 88 ++ src/share/zoneinfo/northamerica | 96 ++ src/share/zoneinfo/pacificnew | 13 + src/share/zoneinfo/scheck.c | 59 ++ src/share/zoneinfo/solar87 | 386 ++++++++ src/share/zoneinfo/systemv | 35 + src/share/zoneinfo/zdump.8 | 42 + src/share/zoneinfo/zdump.c | 209 +++++ src/share/zoneinfo/zic.8 | 294 ++++++ src/share/zoneinfo/zic.c | 1543 +++++++++++++++++++++++++++++++ 17 files changed, 3233 insertions(+) create mode 100644 src/share/zoneinfo/Makefile create mode 100644 src/share/zoneinfo/README create mode 100644 src/share/zoneinfo/Theory create mode 100644 src/share/zoneinfo/asia create mode 100644 src/share/zoneinfo/australasia create mode 100644 src/share/zoneinfo/etcetera create mode 100644 src/share/zoneinfo/europe create mode 100644 src/share/zoneinfo/ialloc.c create mode 100644 src/share/zoneinfo/northamerica create mode 100644 src/share/zoneinfo/pacificnew create mode 100644 src/share/zoneinfo/scheck.c create mode 100644 src/share/zoneinfo/solar87 create mode 100644 src/share/zoneinfo/systemv create mode 100644 src/share/zoneinfo/zdump.8 create mode 100644 src/share/zoneinfo/zdump.c create mode 100644 src/share/zoneinfo/zic.8 create mode 100644 src/share/zoneinfo/zic.c diff --git a/src/share/zoneinfo/Makefile b/src/share/zoneinfo/Makefile new file mode 100644 index 0000000..8252253 --- /dev/null +++ b/src/share/zoneinfo/Makefile @@ -0,0 +1,68 @@ +# @(#)Makefile 1.6 Makefile 1997/12/28 + +DESTDIR= + +# If you want something other than Western United States time used on your +# system, change the line below (after finding the zone you want in the +# time zone files, or adding it to a time zone file). +# Alternately, if you discover you've got the wrong time zone, you can just +# install -c -m 444 /usr/share/zoneinfo/right_zone /etc/localtime + +LOCALTIME= US/Pacific + +# If you want code inspired by certain emerging standards, add +# -DSTD_INSPIRED +# to the end of the "CFLAGS=" line. +# +# If you want to handle solar-time-based time zones, remove the +# "#define NOSOLAR" from the include file usr/include/tzfile.h. +# (and add solar87 to the DATA= line below). + +CFLAGS= -O +SEPFLAG=-i +LINTFLAGS= -phbaxc +CC= cc + +TZCSRCS= zic.c scheck.c ialloc.c +TZCOBJS= zic.o scheck.o ialloc.o +TZDSRCS= zdump.c ialloc.c +TZDOBJS= zdump.o ialloc.o +SOURCES= zic.c zdump.c scheck.c ialloc.c +DATA= asia australasia europe etcetera northamerica \ + pacificnew systemv +ZICMAN= zic.0 +ZICMANSRC= zic.8 +ZDUMAN= zdump.0 +ZDUMANSRC= zdump.8 +MAN= $(ZICMAN) $(ZDUMAN) +MANSRC= $(ZICMANSRC) $(ZDUMAN) +SHARDIR= ${DESTDIR}/usr/share/zoneinfo +MANDIR= ${DESTDIR}/usr/man/cat8 + +all: zdump zic ${ZICMAN} ${ZDUMAN} + +install: zic $(DATA) $(MAN) + (umask 22; ./zic -d ${SHARDIR} $(DATA)) + install -c -m 444 -o bin -g bin ${SHARDIR}/${LOCALTIME} ${DESTDIR}/etc/localtime + install -c -m 444 -o bin -g bin $(ZICMAN) ${MANDIR}/${ZICMAN} + install -c -m 444 -o bin -g bin $(ZDUMAN) ${MANDIR}/${ZDUMAN} + install -c -s -m 755 -o bin -g bin zic ${DESTDIR}/usr/sbin/zic + +zdump.0: $(ZDUMANSRC) + /usr/man/manroff $(ZDUMANSRC) > $(ZDUMAN) + +zic.0: $(ZICMANSRC) + /usr/man/manroff $(ZICMANSRC) > $(ZICMAN) + +zdump: $(TZDOBJS) + $(CC) $(CFLAGS) $(LFLAGS) $(SEPFLAG) $(TZDOBJS) -o $@ + +zic: $(TZCOBJS) + $(CC) $(CFLAGS) $(LFLAGS) $(SEPFLAG) $(TZCOBJS) -o $@ + +lint: $(TZCSRCS) $(TZDSRCS) + lint $(LINTFLAGS) $(CFLAGS) $(TZCSRCS) + lint $(LINTFLAGS) $(CFLAGS) $(TZDSRCS) + +clean: + rm -f *.o zdump zic $(ZICMAN) $(ZDUMAN) diff --git a/src/share/zoneinfo/README b/src/share/zoneinfo/README new file mode 100644 index 0000000..157c34c --- /dev/null +++ b/src/share/zoneinfo/README @@ -0,0 +1,41 @@ +@(#)README 3.2 1996/11/29 + +Please send comments or information to + seismo!elsie!tz +for forwarding to folks interested in time zone matters. + +Be sure to read the comments in "Makefile" and make any changes +needed to make things right for your system. + +This version of the time zone software uses a new format +(based on the work of Guy Harris, a.k.a guy@sun.UUCP) +for the time zone information files. They are stored in a +directory named "/usr/share/zoneinfo". +If you've already compiled programs with older time zone software, +you may need to make a copy of /usr/share/zoneinfo to the old location. + +For better compatability with other versions of time conversion functions, +the time zone abbreviation to be used with localtime's return value is now +pointed to by one of the two elements of the (char *) array tzname, rather +than by the (char *) tz_abbr. If you have code that uses tz_abbr, add a + -DTZA_COMPAT +to the end of the + CFLAGS= +line in "Makefile". + +To use the new functions, use a "-lz" option when compiling or linking. + +Historical local time information has been included here not because it +is particularly useful, but rather to: + +* give an idea of the variety of local time rules that have + existed in the past and thus an idea of the variety that may be + expected in the future; + +* provide a test of the generality of the local time rule description + system. + +The information in the time zone data files is by no means authoritative; +if you know that the rules are different from those in a file, by all means +feel free to change file (and please send the changed version to seismo!elsie!tz +for use in the future). Europeans take note! diff --git a/src/share/zoneinfo/Theory b/src/share/zoneinfo/Theory new file mode 100644 index 0000000..a01994c --- /dev/null +++ b/src/share/zoneinfo/Theory @@ -0,0 +1,130 @@ +@(#)Theory 3.2 1996/11/29 + +These time and date functions are much like the System V Release 2.0 (SVR2) +time and date functions; there are a few additions and changes to extend +the usefulness of the SVR2 functions: + +* In SVR2, time display in a process is controlled by the environment + variable TZ, which "must be a three-letter time zone name, followed + by a number representing the difference between local time and + Greenwich Mean Time in hours, followed by an optional three-letter + name for a daylight time zone;" when the optional daylight time zone is + present, "standard U.S.A. Daylight Savings Time conversion is applied." + This means that SVR2 can't deal with other (for example, Australian) + daylight savings time rules, or situations where more than two + time zone abbreviations are used in an area. + +* In SVR2, time conversion information is compiled into each program + that does time conversion. This means that when time conversion + rules change (as in the United States in 1987), all programs that + do time conversion must be recompiled to ensure proper results. + +* In SVR2, time conversion fails for near-minimum or near-maximum + time_t values when doing conversions for places that don't use GMT. + +* In SVR2, there's no tamper-proof way for a process to learn the + system's best idea of local wall clock. (This is important for + applications that an administrator wants used only at certain times-- + without regard to whether the user has fiddled the "TZ" environment + variable. While an administrator can "do everything in GMT" to get + around the problem, doing so is inconvenient and precludes handling + daylight savings time shifts--as might be required to limit phone + calls to off-peak hours.) + +These are the changes that have been made to the SVR2 functions: + +* The "TZ" environment variable is used in generating the name of a file + from which time zone information is read; "TZ" is no longer constrained + to be a three-letter time zone name followed by a number of hours and + an optional three-letter daylight time zone name. The daylight saving + time rules to be used for a particular time zone are encoded in the + time zone file; the format of the file allows U.S., Australian, and + other rules to be encoded, and allows for situations where more than + two time zone abbreviations are used. + + It was recognized that allowing the "TZ" environment variable to + take on values such as "US/Eastern" might cause "old" programs + (that expect "TZ" to have a certain form) to operate incorrectly; + consideration was given to using some other environment variable + (for example, "TIMEZONE") to hold the string used to generate the + time zone information file name. In the end, however, it was decided + to continue using "TZ": it is widely used for time zone purposes; + separately maintaining both "TZ" and "TIMEZONE" seemed a nuisance; + and systems where "new" forms of "TZ" might cause problems can simply + give time zone files names such as "EST5EDT" which can be used both by + "new" programs (as file names) and "old" programs (as zone names and + offsets). + +* To handle places where more than two time zone abbreviations are used, + the functions "localtime" and "gmtime" set tzname[tmp->tm_isdst] + (where "tmp" is the value the function returns) to the time zone + abbreviation to be used. This differs from SVR2, where the elements + of tzname are only changed as a result of calls to tzset. + +* Since the "TZ" environment variable can now be used to control time + conversion, the "daylight" and "timezone" variables are no longer + needed or supported. (You can use a compile-time option to cause + these variables to be defined and to be set by "tzset"; however, their + values will not be used by "localtime.") + +* The "localtime" function has been set up to deliver correct results + for near-minimum or near-maximum time_t values. (A comment in the + source code tells how to get compatibly wrong results). + +* A function "tzsetwall" has been added to arrange for the system's + best approximation to local wall clock time to be delivered by + subsequent calls to "localtime." Source code for portable + applications that "must" run on local wall clock time should call + "tzsetwall();" if such code is moved to "old" systems that don't provide + tzsetwall, you won't be able to generate an executable program. + (These time zone functions also arrange for local wall clock time to be + used if tzset is called--directly or indirectly--and there's no "TZ" + environment variable; portable applications should not, however, rely + on this behavior since it's not the way SVR2 systems behave.) + +Points of interest to folks with Version 7 or BSD systems: + +* The BSD "timezone" function is not present in this package; + it's impossible to reliably map timezone's arguments (a "minutes west + of GMT" value and a "daylight saving time in effect" flag) to a + time zone abbreviation, and we refuse to guess. + Programs that in the past used the timezone function may now examine + tzname[localtime(&clock)->tm_isdst] to learn the correct time + zone abbreviation to use. Alternatively, use localtime(&clock)->tm_zone + if this has been enabled. + +* The BSD gettimeofday function is not used in this package; + this lets users control the time zone used in doing time conversions. + Users who don't try to control things (that is, users who do not set + the environment variable TZ) get the time conversion specified in the + file "/etc/localtime"; see the time zone compiler writeup for + information on how to initialize this file. + +* The BSD "dysize" function is only included if the preprocessor symbol + BSD_COMPAT is defined. For a year y, the BSD code returns the value + ((y % 4) == 0) : 366 : 365 + while this code returns the value + (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) ? 366 : 365 + There's a comment in the code telling how to get the BSD value. + +The functions that are conditionally compiled if STD_INSPIRED is defined should, +at this point, be looked on primarily as food for thought. They are not in +any sense "standard compatible"--some are not, in fact, specified in *any* +standard. They do, however, represent responses of various authors to +standardization proposals. + +Other time conversion proposals, in particular the one developed by folks at +Hewlett Packard, offer a wider selection of functions that provide capabilities +beyond those provided here. The absence of such functions from this package +is not meant to discourage the development, standardization, or use of such +functions. Rather, their absence reflects the decision to make this package +close to SVR2 (with the exceptions outlined above) to ensure its broad +acceptability. If more powerful time conversion functions can be standardized, +so much the better. + +It's probably not wise to standardize everything in this package. +While the command + nroff -man newctime.3 +produces a document that describes this package, the command + nroff -man -rX3J11 newctime.3 +produces a document that describes the "standardizable" parts. diff --git a/src/share/zoneinfo/asia b/src/share/zoneinfo/asia new file mode 100644 index 0000000..2c97403 --- /dev/null +++ b/src/share/zoneinfo/asia @@ -0,0 +1,5 @@ +# @(#)asia 3.1 +# Incorporates data for Singapore from Robert Elz' asia 1.1 +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone Japan 9:00 - JST +Zone Singapore 8:00 - SST diff --git a/src/share/zoneinfo/australasia b/src/share/zoneinfo/australasia new file mode 100644 index 0000000..31672ff --- /dev/null +++ b/src/share/zoneinfo/australasia @@ -0,0 +1,59 @@ +# @(#)australasia 3.1 +# Incorporates updates for Australia from Robert Elz' australia 1.1 +# and further updates from the Australian consulate. + +# Australian Data (for states with DST), standard rules +# Includes shift in 1987 to follow Vic/NSW rules for ending DST, +# and shift in 1986 to start DST earlier. + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule Oz 1971 1985 - Oct lastSun 2:00 1:00 - +Rule Oz 1986 max - Oct Sun<=24 2:00 1:00 - +Rule Oz 1972 only - Feb 27 3:00 0 - +Rule Oz 1973 1986 - Mar Sun>=1 3:00 0 - +Rule Oz 1987 max - Mar Sun<=21 3:00 0 - + +# Zone NAME GMTOFF RULES FORMAT [UNTIL] +Zone Australia/Tasmania 10:00 Oz EST +Zone Australia/Queensland 10:00 - EST # No DST here +Zone Australia/North 9:30 - CST # No DST here +Zone Australia/West 8:00 - WST # No DST here +Zone Australia/South 9:30 Oz CST + +# Victoria and New South Wales made the jump to a later ending date for +# DST in 1986 rather than 1987. New South Wales also had another variation +# in 1983, but the details of that are unknown to the authors at this time. + +Zone Australia/Victoria 10:00 Oz EST 1985 Oct lastSun 2:00 + 10:00 1:00 EST 1986 Mar Sun<=21 3:00 + 10:00 Oz EST +Link Australia/Victoria Australia/NSW + +# New Zealand, from Elz' asia 1.1 +# Elz says "no guarantees" +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule NZ 1974 max - Oct lastSun 2:00 1:00 D +Rule NZ 1975 max - Mar Sun>=1 3:00 0 S + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone NZ 12:00 NZ NZ%sT # New Zealand + +# +# A footnote here: +# +# . . . +# Date: Thu, j19 Feb 87 12:02:17 EST +# From: Bradley White +# . . . +# I am including a description of Australian time zones. . . +# this stuff is definitely accurate. +# . . . +# a) Australian Eastern Time: (EST = GMT+10:00, EDT = GMT+11:00) +# . . . +# Summer of 86/87 - present (current legislation): +# third Sun Oct 02:00 EST -> third LSun Mar 02:00 EST +# +# If this turns out to be true, substitute Sun<=21 (third Sunday in October) +# for Sun<=24 (next-to-last Sunday in October) above. . .some time before +# October 1988, the first time it makes a difference. +# diff --git a/src/share/zoneinfo/etcetera b/src/share/zoneinfo/etcetera new file mode 100644 index 0000000..b94ed3b --- /dev/null +++ b/src/share/zoneinfo/etcetera @@ -0,0 +1,40 @@ +# @(#)etcetera 3.1 + +Zone GMT 0 - GMT + +# +# Names for zones that might exist, just so people can set a timezone +# that's right for their area, even if it doesn't have a name or dst rules +# (half hour zones are too much to bother with -- when someone asks!) +# + +Zone GMT-12 -12 - GMT-1200 +Zone GMT-11 -11 - GMT-1100 +Zone GMT-10 -10 - GMT-1000 +Zone GMT-9 -9 - GMT-0900 +Zone GMT-8 -8 - GMT-0800 +Zone GMT-7 -7 - GMT-0700 +Zone GMT-6 -6 - GMT-0600 +Zone GMT-5 -5 - GMT-0500 +Zone GMT-4 -4 - GMT-0400 +Zone GMT-3 -3 - GMT-0300 +Zone GMT-2 -2 - GMT-0200 +Zone GMT-1 -1 - GMT-0100 +Zone GMT+1 1 - GMT+0100 +Zone GMT+2 2 - GMT+0200 +Zone GMT+3 3 - GMT+0300 +Zone GMT+4 4 - GMT+0400 +Zone GMT+5 5 - GMT+0500 +Zone GMT+6 6 - GMT+0600 +Zone GMT+7 7 - GMT+0700 +Zone GMT+8 8 - GMT+0800 +Zone GMT+9 9 - GMT+0900 +Zone GMT+10 10 - GMT+1000 +Zone GMT+11 11 - GMT+1100 +Zone GMT+12 12 - GMT+1200 +Zone GMT+13 13 - GMT+1300 # GMT+12 with DST + +Link GMT UTC +Link GMT UCT +Link GMT Universal +Link GMT Greenwich diff --git a/src/share/zoneinfo/europe b/src/share/zoneinfo/europe new file mode 100644 index 0000000..7d2e31d --- /dev/null +++ b/src/share/zoneinfo/europe @@ -0,0 +1,125 @@ +# @(#)europe 3.1 + +# Europe, updated from 4.3BSD and various contributors +# International country codes are used to identify countries' rules and +# zones +# +# This data is by no means authoritative; if you think you know better, go +# ahead and edit the file (and please send any changes to seismo!elsie!tz +# for general use in the future). The use of 1986 as starting years below +# is conservative. +# +# One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from +# the last Sunday in March to the last Sunday in September in 1986. +# The source shows Romania changing a day later than everybody else. +# +# According to Bernard Sieloff's source, Poland is in the MET time zone but +# uses the WE DST rules. The Western USSR uses EET+1 and ME DST rules. +# Bernard Sieloff's source claims Romania switches on the same day, but at +# 00:00 standard time (i.e., 01:00 DST). It also claims that Turkey +# switches on the same day, but switches on at 01:00 standard time +# and off at 00:00 standard time (i.e., 01:00 DST) + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule GB-Eire 1986 max - Mar lastSun 1:00s 1:00 BST +Rule GB-Eire 1986 max - Oct lastSun 1:00s 0 GMT + +Rule W-Eur 1986 max - Mar lastSun 1:00s 1:00 " DST" +Rule W-Eur 1986 max - Sep lastSun 1:00s 0 - + +Rule M-Eur 1986 max - Mar lastSun 2:00s 1:00 " DST" +Rule M-Eur 1986 max - Sep lastSun 2:00s 0 - + +Rule E-Eur 1986 max - Mar lastSun 3:00s 1:00 " DST" +Rule E-Eur 1986 max - Sep lastSun 3:00s 0 - + +Rule Turkey 1986 max - Mar lastSun 1:00 1:00 " DST" +Rule Turkey 1986 max - Sep lastSun 1:00 0 - + +Rule W-SU 1986 max - Mar lastSun 2:00s 1:00 " DST" +Rule W-SU 1986 max - Sep lastSun 2:00s 0 - + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone GB-Eire 0:00 GB-Eire %s +Zone WET 0:00 W-Eur WET%s +Zone Iceland 0:00 - WET +Zone MET 1:00 M-Eur MET%s +Zone Poland 1:00 W-Eur MET%s +Zone EET 2:00 E-Eur EET%s +Zone Turkey 3:00 Turkey EET%s +Zone W-SU 3:00 M-Eur ???? + +# Tom Hoffman says that MET is also known as Central European Time + +Link MET CET + +# +# And now, letters on the subject. . . +# +############################################################################### +# +# ... +# Date: Wed, 28 Jan 87 16:56:27 -0100 +# From: seismo!mcvax!cgcha!wtho (Tom Hofmann) +# Message-Id: <8701281556.AA22174@cgcha.uucp> +# ... +# Subject: Time zone handling +# ... +# +# ...the European time rules are...standardized since 1981, when +# most European counrties started DST. Before that year, only +# a few countries (UK, France, Italy) had DST, each according +# to own national rules. In 1981, however, DST started on +# 'Apr firstSun', and not on 'Mar lastSun' as in the following +# years... +# But also since 1981 there are some more national exceptions +# than listed in 'europe': Switzerland, for example, joined DST +# one year later, Denmark ended DST on 'Oct 1' instead of 'Sep +# lastSun' in 1981---I don't know how they handle now. +# +# Finally, DST ist always from 'Apr 1' to 'Oct 1' in the +# Soviet Union (as far as I know). +# +# Tom Hofmann, Scientific Computer Center, CIBA-GEIGY AG, +# 4002 Basle, Switzerland +# UUCP: ...!mcvax!cernvax!cgcha!wtho +# +############################################################################### +# +# ... +# Date: Wed, 4 Feb 87 22:35:22 +0100 +# From: seismo!mcvax!cwi.nl!dik (Dik T. Winter) +# Message-Id: <8702042135.AA23919@zuring.cwi.nl> +# ... +# Subject: timezones +# ... +# +# The information from Tom Hofmann is (as far as I know) not entirely correct. +# After a request from chongo at amdahl I tried to retrieve all information +# about DST in Europe. I was able to find all from about 1969. +# +# ...standardization +# on DST in Europe started in about 1977 with switches on first Sunday in +# April and last Sunday in September. In UK it was from last but 1 Sunday +# in march to last Sunday in October. In 1981 UK joined Europe insofar that +# the starting day for both shifted to last Sunday in March. And from 1982 +# the whole of Europe used DST, with switch dates April 1 and October 1 in +# the Sovjet Union. In 1985 the SU reverted to standard Europen switch +# dates. Note that currently in the UK the switch back date appears not +# to be the last Sunday in October, but 4 weeks after the last Sunday in +# September (withness 1982 and 1983 with terminating days October 24 and 23). +# +# It should also be remembered that time-zones are not constants; e.g. +# Portugal switched in 1976 from MET (or CET) to WET with DST, and the UK +# used MET throughout from 1967 to 1969, and WET with DST before and after +# that time. Note also that though there were rules for switch dates not +# all countries abided to these dates, and many individual deviations +# occurred, though not since 1982 I believe. Another note: it is always +# assumed that DST is 1 hour ahead of normal time, this need not be the +# case; at least in the Netherlands there have been times when DST was 2 hours +# in advance of normal time. +# +# ... +# dik t. winter, cwi, amsterdam, nederland +# INTERNET : dik@cwi.nl +# BITNET/EARN: dik@mcvax diff --git a/src/share/zoneinfo/ialloc.c b/src/share/zoneinfo/ialloc.c new file mode 100644 index 0000000..32aad04 --- /dev/null +++ b/src/share/zoneinfo/ialloc.c @@ -0,0 +1,88 @@ +/* + * @(#)ialloc.c 1.1 ialloc.c 3/4/87 + */ + +/*LINTLIBRARY*/ + +#include "stdio.h" + +#ifndef alloc_t +#define alloc_t unsigned +#endif /* !alloc_t */ + +#ifdef MAL +#define NULLMAL(x) ((x) == NULL || (x) == MAL) +#else /* !MAL */ +#define NULLMAL(x) ((x) == NULL) +#endif /* !MAL */ + +extern char * calloc(); +extern char * malloc(); +extern char * realloc(); +extern char * strcpy(); + +char * +imalloc(n) +{ +#ifdef MAL + register char * result; + + if (n == 0) + n = 1; + result = malloc((alloc_t) n); + return (result == MAL) ? NULL : result; +#else /* !MAL */ + if (n == 0) + n = 1; + return malloc((alloc_t) n); +#endif /* !MAL */ +} + +char * +icalloc(nelem, elsize) +{ + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + return calloc((alloc_t) nelem, (alloc_t) elsize); +} + +char * +irealloc(pointer, size) +char * pointer; +{ + if (NULLMAL(pointer)) + return imalloc(size); + if (size == 0) + size = 1; + return realloc(pointer, (alloc_t) size); +} + +char * +icatalloc(old, new) +char * old; +char * new; +{ + register char * result; + register oldsize, newsize; + + oldsize = NULLMAL(old) ? 0 : strlen(old); + newsize = NULLMAL(new) ? 0 : strlen(new); + if ((result = irealloc(old, oldsize + newsize + 1)) != NULL) + if (!NULLMAL(new)) + (void) strcpy(result + oldsize, new); + return result; +} + +char * +icpyalloc(string) +char * string; +{ + return icatalloc((char *) NULL, string); +} + +ifree(p) +char * p; +{ + if (!NULLMAL(p)) + free(p); +} diff --git a/src/share/zoneinfo/northamerica b/src/share/zoneinfo/northamerica new file mode 100644 index 0000000..cae8b7b --- /dev/null +++ b/src/share/zoneinfo/northamerica @@ -0,0 +1,96 @@ +# @(#)northamerica 3.1 + +# Despite the performance of existing (4.[123]BSD, System V Release 2.0) code, +# US Daylight Saving Time ended on the last Sunday of *October* in 1974. +# See, for example, the front page of the Saturday, October 26, 1974 +# and Sunday, October 27, 1974 editions of the Washington Post. + +# Note also this from seismo!munnari!kre: +# "I recall also being told by someone once that Canada didn't have +# the DST variations in 74/75 that the US did, but I am not nearly +# sure enough of this to add anything." +# The above has been confirmed by Bob Devine; we'll go with it here. + +# Before the Uniform Time Act of 1966 took effect in 1967, observance of +# Daylight Saving Time in the US was by local option, except during wartime. + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule US 1918 1919 - Mar lastSun 2:00 1:00 D +Rule US 1918 1919 - Oct lastSun 2:00 0 S +Rule US 1942 only - Feb 9 2:00 1:00 W # War +Rule US 1945 only - Sep 30 2:00 0 S +Rule US 1967 max - Oct lastSun 2:00 0 S +Rule US 1967 1973 - Apr lastSun 2:00 1:00 D +Rule US 1974 only - Jan 6 2:00 1:00 D +Rule US 1975 only - Feb 23 2:00 1:00 D +Rule US 1976 1986 - Apr lastSun 2:00 1:00 D +Rule US 1987 max - Apr Sun>=1 2:00 1:00 D + +############################################################################### + +# New names + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone US/Eastern -5:00 US E%sT +Zone US/Central -6:00 US C%sT +Zone US/Mountain -7:00 US M%sT +Zone US/Pacific -8:00 US P%sT +Zone US/Yukon -9:00 US Y%sT + +# Mainland US areas that are always Standard as of 1986. + +Zone US/East-Indiana -5:00 US E%sT 1946 + -5:00 - EST # Always EST as of 1986 +Zone US/Arizona -7:00 US M%sT 1946 + -7:00 - MST # Always MST as of 1986 + +# And then there's Hawaii. +# DST was observed for one day in 1933; +# Standard time was change by half an hour in 1947; +# it's always standard as of 1986. + +Zone US/Hawaii -10:30 US H%sT 1933 Apr 30 2:00 + -10:30 1:00 HDT 1933 May 1 2:00 + -10:30 US H%sT 1947 Jun 8 2:00 + -10:00 - HST + +# Old names, for S5 users + +# Link LINK-FROM LINK-TO +Link US/Eastern EST5EDT +Link US/Central CST6CDT +Link US/Mountain MST7MDT +Link US/Pacific PST8PDT +Link US/East-Indiana EST +Link US/Arizona MST +Link US/Hawaii HST + +################################################################################ + +# Canada is reportedly lots easier than the US--leastways since 1951. +# I don't know what they did before then. +# 4.3BSD claims that it's perfectly regular. +# According to a posting in "comp.bugs.misc", "comp.unix.wizards", etc. +# on February 8, 1987, by Dave Sherman of the Law Society of Upper Canada, +# "...Canada (well, Ontario and at least some of the other provinces) are +# adopting the new daylight savings time rules...". We assume all of +# Canada is doing so. + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule Canada 1969 max - Oct lastSun 2:00 0 S +Rule Canada 1969 1986 - Apr lastSun 2:00 1:00 D +Rule Canada 1987 max - Apr Sun>=1 2:00 1:00 D + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +# Bob Devine says that DST *is* observed in Newfoundland +Zone Canada/Newfoundland -3:30 Canada N%sT +Zone Canada/Atlantic -4:00 Canada A%sT +Zone Canada/Eastern -5:00 Canada E%sT +Zone Canada/Central -6:00 Canada C%sT +Zone Canada/Mountain -7:00 Canada M%sT +Zone Canada/Pacific -8:00 Canada P%sT +Zone Canada/Yukon -9:00 Canada Y%sT + +################################################################################ + +# ?Mexico? !Quien sabe! diff --git a/src/share/zoneinfo/pacificnew b/src/share/zoneinfo/pacificnew new file mode 100644 index 0000000..51087e1 --- /dev/null +++ b/src/share/zoneinfo/pacificnew @@ -0,0 +1,13 @@ +# @(#)pacificnew 3.1 + +# "Pacific Presidential Election Time" has been contemplated by the US Congress + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule Twilite 1987 max - Apr Sun>=1 2:00 1:00 D +Rule Twilite 1987 max uspres Oct lastSun 2:00 1:00 PE +Rule Twilite 1987 max uspres Nov Sun>=7 2:00 0 S +Rule Twilite 1987 max nonpres Oct lastSun 2:00 0 S + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone US/Pacific-New -8:00 US P%sT 1987 + -8:00 Twilite P%sT diff --git a/src/share/zoneinfo/scheck.c b/src/share/zoneinfo/scheck.c new file mode 100644 index 0000000..0fd6fcf --- /dev/null +++ b/src/share/zoneinfo/scheck.c @@ -0,0 +1,59 @@ +/* + * @(#)scheck.c 1.1 scheck.c 3/4/87 + */ + +/*LINTLIBRARY*/ + +#include "stdio.h" +#include "ctype.h" + +extern char * imalloc(); + +char * +scheck(string, format) +char * string; +char * format; +{ + register char * fbuf; + register char * fp; + register char * tp; + register int c; + register char * result; + char dummy; + + result = ""; + if (string == NULL || format == NULL) + return result; + fbuf = imalloc(2 * strlen(format) + 4); + if (fbuf == NULL) + return result; + fp = format; + tp = fbuf; + while ((*tp++ = c = *fp++) != '\0') { + if (c != '%') + continue; + if (*fp == '%') { + *tp++ = *fp++; + continue; + } + *tp++ = '*'; + if (*fp == '*') + ++fp; + while (isascii(*fp) && isdigit(*fp)) + *tp++ = *fp++; + if (*fp == 'l' || *fp == 'h') + *tp++ = *fp++; + else if (*fp == '[') + do *tp++ = *fp++; + while (*fp != '\0' && *fp != ']'); + if ((*tp++ = *fp++) == '\0') + break; + } + *(tp - 1) = '%'; + *tp++ = 'c'; + *tp = '\0'; + if (sscanf(string, fbuf, &dummy) != 1) + result = format; + free(fbuf); + return result; +} diff --git a/src/share/zoneinfo/solar87 b/src/share/zoneinfo/solar87 new file mode 100644 index 0000000..1e02bf3 --- /dev/null +++ b/src/share/zoneinfo/solar87 @@ -0,0 +1,386 @@ +# @(#)solar87 3.1 + +# So much for footnotes about Saudi Arabia. +# Apparent noon times below are for Riyadh; your mileage will vary. +# Times were computed using formulas in the U.S. Naval Observatory's +# Almanac for Computers 1987; the formulas "will give EqT to an accuracy of +# [plus or minus] two seconds during the current year." +# +# Rounding to the nearest five seconds results in fewer than +# 256 different "time types"--a limit that's faced because time types are +# stored on disk as unsigned chars. + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule sol87 1987 only - Jan 1 12:03:20s -0:03:20 - +Rule sol87 1987 only - Jan 2 12:03:50s -0:03:50 - +Rule sol87 1987 only - Jan 3 12:04:15s -0:04:15 - +Rule sol87 1987 only - Jan 4 12:04:45s -0:04:45 - +Rule sol87 1987 only - Jan 5 12:05:10s -0:05:10 - +Rule sol87 1987 only - Jan 6 12:05:40s -0:05:40 - +Rule sol87 1987 only - Jan 7 12:06:05s -0:06:05 - +Rule sol87 1987 only - Jan 8 12:06:30s -0:06:30 - +Rule sol87 1987 only - Jan 9 12:06:55s -0:06:55 - +Rule sol87 1987 only - Jan 10 12:07:20s -0:07:20 - +Rule sol87 1987 only - Jan 11 12:07:45s -0:07:45 - +Rule sol87 1987 only - Jan 12 12:08:10s -0:08:10 - +Rule sol87 1987 only - Jan 13 12:08:30s -0:08:30 - +Rule sol87 1987 only - Jan 14 12:08:55s -0:08:55 - +Rule sol87 1987 only - Jan 15 12:09:15s -0:09:15 - +Rule sol87 1987 only - Jan 16 12:09:35s -0:09:35 - +Rule sol87 1987 only - Jan 17 12:09:55s -0:09:55 - +Rule sol87 1987 only - Jan 18 12:10:15s -0:10:15 - +Rule sol87 1987 only - Jan 19 12:10:35s -0:10:35 - +Rule sol87 1987 only - Jan 20 12:10:55s -0:10:55 - +Rule sol87 1987 only - Jan 21 12:11:10s -0:11:10 - +Rule sol87 1987 only - Jan 22 12:11:30s -0:11:30 - +Rule sol87 1987 only - Jan 23 12:11:45s -0:11:45 - +Rule sol87 1987 only - Jan 24 12:12:00s -0:12:00 - +Rule sol87 1987 only - Jan 25 12:12:15s -0:12:15 - +Rule sol87 1987 only - Jan 26 12:12:30s -0:12:30 - +Rule sol87 1987 only - Jan 27 12:12:40s -0:12:40 - +Rule sol87 1987 only - Jan 28 12:12:55s -0:12:55 - +Rule sol87 1987 only - Jan 29 12:13:05s -0:13:05 - +Rule sol87 1987 only - Jan 30 12:13:15s -0:13:15 - +Rule sol87 1987 only - Jan 31 12:13:25s -0:13:25 - +Rule sol87 1987 only - Feb 1 12:13:35s -0:13:35 - +Rule sol87 1987 only - Feb 2 12:13:40s -0:13:40 - +Rule sol87 1987 only - Feb 3 12:13:50s -0:13:50 - +Rule sol87 1987 only - Feb 4 12:13:55s -0:13:55 - +Rule sol87 1987 only - Feb 5 12:14:00s -0:14:00 - +Rule sol87 1987 only - Feb 6 12:14:05s -0:14:05 - +Rule sol87 1987 only - Feb 7 12:14:10s -0:14:10 - +Rule sol87 1987 only - Feb 8 12:14:10s -0:14:10 - +Rule sol87 1987 only - Feb 9 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 10 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 11 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 12 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 13 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 14 12:14:15s -0:14:15 - +Rule sol87 1987 only - Feb 15 12:14:10s -0:14:10 - +Rule sol87 1987 only - Feb 16 12:14:10s -0:14:10 - +Rule sol87 1987 only - Feb 17 12:14:05s -0:14:05 - +Rule sol87 1987 only - Feb 18 12:14:00s -0:14:00 - +Rule sol87 1987 only - Feb 19 12:13:55s -0:13:55 - +Rule sol87 1987 only - Feb 20 12:13:50s -0:13:50 - +Rule sol87 1987 only - Feb 21 12:13:45s -0:13:45 - +Rule sol87 1987 only - Feb 22 12:13:35s -0:13:35 - +Rule sol87 1987 only - Feb 23 12:13:30s -0:13:30 - +Rule sol87 1987 only - Feb 24 12:13:20s -0:13:20 - +Rule sol87 1987 only - Feb 25 12:13:10s -0:13:10 - +Rule sol87 1987 only - Feb 26 12:13:00s -0:13:00 - +Rule sol87 1987 only - Feb 27 12:12:50s -0:12:50 - +Rule sol87 1987 only - Feb 28 12:12:40s -0:12:40 - +Rule sol87 1987 only - Mar 1 12:12:30s -0:12:30 - +Rule sol87 1987 only - Mar 2 12:12:20s -0:12:20 - +Rule sol87 1987 only - Mar 3 12:12:05s -0:12:05 - +Rule sol87 1987 only - Mar 4 12:11:55s -0:11:55 - +Rule sol87 1987 only - Mar 5 12:11:40s -0:11:40 - +Rule sol87 1987 only - Mar 6 12:11:25s -0:11:25 - +Rule sol87 1987 only - Mar 7 12:11:15s -0:11:15 - +Rule sol87 1987 only - Mar 8 12:11:00s -0:11:00 - +Rule sol87 1987 only - Mar 9 12:10:45s -0:10:45 - +Rule sol87 1987 only - Mar 10 12:10:30s -0:10:30 - +Rule sol87 1987 only - Mar 11 12:10:15s -0:10:15 - +Rule sol87 1987 only - Mar 12 12:09:55s -0:09:55 - +Rule sol87 1987 only - Mar 13 12:09:40s -0:09:40 - +Rule sol87 1987 only - Mar 14 12:09:25s -0:09:25 - +Rule sol87 1987 only - Mar 15 12:09:10s -0:09:10 - +Rule sol87 1987 only - Mar 16 12:08:50s -0:08:50 - +Rule sol87 1987 only - Mar 17 12:08:35s -0:08:35 - +Rule sol87 1987 only - Mar 18 12:08:15s -0:08:15 - +Rule sol87 1987 only - Mar 19 12:08:00s -0:08:00 - +Rule sol87 1987 only - Mar 20 12:07:40s -0:07:40 - +Rule sol87 1987 only - Mar 21 12:07:25s -0:07:25 - +Rule sol87 1987 only - Mar 22 12:07:05s -0:07:05 - +Rule sol87 1987 only - Mar 23 12:06:50s -0:06:50 - +Rule sol87 1987 only - Mar 24 12:06:30s -0:06:30 - +Rule sol87 1987 only - Mar 25 12:06:10s -0:06:10 - +Rule sol87 1987 only - Mar 26 12:05:55s -0:05:55 - +Rule sol87 1987 only - Mar 27 12:05:35s -0:05:35 - +Rule sol87 1987 only - Mar 28 12:05:15s -0:05:15 - +Rule sol87 1987 only - Mar 29 12:05:00s -0:05:00 - +Rule sol87 1987 only - Mar 30 12:04:40s -0:04:40 - +Rule sol87 1987 only - Mar 31 12:04:25s -0:04:25 - +Rule sol87 1987 only - Apr 1 12:04:05s -0:04:05 - +Rule sol87 1987 only - Apr 2 12:03:45s -0:03:45 - +Rule sol87 1987 only - Apr 3 12:03:30s -0:03:30 - +Rule sol87 1987 only - Apr 4 12:03:10s -0:03:10 - +Rule sol87 1987 only - Apr 5 12:02:55s -0:02:55 - +Rule sol87 1987 only - Apr 6 12:02:35s -0:02:35 - +Rule sol87 1987 only - Apr 7 12:02:20s -0:02:20 - +Rule sol87 1987 only - Apr 8 12:02:05s -0:02:05 - +Rule sol87 1987 only - Apr 9 12:01:45s -0:01:45 - +Rule sol87 1987 only - Apr 10 12:01:30s -0:01:30 - +Rule sol87 1987 only - Apr 11 12:01:15s -0:01:15 - +Rule sol87 1987 only - Apr 12 12:00:55s -0:00:55 - +Rule sol87 1987 only - Apr 13 12:00:40s -0:00:40 - +Rule sol87 1987 only - Apr 14 12:00:25s -0:00:25 - +Rule sol87 1987 only - Apr 15 12:00:10s -0:00:10 - +Rule sol87 1987 only - Apr 16 11:59:55s 0:00:05 - +Rule sol87 1987 only - Apr 17 11:59:45s 0:00:15 - +Rule sol87 1987 only - Apr 18 11:59:30s 0:00:30 - +Rule sol87 1987 only - Apr 19 11:59:15s 0:00:45 - +Rule sol87 1987 only - Apr 20 11:59:05s 0:00:55 - +Rule sol87 1987 only - Apr 21 11:58:50s 0:01:10 - +Rule sol87 1987 only - Apr 22 11:58:40s 0:01:20 - +Rule sol87 1987 only - Apr 23 11:58:25s 0:01:35 - +Rule sol87 1987 only - Apr 24 11:58:15s 0:01:45 - +Rule sol87 1987 only - Apr 25 11:58:05s 0:01:55 - +Rule sol87 1987 only - Apr 26 11:57:55s 0:02:05 - +Rule sol87 1987 only - Apr 27 11:57:45s 0:02:15 - +Rule sol87 1987 only - Apr 28 11:57:35s 0:02:25 - +Rule sol87 1987 only - Apr 29 11:57:25s 0:02:35 - +Rule sol87 1987 only - Apr 30 11:57:15s 0:02:45 - +Rule sol87 1987 only - May 1 11:57:10s 0:02:50 - +Rule sol87 1987 only - May 2 11:57:00s 0:03:00 - +Rule sol87 1987 only - May 3 11:56:55s 0:03:05 - +Rule sol87 1987 only - May 4 11:56:50s 0:03:10 - +Rule sol87 1987 only - May 5 11:56:45s 0:03:15 - +Rule sol87 1987 only - May 6 11:56:40s 0:03:20 - +Rule sol87 1987 only - May 7 11:56:35s 0:03:25 - +Rule sol87 1987 only - May 8 11:56:30s 0:03:30 - +Rule sol87 1987 only - May 9 11:56:25s 0:03:35 - +Rule sol87 1987 only - May 10 11:56:25s 0:03:35 - +Rule sol87 1987 only - May 11 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 12 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 13 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 14 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 15 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 16 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 17 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 18 11:56:20s 0:03:40 - +Rule sol87 1987 only - May 19 11:56:25s 0:03:35 - +Rule sol87 1987 only - May 20 11:56:25s 0:03:35 - +Rule sol87 1987 only - May 21 11:56:30s 0:03:30 - +Rule sol87 1987 only - May 22 11:56:35s 0:03:25 - +Rule sol87 1987 only - May 23 11:56:40s 0:03:20 - +Rule sol87 1987 only - May 24 11:56:45s 0:03:15 - +Rule sol87 1987 only - May 25 11:56:50s 0:03:10 - +Rule sol87 1987 only - May 26 11:56:55s 0:03:05 - +Rule sol87 1987 only - May 27 11:57:00s 0:03:00 - +Rule sol87 1987 only - May 28 11:57:10s 0:02:50 - +Rule sol87 1987 only - May 29 11:57:15s 0:02:45 - +Rule sol87 1987 only - May 30 11:57:25s 0:02:35 - +Rule sol87 1987 only - May 31 11:57:30s 0:02:30 - +Rule sol87 1987 only - Jun 1 11:57:40s 0:02:20 - +Rule sol87 1987 only - Jun 2 11:57:50s 0:02:10 - +Rule sol87 1987 only - Jun 3 11:58:00s 0:02:00 - +Rule sol87 1987 only - Jun 4 11:58:10s 0:01:50 - +Rule sol87 1987 only - Jun 5 11:58:20s 0:01:40 - +Rule sol87 1987 only - Jun 6 11:58:30s 0:01:30 - +Rule sol87 1987 only - Jun 7 11:58:40s 0:01:20 - +Rule sol87 1987 only - Jun 8 11:58:50s 0:01:10 - +Rule sol87 1987 only - Jun 9 11:59:05s 0:00:55 - +Rule sol87 1987 only - Jun 10 11:59:15s 0:00:45 - +Rule sol87 1987 only - Jun 11 11:59:30s 0:00:30 - +Rule sol87 1987 only - Jun 12 11:59:40s 0:00:20 - +Rule sol87 1987 only - Jun 13 11:59:50s 0:00:10 - +Rule sol87 1987 only - Jun 14 12:00:05s -0:00:05 - +Rule sol87 1987 only - Jun 15 12:00:15s -0:00:15 - +Rule sol87 1987 only - Jun 16 12:00:30s -0:00:30 - +Rule sol87 1987 only - Jun 17 12:00:45s -0:00:45 - +Rule sol87 1987 only - Jun 18 12:00:55s -0:00:55 - +Rule sol87 1987 only - Jun 19 12:01:10s -0:01:10 - +Rule sol87 1987 only - Jun 20 12:01:20s -0:01:20 - +Rule sol87 1987 only - Jun 21 12:01:35s -0:01:35 - +Rule sol87 1987 only - Jun 22 12:01:50s -0:01:50 - +Rule sol87 1987 only - Jun 23 12:02:00s -0:02:00 - +Rule sol87 1987 only - Jun 24 12:02:15s -0:02:15 - +Rule sol87 1987 only - Jun 25 12:02:25s -0:02:25 - +Rule sol87 1987 only - Jun 26 12:02:40s -0:02:40 - +Rule sol87 1987 only - Jun 27 12:02:50s -0:02:50 - +Rule sol87 1987 only - Jun 28 12:03:05s -0:03:05 - +Rule sol87 1987 only - Jun 29 12:03:15s -0:03:15 - +Rule sol87 1987 only - Jun 30 12:03:30s -0:03:30 - +Rule sol87 1987 only - Jul 1 12:03:40s -0:03:40 - +Rule sol87 1987 only - Jul 2 12:03:50s -0:03:50 - +Rule sol87 1987 only - Jul 3 12:04:05s -0:04:05 - +Rule sol87 1987 only - Jul 4 12:04:15s -0:04:15 - +Rule sol87 1987 only - Jul 5 12:04:25s -0:04:25 - +Rule sol87 1987 only - Jul 6 12:04:35s -0:04:35 - +Rule sol87 1987 only - Jul 7 12:04:45s -0:04:45 - +Rule sol87 1987 only - Jul 8 12:04:55s -0:04:55 - +Rule sol87 1987 only - Jul 9 12:05:05s -0:05:05 - +Rule sol87 1987 only - Jul 10 12:05:15s -0:05:15 - +Rule sol87 1987 only - Jul 11 12:05:20s -0:05:20 - +Rule sol87 1987 only - Jul 12 12:05:30s -0:05:30 - +Rule sol87 1987 only - Jul 13 12:05:40s -0:05:40 - +Rule sol87 1987 only - Jul 14 12:05:45s -0:05:45 - +Rule sol87 1987 only - Jul 15 12:05:50s -0:05:50 - +Rule sol87 1987 only - Jul 16 12:06:00s -0:06:00 - +Rule sol87 1987 only - Jul 17 12:06:05s -0:06:05 - +Rule sol87 1987 only - Jul 18 12:06:10s -0:06:10 - +Rule sol87 1987 only - Jul 19 12:06:15s -0:06:15 - +Rule sol87 1987 only - Jul 20 12:06:15s -0:06:15 - +Rule sol87 1987 only - Jul 21 12:06:20s -0:06:20 - +Rule sol87 1987 only - Jul 22 12:06:25s -0:06:25 - +Rule sol87 1987 only - Jul 23 12:06:25s -0:06:25 - +Rule sol87 1987 only - Jul 24 12:06:25s -0:06:25 - +Rule sol87 1987 only - Jul 25 12:06:30s -0:06:30 - +Rule sol87 1987 only - Jul 26 12:06:30s -0:06:30 - +Rule sol87 1987 only - Jul 27 12:06:30s -0:06:30 - +Rule sol87 1987 only - Jul 28 12:06:30s -0:06:30 - +Rule sol87 1987 only - Jul 29 12:06:25s -0:06:25 - +Rule sol87 1987 only - Jul 30 12:06:25s -0:06:25 - +Rule sol87 1987 only - Jul 31 12:06:25s -0:06:25 - +Rule sol87 1987 only - Aug 1 12:06:20s -0:06:20 - +Rule sol87 1987 only - Aug 2 12:06:15s -0:06:15 - +Rule sol87 1987 only - Aug 3 12:06:10s -0:06:10 - +Rule sol87 1987 only - Aug 4 12:06:05s -0:06:05 - +Rule sol87 1987 only - Aug 5 12:06:00s -0:06:00 - +Rule sol87 1987 only - Aug 6 12:05:55s -0:05:55 - +Rule sol87 1987 only - Aug 7 12:05:50s -0:05:50 - +Rule sol87 1987 only - Aug 8 12:05:40s -0:05:40 - +Rule sol87 1987 only - Aug 9 12:05:35s -0:05:35 - +Rule sol87 1987 only - Aug 10 12:05:25s -0:05:25 - +Rule sol87 1987 only - Aug 11 12:05:15s -0:05:15 - +Rule sol87 1987 only - Aug 12 12:05:05s -0:05:05 - +Rule sol87 1987 only - Aug 13 12:04:55s -0:04:55 - +Rule sol87 1987 only - Aug 14 12:04:45s -0:04:45 - +Rule sol87 1987 only - Aug 15 12:04:35s -0:04:35 - +Rule sol87 1987 only - Aug 16 12:04:25s -0:04:25 - +Rule sol87 1987 only - Aug 17 12:04:10s -0:04:10 - +Rule sol87 1987 only - Aug 18 12:04:00s -0:04:00 - +Rule sol87 1987 only - Aug 19 12:03:45s -0:03:45 - +Rule sol87 1987 only - Aug 20 12:03:30s -0:03:30 - +Rule sol87 1987 only - Aug 21 12:03:15s -0:03:15 - +Rule sol87 1987 only - Aug 22 12:03:00s -0:03:00 - +Rule sol87 1987 only - Aug 23 12:02:45s -0:02:45 - +Rule sol87 1987 only - Aug 24 12:02:30s -0:02:30 - +Rule sol87 1987 only - Aug 25 12:02:15s -0:02:15 - +Rule sol87 1987 only - Aug 26 12:02:00s -0:02:00 - +Rule sol87 1987 only - Aug 27 12:01:40s -0:01:40 - +Rule sol87 1987 only - Aug 28 12:01:25s -0:01:25 - +Rule sol87 1987 only - Aug 29 12:01:05s -0:01:05 - +Rule sol87 1987 only - Aug 30 12:00:50s -0:00:50 - +Rule sol87 1987 only - Aug 31 12:00:30s -0:00:30 - +Rule sol87 1987 only - Sep 1 12:00:10s -0:00:10 - +Rule sol87 1987 only - Sep 2 11:59:50s 0:00:10 - +Rule sol87 1987 only - Sep 3 11:59:35s 0:00:25 - +Rule sol87 1987 only - Sep 4 11:59:15s 0:00:45 - +Rule sol87 1987 only - Sep 5 11:58:55s 0:01:05 - +Rule sol87 1987 only - Sep 6 11:58:35s 0:01:25 - +Rule sol87 1987 only - Sep 7 11:58:15s 0:01:45 - +Rule sol87 1987 only - Sep 8 11:57:55s 0:02:05 - +Rule sol87 1987 only - Sep 9 11:57:30s 0:02:30 - +Rule sol87 1987 only - Sep 10 11:57:10s 0:02:50 - +Rule sol87 1987 only - Sep 11 11:56:50s 0:03:10 - +Rule sol87 1987 only - Sep 12 11:56:30s 0:03:30 - +Rule sol87 1987 only - Sep 13 11:56:10s 0:03:50 - +Rule sol87 1987 only - Sep 14 11:55:45s 0:04:15 - +Rule sol87 1987 only - Sep 15 11:55:25s 0:04:35 - +Rule sol87 1987 only - Sep 16 11:55:05s 0:04:55 - +Rule sol87 1987 only - Sep 17 11:54:45s 0:05:15 - +Rule sol87 1987 only - Sep 18 11:54:20s 0:05:40 - +Rule sol87 1987 only - Sep 19 11:54:00s 0:06:00 - +Rule sol87 1987 only - Sep 20 11:53:40s 0:06:20 - +Rule sol87 1987 only - Sep 21 11:53:15s 0:06:45 - +Rule sol87 1987 only - Sep 22 11:52:55s 0:07:05 - +Rule sol87 1987 only - Sep 23 11:52:35s 0:07:25 - +Rule sol87 1987 only - Sep 24 11:52:15s 0:07:45 - +Rule sol87 1987 only - Sep 25 11:51:55s 0:08:05 - +Rule sol87 1987 only - Sep 26 11:51:35s 0:08:25 - +Rule sol87 1987 only - Sep 27 11:51:10s 0:08:50 - +Rule sol87 1987 only - Sep 28 11:50:50s 0:09:10 - +Rule sol87 1987 only - Sep 29 11:50:30s 0:09:30 - +Rule sol87 1987 only - Sep 30 11:50:10s 0:09:50 - +Rule sol87 1987 only - Oct 1 11:49:50s 0:10:10 - +Rule sol87 1987 only - Oct 2 11:49:35s 0:10:25 - +Rule sol87 1987 only - Oct 3 11:49:15s 0:10:45 - +Rule sol87 1987 only - Oct 4 11:48:55s 0:11:05 - +Rule sol87 1987 only - Oct 5 11:48:35s 0:11:25 - +Rule sol87 1987 only - Oct 6 11:48:20s 0:11:40 - +Rule sol87 1987 only - Oct 7 11:48:00s 0:12:00 - +Rule sol87 1987 only - Oct 8 11:47:45s 0:12:15 - +Rule sol87 1987 only - Oct 9 11:47:25s 0:12:35 - +Rule sol87 1987 only - Oct 10 11:47:10s 0:12:50 - +Rule sol87 1987 only - Oct 11 11:46:55s 0:13:05 - +Rule sol87 1987 only - Oct 12 11:46:40s 0:13:20 - +Rule sol87 1987 only - Oct 13 11:46:25s 0:13:35 - +Rule sol87 1987 only - Oct 14 11:46:10s 0:13:50 - +Rule sol87 1987 only - Oct 15 11:45:55s 0:14:05 - +Rule sol87 1987 only - Oct 16 11:45:45s 0:14:15 - +Rule sol87 1987 only - Oct 17 11:45:30s 0:14:30 - +Rule sol87 1987 only - Oct 18 11:45:20s 0:14:40 - +Rule sol87 1987 only - Oct 19 11:45:05s 0:14:55 - +Rule sol87 1987 only - Oct 20 11:44:55s 0:15:05 - +Rule sol87 1987 only - Oct 21 11:44:45s 0:15:15 - +Rule sol87 1987 only - Oct 22 11:44:35s 0:15:25 - +Rule sol87 1987 only - Oct 23 11:44:25s 0:15:35 - +Rule sol87 1987 only - Oct 24 11:44:20s 0:15:40 - +Rule sol87 1987 only - Oct 25 11:44:10s 0:15:50 - +Rule sol87 1987 only - Oct 26 11:44:05s 0:15:55 - +Rule sol87 1987 only - Oct 27 11:43:55s 0:16:05 - +Rule sol87 1987 only - Oct 28 11:43:50s 0:16:10 - +Rule sol87 1987 only - Oct 29 11:43:45s 0:16:15 - +Rule sol87 1987 only - Oct 30 11:43:45s 0:16:15 - +Rule sol87 1987 only - Oct 31 11:43:40s 0:16:20 - +Rule sol87 1987 only - Nov 1 11:43:40s 0:16:20 - +Rule sol87 1987 only - Nov 2 11:43:35s 0:16:25 - +Rule sol87 1987 only - Nov 3 11:43:35s 0:16:25 - +Rule sol87 1987 only - Nov 4 11:43:35s 0:16:25 - +Rule sol87 1987 only - Nov 5 11:43:35s 0:16:25 - +Rule sol87 1987 only - Nov 6 11:43:40s 0:16:20 - +Rule sol87 1987 only - Nov 7 11:43:40s 0:16:20 - +Rule sol87 1987 only - Nov 8 11:43:45s 0:16:15 - +Rule sol87 1987 only - Nov 9 11:43:50s 0:16:10 - +Rule sol87 1987 only - Nov 10 11:43:55s 0:16:05 - +Rule sol87 1987 only - Nov 11 11:44:00s 0:16:00 - +Rule sol87 1987 only - Nov 12 11:44:05s 0:15:55 - +Rule sol87 1987 only - Nov 13 11:44:15s 0:15:45 - +Rule sol87 1987 only - Nov 14 11:44:20s 0:15:40 - +Rule sol87 1987 only - Nov 15 11:44:30s 0:15:30 - +Rule sol87 1987 only - Nov 16 11:44:40s 0:15:20 - +Rule sol87 1987 only - Nov 17 11:44:50s 0:15:10 - +Rule sol87 1987 only - Nov 18 11:45:05s 0:14:55 - +Rule sol87 1987 only - Nov 19 11:45:15s 0:14:45 - +Rule sol87 1987 only - Nov 20 11:45:30s 0:14:30 - +Rule sol87 1987 only - Nov 21 11:45:45s 0:14:15 - +Rule sol87 1987 only - Nov 22 11:46:00s 0:14:00 - +Rule sol87 1987 only - Nov 23 11:46:15s 0:13:45 - +Rule sol87 1987 only - Nov 24 11:46:30s 0:13:30 - +Rule sol87 1987 only - Nov 25 11:46:50s 0:13:10 - +Rule sol87 1987 only - Nov 26 11:47:10s 0:12:50 - +Rule sol87 1987 only - Nov 27 11:47:25s 0:12:35 - +Rule sol87 1987 only - Nov 28 11:47:45s 0:12:15 - +Rule sol87 1987 only - Nov 29 11:48:05s 0:11:55 - +Rule sol87 1987 only - Nov 30 11:48:30s 0:11:30 - +Rule sol87 1987 only - Dec 1 11:48:50s 0:11:10 - +Rule sol87 1987 only - Dec 2 11:49:10s 0:10:50 - +Rule sol87 1987 only - Dec 3 11:49:35s 0:10:25 - +Rule sol87 1987 only - Dec 4 11:50:00s 0:10:00 - +Rule sol87 1987 only - Dec 5 11:50:25s 0:09:35 - +Rule sol87 1987 only - Dec 6 11:50:50s 0:09:10 - +Rule sol87 1987 only - Dec 7 11:51:15s 0:08:45 - +Rule sol87 1987 only - Dec 8 11:51:40s 0:08:20 - +Rule sol87 1987 only - Dec 9 11:52:05s 0:07:55 - +Rule sol87 1987 only - Dec 10 11:52:30s 0:07:30 - +Rule sol87 1987 only - Dec 11 11:53:00s 0:07:00 - +Rule sol87 1987 only - Dec 12 11:53:25s 0:06:35 - +Rule sol87 1987 only - Dec 13 11:53:55s 0:06:05 - +Rule sol87 1987 only - Dec 14 11:54:25s 0:05:35 - +Rule sol87 1987 only - Dec 15 11:54:50s 0:05:10 - +Rule sol87 1987 only - Dec 16 11:55:20s 0:04:40 - +Rule sol87 1987 only - Dec 17 11:55:50s 0:04:10 - +Rule sol87 1987 only - Dec 18 11:56:20s 0:03:40 - +Rule sol87 1987 only - Dec 19 11:56:50s 0:03:10 - +Rule sol87 1987 only - Dec 20 11:57:20s 0:02:40 - +Rule sol87 1987 only - Dec 21 11:57:50s 0:02:10 - +Rule sol87 1987 only - Dec 22 11:58:20s 0:01:40 - +Rule sol87 1987 only - Dec 23 11:58:50s 0:01:10 - +Rule sol87 1987 only - Dec 24 11:59:20s 0:00:40 - +Rule sol87 1987 only - Dec 25 11:59:50s 0:00:10 - +Rule sol87 1987 only - Dec 26 12:00:20s -0:00:20 - +Rule sol87 1987 only - Dec 27 12:00:45s -0:00:45 - +Rule sol87 1987 only - Dec 28 12:01:15s -0:01:15 - +Rule sol87 1987 only - Dec 29 12:01:45s -0:01:45 - +Rule sol87 1987 only - Dec 30 12:02:15s -0:02:15 - +Rule sol87 1987 only - Dec 31 12:02:45s -0:02:45 - + +# Riyadh is at about 46 degrees 46 minutes East: 3 hrs, 7 mins, 4 secs +# Before and after 1987, we'll operate on local mean solar time. + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone Mideast/Riyadh 3:07:04 - ?? 1987 + 3:07:04 sol87 ?? 1988 + 3:07:04 - ?? diff --git a/src/share/zoneinfo/systemv b/src/share/zoneinfo/systemv new file mode 100644 index 0000000..b5d5fee --- /dev/null +++ b/src/share/zoneinfo/systemv @@ -0,0 +1,35 @@ +# @(#)systemv 3.1 + +# +# Old rules, should the need arise. +# No attempt is made to handle Newfoundland, since it cannot be expressed +# using the System V "TZ" scheme (half-hour offset), or anything outside +# North America (no support for non-standard DST start/end dates), nor +# the change in the DST rules in the US in 1987 (can't split between +# Canada, with no changes, and the US) +# + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D +Rule SystemV min 1973 - Oct lastSun 2:00 0 S +Rule SystemV 1974 only - Jan 6 2:00 1:00 D +Rule SystemV 1974 only - Nov lastSun 2:00 0 S +Rule SystemV 1975 only - Feb 23 2:00 1:00 D +Rule SystemV 1975 only - Oct lastSun 2:00 0 S +Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D +Rule SystemV 1976 max - Oct lastSun 2:00 0 S + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone SystemV/AST4ADT -4:00 SystemV A%sT +Zone SystemV/EST5EDT -5:00 SystemV E%sT +Zone SystemV/CST6CDT -6:00 SystemV C%sT +Zone SystemV/MST7MDT -7:00 SystemV M%sT +Zone SystemV/PST8PDT -8:00 SystemV P%sT +Zone SystemV/YST9YDT -9:00 SystemV Y%sT +Zone SystemV/AST4 -4:00 - AST +Zone SystemV/EST5 -5:00 - EST +Zone SystemV/CST6 -6:00 - CST +Zone SystemV/MST7 -7:00 - MST +Zone SystemV/PST8 -8:00 - PST +Zone SystemV/YST9 -9:00 - YST +Zone SystemV/HST10 -10:00 - HST diff --git a/src/share/zoneinfo/zdump.8 b/src/share/zoneinfo/zdump.8 new file mode 100644 index 0000000..b70c93f --- /dev/null +++ b/src/share/zoneinfo/zdump.8 @@ -0,0 +1,42 @@ +.TH ZDUMP 8 +.SH NAME +zdump \- time zone dumper +.SH SYNOPSIS +.B zdump +[ +.B \-v +] [ +.B \-c +cutoffyear ] [ zonename ... ] +.SH DESCRIPTION +.I Zdump +prints the current time in each +.I zonename +named on the command line. +.PP +These options are available: +.TP +.B \-v +For each +.I zonename +on the command line, +print the current time, +the time at the lowest possible time value, +the time one day after the lowest possible time value, +the times both one second before and exactly at +each time at which the rules for computing local time change, +the time at the highest possible time value, +and the time at one day less than the highest possible time value. +Each line ends with +.B isdst=1 +if the given time is Daylight Saving Time or +.B isdst=0 +otherwise. +.TP +.BI "\-c " cutoffyear +Cut off the verbose output near the start of the given year. +.SH FILES +/usr/share/zoneinfo standard zone information directory +.SH "SEE ALSO" +newctime(3), tzfile(5), zic(8) +.. @(#)zdump.8 3.2 diff --git a/src/share/zoneinfo/zdump.c b/src/share/zoneinfo/zdump.c new file mode 100644 index 0000000..5c8925d --- /dev/null +++ b/src/share/zoneinfo/zdump.c @@ -0,0 +1,209 @@ +/* + * @(#)zdump.c 1.1 zdump.c 3/4/87 + */ + +#include "stdio.h" + +#include "sys/types.h" +#include "tzfile.h" +#include "time.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +extern char * asctime(); +extern char ** environ; +extern struct tm * gmtime(); +extern char * imalloc(); +extern char * optarg; +extern int optind; +extern char * sprintf(); +extern long time(); +extern char * tzname[2]; +extern void tzset(); + +/* +** For the benefit of cyntax... +*/ + +static long tzdecode(); +static readerr(); +static show(); + +static int longest; + +static long +tzdecode(codep) +char * codep; +{ + register int i; + register long result; + + result = 0; + for (i = 0; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + return result; +} + +main(argc, argv) +int argc; +char * argv[]; +{ + register FILE * fp; + register int i, j, c; + register int vflag; + register char * cutoff; + register int cutyear; + register long cuttime; + time_t now; + time_t t; + long timecnt; + char buf[BUFSIZ]; + + vflag = 0; + cutoff = NULL; + while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') + if (c == 'v') + vflag = 1; + else cutoff = optarg; + if (c != EOF || optind == argc - 1 && strcmp(argv[optind], "=") == 0) { + (void) fprintf(stderr, "%s: usage is %s [ -v ] zonename ...\n", + argv[0], argv[0]); + exit(1); + } + if (cutoff != NULL) + cutyear = atoi(cutoff); + /* + ** VERY approximate. + */ + cuttime = (long) (cutyear - EPOCH_YEAR) * + SECS_PER_HOUR * HOURS_PER_DAY * DAYS_PER_NYEAR; + (void) time(&now); + longest = 0; + for (i = optind; i < argc; ++i) + if (strlen(argv[i]) > longest) + longest = strlen(argv[i]); + for (i = optind; i < argc; ++i) { + register char ** saveenv; + char * tzequals; + char * fakeenv[2]; + + tzequals = imalloc(strlen(argv[i]) + 4); + if (tzequals == NULL) { + (void) fprintf(stderr, "%s: can't allocate memory\n", + argv[0]); + exit(1); + } + (void) sprintf(tzequals, "TZ=%s", argv[i]); + fakeenv[0] = tzequals; + fakeenv[1] = NULL; + saveenv = environ; + environ = fakeenv; + (void) tzset(); + environ = saveenv; + show(argv[i], now, FALSE); + if (!vflag) + continue; + if (argv[i][0] == '/') + fp = fopen(argv[i], "r"); + else { + j = strlen(TZDIR) + 1 + strlen(argv[i]) + 1; + if (j > sizeof buf) { + (void) fprintf(stderr, + "%s: timezone name %s/%s is too long\n", + argv[0], TZDIR, argv[i]); + exit(1); + } + (void) sprintf(buf, "%s/%s", TZDIR, argv[i]); + fp = fopen(buf, "r"); + } + if (fp == NULL) { + (void) fprintf(stderr, "%s: Can't open ", argv[0]); + perror(argv[i]); + exit(1); + } + { + char code[4]; + +(void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0); + if (fread((char *) code, sizeof code, 1, fp) != 1) + readerr(fp, argv[0], argv[i]); + timecnt = tzdecode(code); + (void) fseek(fp, (long) (2 * sizeof code), 1); + } + t = 0x80000000; + if (t > 0) /* time_t is unsigned */ + t = 0; + show(argv[i], t, TRUE); + t += SECS_PER_HOUR * HOURS_PER_DAY; + show(argv[i], t, TRUE); + while (timecnt-- > 0) { + char code[4]; + + if (fread((char *) code, sizeof code, 1, fp) != 1) + readerr(fp, argv[0], argv[i]); + t = tzdecode(code); + if (cutoff != NULL && t > cuttime) + break; + show(argv[i], t - 1, TRUE); + show(argv[i], t, TRUE); + } + if (fclose(fp)) { + (void) fprintf(stderr, "%s: Error closing ", argv[0]); + perror(argv[i]); + exit(1); + } + t = 0xffffffff; + if (t < 0) /* time_t is signed */ + t = 0x7fffffff ; + t -= SECS_PER_HOUR * HOURS_PER_DAY; + show(argv[i], t, TRUE); + t += SECS_PER_HOUR * HOURS_PER_DAY; + show(argv[i], t, TRUE); + free(tzequals); + } + if (fflush(stdout) || ferror(stdout)) { + (void) fprintf(stderr, "%s: Error writing standard output ", + argv[0]); + perror("standard output"); + exit(1); + } + return 0; +} + +static +show(zone, t, v) +char * zone; +time_t t; +{ + struct tm * tmp; + extern struct tm * localtime(); + + (void) printf("%-*s ", longest, zone); + if (v) + (void) printf("%.24s GMT = ", asctime(gmtime(&t))); + tmp = localtime(&t); + (void) printf("%.24s", asctime(tmp)); + if (*tzname[tmp->tm_isdst] != '\0') + (void) printf(" %s", tzname[tmp->tm_isdst]); + if (v) { + (void) printf(" isdst=%d", tmp->tm_isdst); + (void) printf(" gmtoff=%ld", tmp->tm_gmtoff); + } + (void) printf("\n"); +} + +static +readerr(fp, progname, filename) +FILE * fp; +char * progname; +char * filename; +{ + (void) fprintf(stderr, "%s: Error reading ", progname); + if (ferror(fp)) + perror(filename); + else (void) fprintf(stderr, "%s: Premature EOF\n", filename); + exit(1); +} diff --git a/src/share/zoneinfo/zic.8 b/src/share/zoneinfo/zic.8 new file mode 100644 index 0000000..bf124e8 --- /dev/null +++ b/src/share/zoneinfo/zic.8 @@ -0,0 +1,294 @@ +.TH ZIC 8 +.SH NAME +zic \- time zone compiler +.SH SYNOPSIS +.B zic +[ +.B \-v +] [ +.B \-d +.I directory +] [ +.B \-l +.I localtime +] [ +.I filename +\&... ] +.SH DESCRIPTION +.I Zic +reads text from the file(s) named on the command line +and creates the time conversion information files specified in this input. +If a +.I filename +is +.BR \- , +the standard input is read. +.PP +These options are available: +.TP +.BI "\-d " directory +Create time conversion information files in the named directory rather than +in the standard directory named below. +.TP +.BI "\-l " timezone +Use the given time zone as local time. +.I Zic +will act as if the file contained a link line of the form +.sp +.ti +.5i +Link \fItimezone\fP localtime +.TP +.B \-v +Complain if a year that appears in a data file is outside the range +of years representable by +.IR time (2) +values. +.sp +Input lines are made up of fields. +Fields are separated from one another by any number of white space characters. +Leading and trailing white space on input lines is ignored. +An unquoted sharp character (#) in the input introduces a comment which extends +to the end of the line the sharp character appears on. +White space characters and sharp characters may be enclosed in double quotes +(") if they're to be used as part of a field. +Any line that is blank (after comment stripping) is ignored. +Non-blank lines are expected to be of one of three types: +rule lines, zone lines, and link lines. +.PP +A rule line has the form +.nf +.B +.ti +.5i +.ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'TYPE\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u +.sp +Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +.sp +For example: +.ti +.5i +.sp +Rule USA 1969 1973 \- Apr lastSun 2:00 1:00 D +.sp +.fi +The fields that make up a rule line are: +.TP "\w'LETTER/S'u" +.B NAME +Gives the (arbitrary) name of the set of rules this rule is part of. +.TP +.B FROM +Gives the first year in which the rule applies. +The word +.B minimum +(or an abbreviation) means the minimum year with a representable time value. +The word +.B maximum +(or an abbreviation) means the maximum year with a representable time value. +.TP +.B TO +Gives the final year in which the rule applies. +In addition to +.B minimum +and +.B maximum +(as above), +the word +.B only +(or an abbreviation) +may be used to repeat the value of the +.B FROM +field. +.TP +.B TYPE +Gives the type of year in which the year applies. +If +.B TYPE +is +.B \- +then the rule applies in all years between +.B FROM +and +.B TO +inclusive; +if +.B TYPE +is +.BR uspres , +the rule applies in U.S. Presidential election years; +if +.B TYPE +is +.BR nonpres , +the rule applies in years other than U.S. Presidential election years. +If +.B TYPE +is something else, then +.I zic +executes the command +.ti +.5i +\fByearistype\fP \fIyear\fP \fItype\fP +.br +to check the type of a year: +an exit status of zero is taken to mean that the year is of the given type; +an exit status of one is taken to mean that the year is not of the given type. +.TP +.B IN +Names the month in which the rule takes effect. +Month names may be abbreviated. +.TP +.B ON +Gives the day on which the rule takes effect. +Recognized forms include: +.nf +.in +.5i +.sp +.ta \w'Sun<=25\0\0'u +5 the fifth of the month +lastSun the last Sunday in the month +lastMon the last Monday in the month +Sun>=8 first Sunday on or after the eighth +Sun<=25 last Sunday on or before the 25th +.fi +.in -.5i +.sp +Names of days of the week may be abbreviated or spelled out in full. +Note that there must be no spaces within the +.B ON +field. +.TP +.B AT +Gives the time of day at which the rule takes affect. +Recognized forms include: +.nf +.in +.5i +.sp +.ta \w'1:28:13\0\0'u +2 time in hours +2:00 time in hours and minutes +15:00 24-hour format time (for times after noon) +1:28:14 time in hours, minutes, and seconds +.fi +.in -.5i +.sp +Any of these forms may be followed by the letter +.B w +if the given time is local ``wall clock'' time or +.B s +if the given time is local ``standard'' time; in the absence of +.B w +or +.BR s , +wall clock time is assumed. +.TP +.B SAVE +Gives the amount of time to be added to local standard time when the rule is in +effect. +This field has the same format as the +.B AT +field +(although, of course, the +.B w +and +.B s +suffixes are not used). +.TP +.B LETTER/S +Gives the ``variable part'' (for example, the ``S'' or ``D'' in ``EST'' +or ``EDT'') of time zone abbreviations to be used when this rule is in effect. +If this field is +.BR \- , +the variable part is null. +.PP +A zone line has the form +.sp +.nf +.ti +.5i +.ta \w'Zone\0\0'u +\w'Australia/South\-west\0\0'u +\w'GMTOFF\0\0'u +\w'RULES/SAVE\0\0'u +\w'FORMAT\0\0'u +Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +.sp +For example: +.sp +.ti +.5i +Zone Australia/South\-west 9:30 Aus CST 1987 Mar 15 2:00 +.sp +.fi +The fields that make up a zone line are: +.TP "\w'GMTOFF'u" +.B NAME +The name of the time zone. +This is the name used in creating the time conversion information file for the +zone. +.TP +.B GMTOFF +The amount of time to add to GMT to get standard time in this zone. +This field has the same format as the +.B AT +and +.B SAVE +fields of rule lines; +begin the field with a minus sign if time must be subtracted from GMT. +.TP +.B RULES/SAVE +The name of the rule(s) that apply in the time zone or, +alternately, an amount of time to add to local standard time. +If this field is +.B \- +then standard time always applies in the time zone. +.TP +.B FORMAT +The format for time zone abbreviations in this time zone. +The pair of characters +.B %s +is used to show where the ``variable part'' of the time zone abbreviation goes. +.B UNTIL +The time at which the GMT offset or the rule(s) change for a location. +It is specified as a year, a month, a day, and a time of day. +If this is specified, +the time zone information is generated from the given GMT offset +and rule change until the time specified. +.IP +The next line must be a +``continuation'' line; this has the same form as a zone line except that the +string ``Zone'' and the name are omitted, as the continuation line will +place information starting at the time specified as the +.B UNTIL +field in the previous line in the file used by the previous line. +Continuation lines may contain an +.B UNTIL +field, just as zone lines do, indicating that the next line is a further +continuation. +.PP +A link line has the form +.sp +.nf +.ti +.5i +.if t .ta \w'Link\0\0'u +\w'LINK-FROM\0\0'u +.if n .ta \w'Link\0\0'u +\w'US/Eastern\0\0'u +Link LINK-FROM LINK-TO +.sp +For example: +.sp +.ti +.5i +Link US/Eastern EST5EDT +.sp +.fi +The +.B LINK-FROM +field should appear as the +.B NAME +field in some zone line; +the +.B LINK-TO +field is used as an alternate name for that zone. +.PP +Except for continuation lines, +lines may appear in any order in the input. +.SH NOTE +For areas with more than two types of local time, +you may need to use local standard time in the +.B AT +field of the earliest transition time's rule to ensure that +the earliest transition time recorded in the compiled file is correct. +.SH FILES +/usr/share/zoneinfo standard directory used for created files +.SH "SEE ALSO" +newctime(3), tzfile(5), zdump(8) +.. @(#)zic.8 3.2 diff --git a/src/share/zoneinfo/zic.c b/src/share/zoneinfo/zic.c new file mode 100644 index 0000000..752613d --- /dev/null +++ b/src/share/zoneinfo/zic.c @@ -0,0 +1,1543 @@ +/* + * @(#)zic.c 1.1 zic.c 3/4/87 + */ + +#include "stdio.h" +#include "ctype.h" +#include "sys/types.h" +#include "sys/stat.h" +#include "sys/file.h" +#include "strings.h" +#include "time.h" +#include "tzfile.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +extern char * icpyalloc(); +extern char * imalloc(); +extern char * irealloc(); +extern char * optarg; +extern int optind; +extern char * scheck(); +extern char * sprintf(); + +static addtt(); +static addtype(); +static associate(); +static int charcnt; +static ciequal(); +static long eitol(); +static int errors; +static char * filename; +static char ** getfields(); +static long gethms(); +static infile(); +static inlink(); +static inrule(); +static inzcont(); +static inzone(); +static inzsub(); +static int linenum; +static lowerit(); +static time_t max_time; +static int max_year; +static time_t min_time; +static int min_year; +static mkdirs(); +static newabbr(); +static int noise; +static nondunlink(); +static long oadd(); +static outzone(); +static char * progname; +static char * rfilename; +static int rlinenum; +static time_t rpytime(); +static rulesub(); +static setboundaries(); +static time_t tadd(); +static int timecnt; +static int tt_signed; +static int typecnt; +static yearistype(); + +/* +** Line codes. +*/ + +#define LC_RULE 0 +#define LC_ZONE 1 +#define LC_LINK 2 + +/* +** Which fields are which on a Zone line. +*/ + +#define ZF_NAME 1 +#define ZF_GMTOFF 2 +#define ZF_RULE 3 +#define ZF_FORMAT 4 +#define ZF_UNTILYEAR 5 +#define ZF_UNTILMONTH 6 +#define ZF_UNTILDAY 7 +#define ZF_UNTILTIME 8 +#define ZONE_MINFIELDS 5 +#define ZONE_MAXFIELDS 9 + +/* +** Which fields are which on a Zone continuation line. +*/ + +#define ZFC_GMTOFF 0 +#define ZFC_RULE 1 +#define ZFC_FORMAT 2 +#define ZFC_UNTILYEAR 3 +#define ZFC_UNTILMONTH 4 +#define ZFC_UNTILDAY 5 +#define ZFC_UNTILTIME 6 +#define ZONEC_MINFIELDS 3 +#define ZONEC_MAXFIELDS 7 + +/* +** Which files are which on a Rule line. +*/ + +#define RF_NAME 1 +#define RF_LOYEAR 2 +#define RF_HIYEAR 3 +#define RF_COMMAND 4 +#define RF_MONTH 5 +#define RF_DAY 6 +#define RF_TOD 7 +#define RF_STDOFF 8 +#define RF_ABBRVAR 9 +#define RULE_FIELDS 10 + +/* +** Which fields are which on a Link line. +*/ + +#define LF_FROM 1 +#define LF_TO 2 +#define LINK_FIELDS 3 + +struct rule { + char * r_filename; + int r_linenum; + char * r_name; + + int r_loyear; /* for example, 1986 */ + int r_hiyear; /* for example, 1986 */ + char * r_yrtype; + + int r_month; /* 0..11 */ + + int r_dycode; /* see below */ + int r_dayofmonth; + int r_wday; + + long r_tod; /* time from midnight */ + int r_todisstd; /* above is standard time if TRUE */ + /* above is wall clock time if FALSE */ + long r_stdoff; /* offset from standard time */ + char * r_abbrvar; /* variable part of time zone abbreviation */ + + int r_todo; /* a rule to do (used in outzone) */ + time_t r_temp; /* used in outzone */ +}; + +/* +** r_dycode r_dayofmonth r_wday +*/ +#define DC_DOM 0 /* 1..31 */ /* unused */ +#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ +#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ + +/* +** Year synonyms. +*/ + +#define YR_MINIMUM 0 +#define YR_MAXIMUM 1 +#define YR_ONLY 2 + +static struct rule * rules; +static int nrules; /* number of rules */ + +struct zone { + char * z_filename; + int z_linenum; + + char * z_name; + long z_gmtoff; + char * z_rule; + char * z_format; + + long z_stdoff; + + struct rule * z_rules; + int z_nrules; + + struct rule z_untilrule; + time_t z_untiltime; +}; + +static struct zone * zones; +static int nzones; /* number of zones */ + +struct link { + char * l_filename; + int l_linenum; + char * l_from; + char * l_to; +}; + +static struct link * links; +static int nlinks; + +struct lookup { + char * l_word; + int l_value; +}; + +static struct lookup * byword(); + +static struct lookup line_codes[] = { + "Rule", LC_RULE, + "Zone", LC_ZONE, + "Link", LC_LINK, + NULL, 0 +}; + +static struct lookup mon_names[] = { + "January", TM_JANUARY, + "February", TM_FEBRUARY, + "March", TM_MARCH, + "April", TM_APRIL, + "May", TM_MAY, + "June", TM_JUNE, + "July", TM_JULY, + "August", TM_AUGUST, + "September", TM_SEPTEMBER, + "October", TM_OCTOBER, + "November", TM_NOVEMBER, + "December", TM_DECEMBER, + NULL, 0 +}; + +static struct lookup wday_names[] = { + "Sunday", TM_SUNDAY, + "Monday", TM_MONDAY, + "Tuesday", TM_TUESDAY, + "Wednesday", TM_WEDNESDAY, + "Thursday", TM_THURSDAY, + "Friday", TM_FRIDAY, + "Saturday", TM_SATURDAY, + NULL, 0 +}; + +static struct lookup lasts[] = { + "last-Sunday", TM_SUNDAY, + "last-Monday", TM_MONDAY, + "last-Tuesday", TM_TUESDAY, + "last-Wednesday", TM_WEDNESDAY, + "last-Thursday", TM_THURSDAY, + "last-Friday", TM_FRIDAY, + "last-Saturday", TM_SATURDAY, + NULL, 0 +}; + +static struct lookup begin_years[] = { + "minimum", YR_MINIMUM, + "maximum", YR_MAXIMUM, + NULL, 0 +}; + +static struct lookup end_years[] = { + "minimum", YR_MINIMUM, + "maximum", YR_MAXIMUM, + "only", YR_ONLY, + NULL, 0 +}; + +static int len_months[2][MONS_PER_YEAR] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static int len_years[2] = { + DAYS_PER_NYEAR, DAYS_PER_LYEAR +}; + +static time_t ats[TZ_MAX_TIMES]; +static unsigned char types[TZ_MAX_TIMES]; +static long gmtoffs[TZ_MAX_TYPES]; +static char isdsts[TZ_MAX_TYPES]; +static char abbrinds[TZ_MAX_TYPES]; +static char chars[TZ_MAX_CHARS]; + +/* +** Memory allocation. +*/ + +static char * +memcheck(ptr) +char * ptr; +{ + if (ptr == NULL) { + perror(progname); + exit(1); + } + return ptr; +} + +#define emalloc(size) memcheck(imalloc(size)) +#define erealloc(ptr, size) memcheck(irealloc(ptr, size)) +#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) + +/* +** Error handling. +*/ + +static +eats(name, num, rname, rnum) +char * name; +char * rname; +{ + filename = name; + linenum = num; + rfilename = rname; + rlinenum = rnum; +} + +static +eat(name, num) +char * name; +{ + eats(name, num, (char *) NULL, -1); +} + +static +error(string) +char * string; +{ + /* + ** Match the format of "cc" to allow sh users to + ** zic ... 2>&1 | error -t "*" -v + ** on BSD systems. + */ + (void) fprintf(stderr, "\"%s\", line %d: %s", + filename, linenum, string); + if (rfilename != NULL) + (void) fprintf(stderr, " (rule from \"%s\", line %d)", + rfilename, rlinenum); + (void) fprintf(stderr, "\n"); + ++errors; +} + +static +usage() +{ + (void) fprintf(stderr, +"%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n", + progname, progname); + exit(1); +} + +static char * lcltime = NULL; +static char * directory = NULL; + +main(argc, argv) +int argc; +char * argv[]; +{ + register int i, j; + register int c; + +#ifdef unix + umask(umask(022) | 022); +#endif + progname = argv[0]; + while ((c = getopt(argc, argv, "d:l:v")) != EOF) + switch (c) { + default: + usage(); + case 'd': + if (directory == NULL) + directory = optarg; + else { + (void) fprintf(stderr, +"%s: More than one -d option specified\n", + progname); + exit(1); + } + break; + case 'l': + if (lcltime == NULL) + lcltime = optarg; + else { + (void) fprintf(stderr, +"%s: More than one -l option specified\n", + progname); + exit(1); + } + break; + case 'v': + noise = TRUE; + break; + } + if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) + usage(); /* usage message by request */ + if (directory == NULL) + directory = TZDIR; + + setboundaries(); + + zones = (struct zone *) emalloc(0); + rules = (struct rule *) emalloc(0); + links = (struct link *) emalloc(0); + for (i = optind; i < argc; ++i) + infile(argv[i]); + if (errors) + exit(1); + associate(); + for (i = 0; i < nzones; i = j) { + /* + * Find the next non-continuation zone entry. + */ + for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) + ; + outzone(&zones[i], j - i); + } + /* + ** We'll take the easy way out on this last part. + */ + if (chdir(directory) != 0) { + (void) fprintf(stderr, "%s: Can't chdir to ", progname); + perror(directory); + exit(1); + } + for (i = 0; i < nlinks; ++i) { + nondunlink(links[i].l_to); + if (link(links[i].l_from, links[i].l_to) != 0) { + (void) fprintf(stderr, "%s: Can't link %s to ", + progname, links[i].l_from); + perror(links[i].l_to); + exit(1); + } + } + if (lcltime != NULL) { + nondunlink(TZDEFAULT); + if (link(lcltime, TZDEFAULT) != 0) { + (void) fprintf(stderr, "%s: Can't link %s to ", + progname, lcltime); + perror(TZDEFAULT); + exit(1); + } + } + exit((errors == 0) ? 0 : 1); +} + +static +setboundaries() +{ + register time_t bit; + + for (bit = 1; bit > 0; bit <<= 1) + ; + if (bit == 0) { /* time_t is an unsigned type */ + tt_signed = FALSE; + min_time = 0; + max_time = ~(time_t) 0; + } else { + tt_signed = TRUE; + min_time = bit; + max_time = bit; + ++max_time; + max_time = -max_time; + } + min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; + max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; +} + +/* +** We get to be careful here since there's a fair chance of root running us. +*/ + +static +nondunlink(name) +char * name; +{ + struct stat s; + + if (stat(name, &s) != 0) + return; + if ((s.st_mode & S_IFMT) == S_IFDIR) + return; + (void) unlink(name); +} + +/* +** Associate sets of rules with zones. +*/ + +/* +** Sort by rule name. +*/ + +static +rcomp(cp1, cp2) +char * cp1; +char * cp2; +{ + return strcmp(((struct rule *) cp1)->r_name, + ((struct rule *) cp2)->r_name); +} + +static +associate() +{ + register struct zone * zp; + register struct rule * rp; + register int base, out; + register int i; + + if (nrules != 0) + (void) qsort((char *) rules, nrules, sizeof *rules, rcomp); + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + zp->z_rules = NULL; + zp->z_nrules = 0; + } + for (base = 0; base < nrules; base = out) { + rp = &rules[base]; + for (out = base + 1; out < nrules; ++out) + if (strcmp(rp->r_name, rules[out].r_name) != 0) + break; + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + if (strcmp(zp->z_rule, rp->r_name) != 0) + continue; + zp->z_rules = rp; + zp->z_nrules = out - base; + } + } + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + if (zp->z_nrules == 0) { + /* + ** Maybe we have a local standard time offset. + */ + eat(zp->z_filename, zp->z_linenum); + zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE); + /* + ** Note, though, that if there's no rule, + ** a '%s' in the format is a bad thing. + */ + if (index(zp->z_format, '%') != 0) + error("%s in ruleless zone"); + } + } + if (errors) + exit(1); +} + +static +infile(name) +char * name; +{ + register FILE * fp; + register char ** fields; + register char * cp; + register struct lookup * lp; + register int nfields; + register int wantcont; + register int num; + char buf[BUFSIZ]; + + if (strcmp(name, "-") == 0) { + name = "standard input"; + fp = stdin; + } else if ((fp = fopen(name, "r")) == NULL) { + (void) fprintf(stderr, "%s: Can't open ", progname); + perror(name); + exit(1); + } + wantcont = FALSE; + for (num = 1; ; ++num) { + eat(name, num); + if (fgets(buf, sizeof buf, fp) != buf) + break; + cp = index(buf, '\n'); + if (cp == NULL) { + error("line too long"); + exit(1); + } + *cp = '\0'; + fields = getfields(buf); + nfields = 0; + while (fields[nfields] != NULL) { + if (ciequal(fields[nfields], "-")) + fields[nfields] = ""; + ++nfields; + } + if (nfields == 0) { + /* nothing to do */ + } else if (wantcont) { + wantcont = inzcont(fields, nfields); + } else { + lp = byword(fields[0], line_codes); + if (lp == NULL) + error("input line of unknown type"); + else switch ((int) (lp->l_value)) { + case LC_RULE: + inrule(fields, nfields); + wantcont = FALSE; + break; + case LC_ZONE: + wantcont = inzone(fields, nfields); + break; + case LC_LINK: + inlink(fields, nfields); + wantcont = FALSE; + break; + default: /* "cannot happen" */ + (void) fprintf(stderr, +"%s: panic: Invalid l_value %d\n", + progname, lp->l_value); + exit(1); + } + } + free((char *) fields); + } + if (ferror(fp)) { + (void) fprintf(stderr, "%s: Error reading ", progname); + perror(filename); + exit(1); + } + if (fp != stdin && fclose(fp)) { + (void) fprintf(stderr, "%s: Error closing ", progname); + perror(filename); + exit(1); + } + if (wantcont) + error("expected continuation line not found"); +} + +/* +** Convert a string of one of the forms +** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss +** into a number of seconds. +** A null string maps to zero. +** Call error with errstring and return zero on errors. +*/ + +static long +gethms(string, errstring, signable) +char * string; +char * errstring; +{ + int hh, mm, ss, sign; + + if (string == NULL || *string == '\0') + return 0; + if (!signable) + sign = 1; + else if (*string == '-') { + sign = -1; + ++string; + } else sign = 1; + if (sscanf(string, scheck(string, "%d"), &hh) == 1) + mm = ss = 0; + else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) + ss = 0; + else if (sscanf(string, scheck(string, "%d:%d:%d"), + &hh, &mm, &ss) != 3) { + error(errstring); + return 0; + } + if (hh < 0 || hh >= HOURS_PER_DAY || + mm < 0 || mm >= MINS_PER_HOUR || + ss < 0 || ss >= SECS_PER_MIN) { + error(errstring); + return 0; + } + return eitol(sign) * + (eitol(hh * MINS_PER_HOUR + mm) * + eitol(SECS_PER_MIN) + eitol(ss)); +} + +static +inrule(fields, nfields) +register char ** fields; +{ + struct rule r; + + if (nfields != RULE_FIELDS) { + error("wrong number of fields on Rule line"); + return; + } + if (*fields[RF_NAME] == '\0') { + error("nameless rule"); + return; + } + r.r_filename = filename; + r.r_linenum = linenum; + r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); + rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], + fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); + r.r_name = ecpyalloc(fields[RF_NAME]); + r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); + rules = (struct rule *) erealloc((char *) rules, + (nrules + 1) * sizeof *rules); + rules[nrules++] = r; +} + +static +inzone(fields, nfields) +register char ** fields; +{ + register int i; + char buf[132]; + + if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { + error("wrong number of fields on Zone line"); + return FALSE; + } + if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { + (void) sprintf(buf, + "\"Zone %s\" line and -l option are mutually exclusive", + TZDEFAULT); + error(buf); + return FALSE; + } + for (i = 0; i < nzones; ++i) + if (zones[i].z_name != NULL && + strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { + (void) sprintf(buf, +"duplicate zone name %s (file \"%s\", line %d)", + fields[ZF_NAME], + zones[i].z_filename, + zones[i].z_linenum); + error(buf); + return FALSE; + } + return inzsub(fields, nfields, FALSE); +} + +static +inzcont(fields, nfields) +register char ** fields; +{ + if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { + error("wrong number of fields on Zone continuation line"); + return FALSE; + } + return inzsub(fields, nfields, TRUE); +} + +static +inzsub(fields, nfields, iscont) +register char ** fields; +{ + register char * cp; + struct zone z; + register int i_gmtoff, i_rule, i_format; + register int i_untilyear, i_untilmonth; + register int i_untilday, i_untiltime; + register int hasuntil; + + if (iscont) { + i_gmtoff = ZFC_GMTOFF; + i_rule = ZFC_RULE; + i_format = ZFC_FORMAT; + i_untilyear = ZFC_UNTILYEAR; + i_untilmonth = ZFC_UNTILMONTH; + i_untilday = ZFC_UNTILDAY; + i_untiltime = ZFC_UNTILTIME; + z.z_name = NULL; + } else { + i_gmtoff = ZF_GMTOFF; + i_rule = ZF_RULE; + i_format = ZF_FORMAT; + i_untilyear = ZF_UNTILYEAR; + i_untilmonth = ZF_UNTILMONTH; + i_untilday = ZF_UNTILDAY; + i_untiltime = ZF_UNTILTIME; + z.z_name = ecpyalloc(fields[ZF_NAME]); + } + z.z_filename = filename; + z.z_linenum = linenum; + z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); + if ((cp = index(fields[i_format], '%')) != 0) { + if (*++cp != 's' || index(cp, '%') != 0) { + error("invalid abbreviation format"); + return FALSE; + } + } + z.z_rule = ecpyalloc(fields[i_rule]); + z.z_format = ecpyalloc(fields[i_format]); + hasuntil = nfields > i_untilyear; + if (hasuntil) { + z.z_untilrule.r_filename = filename; + z.z_untilrule.r_linenum = linenum; + rulesub(&z.z_untilrule, + fields[i_untilyear], + "only", + "", + (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", + (nfields > i_untilday) ? fields[i_untilday] : "1", + (nfields > i_untiltime) ? fields[i_untiltime] : "0"); + z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); + if (iscont && nzones > 0 && z.z_untiltime < max_time && + z.z_untiltime > min_time && + zones[nzones - 1].z_untiltime >= z.z_untiltime) { +error("Zone continuation line end time is not after end time of previous line"); + return FALSE; + } + } + zones = (struct zone *) erealloc((char *) zones, + (nzones + 1) * sizeof *zones); + zones[nzones++] = z; + /* + ** If there was an UNTIL field on this line, + ** there's more information about the zone on the next line. + */ + return hasuntil; +} + +static +inlink(fields, nfields) +register char ** fields; +{ + struct link l; + + if (nfields != LINK_FIELDS) { + error("wrong number of fields on Link line"); + return; + } + if (*fields[LF_FROM] == '\0') { + error("blank FROM field on Link line"); + return; + } + if (*fields[LF_TO] == '\0') { + error("blank TO field on Link line"); + return; + } + l.l_filename = filename; + l.l_linenum = linenum; + l.l_from = ecpyalloc(fields[LF_FROM]); + l.l_to = ecpyalloc(fields[LF_TO]); + links = (struct link *) erealloc((char *) links, + (nlinks + 1) * sizeof *links); + links[nlinks++] = l; +} + +static +rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) +register struct rule * rp; +char * loyearp; +char * hiyearp; +char * typep; +char * monthp; +char * dayp; +char * timep; +{ + register struct lookup * lp; + register char * cp; + + if ((lp = byword(monthp, mon_names)) == NULL) { + error("invalid month name"); + return; + } + rp->r_month = lp->l_value; + rp->r_todisstd = FALSE; + cp = timep; + if (*cp != '\0') { + cp += strlen(cp) - 1; + switch (lowerit(*cp)) { + case 's': + rp->r_todisstd = TRUE; + *cp = '\0'; + break; + case 'w': + rp->r_todisstd = FALSE; + *cp = '\0'; + break; + } + } + rp->r_tod = gethms(timep, "invalid time of day", FALSE); + /* + ** Year work. + */ + cp = loyearp; + if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { + case YR_MINIMUM: + rp->r_loyear = min_year; + break; + case YR_MAXIMUM: + rp->r_loyear = max_year; + break; + default: /* "cannot happen" */ + (void) fprintf(stderr, + "%s: panic: Invalid l_value %d\n", + progname, lp->l_value); + exit(1); + } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 || + rp->r_loyear < min_year || rp->r_loyear > max_year) { + if (noise) + error("invalid starting year"); + if (rp->r_loyear > max_year) + return; + } + cp = hiyearp; + if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { + case YR_MINIMUM: + rp->r_hiyear = min_year; + break; + case YR_MAXIMUM: + rp->r_hiyear = max_year; + break; + case YR_ONLY: + rp->r_hiyear = rp->r_loyear; + break; + default: /* "cannot happen" */ + (void) fprintf(stderr, + "%s: panic: Invalid l_value %d\n", + progname, lp->l_value); + exit(1); + } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 || + rp->r_hiyear < min_year || rp->r_hiyear > max_year) { + if (noise) + error("invalid ending year"); + if (rp->r_hiyear < min_year) + return; + } + if (rp->r_hiyear < min_year) + return; + if (rp->r_loyear < min_year) + rp->r_loyear = min_year; + if (rp->r_hiyear > max_year) + rp->r_hiyear = max_year; + if (rp->r_loyear > rp->r_hiyear) { + error("starting year greater than ending year"); + return; + } + if (*typep == '\0') + rp->r_yrtype = NULL; + else { + if (rp->r_loyear == rp->r_hiyear) { + error("typed single year"); + return; + } + rp->r_yrtype = ecpyalloc(typep); + } + /* + ** Day work. + ** Accept things such as: + ** 1 + ** last-Sunday + ** Sun<=20 + ** Sun>=7 + */ + if ((lp = byword(dayp, lasts)) != NULL) { + rp->r_dycode = DC_DOWLEQ; + rp->r_wday = lp->l_value; + rp->r_dayofmonth = len_months[1][rp->r_month]; + } else { + if ((cp = index(dayp, '<')) != 0) + rp->r_dycode = DC_DOWLEQ; + else if ((cp = index(dayp, '>')) != 0) + rp->r_dycode = DC_DOWGEQ; + else { + cp = dayp; + rp->r_dycode = DC_DOM; + } + if (rp->r_dycode != DC_DOM) { + *cp++ = 0; + if (*cp++ != '=') { + error("invalid day of month"); + return; + } + if ((lp = byword(dayp, wday_names)) == NULL) { + error("invalid weekday name"); + return; + } + rp->r_wday = lp->l_value; + } + if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || + rp->r_dayofmonth <= 0 || + (rp->r_dayofmonth > len_months[1][rp->r_month])) { + error("invalid day of month"); + return; + } + } +} + +static +puttzcode(val, fp) +long val; +FILE * fp; +{ + register int c; + register int shift; + + for (shift = 24; shift >= 0; shift -= 8) { + c = val >> shift; + (void) putc(c, fp); + } +} + +static +writezone(name) +char * name; +{ + register FILE * fp; + register int i; + char fullname[BUFSIZ]; + + if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) { + (void) fprintf(stderr, + "%s: File name %s/%s too long\n", progname, + directory, name); + exit(1); + } + (void) sprintf(fullname, "%s/%s", directory, name); + if ((fp = fopen(fullname, "w")) == NULL) { + if (mkdirs(fullname) != 0) + exit(1); + if ((fp = fopen(fullname, "w")) == NULL) { + (void) fprintf(stderr, "%s: Can't create ", progname); + perror(fullname); + exit(1); + } + } + (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0); + puttzcode(eitol(timecnt), fp); + puttzcode(eitol(typecnt), fp); + puttzcode(eitol(charcnt), fp); + for (i = 0; i < timecnt; ++i) + puttzcode((long) ats[i], fp); + if (timecnt > 0) + (void) fwrite((char *) types, sizeof types[0], + (int) timecnt, fp); + for (i = 0; i < typecnt; ++i) { + puttzcode((long) gmtoffs[i], fp); + (void) putc(isdsts[i], fp); + (void) putc(abbrinds[i], fp); + } + if (charcnt != 0) + (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp); + if (ferror(fp) || fclose(fp)) { + (void) fprintf(stderr, "%s: Write error on ", progname); + perror(fullname); + exit(1); + } +} + +static +outzone(zpfirst, zonecount) +struct zone * zpfirst; +{ + register struct zone * zp; + register struct rule * rp; + register int i, j; + register int usestart, useuntil; + register time_t starttime, untiltime; + register long gmtoff; + register long stdoff; + register int year; + register long startoff; + register int startisdst; + register int type; + char startbuf[BUFSIZ]; + + /* + ** Now. . .finally. . .generate some useful data! + */ + timecnt = 0; + typecnt = 0; + charcnt = 0; + /* + ** Two guesses. . .the second may well be corrected later. + */ + gmtoff = zpfirst->z_gmtoff; + stdoff = 0; + for (i = 0; i < zonecount; ++i) { + usestart = i > 0; + useuntil = i < (zonecount - 1); + zp = &zpfirst[i]; + eat(zp->z_filename, zp->z_linenum); + startisdst = -1; + if (zp->z_nrules == 0) { + type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff), + zp->z_format, zp->z_stdoff != 0); + if (usestart) + addtt(starttime, type); + gmtoff = zp->z_gmtoff; + stdoff = zp->z_stdoff; + } else for (year = min_year; year <= max_year; ++year) { + if (useuntil && year > zp->z_untilrule.r_hiyear) + break; + /* + ** Mark which rules to do in the current year. + ** For those to do, calculate rpytime(rp, year); + */ + for (j = 0; j < zp->z_nrules; ++j) { + rp = &zp->z_rules[j]; + eats(zp->z_filename, zp->z_linenum, + rp->r_filename, rp->r_linenum); + rp->r_todo = year >= rp->r_loyear && + year <= rp->r_hiyear && + yearistype(year, rp->r_yrtype); + if (rp->r_todo) + rp->r_temp = rpytime(rp, year); + } + for ( ; ; ) { + register int k; + register time_t jtime, ktime; + register long offset; + char buf[BUFSIZ]; + + if (useuntil) { + /* + ** Turn untiltime into GMT + ** assuming the current gmtoff and + ** stdoff values. + */ + offset = gmtoff; + if (!zp->z_untilrule.r_todisstd) + offset = oadd(offset, stdoff); + untiltime = tadd(zp->z_untiltime, + -offset); + } + /* + ** Find the rule (of those to do, if any) + ** that takes effect earliest in the year. + */ + k = -1; + for (j = 0; j < zp->z_nrules; ++j) { + rp = &zp->z_rules[j]; + if (!rp->r_todo) + continue; + eats(zp->z_filename, zp->z_linenum, + rp->r_filename, rp->r_linenum); + offset = gmtoff; + if (!rp->r_todisstd) + offset = oadd(offset, stdoff); + jtime = rp->r_temp; + if (jtime == min_time || + jtime == max_time) + continue; + jtime = tadd(jtime, -offset); + if (k < 0 || jtime < ktime) { + k = j; + ktime = jtime; + } + } + if (k < 0) + break; /* go on to next year */ + rp = &zp->z_rules[k]; + rp->r_todo = FALSE; + if (useuntil && ktime >= untiltime) + break; + if (usestart) { + if (ktime < starttime) { + stdoff = rp->r_stdoff; + startoff = oadd(zp->z_gmtoff, + rp->r_stdoff); + (void) sprintf(startbuf, + zp->z_format, + rp->r_abbrvar); + startisdst = + rp->r_stdoff != 0; + continue; + } + if (ktime != starttime && + startisdst >= 0) +addtt(starttime, addtype(startoff, startbuf, startisdst)); + usestart = FALSE; + } + eats(zp->z_filename, zp->z_linenum, + rp->r_filename, rp->r_linenum); + (void) sprintf(buf, zp->z_format, + rp->r_abbrvar); + offset = oadd(zp->z_gmtoff, rp->r_stdoff); + type = addtype(offset, buf, rp->r_stdoff != 0); + if (timecnt != 0 || rp->r_stdoff != 0) + addtt(ktime, type); + gmtoff = zp->z_gmtoff; + stdoff = rp->r_stdoff; + } + } + /* + ** Now we may get to set starttime for the next zone line. + */ + if (useuntil) + starttime = tadd(zp->z_untiltime, + -gmtoffs[types[timecnt - 1]]); + } + writezone(zpfirst->z_name); +} + +static +addtt(starttime, type) +time_t starttime; +{ + if (timecnt != 0 && type == types[timecnt - 1]) + return; /* easy enough! */ + if (timecnt >= TZ_MAX_TIMES) { + error("too many transitions?!"); + exit(1); + } + ats[timecnt] = starttime; + types[timecnt] = type; + ++timecnt; +} + +static +addtype(gmtoff, abbr, isdst) +long gmtoff; +char * abbr; +{ + register int i, j; + + /* + ** See if there's already an entry for this zone type. + ** If so, just return its index. + */ + for (i = 0; i < typecnt; ++i) { + if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && + strcmp(abbr, &chars[abbrinds[i]]) == 0) + return i; + } + /* + ** There isn't one; add a new one, unless there are already too + ** many. + */ + if (typecnt >= TZ_MAX_TYPES) { + error("too many local time types"); + exit(1); + } + gmtoffs[i] = gmtoff; + isdsts[i] = isdst; + + for (j = 0; j < charcnt; ++j) + if (strcmp(&chars[j], abbr) == 0) + break; + if (j == charcnt) + newabbr(abbr); + abbrinds[i] = j; + ++typecnt; + return i; +} + +static +yearistype(year, type) +char * type; +{ + char buf[BUFSIZ]; + int result; + + if (type == NULL || *type == '\0') + return TRUE; + if (strcmp(type, "uspres") == 0) + return (year % 4) == 0; + if (strcmp(type, "nonpres") == 0) + return (year % 4) != 0; + (void) sprintf(buf, "yearistype %d %s", year, type); + result = system(buf); + if (result == 0) + return TRUE; + if (result == 1 << 8) + return FALSE; + error("Wild result from command execution"); + (void) fprintf(stderr, "%s: command was '%s', result was %d\n", + progname, buf, result); + for ( ; ; ) + exit(1); +} + +static +lowerit(a) +{ + return (isascii(a) && isupper(a)) ? tolower(a) : a; +} + +static +ciequal(ap, bp) /* case-insensitive equality */ +register char * ap; +register char * bp; +{ + while (lowerit(*ap) == lowerit(*bp++)) + if (*ap++ == '\0') + return TRUE; + return FALSE; +} + +static +isabbr(abbr, word) +register char * abbr; +register char * word; +{ + if (lowerit(*abbr) != lowerit(*word)) + return FALSE; + ++word; + while (*++abbr != '\0') + do if (*word == '\0') + return FALSE; + while (lowerit(*word++) != lowerit(*abbr)); + return TRUE; +} + +static struct lookup * +byword(word, table) +register char * word; +register struct lookup * table; +{ + register struct lookup * foundlp; + register struct lookup * lp; + + if (word == NULL || table == NULL) + return NULL; + /* + ** Look for exact match. + */ + for (lp = table; lp->l_word != NULL; ++lp) + if (ciequal(word, lp->l_word)) + return lp; + /* + ** Look for inexact match. + */ + foundlp = NULL; + for (lp = table; lp->l_word != NULL; ++lp) + if (isabbr(word, lp->l_word)) + if (foundlp == NULL) + foundlp = lp; + else return NULL; /* multiple inexact matches */ + return foundlp; +} + +static char ** +getfields(cp) +register char * cp; +{ + register char * dp; + register char ** array; + register int nsubs; + + if (cp == NULL) + return NULL; + array = (char **) emalloc((strlen(cp) + 1) * sizeof *array); + nsubs = 0; + for ( ; ; ) { + while (isascii(*cp) && isspace(*cp)) + ++cp; + if (*cp == '\0' || *cp == '#') + break; + array[nsubs++] = dp = cp; + do { + if ((*dp = *cp++) != '"') + ++dp; + else while ((*dp = *cp++) != '"') + if (*dp != '\0') + ++dp; + else error("Odd number of quotation marks"); + } while (*cp != '\0' && *cp != '#' && + (!isascii(*cp) || !isspace(*cp))); + if (isascii(*cp) && isspace(*cp)) + ++cp; + *dp = '\0'; + } + array[nsubs] = NULL; + return array; +} + +static long +oadd(t1, t2) +long t1; +long t2; +{ + register long t; + + t = t1 + t2; + if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { + error("time overflow"); + exit(1); + } + return t; +} + +static time_t +tadd(t1, t2) +time_t t1; +long t2; +{ + register time_t t; + + if (t1 == max_time && t2 > 0) + return max_time; + if (t1 == min_time && t2 < 0) + return min_time; + t = t1 + t2; + if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { + error("time overflow"); + exit(1); + } + return t; +} + +/* +** Given a rule, and a year, compute the date - in seconds since January 1, +** 1970, 00:00 LOCAL time - in that year that the rule refers to. +*/ + +static time_t +rpytime(rp, wantedy) +register struct rule * rp; +register int wantedy; +{ + register int y, m, i; + register long dayoff; /* with a nod to Margaret O. */ + register time_t t; + + dayoff = 0; + m = TM_JANUARY; + y = EPOCH_YEAR; + while (wantedy != y) { + if (wantedy > y) { + i = len_years[isleap(y)]; + ++y; + } else { + --y; + i = -len_years[isleap(y)]; + } + dayoff = oadd(dayoff, eitol(i)); + } + while (m != rp->r_month) { + i = len_months[isleap(y)][m]; + dayoff = oadd(dayoff, eitol(i)); + ++m; + } + i = rp->r_dayofmonth; + if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { + if (rp->r_dycode == DC_DOWLEQ) + --i; + else { + error("use of 2/29 in non leap-year"); + exit(1); + } + } + --i; + dayoff = oadd(dayoff, eitol(i)); + if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { + register long wday; + +#define LDAYS_PER_WEEK ((long) DAYS_PER_WEEK) + wday = eitol(EPOCH_WDAY); + /* + ** Don't trust mod of negative numbers. + */ + if (dayoff >= 0) + wday = (wday + dayoff) % LDAYS_PER_WEEK; + else { + wday -= ((-dayoff) % LDAYS_PER_WEEK); + if (wday < 0) + wday += LDAYS_PER_WEEK; + } + while (wday != eitol(rp->r_wday)) + if (rp->r_dycode == DC_DOWGEQ) { + dayoff = oadd(dayoff, (long) 1); + if (++wday >= LDAYS_PER_WEEK) + wday = 0; + ++i; + } else { + dayoff = oadd(dayoff, (long) -1); + if (--wday < 0) + wday = LDAYS_PER_WEEK; + --i; + } + if (i < 0 || i >= len_months[isleap(y)][m]) { + error("no day in month matches rule"); + exit(1); + } + } + if (dayoff < 0 && !tt_signed) { + if (wantedy == rp->r_loyear) + return min_time; + error("time before zero"); + exit(1); + } + t = (time_t) dayoff * SECS_PER_DAY; + /* + ** Cheap overflow check. + */ + if (t / SECS_PER_DAY != dayoff) { + if (wantedy == rp->r_hiyear) + return max_time; + if (wantedy == rp->r_loyear) + return min_time; + error("time overflow"); + exit(1); + } + return tadd(t, rp->r_tod); +} + +static +newabbr(string) +char * string; +{ + register int i; + + i = strlen(string) + 1; + if (charcnt + i >= TZ_MAX_CHARS) { + error("too many, or too long, time zone abbreviations"); + exit(1); + } + (void) strcpy(&chars[charcnt], string); + charcnt += eitol(i); +} + +static +mkdirs(name) +char * name; +{ + register char * cp; + + if ((cp = name) == NULL || *cp == '\0') + return 0; + while ((cp = index(cp + 1,'/')) != 0) { + *cp = '\0'; + if (access(name,F_OK) && mkdir(name,0755)) { + perror(name); + return -1; + } + *cp = '/'; + } + return 0; +} + +static long +eitol(i) +{ + long l; + + l = i; + if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) { + (void) fprintf(stderr, "%s: %d did not sign extend correctly\n", + progname, i); + exit(1); + } + return l; +} + +/* +** UNIX is a registered trademark of AT&T. +*/