summaryrefslogtreecommitdiff
path: root/usr.sbin/zic
diff options
context:
space:
mode:
authorEdwin Groothuis <edwin@FreeBSD.org>2009-05-23 06:31:50 +0000
committerEdwin Groothuis <edwin@FreeBSD.org>2009-05-23 06:31:50 +0000
commitdfc79e892f85abf6795318009680a31a8813109c (patch)
treedc007639a92f090be57a9884d0c66506ca4ecb14 /usr.sbin/zic
parent9f1994b5e6c53601611a28bbad7e11ac327e8c9c (diff)
downloadsrc-test2-dfc79e892f85abf6795318009680a31a8813109c.tar.gz
src-test2-dfc79e892f85abf6795318009680a31a8813109c.zip
Notes
Diffstat (limited to 'usr.sbin/zic')
-rw-r--r--usr.sbin/zic/Arts.htm178
-rw-r--r--usr.sbin/zic/README13
-rw-r--r--usr.sbin/zic/Theory111
-rw-r--r--usr.sbin/zic/ialloc.c7
-rw-r--r--usr.sbin/zic/private.h139
-rw-r--r--usr.sbin/zic/scheck.c14
-rw-r--r--usr.sbin/zic/tz-art.htm278
-rw-r--r--usr.sbin/zic/tz-link.htm443
-rw-r--r--usr.sbin/zic/zdump.818
-rw-r--r--usr.sbin/zic/zdump.c523
-rw-r--r--usr.sbin/zic/zic.8105
-rw-r--r--usr.sbin/zic/zic.c1105
12 files changed, 1495 insertions, 1439 deletions
diff --git a/usr.sbin/zic/Arts.htm b/usr.sbin/zic/Arts.htm
deleted file mode 100644
index baa84ed77431..000000000000
--- a/usr.sbin/zic/Arts.htm
+++ /dev/null
@@ -1,178 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<!-- $FreeBSD$ -->
-<HTML>
-<HEAD>
-<TITLE>Time and the Arts</TITLE>
-</HEAD>
-<BODY>
-<H1>Time and the Arts</H1>
-<P>
-<H6>
-@(#)Arts.htm 7.18
-</H6>
-</P>
-<PRE>
-Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:
---------------------------------------------------------------------------
-Artist: Karrin Allyson
-CD: I Didn't Know About You
-Copyright Date: 1993
-Label: Concord Jazz, Inc.
-ID: CCD-4543
-Track Time: 3:44
-Personnel: Karrin Allyson, vocal
- Russ Long, piano
- Gerald Spaits, bass
- Todd Strait, drums
-Notes: CD notes "additional lyric by Karrin Allyson;
- arranged by Russ Long and Karrin Allyson"
-ADO Rating: 1 star
-<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||175928">AMG Rating: 3.5 stars</A>
-Penguin Rating: 3.5 stars
---------------------------------------------------------------------------
-Artist: Kevin Mahogany
-CD: Double Rainbow
-Copyright Date: 1993
-Label: Enja Records
-ID: ENJ-7097 2
-Track Time: 6:27
-Personnel: Kevin Mahogany, vocal
- Kenny Barron, piano
- Ray Drummond, bss
- Ralph Moore, tenor saxophone
- Lewis Nash, drums
-ADO Rating: 1.5 stars
-<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||262654">AMG Rating: unrated</A>
-Penguin Rating: 3 stars
---------------------------------------------------------------------------
-Artist: Joe Williams
-CD: Here's to Life
-Copyright Date: 1994
-Label: Telarc International Corporation
-ID: CD-83357
-Track Time: 3:58
-Personnel: Joe Williams, vocal
- The Robert Farnon [39 piece] Orchestra
-Notes: On-line information and samples available at
- <A HREF="http://www.telarc.com/telarc/releases/release.req?ID=83357">http://telarc.dmn.com/telarc/releases/release.req?ID=83357</A>
-ADO Rating: black dot
-<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||194434">AMG Rating: 2 stars</A>
-Penguin Rating: 3 stars
---------------------------------------------------------------------------
-Artist: Charles Fambrough
-CD: Keeper of the Spirit
-Copyright Date: 1995
-Label: AudioQuest Music
-ID: AQ-CD1033
-Track Time: 7:07
-Personnel: Charles Fambrough, bass
- Joel Levine, tenor recorder
- Edward Simon, piano
- Lenny White, drums
- Marion Simon, percussion
-Notes: On-line information and samples available at
- <A HREF="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</A>
-ADO Rating: 2 stars
-<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||224430">AMG Rating: unrated</A>
-Penguin Rating: 3 stars
-==========================================================================
-Also of note:
---------------------------------------------------------------------------
-Artist: Holly Cole Trio
-CD: Blame It On My Youth
-Copyright Date: 1992
-Label: Manhattan
-ID: CDP 7 97349 2
-Total Time: 37:45
-Personnel: Holly Cole, voice
- Aaron Davis, piano
- David Piltch, string bass
-Notes: Lyrical reference to "Eastern Standard Time" in
- Tom Waits' "Purple Avenue"
-ADO Rating: 2.5 stars
-<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||157959">AMG Rating: 2 stars</A>
-Penguin Rating: unrated
---------------------------------------------------------------------------
-Artist: Milt Hinton
-CD: Old Man Time
-Copyright Date: 1990
-Label: Chiaroscuro
-ID: CR(D) 310
-Total Time: 149:38 (two CDs)
-Personnel: Milt Hinton, bass
- Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet
- Al Grey, trombone
- Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
- clarinet and saxophone
- John Bunch, Red Richards, Norman Simmons, Derek Smith,
- Ralph Sutton, piano
- Danny Barker, Al Casey, guitar
- Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
- drums
- Lionel Hampton, vibraphone
- Cab Calloway, Joe Williams, vocal
- Buck Clayton, arrangements
-Notes: tunes include Old Man Time, Time After Time,
- Sometimes I'm Happy,
- A Hot Time in the Old Town Tonight,
- Four or Five Times, Now's the Time,
- Time on My Hands, This Time It's Us,
- and Good Time Charlie
- On-line samples available at
- <A HREF="http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html">http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html</A>
-ADO Rating: 3 stars
-<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||162344">AMG Rating: 4.5 stars</A>
-Penguin Rating: 3 stars
---------------------------------------------------------------------------
-Artist: Paul Broadbent
-CD: Pacific Standard Time
-Copyright Date: 1995
-Label: Concord Jazz, Inc.
-ID: CCD-4664
-Total Time: 62:42
-Personnel: Paul Broadbent, piano
- Putter Smith, Bass
- Frank Gibson, Jr., drums
-Notes: The CD cover features an analemma for equation of time fans
-ADO Rating: 1 star
-<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||223722">AMG Rating: 3 stars</A>
-Penguin Rating: 3.5 stars
---------------------------------------------------------------------------
-Artist: Anthony Braxton/Richard Teitelbaum
-CD: Silence/Time Zones
-Copyright Date: 1996
-Label: Black Lion
-ID: BLCD 760221
-Total Time: 72:58
-Personnel: Anthony Braxton, sopranino and alto saxophones,
- contrebasse clarinet, miscellaneous instruments
- Leo Smith, trumpet and miscellaneous instruments
- Leroy Jenkins, violin and miscellaneous instruments
- Richard Teitelbaum, modular moog and micromoog synthesizer
-ADO Rating: black dot
-<A HREF="http://205.186.189.2/cg/AMG_.exe?sql=A310757">AMG Rating: unrated</A>
---------------------------------------------------------------------------
-Artist: Jules Verne
-Book: Le Tour du Monde en Quatre-Vingts Jours
- (Around the World in Eighty Days)
-Notes: Wall-clock time plays a central role in the plot.
- European readers of the 1870s clearly held the U.S. press in
- deep contempt; the protagonists cross the U.S. without once
- reading a paper.
- An on-line French-language version of the book
- "with illustrations from the original 1873 French-language edition"
- is available at
- <A HREF="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</A>
- An on-line English-language translation of the book is available at
- <A HREF="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</A>
---------------------------------------------------------------------------
-Film: Bell Science - About Time
-Notes: The Frank Baxter/Richard Deacon extravaganza
- Information on ordering is available at
- <A HREF="http://www.videoflicks.com/VF/38/038332.htm">http://www.videoflicks.com/VF/38/038332.htm</A>
---------------------------------------------------------------------------
-The syndicated comic strip "Dilbert" featured an all-too-rare example of
-time zone humor on 1998-03-14.
-</PRE>
-</BODY>
-</HTML>
diff --git a/usr.sbin/zic/README b/usr.sbin/zic/README
index 985a5118468f..12420b9c467c 100644
--- a/usr.sbin/zic/README
+++ b/usr.sbin/zic/README
@@ -1,4 +1,5 @@
-@(#)README 7.11
+@(#)README 8.2
+$FreeBSD$
"What time is it?" -- Richard Deacon as The King
"Any time you want it to be." -- Frank Baxter as The Scientist
@@ -52,8 +53,10 @@ substituting your desired installation directory for "$HOME/tzdir":
To use the new functions, use a "-ltz" option when compiling or linking.
-Historical local time information has been included here not because it
-is particularly useful, but rather to:
+Historical local time information has been included here to:
+
+* provide a compendium of data about the history of civil time
+ that is useful even if the data are not 100% accurate;
* 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
@@ -63,7 +66,9 @@ is particularly useful, but rather to:
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
+the files currently do not even attempt to cover all time stamps before
+1970, and there are undoubtedly errors even for time stamps since 1970.
+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
tz@elsie.nci.nih.gov for use in the future). Europeans take note!
diff --git a/usr.sbin/zic/Theory b/usr.sbin/zic/Theory
index cbf53b9e7d73..ac67416d3622 100644
--- a/usr.sbin/zic/Theory
+++ b/usr.sbin/zic/Theory
@@ -1,5 +1,5 @@
-@(#)Theory 7.15
-
+@(#)Theory 8.2
+$FreeBSD$
----- Outline -----
@@ -12,26 +12,27 @@
----- Time and date functions -----
-These time and date functions are upwards compatible with POSIX.1,
+These time and date functions are upwards compatible with POSIX,
an international standard for UNIX-like systems.
-As of this writing, the current edition of POSIX.1 is:
+As of this writing, the current edition of POSIX is:
- Information technology --Portable Operating System Interface (POSIX (R))
- -- Part 1: System Application Program Interface (API) [C Language]
- ISO/IEC 9945-1:1996
- ANSI/IEEE Std 1003.1, 1996 Edition
- 1996-07-12
+ Standard for Information technology
+ -- Portable Operating System Interface (POSIX (R))
+ -- System Interfaces
+ IEEE Std 1003.1, 2004 Edition
+ <http://www.opengroup.org/online-pubs?DOC=7999959899>
+ <http://www.opengroup.org/pubs/catalog/t041.htm>
-POSIX.1 has the following properties and limitations.
+POSIX has the following properties and limitations.
-* In POSIX.1, time display in a process is controlled by the
- environment variable TZ. Unfortunately, the POSIX.1 TZ string takes
+* In POSIX, time display in a process is controlled by the
+ environment variable TZ. Unfortunately, the POSIX TZ string takes
a form that is hard to describe and is error-prone in practice.
- Also, POSIX.1 TZ strings can't deal with other (for example, Israeli)
+ Also, POSIX TZ strings can't deal with other (for example, Israeli)
daylight saving time rules, or situations where more than two
time zone abbreviations are used in an area.
- The POSIX.1 TZ string takes the following form:
+ The POSIX TZ string takes the following form:
stdoffset[dst[offset],date[/time],date[/time]]
@@ -40,6 +41,9 @@ POSIX.1 has the following properties and limitations.
std and dst
are 3 or more characters specifying the standard
and daylight saving time (DST) zone names.
+ Starting with POSIX.1-2001, std and dst may also be
+ in a quoted form like "<UTC+10>"; this allows
+ "+" and "-" in the names.
offset
is of the form `[-]hh:[mm[:ss]]' and specifies the
offset west of UTC. The default DST offset is one hour
@@ -62,14 +66,25 @@ POSIX.1 has the following properties and limitations.
and `5' stands for the last week in which day d appears
(which may be either the 4th or 5th week).
-* In POSIX.1, when a TZ value like "EST5EDT" is parsed,
- typically the current US DST rules are used,
+ Here is an example POSIX TZ string, for US Pacific time using rules
+ appropriate from 1987 through 2006:
+
+ TZ='PST8PDT,M4.1.0/02:00,M10.5.0/02:00'
+
+ This POSIX TZ string is hard to remember, and mishandles time stamps
+ before 1987 and after 2006. With this package you can use this
+ instead:
+
+ TZ='America/Los_Angeles'
+
+* POSIX does not define the exact meaning of TZ values like "EST5EDT".
+ Typically the current US DST rules are used to interpret such values,
but this means that the US DST rules are compiled into each program
that does time conversion. This means that when US 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 POSIX.1, there's no tamper-proof way for a process to learn the
+* In POSIX, 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
@@ -78,9 +93,9 @@ POSIX.1 has the following properties and limitations.
daylight saving time shifts--as might be required to limit phone
calls to off-peak hours.)
-* POSIX.1 requires that systems ignore leap seconds.
+* POSIX requires that systems ignore leap seconds.
-These are the extensions that have been made to the POSIX.1 functions:
+These are the extensions that have been made to the POSIX functions:
* The "TZ" environment variable is used in generating the name of a file
from which time zone information is read (or is interpreted a la
@@ -108,7 +123,7 @@ These are the extensions that have been made to the POSIX.1 functions:
* 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 POSIX.1, where the elements
+ abbreviation to be used. This differs from POSIX, 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
@@ -131,8 +146,7 @@ These are the extensions that have been made to the POSIX.1 functions:
environment variable; portable applications should not, however, rely
on this behavior since it's not the way SVR2 systems behave.)
-* These functions can account for leap seconds, thanks to Bradley White
- (bww@k.cs.cmu.edu).
+* These functions can account for leap seconds, thanks to Bradley White.
Points of interest to folks with other systems:
@@ -173,9 +187,9 @@ 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
-contain valid extensions to POSIX.1, to ensure its broad
-acceptability. If more powerful time conversion functions can be standardized,
-so much the better.
+contain valid extensions to POSIX, to ensure its broad acceptability. If
+more powerful time conversion functions can be standardized, so much the
+better.
----- Names of time zone rule files -----
@@ -228,6 +242,8 @@ in decreasing order of importance:
Include at least one location per time zone rule set per country.
One such location is enough. Use ISO 3166 (see the file
iso3166.tab) to help decide whether something is a country.
+ However, uninhabited ISO 3166 regions like Bouvet Island
+ do not need locations, since local time is not defined there.
If all the clocks in a country's region have agreed since 1970,
don't bother to include more than one location
even if subregions' clocks disagreed before 1970.
@@ -263,7 +279,8 @@ in decreasing order of importance:
If a name is changed, put its old spelling in the `backward' file.
The file `zone.tab' lists the geographical locations used to name
-time zone rule files.
+time zone rule files. It is intended to be an exhaustive list
+of canonical names for geographic regions.
Older versions of this package used a different naming scheme,
and these older names are still supported.
@@ -277,7 +294,7 @@ and `Factory' (see the file `factory').
----- Time zone abbreviations -----
When this package is installed, it generates time zone abbreviations
-like `EST' to be compatible with human tradition and POSIX.1.
+like `EST' to be compatible with human tradition and POSIX.
Here are the general rules used for choosing time zone abbreviations,
in decreasing order of importance:
@@ -292,17 +309,16 @@ in decreasing order of importance:
preferred "ChST", so the rule has been relaxed.
This rule guarantees that all abbreviations could have
- been specified by a POSIX.1 TZ string. POSIX.1
+ been specified by a POSIX TZ string. POSIX
requires at least three characters for an
- abbreviation. POSIX.1-1996 says that an abbreviation
+ abbreviation. POSIX through 2000 says that an abbreviation
cannot start with ':', and cannot contain ',', '-',
- '+', NUL, or a digit. Draft 7 of POSIX 1003.1-200x
- changes this rule to say that an abbreviation can
- contain only '-', '+', and alphanumeric characters in
- the current locale. To be portable to both sets of
+ '+', NUL, or a digit. POSIX from 2001 on changes this
+ rule to say that an abbreviation can contain only '-', '+',
+ and alphanumeric characters from the portable character set
+ in the current locale. To be portable to both sets of
rules, an abbreviation must therefore use only ASCII
- letters, as these are the only letters that are
- alphabetic in all locales.
+ letters.
Use abbreviations that are in common use among English-speakers,
e.g. `EST' for Eastern Standard Time in North America.
@@ -328,8 +344,9 @@ in decreasing order of importance:
and then append `T', `ST', etc. as before;
e.g. `VLAST' for VLAdivostok Summer Time.
- Use "zzz" for locations while uninhabited. The mnemonic is that
- these locations are, in some sense, asleep.
+ Use UTC (with time zone abbreviation "zzz") for locations while
+ uninhabited. The "zzz" mnemonic is that these locations are,
+ in some sense, asleep.
Application writers should note that these abbreviations are ambiguous
in practice: e.g. `EST' has a different meaning in Australia than
@@ -343,10 +360,10 @@ abbreviations like `EST'; this avoids the ambiguity.
Calendrical issues are a bit out of scope for a time zone database,
but they indicate the sort of problems that we would run into if we
extended the time zone database further into the past. An excellent
-resource in this area is Nachum Dershowitz and Edward M. Reingold,
-<a href="http://emr.cs.uiuc.edu/home/reingold/calendar-book/index.shtml">
-Calendrical Calculations
-</a>, Cambridge University Press (1997). Other information and
+resource in this area is Edward M. Reingold and Nachum Dershowitz,
+<a href="http://emr.cs.uiuc.edu/home/reingold/calendar-book/second-edition/">
+Calendrical Calculations: The Millennium Edition
+</a>, Cambridge University Press (2001). Other information and
sources are given below. They sometimes disagree.
@@ -359,7 +376,7 @@ and (in Paris only) 1871-05-06 through 1871-05-23.
Russia
-From Chris Carrier <72157.3334@CompuServe.COM> (1996-12-02):
+From Chris Carrier (1996-12-02):
On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar''
with 30-day months plus 5 holidays, with a 5-day week.
On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
@@ -374,7 +391,7 @@ by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But:
From: Petteri Sulonen (via Usenet)
Date: 14 Jan 1999 00:00:00 GMT
-Message-ID: <Petteri.Sulonen-1401991626030001@lapin-kulta.in.helsinki.fi>
+...
If your source is correct, how come documents between 1929 -- 1940 were
still dated using the conventional, Gregorian calendar?
@@ -387,7 +404,7 @@ Executive Committee of the Supreme Soviet, if you like.
Sweden (and Finland)
-From: msb@sq.com (Mark Brader)
+From: Mark Brader
<a href="news:1996Jul6.012937.29190@sq.com">
Subject: Re: Gregorian reform -- a part of locale?
</a>
@@ -415,11 +432,11 @@ kalendervasen" by Lars-Olof Lode'n (no date was given).)
Grotefend's data
-From: "Michael Palmer" <mpalmer@netcom.com> [with one obvious typo fixed]
+From: "Michael Palmer" [with one obvious typo fixed]
Subject: Re: Gregorian Calendar (was Re: Another FHC related question
Newsgroups: soc.genealogy.german
Date: Tue, 9 Feb 1999 02:32:48 -800
-Message-ID: <199902091032.CAA09644@netcom10.netcom.com>
+...
The following is a(n incomplete) listing, arranged chronologically, of
European states, with the date they converted from the Julian to the
@@ -546,7 +563,7 @@ Sources:
Michael Allison and Robert Schmunk,
"Technical Notes on Mars Solar Time as Adopted by the Mars24 Sunclock"
-<http://www.giss.nasa.gov/tools/mars24/help/notes.html> (2004-03-15).
+<http://www.giss.nasa.gov/tools/mars24/help/notes.html> (2004-07-30).
Jia-Rui Chong, "Workdays Fit for a Martian", Los Angeles Times
(2004-01-14), pp A1, A20-A21.
diff --git a/usr.sbin/zic/ialloc.c b/usr.sbin/zic/ialloc.c
index a069032eda51..1694c2905c74 100644
--- a/usr.sbin/zic/ialloc.c
+++ b/usr.sbin/zic/ialloc.c
@@ -1,6 +1,11 @@
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
#ifndef lint
#ifndef NOID
-static const char elsieid[] = "@(#)ialloc.c 8.29";
+static const char elsieid[] = "@(#)ialloc.c 8.30";
#endif /* !defined NOID */
#endif /* !defined lint */
diff --git a/usr.sbin/zic/private.h b/usr.sbin/zic/private.h
index 315f33a4a2f1..ecbf6124859a 100644
--- a/usr.sbin/zic/private.h
+++ b/usr.sbin/zic/private.h
@@ -4,7 +4,7 @@
/*
** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson.
*/
/*
@@ -30,10 +30,12 @@
#ifndef lint
#ifndef NOID
-static const char privatehid[] = "@(#)private.h 7.53";
+static const char privatehid[] = "@(#)private.h 8.6";
#endif /* !defined NOID */
#endif /* !defined lint */
+#define GRANDPARENTED "Local time zone must be set--see zic manual page"
+
/*
** Defaults for preprocessor symbols.
** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
@@ -43,10 +45,6 @@ static const char privatehid[] = "@(#)private.h 7.53";
#define HAVE_GETTEXT 0
#endif /* !defined HAVE_GETTEXT */
-#ifndef HAVE_STRERROR
-#define HAVE_STRERROR 1
-#endif /* !defined HAVE_STRERROR */
-
#ifndef HAVE_SYMLINK
#define HAVE_SYMLINK 1
#endif /* !defined HAVE_SYMLINK */
@@ -71,47 +69,94 @@ static const char privatehid[] = "@(#)private.h 7.53";
#include "stdio.h"
#include "errno.h"
#include "string.h"
-#include "limits.h" /* for CHAR_BIT */
+#include "limits.h" /* for CHAR_BIT et al. */
#include "time.h"
#include "stdlib.h"
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#include "libintl.h"
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
-#if HAVE_SYS_WAIT_H - 0
+#if HAVE_SYS_WAIT_H
#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
-#endif /* HAVE_SYS_WAIT_H - 0 */
+#endif /* HAVE_SYS_WAIT_H */
-#if HAVE_UNISTD_H - 0
-#include "unistd.h" /* for F_OK and R_OK */
-#endif /* HAVE_UNISTD_H - 0 */
+#if HAVE_UNISTD_H
+#include "unistd.h" /* for F_OK and R_OK, and other POSIX goodness */
+#endif /* HAVE_UNISTD_H */
-#if !(HAVE_UNISTD_H - 0)
#ifndef F_OK
#define F_OK 0
#endif /* !defined F_OK */
#ifndef R_OK
#define R_OK 4
#endif /* !defined R_OK */
-#endif /* !(HAVE_UNISTD_H - 0) */
-/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
-#define P(x) x
+/*
+** Define HAVE_STDINT_H's default value here, rather than at the
+** start, since __GLIBC__'s value depends on previously-included
+** files.
+** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
+*/
+#ifndef HAVE_STDINT_H
+#define HAVE_STDINT_H \
+ (199901 <= __STDC_VERSION__ || \
+ 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
+#endif /* !defined HAVE_STDINT_H */
+
+#if HAVE_STDINT_H
+#include "stdint.h"
+#endif /* !HAVE_STDINT_H */
+
+#ifndef INT_FAST64_MAX
+/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
+#if defined LLONG_MAX || defined __LONG_LONG_MAX__
+typedef long long int_fast64_t;
+#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#if (LONG_MAX >> 31) < 0xffffffff
+Please use a compiler that supports a 64-bit integer type (or wider);
+you may need to compile with "-DHAVE_STDINT_H".
+#endif /* (LONG_MAX >> 31) < 0xffffffff */
+typedef long int_fast64_t;
+#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#endif /* !defined INT_FAST64_MAX */
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif /* !defined INT32_MAX */
+#ifndef INT32_MIN
+#define INT32_MIN (-1 - INT32_MAX)
+#endif /* !defined INT32_MIN */
+
+/*
+** Workarounds for compilers/systems.
+ */
+
+/*
+** Some time.h implementations don't declare asctime_r.
+** Others might define it as a macro.
+** Fix the former without affecting the latter.
+ */
+#ifndef asctime_r
+extern char * asctime_r(struct tm const *, char *);
+#endif
+
+
/*
** Private function declarations.
*/
-char * icalloc P((int nelem, int elsize));
-char * icatalloc P((char * old, const char * new));
-char * icpyalloc P((const char * string));
-char * imalloc P((int n));
-void * irealloc P((void * pointer, int size));
-void icfree P((char * pointer));
-void ifree P((char * pointer));
-char * scheck P((const char *string, const char *format));
+char * icalloc (int nelem, int elsize);
+char * icatalloc (char * old, const char * new);
+char * icpyalloc (const char * string);
+char * imalloc (int n);
+void * irealloc (void * pointer, int size);
+void icfree (char * pointer);
+void ifree (char * pointer);
+const char * scheck (const char *string, const char *format);
/*
** Finally, some convenience items.
@@ -133,6 +178,15 @@ char * scheck P((const char *string, const char *format));
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
+/*
+** Since the definition of TYPE_INTEGRAL contains floating point numbers,
+** it cannot be used in preprocessor directives.
+*/
+
+#ifndef TYPE_INTEGRAL
+#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
+#endif /* !defined TYPE_INTEGRAL */
+
#ifndef INT_STRLEN_MAXIMUM
/*
** 302 / 1000 is log10(2.0) rounded up.
@@ -141,7 +195,8 @@ char * scheck P((const char *string, const char *format));
** add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
- ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/*
@@ -175,11 +230,11 @@ char * scheck P((const char *string, const char *format));
*/
#ifndef _
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#define _(msgid) gettext(msgid)
-#else /* !(HAVE_GETTEXT - 0) */
+#else /* !HAVE_GETTEXT */
#define _(msgid) msgid
-#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !HAVE_GETTEXT */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
@@ -190,4 +245,28 @@ char * scheck P((const char *string, const char *format));
** UNIX was a registered trademark of The Open Group in 2003.
*/
+#ifndef YEARSPERREPEAT
+#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+#endif /* !defined YEARSPERREPEAT */
+
+/*
+** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+*/
+
+#ifndef AVGSECSPERYEAR
+#define AVGSECSPERYEAR 31556952L
+#endif /* !defined AVGSECSPERYEAR */
+
+#ifndef SECSPERREPEAT
+#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+#endif /* !defined SECSPERREPEAT */
+
+#ifndef SECSPERREPEAT_BITS
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+#endif /* !defined SECSPERREPEAT_BITS */
+
+ /*
+ ** UNIX was a registered trademark of The Open Group in 2003.
+ */
+
#endif /* !defined PRIVATE_H */
diff --git a/usr.sbin/zic/scheck.c b/usr.sbin/zic/scheck.c
index 692bf1a07934..abdb4ba5c79b 100644
--- a/usr.sbin/zic/scheck.c
+++ b/usr.sbin/zic/scheck.c
@@ -1,6 +1,11 @@
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
#ifndef lint
#ifndef NOID
-static const char elsieid[] = "@(#)scheck.c 8.15";
+static const char elsieid[] = "@(#)scheck.c 8.19";
#endif /* !defined lint */
#endif /* !defined NOID */
@@ -13,7 +18,7 @@ static const char rcsid[] =
#include "private.h"
-char *
+const char *
scheck(string, format)
const char * const string;
const char * const format;
@@ -22,11 +27,10 @@ const char * const format;
register const char * fp;
register char * tp;
register int c;
- register char * result;
+ register const char * result;
char dummy;
- static char nada;
- result = &nada;
+ result = "";
if (string == NULL || format == NULL)
return result;
fbuf = imalloc((int) (2 * strlen(format) + 4));
diff --git a/usr.sbin/zic/tz-art.htm b/usr.sbin/zic/tz-art.htm
deleted file mode 100644
index 56f78ace2e0d..000000000000
--- a/usr.sbin/zic/tz-art.htm
+++ /dev/null
@@ -1,278 +0,0 @@
-<?xml version="1.0" encoding="US-ASCII"?>
-<!DOCTYPE html
-PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
-<title>Time and the Arts</title>
-</head>
-<body>
-<h1>Time and the Arts</h1>
-<address>
-@(#)tz-art.htm 7.53
-</address>
-<p>
-Please send corrections to this web page to the
-<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.</p>
-<p>
-See also <a href="tz-link.htm">Sources for Time Zone and Daylight Saving Time Data</a>.</p>
-<hr />
-<p>
-Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:</p>
-<table>
-<tr><td>Artist</td><td>Karrin Allyson</td></tr>
-<tr><td>CD</td><td>I Didn't Know About You</td></tr>
-<tr><td>Copyright Date</td><td>1993</td></tr>
-<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
-<tr><td>ID</td><td>CCD-4543</td></tr>
-<tr><td>Track Time</td><td>3:44</td></tr>
-<tr><td>Personnel</td><td>Karrin Allyson, vocal;
-Russ Long, piano;
-Gerald Spaits, bass;
-Todd Strait, drums</td></tr>
-<tr><td>Notes</td><td>CD notes "additional lyric by Karrin Allyson;
-arranged by Russ Long and Karrin Allyson"</td></tr>
-<tr><td>ADO Rating</td><td>1 star</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A1fdovw9ta92k">AMG Rating</a></td><td>4 stars</td></tr>
-<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Kevin Mahogany</td></tr>
-<tr><td>CD</td><td>Double Rainbow</td></tr>
-<tr><td>Copyright Date</td><td>1993</td></tr>
-<tr><td>Label</td><td>Enja Records</td></tr>
-<tr><td>ID</td><td>ENJ-7097 2</td></tr>
-<tr><td>Track Time</td><td>6:27</td></tr>
-<tr><td>Personnel</td><td>Kevin Mahogany, vocal;
-Kenny Barron, piano;
-Ray Drummond, bass;
-Ralph Moore, tenor saxophone;
-Lewis Nash, drums</td></tr>
-<tr><td>ADO Rating</td><td>1.5 stars</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Akikbikzjbb19">AMG Rating</a></td><td>3 stars</td></tr>
-<tr><td>Penguin Rating</td><td>3 stars</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Joe Williams</td></tr>
-<tr><td>CD</td><td>Here's to Life</td></tr>
-<tr><td>Copyright Date</td><td>1994</td></tr>
-<tr><td>Label</td><td>Telarc International Corporation</td></tr>
-<tr><td>ID</td><td>CD-83357</td></tr>
-<tr><td>Track Time</td><td>3:58</td></tr>
-<tr><td>Personnel</td><td>Joe Williams, vocal
-The Robert Farnon [39 piece] Orchestra</td></tr>
-<tr><td>Notes</td><td>This CD is also available as part of a 3-CD package from
-Telarc, "Triple Play" (CD-83461)</td></tr>
-<tr><td>ADO Rating</td><td>black dot</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Amyyvad6kt8w1">AMG Rating</a></td><td>2 stars</td></tr>
-<tr><td>Penguin Rating</td><td>3 stars</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Charles Fambrough</td></tr>
-<tr><td>CD</td><td>Keeper of the Spirit</td></tr>
-<tr><td>Copyright Date</td><td>1995</td></tr>
-<tr><td>Label</td><td>AudioQuest Music</td></tr>
-<tr><td>ID</td><td>AQ-CD1033</td></tr>
-<tr><td>Track Time</td><td>7:07</td></tr>
-<tr><td>Personnel</td><td>Charles Fambrough, bass;
-Joel Levine, tenor recorder;
-Edward Simon, piano;
-Lenny White, drums;
-Marion Simon, percussion</td></tr>
-<tr><td>Notes</td><td>On-line information and samples available at
-<a href="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</a></td></tr>
-<tr><td>ADO Rating</td><td>2 stars</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A5rkcikcjbb89">AMG Rating</a></td><td>unrated</td></tr>
-<tr><td>Penguin Rating</td><td>3 stars</td></tr>
-</table>
-<hr />
-<p>Also of note:</p>
-<table>
-<tr><td>Artist</td><td>Holly Cole Trio</td></tr>
-<tr><td>CD</td><td>Blame It On My Youth</td></tr>
-<tr><td>Copyright Date</td><td>1992</td></tr>
-<tr><td>Label</td><td>Manhattan</td></tr>
-<tr><td>ID</td><td>CDP 7 97349 2</td></tr>
-<tr><td>Total Time</td><td>37:45</td></tr>
-<tr><td>Personnel</td><td>Holly Cole, voice;
-Aaron Davis, piano;
-David Piltch, string bass</td></tr>
-<tr><td>Notes</td><td>Lyrical reference to "Eastern Standard Time" in
-Tom Waits' "Purple Avenue"</td></tr>
-<tr><td>ADO Rating</td><td>2.5 stars</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A3a9ds37ya3dg">AMG Rating</a></td><td>3 stars</td></tr>
-<tr><td>Penguin Rating</td><td>unrated</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Milt Hinton</td></tr>
-<tr><td>CD</td><td>Old Man Time</td></tr>
-<tr><td>Copyright Date</td><td>1990</td></tr>
-<tr><td>Label</td><td>Chiaroscuro</td></tr>
-<tr><td>ID</td><td>CR(D) 310</td></tr>
-<tr><td>Total Time</td><td>149:38 (two CDs)</td></tr>
-<tr><td>Personnel</td><td>Milt Hinton, bass;
-Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet;
-Al Grey, trombone;
-Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
-clarinet and saxophone;
-John Bunch, Red Richards, Norman Simmons, Derek Smith,
-Ralph Sutton, piano;
-Danny Barker, Al Casey, guitar;
-Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
-drums;
-Lionel Hampton, vibraphone;
-Cab Calloway, Joe Williams, vocal;
-Buck Clayton, arrangements</td></tr>
-<tr><td>Notes</td><td>tunes include Old Man Time, Time After Time,
-Sometimes I'm Happy,
-A Hot Time in the Old Town Tonight,
-Four or Five Times, Now's the Time,
-Time on My Hands, This Time It's Us,
-and Good Time Charlie
-On-line samples available at
-<a href="http://www.chiaroscurojazz.com/albuminfo.php4?albumid=49">http://www.chiaroscurojazz.com/albuminfo.php3?albumid=49</a></td></tr>
-<tr><td>ADO Rating</td><td>3 stars</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A1cbyxdab8ola">AMG Rating</a></td><td>4.5 stars</td></tr>
-<tr><td>Penguin Rating</td><td>3 stars</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Alan Broadbent</td></tr>
-<tr><td>CD</td><td>Pacific Standard Time</td></tr>
-<tr><td>Copyright Date</td><td>1995</td></tr>
-<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
-<tr><td>ID</td><td>CCD-4664</td></tr>
-<tr><td>Total Time</td><td>62:42</td></tr>
-<tr><td>Personnel</td><td>Alan Broadbent, piano;
-Putter Smith, Bass;
-Frank Gibson, Jr., drums</td></tr>
-<tr><td>Notes</td><td>The CD cover features an analemma for equation-of-time fans</td></tr>
-<tr><td>ADO Rating</td><td>1 star</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Asl8zefuk8gfo">AMG Rating</a></td><td>4 stars</td></tr>
-<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Anthony Braxton/Richard Teitelbaum</td></tr>
-<tr><td>CD</td><td>Silence/Time Zones</td></tr>
-<tr><td>Copyright Date</td><td>1996</td></tr>
-<tr><td>Label</td><td>Black Lion</td></tr>
-<tr><td>ID</td><td>BLCD 760221</td></tr>
-<tr><td>Total Time</td><td>72:58</td></tr>
-<tr><td>Personnel</td><td>Anthony Braxton, sopranino and alto saxophones,
-contrebasse clarinet, miscellaneous instruments;
-Leo Smith, trumpet and miscellaneous instruments;
-Leroy Jenkins, violin and miscellaneous instruments;
-Richard Teitelbaum, modular moog and micromoog synthesizer</td></tr>
-<tr><td>ADO Rating</td><td>black dot</td></tr>
-<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A5bkvu3xjan1k">AMG Rating</a></td><td>unrated</td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Artist</td><td>Jules Verne</td></tr>
-<tr><td>Book</td><td>Le Tour du Monde en Quatre-Vingts Jours
-(Around the World in Eighty Days)</td></tr>
-<tr><td>Notes</td><td>Wall-clock time plays a central role in the plot.
-European readers of the 1870s clearly held the U.S. press in
-deep contempt; the protagonists cross the U.S. without once
-reading a paper.
-An on-line French-language version of the book
-"with illustrations from the original 1873 French-language edition"
-is available at
-<a href="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</a>
-An on-line English-language translation of the book is available at
-<a href="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</a></td></tr>
-<tr><td>&nbsp;</td></tr>
-<tr><td>Film</td><td>Bell Science - About Time</td></tr>
-<tr><td>Notes</td><td>The Frank Baxter/Richard Deacon extravaganza
-Information on ordering is available at
-<a href="http://www.videoflicks.com/VF2/1035/1035893.ihtml">http://www.videoflicks.com/VF2/1035/1035893.ihtml</a></td></tr>
-</table>
-<hr />
-<ul>
-<li>
-An episode of "The Adventures of Superman" entitled "The Mysterious
-Cube," first aired 1958-02-24, had Superman convincing the controllers
-of WWV to broadcast time signals five minutes ahead of actual time;
-doing so got a crook trying to beat the statute of limitations to
-emerge a bit too early from the titular enclosure.
-</li>
-<li>
-The 1960s ITC television series "The Prisoner" included an episode
-entitled "The Chimes of Big Ben" in which our protagonist tumbled to
-the fraudulent nature of a Poland-to-England escape upon hearing "Big
-Ben" chiming on Polish local time.
-</li>
-<li>
-The series "Seinfeld" included an episode entitled "The Susie," first
-broadcast 1997-02-13, in which Kramer decides that daylight saving time
-isn't coming fast enough, so he sets his watch ahead an hour.
-</li>
-<li>
-The syndicated comic strip "Dilbert" featured an all-too-rare example of
-time zone humor on 1998-03-14.
-</li>
-<li>
-Surrealist artist Guy Billout's work "Date Line" appeared on page 103
-of the 1999-11 Atlantic Monthly.
-</li>
-<li>
-"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of Time
-Magazine's 2002-11-11 issue; among other things, it proposed
-year-round DST as a way of lessening wintertime despair.
-</li>
-<li>
-The "20 Hours in America" episode of "The West Wing," first aired 2002-09-25,
-saw White House staffers stranded in Indiana; they thought they had time to
-catch Air Force One but were done in by intra-Indiana local time changes.
-</li>
-<li>
-"In what time zone would you find New York City?" was a $200 question on
-the 1999-11-13 United States airing of "Who Wants to Be a Millionaire?"
-"In 1883, what industry led the movement to divide the U.S. into four time
-zones?" was a $32,000 question on the 2001-05-23 United States airing of
-"Who Wants to Be a Millionaire?" At this rate, the million-dollar time-zone
-question should have been asked 2002-06-04.
-</li>
-</ul>
-<hr />
-<ul>
-<li>
-"We're been using the five-cent nickle in this country since 1492.
-Now that's pretty near 100 years, daylight savings [sic]."
-(Groucho Marx as Captain Spaulding in "Animal Crackers", 1930,
-as noted by Will Fitzerald, wfitzgerald@ameritech.net)
-</li>
-<li>
-"Good news."
-"What did they do? Extend Daylight Saving Time year round?"
-(Professional tanner George Hamilton, in dialog from a
-May, 1999 episode of the syndicated television series "Baywatch")
-</li>
-<li>
-"A fundamental belief held by Americans is that if you are on land, you
-cannot be killed by a fish...So most Americans remain on land, believing
-they're safe. Unfortunately, this belief&mdash;like so many myths, such as that
-there's a reason for 'Daylight Saving Time'&mdash;is false."
-(Dave Barry column, 2000-07-02)
-</li>
-<li>
-"I once had sex for an hour and five minutes, but that was on the day
-when you turn the clocks ahead."
-(Garry Shandling, 52nd Annual Emmys, 2000-09-10)
-</li>
-<li>
-"Would it impress you if I told you I invented Daylight Savings Time?"
-("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of "Angel,"
-originally aired 2002-02-25)
-</li>
-<li>
-"I thought you said Tulsa was a three hour flight."
-"Well, you're forgetting about the time difference."
-("Chandler" and "Joey" in dialog from the episode of "Friends" first
-aired 2002-12-05)
-</li>
-<li>
-"Is that a pertinent fact,
-or are you trying to dazzle me with your command of time zones?"
-(Kelsey Grammer as "Frasier Crane")
-</li>
-<li>
-"Don't worry about the world coming to an end today.
-It is already tomorrow in Australia."
-(Charles M. Schulz, provided by Steve Summit)
-</li>
-</ul>
-</body>
-</html>
diff --git a/usr.sbin/zic/tz-link.htm b/usr.sbin/zic/tz-link.htm
deleted file mode 100644
index 0e6307300709..000000000000
--- a/usr.sbin/zic/tz-link.htm
+++ /dev/null
@@ -1,443 +0,0 @@
-<?xml version="1.0" encoding="US-ASCII"?>
-<!DOCTYPE html
- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<title>Sources for Time Zone and Daylight Saving Time Data</title>
-<link rel="schema.DC" href="http://purl.org/DC/elements/1.1/" />
-<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
-<meta name="DC.Creator" content="Eggert, Paul" />
-<meta name="DC.Contributor" content="Olson, Arthur David" />
-<meta name="DC.Date" content="2004-05-24" />
-<meta name="DC.Description"
- content="Sources of information about time zones and daylight saving time" />
-<meta name="DC.Identifier" content="http://www.twinsun.com/tz/tz-link.htm" />
-<meta name="Keywords"
- content="database,daylight saving,DST,time zone,timezone,tz,zoneinfo" />
-</head>
-<body>
-<h1>Sources for Time Zone and Daylight Saving Time Data</h1>
-<address>
-@(#)tz-link.htm 7.42
-</address>
-<p>
-Please send corrections to this web page to the
-<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.
-</p>
-<h2>The <code>tz</code> database</h2>
-<p>
-The public-domain time zone database contains code and data
-that represent the history of local time
-for many representative locations around the globe.
-It is updated periodically to reflect changes made by political bodies
-to UTC offsets and daylight-saving rules.
-This database (often called <code>tz</code> or <code>zoneinfo</code>)
-is used by several implementations,
-including
-<a href="http://www.gnu.org/software/libc/">the GNU C Library</a> used in
-<a href="http://www.linux.org/">GNU/Linux</a>,
-<a href="http://www.freebsd.org/">FreeBSD</a>,
-<a href="http://www.netbsd.org/">NetBSD</a>,
-<a href="http://www.openbsd.org/">OpenBSD</a>,
-<a href="http://www.cygwin.com/">Cygwin</a>,
-<a href="http://www.delorie.com/djgpp/">DJGPP</a>,
-<a href="http://www.hp.com/products1/unix/operating/">HP-UX</a>,
-<a href="http://www.sgi.com/developers/technology/irix/">IRIX</a>,
-<a href="http://www.apple.com/macosx/">Mac OS X</a>,
-<a href="http://h71000.www7.hp.com/">OpenVMS</a>,
-<a href="http://wwws.sun.com/software/solaris/">Solaris</a>,
-<a href="http://www.tru64unix.compaq.com/">Tru64</a>, and
-<a href="http://www.sco.com/products/unixware/">UnixWare</a>.</p>
-<p>
-Each location in the database represents a national region where all
-clocks keeping local time have agreed since 1970.
-Locations are identified by continent or ocean and then by the name of
-the location, which is typically the largest city within the region.
-For example, <code>America/New_York</code>
-represents most of the US eastern time zone;
-<code>America/Indianapolis</code> represents most of Indiana, which
-uses eastern time without daylight saving time (DST);
-<code>America/Detroit</code> represents most of Michigan, which uses
-eastern time but with different DST rules in 1975;
-and other entries represent smaller regions like Starke County,
-Kentucky, which switched from central to eastern time in 1991.
-To use the database, set the <code>TZ</code> environment variable to
-the location's full name, e.g., <code>TZ="America/New_York"</code>.</p>
-<p>
-In the <code>tz</code> database's
-<a href="ftp://elsie.nci.nih.gov/pub/">FTP distribution</a>,
-the code is in the file <code>tzcode<var>C</var>.tar.gz</code>,
-where <code><var>C</var></code> is the code's version;
-similarly, the data are in <code>tzdata<var>D</var>.tar.gz</code>,
-where <code><var>D</var></code> is the data's version.
-The following shell commands download
-these files to a GNU/Linux or similar host; see the downloaded
-<code>README</code> file for what to do next.</p>
-<pre style="margin-left: 2em"><code><a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
-<a href="http://www.gnu.org/software/gzip/">gzip</a> -dc tzcode*.tar.gz | <a href="http://www.gnu.org/software/tar/">tar</a> -xf -
-gzip -dc tzdata*.tar.gz | tar -xf -
-</code></pre>
-<p>
-The code lets you compile the <code>tz</code> source files into
-machine-readable binary files, one for each location. It also lets
-you read a <code>tz</code> binary file and interpret time stamps for that
-location.</p>
-<p>
-The data are by no means authoritative. If you find errors, please
-send changes to the <a href="mailto:tz@elsie.nci.nih.gov">time zone
-mailing list</a>. You can also <a
-href="mailto:tz-request@elsie.nci.nih.gov">subscribe</a> to the
-mailing list, retrieve the <a
-href="ftp://elsie.nci.nih.gov/pub/tzarchive.gz">archive of old
-messages</a> (in gzip compressed format), or retrieve <a
-href="ftp://munnari.oz.au/pub/oldtz/">archived older versions of code
-and data</a>.</p>
-<p>
-The Web has several other sources for time zone and daylight saving time data.
-Here are some recent links that may be of interest.
-</p>
-<h2>Web pages using recent versions of the <code>tz</code> database</h2>
-<ul>
-<li><a href="http://twiki.org/cgi-bin/xtra/tzdate">Date and Time Gateway</a>
-is a text-based point-and-click interface to tables of current time
-throughout the world.</li>
-<li>Fancier web interfaces, roughly in ascending order of complexity, include:
-<ul>
-<li><a href="http://www.hilink.com.au/times/">Local Times Around the
-World</a></li>
-<li><a href="http://www.convertit.com/Go/ConvertIt/World_Time/Current_Time.ASP">Current Time in 1000 Places</a></li>
-<li><a href="http://timezoneconverter.com/">Time Zone Converter</a></li>
-</ul></li>
-<li><a href="http://www.holidayfestival.com/">The Worldwide Holiday
-&amp; Festival Site</a> lists DST-related clock changes along with
-holidays.</li>
-<li><a href="http://www.timeanddate.com/worldclock/">The World Clock -
-Time Zones</a>
-is a web interface to a time zone database derived from
-<code>tz</code>'s.</li>
-</ul>
-<h2>Other time zone database formats</h2>
-<ul>
-<li>The <a href="ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt">
-Internet Calendaring and Scheduling Core Object Specification
-(iCalendar)</a> specification published by the <a
-href="http://www.ietf.org/html.charters/calsch-charter.html">IETF
-Calendaring and Scheduling Working Group (calsch)</a> covers time zone
-data; see its VTIMEZONE calendar component.</li>
-<li>The <a
-href="http://lists.w3.org/Archives/Public/www-rdf-calendar/">www-rdf-calendar</a>
-list discusses <a href="http://www.w3.org/RDF/">RDF</a>-based calendar
-and group scheduling systems, and has a <a
-href="http://www.w3.org/2002/12/cal/#tzd">workspace on time zone
-data</a> converted from <code>tz</code>. An earlier <a
-href="http://www.w3.org/2000/01/foo">schema</a> was sketched out by <a
-href="http://www.w3.org/People/Berners-Lee/">Tim Berners-Lee</a>.</li>
-<li><a
-href="http://www.calsch.org/ietf/archives/draft-ietf-calsch-many-xcal-02.txt">XCal</a>
-was a draft <a href="http://www.w3.org/XML/">XML</a> document type
-definition that corresponded to iCalendar.</li>
-</ul>
-<h2>Other <code>tz</code> compilers</h2>
-<ul>
-<li><a href="http://www.dachaplin.dsl.pipex.com/vzic">Vzic iCalendar
-Timezone Converter</a> describes a program Vzic that compiles
-<code>tz</code> source into iCalendar-compatible VTIMEZONE files.
-Vzic is freely
-available under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU
-General Public License (GPL)</a>.</li>
-<li><a
-href="http://search.cpan.org/dist/DateTime-TimeZone/">DateTime::TimeZone</a>
-contains a script <code>parse_olson</code> that compiles
-<code>tz</code> source into <a href="http://www.perl.org/">Perl</a>
-modules. It is part of the Perl <a
-href="http://datetime.perl.org/">DateTime Project</a>, which is freely
-available under both the GPL and the Perl <a
-href="http://www.perl.com/language/misc/Artistic.html">Artistic
-License</a>. DateTime::TimeZone also contains a script
-<code>tests_from_zdump</code> that generates test cases for each clock
-transition in the <code>tz</code> database.</li>
-<li><a href="http://oss.software.ibm.com/icu/">International Components for
-Unicode (ICU)</a> contains a C/C++ library for internationalization that
-has a compiler from <samp>tz</samp> source into an ICU-specific format.
-ICU is freely available under a BSD-style license.</li>
-<li><a href="http://joda-time.sourceforge.net/">Joda Time - Java date
-and time API</a> contains a class
-<code>org.joda.time.tz.ZoneInfoCompiler</code> that compiles
-<code>tz</code> source into a Joda-specific binary format. Joda Time
-is freely available under a BSD-style license.</li>
-</ul>
-<h2>Other <code>tz</code> binary file readers</h2>
-<ul>
-<li>The <a href="http://www.gnu.org/software/libc/">GNU C Library</a>
-has an independent, thread-safe implementation of
-a <code>tz</code> binary file reader.
-This library is freely available under the
-<a href="http://www.gnu.org/copyleft/lesser.html">
-GNU Lesser General Public License (LGPL)</a>,
-and is widely used in GNU/Linux systems.</li>
-<li><a href="http://www.bmsi.com/java/#TZ">ZoneInfo.java</a>
-is a <code>tz</code> binary file reader written in Java.
-It is freely available under the GNU LGPL.</li>
-<li><a href="http://s.keim.free.fr/tz/doc.html">Python time zones</a>
-is a <code>tz</code> binary file reader written in <a
-href="http://www.python.org/">Python</a>. It is freely available
-under a BSD-style license.</li>
-</ul>
-<h2>Other <code>tz</code>-based time zone conversion software</h2>
-<ul>
-<li><a href="http://java.sun.com/">Sun Java</a> releases since 1.4
-contain a copy of a recent <samp>tz</samp> database in a Java-specific
-format.</li>
-<li><a
-href="http://www1.tip.nl/~t876506/AboutTimeZonesHC.html">HyperCard
-time zones calculator</a> is a HyperCard stack.</li>
-<li><a
-href="http://www.cimmyt.org/timezone/">World Time Explorer</a> is a
-Microsoft Windows program.</li>
-</ul>
-<h2>Other time zone databases</h2>
-<ul>
-<li><a href="http://www.astro.com/cgi-bin/atlw3/aq.cgi?lang=e">Atlas Query
-- Astrodienst</a> is Astrodienst's Web version of Shanks's
-excellent time zone history atlases published in both <a
-href="http://astrocom.com/software/pcatlas.php">computer</a> and <a
-href="http://astrocom.com/books/xrefa.php#SHANKS">book</a> form by <a
-href="http://astrocom.com/">Astro Communications Services</a>.</li>
-<li><a href="http://worldtime.com/">WORLDTIME: interactive atlas,
-time info, public holidays</a>
-contains information on local time, sunrise and sunset,
-and public holidays in several hundred cities around the world.</li>
-<li><a href="http://www.worldtimeserver.com/">World Time Server</a>
-is another time zone database.</li>
-<li><a href="http://tycho.usno.navy.mil/tzones.html">World Time Zones</a>
-contains data from the Time Service Department of the US Naval Observatory
-(USNO), used as the source
-for the <code>usno*</code> files in the <code>tz</code> distribution.</li>
-<li><a href="http://www.airportcitycodes.com/aaa/">Airlines, Airplanes
-and Airports</a> lists current standard times for thousands of
-airports around the world. This seems to be derived from
-the <a href="http://www.iata.org/sked/publications/">Standard
-Schedules Information Manual (SSIM)</a> of the
-the <a href="http://www.iata.org/">International Air Transport
-Association</a>,
-which gives current time zone rules for
-all the airports served by commercial aviation.</li>
-</ul>
-<h2>Maps</h2>
-<ul>
-<li>The <a href="http://www.odci.gov/">United States Central
-Intelligence Agency (CIA)</a> publishes a <a
-href="http://www.odci.gov/cia/publications/factbook/reference_maps/pdf/time_zones.pdf">time
-zone map</a>; the
-<a
-href="http://www.lib.utexas.edu/maps/world.html">Perry-Casta&ntilde;eda
-Library Map Collection</a>
-of the University of Texas at Austin has copies of
-recent editions.
-The pictorial quality is good,
-but the maps do not indicate summer time,
-and parts of the data are a few years out of date.</li>
-<li><a href="http://worldtimezone.com/">World timezones map with
-current time</a>
-has several fancy time zone maps; it covers Russia particularly well.
-The maps' pictorial quality is not quite as good as the CIA's
-but the maps are more up to date.</li>
-</ul>
-<h2>Time zone boundaries</h2>
-<ul>
-<li><a href="http://home-4.tiscali.nl/~t876506/Multizones.html">Time
-zone boundaries for multizone countries</a> summarizes legal
-boundaries between time zones within countries.</li>
-<li>Manifold.net's <a
-href="http://www.manifold.net/download/freemaps.html">Free Maps and
-GIS Data</a> includes a Manifold-format map of world time zone
-boundaries distributed under the GPL. The GeoCommunity's <a
-href="http://software.geocomm.com/data/intl_timezones.html">International
-Time Zones</a> publishes the same data in other formats.</li>
-<li>The US Geological Survey's National Atlas of the United States
-publishes the <a href="http://www.nationalatlas.gov/timeznm.html">Time
-Zones of the United States</a> in the public domain.</li>
-<li>The GeoCommunity lists several commercial sources for <a
-href="http://spatialnews.geocomm.com/features/timezones/">International
-Time Zones and Time Zone Data</a>.</li>
-</ul>
-<h2>Civil time concepts and history</h2>
-<ul>
-<li><a href="http://physics.nist.gov/time">A Walk through Time</a>
-surveys the evolution of timekeeping.</li>
-<li><a href="http://webexhibits.org/daylightsaving/">About Daylight
-Saving Time - History, rationale, laws and dates</a>
-is an overall history of DST.</li>
-<li><a href="http://toi.iriti.cnr.it/">The
-Time of Internet</a>
-describes time zones and daylight saving time,
-with diagrams.
-The time zone map is out of date, however.</li>
-<li><a href="http://www.phys.uu.nl/~vgent/idl/idl.htm">A History of
-the International Date Line</a> tells the story of the most important
-time zone boundary.</li>
-<li><a href="http://www.statoids.com/tconcept.html">Basic Time
-Zone Concepts</a> discusses terminological issues behind time zones.</li>
-</ul>
-<h2>National histories of legal time</h2>
-<dl>
-<dt>Australia</dt>
-<dd>The Community Relations Division of the New South Wales (NSW)
-Attorney General's Department maintains a <a
-href="http://www.lawlink.nsw.gov.au/crd.nsf/pages/time2">history of
-daylight saving in NSW</a>.</dd>
-<dt>Austria</dt>
-<dd>The Federal Office of Metrology and Surveying publishes a
-table of <a href="http://www.metrologie.at/pdf/sommerzeit.pdf"
-hreflang="de">daylight saving time in Austria (in German)</a>.</dd>
-<dt>Belgium</dt>
-<dd>The Royal Observatory of Belgium maintains a table of <a
-href="http://www.astro.oma.be/GENERAL/INFO/nli001a.html"
-hreflang="nl">time in Belgium (in Dutch)</a>.</dd>
-<dt>Brazil</dt>
-<dd>The Time Service Department of the National Observatory
-records <a href="http://pcdsh01.on.br/DecHV.html"
-hreflang="pt-BR">Brazil's daylight saving time decrees (in
-Portuguese)</a>.</dd>
-<dt>Canada</dt>
-<dd>The Institute for National Measurement Standards publishes current
-and some older information about <a
-href="http://inms-ienm.nrc-cnrc.gc.ca/time_services/daylight_savings_e.html">Time
-Zones and Daylight Saving Time</a>.</dd>
-<dt>Chile</dt>
-<dd>WebExhibits publishes a <a
-href="http://webexhibits.org/daylightsaving/chile.html"
-hreflang="es">history of official time (in Spanish)</a> originally
-written by the Chilean Hydrographic and Oceanographic Service.</dd>
-<dt>Germany</dt>
-<dd>The National Institute for Science and Technology maintains the <a
-href="http://www.ptb.de/en/org/4/44/441/dars_e.htm">Realisation of
-Legal Time in Germany</a>.</dd>
-<dt>Israel</dt>
-<dd>The Interior Ministry periodically issues <a
-href="ftp://ftp.cs.huji.ac.il/pub/tz/announcements/"
-hreflang="he">announcements (in Hebrew)</a>.</dd>
-<dt>Mexico</dt>
-<dd>The Investigation and Analysis Service of the Mexican Library of
-Congress has published a <a
-href="http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/"
-hreflang="es">history of Mexican local time (in Spanish)</a>.</dd>
-<dt>Malaysia</dt>
-<dd>See Singapore below.</dd>
-<dt>Netherlands</dt>
-<dd><a href="http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm"
-hreflang="nl">Legal time in the Netherlands (in Dutch)</a>
-covers the history of local time in the Netherlands from ancient times.</dd>
-<dt>New Zealand</dt>
-<dd>The Department of Internal Affairs maintains a brief history <a
-href="http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Resource-material-Information-We-Provide-About-Daylight-Saving">about
-daylight saving</a>. The privately-maintained <a
-href="http://www.astrologyhouse.co.nz/timechanges.htm">Time Changes in
-New Zealand</a> has more details.</dd>
-<dt>Singapore</dt>
-<dd><a
-href="http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html">Why
-is Singapore in the "Wrong" Time Zone?</a> details the
-history of legal time in Singapore and Malaysia.</dd>
-<dt>United Kingdom</dt>
-<dd><a
-href="http://www.srcf.ucam.org/~jsm28/british-time/">History of
-legal time in Britain</a> discusses in detail the country
-with perhaps the best-documented history of clock adjustments.
-The National Physical Laboratory also maintains an <a
-href="http://www.npl.co.uk/time/summer_time_archive.html">archive
-of summer time dates</a>.</dd>
-</dl>
-<h2>Precision timekeeping</h2>
-<ul>
-<li><a
-href="http://literature.agilent.com/litwebbin/purl.cgi?org_id=tmo&amp;pub_id=5965-7984E">The
-Science of Timekeeping</a> is a thorough introduction
-to the theory and practice of precision timekeeping.</li>
-<li><a href="http://www.ntp.org/">NTP: The Network Time Protocol</a>
-discusses how to synchronize clocks of
-Internet hosts.</li>
-<li><a href="http://gauss.gge.unb.ca/GMT.UT.and.the.RGO.txt"
-charset="macintosh">A
-Few Facts Concerning GMT, UT, and the RGO</a>
-answers questions like "What is the difference between GMT and UTC?"</li>
-<li><a
-href="http://www.gb.nrao.edu/~rfisher/Ephemerides/times.html">Astronomical
-Times</a> explains more abstruse astronomical time scales like TT, TCG,
-and TDB.</li>
-<li>The <a href="http://www.iau.org/">IAU</a>'s <a
-href="http://www.iau-sofa.rl.ac.uk/">Standards Of Fundamental
-Astronomy</a> (SOFA) initiative publishes Fortran code for converting
-among time scales like TAI, TDB, TT and UTC.</li>
-<li><a href="http://www.jpl.nasa.gov/basics/bsf2-3.htm">Basics of
-Space Flight - Reference Systems - Time Conventions</a>
-briefly explains interplanetary space flight timekeeping.</li>
-<li><a
-href="http://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical
-Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a> briefly
-describes Mars Coordinated Time (MTC) and the diverse local time
-scales used by each landed mission on Mars.</li>
-<li><a
-href="http://hpiers.obspm.fr/eop-pc/products/bulletins/bulletins.html">Bulletins
-maintained by the IERS EOP (PC)</a> contains official publications of
-the Earth Orientation Parameters Product Center of the
-International Earth Rotation Service, the committee that decides
-when leap seconds occur.</li>
-<li>The <a
-href="http://www.mail-archive.com/leapsecs@rom.usno.navy.mil/">Leap
-Second Discussion List</a> covers McCarthy and Klepczynski's proposal
-to discontinue leap seconds, published in <a
-href="http://www.gpsworld.com/">GPS World</a> <strong>10</strong>, 11
-(1999-11), 50&ndash;57 and discussed further in R. A. Nelson et al.,
-<a href="http://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
-leap second: its history and possible future</a>,
-<a href="http://www.bipm.fr/metrologia/metrologia.html">Metrologia</a>
-<strong>38</strong> (2001), 509&ndash;529.
-<a href="http://www.ucolick.org/~sla/leapsecs/onlinebib.html">The
-Future of Leap Seconds</a> catalogs information about this
-contentious issue.</li>
-</ul>
-<h2>Time notation</h2>
-<ul>
-<li>
-<a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">A Summary of
-the International Standard Date and Time Notation</a> is a good
-summary of ISO
-8601:1988 - Data elements and interchange formats - Information interchange
-- Representation of dates and times (which has been superseded by
-<a href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780">ISO 8601:2000</a>).</li>
-<li>
-Section 3.3 of <a
-href="ftp://ftp.rfc-editor.org/in-notes/rfc2822.txt">Internet RFC 2822</a>
-specifies the time notation used in email and <a
-href="ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt">HTTP</a> headers.</li>
-<li>
-<a href="ftp://ftp.rfc-editor.org/in-notes/rfc3339.txt">Internet RFC
-3339</a> specifies an ISO 8601 profile for use in new Internet
-protocols.</li>
-<li>
-<a href="http://www.exit109.com/~ghealton/y2k/yrexamples.html">The
-Best of Dates, the Worst of Dates</a> covers many problems encountered
-by software developers when handling dates and time stamps.</li>
-<li>
-Alphabetic time zone abbreviations should not be used as unique
-identifiers for UTC offsets as they are ambiguous in practice. For
-example, "EST" denotes 5 hours behind UTC in English-speaking North
-America, but it denotes 10 or 11 hours ahead of UTC in Australia;
-and French-speaking North Americans prefer "HNE" to "EST". For
-compatibility with <a href="http://www.pasc.org/#POSIX">POSIX</a> the
-<code>tz</code> database contains English abbreviations for all time
-stamps but in many cases these are merely inventions of the database
-maintainers.</li>
-</ul>
-<h2>Related indexes</h2>
-<ul>
-<li><a href="tz-art.htm">Time and the Arts</a></li>
-<li><a href="http://dmoz.org/Reference/Time/">Open Directory -
-Reference: Time</a></li>
-<li><a href="http://directory.google.com/Top/Reference/Time/">Google Directory - Reference &gt; Time</a></li>
-<li><a href="http://dir.yahoo.com/Science/Measurements_and_Units/Time/">Yahoo! Science &gt; Measurements and Units &gt; Time</a></li>
-</ul>
-</body>
-</html>
diff --git a/usr.sbin/zic/zdump.8 b/usr.sbin/zic/zdump.8
index 3a685fd7ea0d..a7f09787dec4 100644
--- a/usr.sbin/zic/zdump.8
+++ b/usr.sbin/zic/zdump.8
@@ -12,7 +12,7 @@
.Nm
.Op Fl -version
.Op Fl v
-.Op Fl c Ar cutoffyear
+.Op Fl c Ar [loyear,]hiyear
.Op Ar zonename ...
.Sh DESCRIPTION
The
@@ -40,9 +40,21 @@ Each line ends with
if the given time is Daylight Saving Time or
.Em isdst=0
otherwise.
-.It Fl c Ar cutoffyear
-Cut off the verbose output near the start of the given year.
+.It Fl c Ar loyear,hiyear
+Cut off verbose output near the start of the given year(s).
+By default,
+the program cuts off verbose output near the starts of the years -500 and 2500.
.El
+.Sh LIMITATIONS
+The
+.Fl v
+option may not be used on systems with floating-point time_t values
+that are neither float nor double.
+.Pp
+Time discontinuities are found by sampling the results returned by localtime
+at twelve-hour intervals.
+This works in all real-world cases;
+one can construct artificial time zones for which this fails.
.Sh "SEE ALSO"
.Xr ctime 3 ,
.Xr tzfile 5 ,
diff --git a/usr.sbin/zic/zdump.c b/usr.sbin/zic/zdump.c
index 980c8a80d22d..ca9c3695e977 100644
--- a/usr.sbin/zic/zdump.c
+++ b/usr.sbin/zic/zdump.c
@@ -1,8 +1,7 @@
-static const char elsieid[] = "@(#)zdump.c 7.31";
-
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
+static char elsieid[] = "@(#)zdump.c 8.8";
#endif /* not lint */
/*
@@ -18,6 +17,19 @@ static const char rcsid[] =
#include <sys/types.h> /* for time_t */
#include <time.h> /* for struct tm */
#include <unistd.h>
+#include <float.h> /* for FLT_MAX and DBL_MAX */
+#include <ctype.h> /* for isalpha et al. */
+#ifndef isascii
+#define isascii(x) 1
+#endif /* !defined isascii */
+
+#ifndef ZDUMP_LO_YEAR
+#define ZDUMP_LO_YEAR (-500)
+#endif /* !defined ZDUMP_LO_YEAR */
+
+#ifndef ZDUMP_HI_YEAR
+#define ZDUMP_HI_YEAR 2500
+#endif /* !defined ZDUMP_HI_YEAR */
#ifndef MAX_STRING_LENGTH
#define MAX_STRING_LENGTH 1024
@@ -68,19 +80,32 @@ static const char rcsid[] =
#endif /* !defined DAYSPERNYEAR */
#ifndef isleap
-#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#endif /* !defined isleap */
-#if HAVE_GETTEXT - 0
+#ifndef isleap_sum
+/*
+** See tzfile.h for details on isleap_sum.
+*/
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
+#endif /* !defined isleap_sum */
+
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
+#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT 0
+#endif
+#if HAVE_GETTEXT
#include "locale.h" /* for setlocale */
#include "libintl.h"
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
#ifndef GNUC_or_lint
#ifdef lint
#define GNUC_or_lint
-#endif /* defined lint */
-#ifndef lint
+#else /* !defined lint */
#ifdef __GNUC__
#define GNUC_or_lint
#endif /* defined __GNUC__ */
@@ -90,8 +115,7 @@ static const char rcsid[] =
#ifndef INITIALIZE
#ifdef GNUC_or_lint
#define INITIALIZE(x) ((x) = 0)
-#endif /* defined GNUC_or_lint */
-#ifndef GNUC_or_lint
+#else /* !defined GNUC_or_lint */
#define INITIALIZE(x)
#endif /* !defined GNUC_or_lint */
#endif /* !defined INITIALIZE */
@@ -103,35 +127,111 @@ static const char rcsid[] =
*/
#ifndef _
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#define _(msgid) gettext(msgid)
-#else /* !(HAVE_GETTEXT - 0) */
+#else /* !(HAVE_GETTEXT) */
#define _(msgid) msgid
-#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !(HAVE_GETTEXT) */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
#define TZ_DOMAIN "tz"
#endif /* !defined TZ_DOMAIN */
-#ifndef P
-#ifdef __STDC__
-#define P(x) x
-#endif /* defined __STDC__ */
-#ifndef __STDC__
-#define P(x) ()
-#endif /* !defined __STDC__ */
-#endif /* !defined P */
-
extern char ** environ;
extern char * tzname[2];
-static char * abbr P((struct tm * tmp));
-static long delta P((struct tm * newp, struct tm * oldp));
-static time_t hunt P((char * name, time_t lot, time_t hit));
+static time_t absolute_min_time;
+static time_t absolute_max_time;
static size_t longest;
-static void show P((char * zone, time_t t, int v));
-static void usage(void);
+static char * progname;
+static int warned;
+
+static void usage(const char *progname, FILE *stream, int status);
+static char * abbr(struct tm * tmp);
+static void abbrok(const char * abbrp, const char * zone);
+static long delta(struct tm * newp, struct tm * oldp);
+static void dumptime(const struct tm * tmp);
+static time_t hunt(char * name, time_t lot, time_t hit);
+static void setabsolutes(void);
+static void show(char * zone, time_t t, int v);
+static const char * tformat(void);
+static time_t yeartot(long y);
+
+#ifndef TYPECHECK
+#define my_localtime localtime
+#else /* !defined TYPECHECK */
+static struct tm *
+my_localtime(tp)
+time_t * tp;
+{
+ register struct tm * tmp;
+
+ tmp = localtime(tp);
+ if (tp != NULL && tmp != NULL) {
+ struct tm tm;
+ register time_t t;
+
+ tm = *tmp;
+ t = mktime(&tm);
+ if (t - *tp >= 1 || *tp - t >= 1) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\n%s: ", progname);
+ (void) fprintf(stderr, tformat(), *tp);
+ (void) fprintf(stderr, " ->");
+ (void) fprintf(stderr, " year=%d", tmp->tm_year);
+ (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
+ (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
+ (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
+ (void) fprintf(stderr, " min=%d", tmp->tm_min);
+ (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
+ (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
+ (void) fprintf(stderr, " -> ");
+ (void) fprintf(stderr, tformat(), t);
+ (void) fprintf(stderr, "\n");
+ }
+ }
+ return tmp;
+}
+#endif /* !defined TYPECHECK */
+
+static void
+abbrok(abbrp, zone)
+const char * const abbrp;
+const char * const zone;
+{
+ register const char * cp;
+ register char * wp;
+
+ if (warned)
+ return;
+ cp = abbrp;
+ wp = NULL;
+ while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp))
+ ++cp;
+ if (cp - abbrp == 0)
+ wp = _("lacks alphabetic at start");
+ else if (cp - abbrp < 3)
+ wp = _("has fewer than 3 alphabetics");
+ else if (cp - abbrp > 6)
+ wp = _("has more than 6 alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii((unsigned char) *cp) &&
+ isdigit((unsigned char) *cp))
+ if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ ++cp;
+ if (*cp != '\0')
+ wp = _("differs from POSIX standard");
+ }
+ if (wp == NULL)
+ return;
+ (void) fflush(stdout);
+ (void) fprintf(stderr,
+ _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"),
+ progname, zone, abbrp, wp);
+ warned = TRUE;
+}
int
main(argc, argv)
@@ -141,60 +241,77 @@ char * argv[];
register int i;
register int c;
register int vflag;
- register char * cutoff;
- register int cutyear;
- register long cuttime;
- char ** fakeenv;
+ register char * cutarg;
+ register long cutloyear = ZDUMP_LO_YEAR;
+ register long cuthiyear = ZDUMP_HI_YEAR;
+ register time_t cutlotime;
+ register time_t cuthitime;
+ register char ** fakeenv;
time_t now;
time_t t;
time_t newt;
- time_t hibit;
struct tm tm;
struct tm newtm;
+ register struct tm * tmp;
+ register struct tm * newtmp;
- INITIALIZE(cuttime);
-#if HAVE_GETTEXT - 0
+ INITIALIZE(cutlotime);
+ INITIALIZE(cuthitime);
+#if HAVE_GETTEXT
(void) setlocale(LC_MESSAGES, "");
#ifdef TZ_DOMAINDIR
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
-#endif /* defined(TEXTDOMAINDIR) */
+#endif /* TEXTDOMAINDIR */
(void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
errx(EXIT_SUCCESS, "%s", elsieid);
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(progname, stdout, EXIT_SUCCESS);
}
vflag = 0;
- cutoff = NULL;
+ cutarg = NULL;
while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
if (c == 'v')
vflag = 1;
- else cutoff = optarg;
+ else cutarg = optarg;
if ((c != -1) ||
(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
- usage();
+ usage(progname, stderr, EXIT_FAILURE);
}
- if (cutoff != NULL) {
- int y;
-
- cutyear = atoi(cutoff);
- cuttime = 0;
- for (y = EPOCH_YEAR; y < cutyear; ++y)
- cuttime += DAYSPERNYEAR + isleap(y);
- cuttime *= SECSPERHOUR * HOURSPERDAY;
+ if (vflag) {
+ if (cutarg != NULL) {
+ long lo;
+ long hi;
+ char dummy;
+
+ if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
+ cuthiyear = hi;
+ } else if (sscanf(cutarg, "%ld,%ld%c",
+ &lo, &hi, &dummy) == 2) {
+ cutloyear = lo;
+ cuthiyear = hi;
+ } else {
+(void) fprintf(stderr, _("%s: wild -c argument %s\n"),
+ progname, cutarg);
+ exit(EXIT_FAILURE);
+ }
+ }
+ setabsolutes();
+ cutlotime = yeartot(cutloyear);
+ cuthitime = yeartot(cuthiyear);
}
(void) time(&now);
longest = 0;
for (i = optind; i < argc; ++i)
if (strlen(argv[i]) > longest)
longest = strlen(argv[i]);
- for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
- continue;
{
register int from;
register int to;
- for (i = 0; environ[i] != NULL; ++i)
+ for (i = 0; environ[i] != NULL; ++i)
continue;
fakeenv = (char **) malloc((size_t) ((i + 2) *
sizeof *fakeenv));
@@ -219,43 +336,43 @@ char * argv[];
show(argv[i], now, FALSE);
continue;
}
- /*
- ** Get lowest value of t.
- */
- t = hibit;
- if (t > 0) /* time_t is unsigned */
- t = 0;
+ warned = FALSE;
+ t = absolute_min_time;
show(argv[i], t, TRUE);
t += SECSPERHOUR * HOURSPERDAY;
show(argv[i], t, TRUE);
- tm = *localtime(&t);
- (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ if (t < cutlotime)
+ t = cutlotime;
+ tmp = my_localtime(&t);
+ if (tmp != NULL) {
+ tm = *tmp;
+ (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ }
for ( ; ; ) {
- if (cutoff != NULL && t >= cuttime)
+ if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12)
break;
newt = t + SECSPERHOUR * 12;
- if (cutoff != NULL && newt >= cuttime)
- break;
- if (newt <= t)
- break;
- newtm = *localtime(&newt);
- if (delta(&newtm, &tm) != (newt - t) ||
+ newtmp = localtime(&newt);
+ if (newtmp != NULL)
+ newtm = *newtmp;
+ if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
+ (delta(&newtm, &tm) != (newt - t) ||
newtm.tm_isdst != tm.tm_isdst ||
- strcmp(abbr(&newtm), buf) != 0) {
+ strcmp(abbr(&newtm), buf) != 0)) {
newt = hunt(argv[i], t, newt);
- newtm = *localtime(&newt);
- (void) strncpy(buf, abbr(&newtm),
- (sizeof buf) - 1);
+ newtmp = localtime(&newt);
+ if (newtmp != NULL) {
+ newtm = *newtmp;
+ (void) strncpy(buf,
+ abbr(&newtm),
+ (sizeof buf) - 1);
+ }
}
t = newt;
tm = newtm;
+ tmp = newtmp;
}
- /*
- ** Get highest value of t.
- */
- t = ~((time_t) 0);
- if (t < 0) /* time_t is signed */
- t &= ~hibit;
+ t = absolute_max_time;
t -= SECSPERHOUR * HOURSPERDAY;
show(argv[i], t, TRUE);
t += SECSPERHOUR * HOURSPERDAY;
@@ -264,45 +381,133 @@ char * argv[];
if (fflush(stdout) || ferror(stdout))
errx(EXIT_FAILURE, _("error writing standard output"));
exit(EXIT_SUCCESS);
+ /* If exit fails to exit... */
+ return(EXIT_FAILURE);
+}
+
+static void
+setabsolutes(void)
+{
+ if (0.5 == (time_t) 0.5) {
+ /*
+ ** time_t is floating.
+ */
+ if (sizeof (time_t) == sizeof (float)) {
+ absolute_min_time = (time_t) -FLT_MAX;
+ absolute_max_time = (time_t) FLT_MAX;
+ } else if (sizeof (time_t) == sizeof (double)) {
+ absolute_min_time = (time_t) -DBL_MAX;
+ absolute_max_time = (time_t) DBL_MAX;
+ } else {
+ (void) fprintf(stderr,
+_("%s: use of -v on system with floating time_t other than float or double\n"),
+ progname);
+ exit(EXIT_FAILURE);
+ }
+ } else if (0 > (time_t) -1) {
+ /*
+ ** time_t is signed. Assume overflow wraps around.
+ */
+ time_t t = 0;
+ time_t t1 = 1;
- /* gcc -Wall pacifier */
- for ( ; ; )
- continue;
+ while (t < t1) {
+ t = t1;
+ t1 = 2 * t1 + 1;
+ }
+
+ absolute_max_time = t;
+ t = -t;
+ absolute_min_time = t - 1;
+ if (t < absolute_min_time)
+ absolute_min_time = t;
+ } else {
+ /*
+ ** time_t is unsigned.
+ */
+ absolute_min_time = 0;
+ absolute_max_time = absolute_min_time - 1;
+ }
+}
+
+static time_t
+yeartot(y)
+const long y;
+{
+ register long myy;
+ register long seconds;
+ register time_t t;
+
+ myy = EPOCH_YEAR;
+ t = 0;
+ while (myy != y) {
+ if (myy < y) {
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ ++myy;
+ if (t > absolute_max_time - seconds) {
+ t = absolute_max_time;
+ break;
+ }
+ t += seconds;
+ } else {
+ --myy;
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ if (t < absolute_min_time + seconds) {
+ t = absolute_min_time;
+ break;
+ }
+ t -= seconds;
+ }
+ }
+ return t;
}
static void
-usage(void)
+usage(const char *progname, FILE *stream, int status)
{
- fprintf(stderr,
-_("usage: zdump [--version] [-v] [-c cutoff] zonename ...\n"));
- exit(EXIT_FAILURE);
+ fprintf(stream,
+_("usage: %s [--version] [-v] [--help] [-c [loyear,]hiyear] zonename ...\n\
+\n\
+Report bugs to tz@elsie.nci.nih.gov.\n"), progname);
+ exit(status);
}
static time_t
-hunt(name, lot, hit)
-char * name;
-time_t lot;
-time_t hit;
+hunt(char *name, time_t lot, time_t hit)
{
- time_t t;
- struct tm lotm;
- struct tm tm;
- static char loab[MAX_STRING_LENGTH];
-
- lotm = *localtime(&lot);
- (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
- while ((hit - lot) >= 2) {
- t = lot / 2 + hit / 2;
+ time_t t;
+ long diff;
+ struct tm lotm;
+ register struct tm * lotmp;
+ struct tm tm;
+ register struct tm * tmp;
+ char loab[MAX_STRING_LENGTH];
+
+ lotmp = my_localtime(&lot);
+ if (lotmp != NULL) {
+ lotm = *lotmp;
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ }
+ for ( ; ; ) {
+ diff = (long) (hit - lot);
+ if (diff < 2)
+ break;
+ t = lot;
+ t += diff / 2;
if (t <= lot)
++t;
else if (t >= hit)
--t;
- tm = *localtime(&t);
- if (delta(&tm, &lotm) == (t - lot) &&
+ tmp = my_localtime(&t);
+ if (tmp != NULL)
+ tm = *tmp;
+ if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
+ (delta(&tm, &lotm) == (t - lot) &&
tm.tm_isdst == lotm.tm_isdst &&
- strcmp(abbr(&tm), loab) == 0) {
+ strcmp(abbr(&tm), loab) == 0)) {
lot = t;
lotm = tm;
+ lotmp = tmp;
} else hit = t;
}
show(name, lot, TRUE);
@@ -311,7 +516,7 @@ time_t hit;
}
/*
-** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
+** Thanks to Paul Eggert for logic used in delta.
*/
static long
@@ -319,14 +524,14 @@ delta(newp, oldp)
struct tm * newp;
struct tm * oldp;
{
- long result;
- int tmy;
+ register long result;
+ register int tmy;
if (newp->tm_year < oldp->tm_year)
return -delta(oldp, newp);
result = 0;
for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
- result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
+ result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
result += newp->tm_yday - oldp->tm_yday;
result *= HOURSPERDAY;
result += newp->tm_hour - oldp->tm_hour;
@@ -338,27 +543,36 @@ struct tm * oldp;
}
static void
-show(zone, t, v)
-char * zone;
-time_t t;
-int v;
+show(char *zone, time_t t, int v)
{
- struct tm * tmp;
+ register struct tm * tmp;
(void) printf("%-*s ", (int) longest, zone);
- if (v)
- (void) printf("%.24s UTC = ", asctime(gmtime(&t)));
- tmp = localtime(&t);
- (void) printf("%.24s", asctime(tmp));
- if (*abbr(tmp) != '\0')
- (void) printf(" %s", abbr(tmp));
if (v) {
- (void) printf(" isdst=%d", tmp->tm_isdst);
+ tmp = gmtime(&t);
+ if (tmp == NULL) {
+ (void) printf(tformat(), t);
+ } else {
+ dumptime(tmp);
+ (void) printf(" UTC");
+ }
+ (void) printf(" = ");
+ }
+ tmp = my_localtime(&t);
+ dumptime(tmp);
+ if (tmp != NULL) {
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
#ifdef TM_GMTOFF
- (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
#endif /* defined TM_GMTOFF */
+ }
}
(void) printf("\n");
+ if (tmp != NULL && *abbr(tmp) != '\0')
+ abbrok(abbr(tmp), zone);
}
static char *
@@ -373,3 +587,84 @@ struct tm * tmp;
result = tzname[tmp->tm_isdst];
return (result == NULL) ? &nada : result;
}
+
+/*
+** The code below can fail on certain theoretical systems;
+** it works on all known real-world systems as of 2004-12-30.
+*/
+
+static const char *
+tformat(void)
+{
+ if (0.5 == (time_t) 0.5) { /* floating */
+ if (sizeof (time_t) > sizeof (double))
+ return "%Lg";
+ return "%g";
+ }
+ if (0 > (time_t) -1) { /* signed */
+ if (sizeof (time_t) > sizeof (long))
+ return "%lld";
+ if (sizeof (time_t) > sizeof (int))
+ return "%ld";
+ return "%d";
+ }
+ if (sizeof (time_t) > sizeof (unsigned long))
+ return "%llu";
+ if (sizeof (time_t) > sizeof (unsigned int))
+ return "%lu";
+ return "%u";
+}
+
+static void
+dumptime(timeptr)
+register const struct tm * timeptr;
+{
+ static const char wday_name[][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static const char mon_name[][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ register const char * wn;
+ register const char * mn;
+ register int lead;
+ register int trail;
+
+ if (timeptr == NULL) {
+ (void) printf("NULL");
+ return;
+ }
+ /*
+ ** The packaged versions of localtime and gmtime never put out-of-range
+ ** values in tm_wday or tm_mon, but since this code might be compiled
+ ** with other (perhaps experimental) versions, paranoia is in order.
+ */
+ if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
+ (int) (sizeof wday_name / sizeof wday_name[0]))
+ wn = "???";
+ else wn = wday_name[timeptr->tm_wday];
+ if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
+ (int) (sizeof mon_name / sizeof mon_name[0]))
+ mn = "???";
+ else mn = mon_name[timeptr->tm_mon];
+ (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
+ wn, mn,
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec);
+#define DIVISOR 10
+ trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
+ lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
+ trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (lead == 0)
+ (void) printf("%d", trail);
+ else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
+}
diff --git a/usr.sbin/zic/zic.8 b/usr.sbin/zic/zic.8
index 76a5a883cd9d..71a1bcbfb36c 100644
--- a/usr.sbin/zic/zic.8
+++ b/usr.sbin/zic/zic.8
@@ -120,9 +120,9 @@ 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:
-.Dl "Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S"
+.Dl "Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
For example:
-.Dl "Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D"
+.Dl "Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D
.Pp
The fields that make up a rule line are:
.Bl -tag -width "LETTER/S" -offset indent
@@ -260,9 +260,9 @@ the variable part is null.
.El
.Pp
A zone line has the form:
-.Dl "Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]"
+.Dl "Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]]
For example:
-.Dl "Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00"
+.Dl "Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
The fields that make up a zone line are:
.Bl -tag -width indent
.It NAME
@@ -293,15 +293,15 @@ of the time zone abbreviation goes.
Alternately,
a slash (/)
separates standard and daylight abbreviations.
-.It UNTIL
+.It UNTILYEAR [MONTH [DAY [TIME]]]
The time at which the UTC 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 UTC offset
and rule change until the time specified.
The month, day, and time of day have the same format as the IN, ON, and AT
-columns of a rule; trailing columns can be omitted, and default to the
-earliest possible value for the missing columns.
+fields of a rule; trailing fields can be omitted, and default to the
+earliest possible value for the missing fields.
.Pp
The next line must be a
.Dq continuation
@@ -310,18 +310,18 @@ string
.Dq Zone
and the name are omitted, as the continuation line will
place information starting at the time specified as the
-.Em UNTIL
-field in the previous line in the file used by the previous line.
-Continuation lines may contain an
-.Em UNTIL
-field, just as zone lines do, indicating that the next line is a further
+.Em until
+information in the previous line in the file used by the previous line.
+Continuation lines may contain
+.Em until
+information, just as zone lines do, indicating that the next line is a further
continuation.
.El
.Pp
A link line has the form
-.Dl "Link LINK-FROM LINK-TO"
+.Dl "Link LINK-FROM LINK-TO
For example:
-.Dl "Link Europe/Istanbul Asia/Istanbul"
+.Dl "Link Europe/Istanbul Asia/Istanbul
The
.Em LINK-FROM
field should appear as the
@@ -335,9 +335,9 @@ Except for continuation lines,
lines may appear in any order in the input.
.Pp
Lines in the file that describes leap seconds have the following form:
-.Dl "Leap YEAR MONTH DAY HH:MM:SS CORR R/S"
+.Dl "Leap YEAR MONTH DAY HH:MM:SS CORR R/S
For example:
-.Dl "Leap 1974 Dec 31 23:59:60 + S"
+.Dl "Leap 1974 Dec 31 23:59:60 + S
The
.Em YEAR ,
.Em MONTH ,
@@ -376,12 +376,81 @@ or
.Dq Rolling
if the leap second time given by the other fields should be interpreted as
local wall clock time.
-.Sh NOTE
+.Sh "EXTENDED EXAMPLE"
+Here is an extended example of
+.Nm
+input, intended to illustrate many of its features.
+.br
+.ne 22
+.nf
+.in +2m
+.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
+Rule Swiss 1940 only - Nov 2 0:00 1:00 S
+Rule Swiss 1940 only - Dec 31 0:00 0 -
+Rule Swiss 1941 1942 - May Sun>=1 2:00 1:00 S
+Rule Swiss 1941 1942 - Oct Sun>=1 0:00 0
+.sp .5
+Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S
+Rule EU 1977 only - Sep lastSun 1:00u 0 -
+Rule EU 1978 only - Oct 1 1:00u 0 -
+Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
+Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
+Rule EU 1996 max - Oct lastSun 1:00u 0 -
+.sp
+.ta \w'# Zone\0\0'u +\w'Europe/Zurich\0\0'u +\w'0:34:08\0\0'u +\w'RULES/SAVE\0\0'u +\w'FORMAT\0\0'u
+# Zone NAME GMTOFF RULES FORMAT UNTIL
+Zone Europe/Zurich 0:34:08 - LMT 1848 Sep 12
+ 0:29:44 - BMT 1894 Jun
+ 1:00 Swiss CE%sT 1981
+ 1:00 EU CE%sT
+.sp
+Link Europe/Zurich Switzerland
+.sp
+.in
+.fi
+In this example, the zone is named Europe/Zurich but it has an alias
+as Switzerland.
+Zurich was 34 minutes and 8 seconds west of GMT until 1848-09-12
+at 00:00, when the offset changed to 29 minutes and 44 seconds.
+After 1894-06-01 at 00:00 Swiss daylight saving rules (defined with
+lines beginning with "Rule Swiss") apply, and the GMT offset became
+one hour.
+From 1981 to the present, EU daylight saving rules have applied,
+and the UTC offset has remained at one hour.
+.Pp
+In 1940, daylight saving time applied from November 2 at 00:00 to
+December 31 at 00:00.
+In 1941 and 1942, daylight saving time applied from the first Sunday
+in May at 02:00 to the first Sunday in October at 00:00.
+The pre-1981 EU daylight-saving rules have no effect here, but are
+included for completeness.
+Since 1981, daylight saving has begun on the last Sunday in March
+at 01:00 UTC.
+Until 1995 it ended the last Sunday in September at 01:00 UTC, but
+this changed to the last Sunday in October starting in 1996.
+.Pp
+For purposes of display, "LMT" and "BMT" were initially used,
+respectively.
+Since Swiss rules and later EU rules were applied, the display name
+for the timezone has been CET for standard time and CEST for daylight
+saving time.
+.Sh NOTES
For areas with more than two types of local time,
you may need to use local standard time in the
.Em AT
field of the earliest transition time's rule to ensure that
the earliest transition time recorded in the compiled file is correct.
+.Pp
+If, for a particular zone, a clock advance caused by the start of
+daylight saving coincides with and is equal to a clock retreat
+caused by a change in UTC offset,
+.Nm
+produces a single transition to daylight saving at the new UTC offset
+(without any change in wall clock time).
+To get separate transitions use multiple zone continuation lines
+specifying transition instants using universal time.
.Sh FILES
.Bl -tag -width /usr/share/zoneinfo -compact
.It /usr/share/zoneinfo
@@ -391,4 +460,4 @@ standard directory used for created files
.Xr ctime 3 ,
.Xr tzfile 5 ,
.Xr zdump 8
-.\" @(#)zic.8 7.18
+.\" @(#)zic.8 8.4
diff --git a/usr.sbin/zic/zic.c b/usr.sbin/zic/zic.c
index 10d79a898a2c..cb959586a449 100644
--- a/usr.sbin/zic/zic.c
+++ b/usr.sbin/zic/zic.c
@@ -1,4 +1,9 @@
-static const char elsieid[] = "@(#)zic.c 7.116";
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
+static const char elsieid[] = "@(#)zic.c 8.19";
#ifndef lint
static const char rcsid[] =
@@ -13,11 +18,19 @@ static const char rcsid[] =
#include <sys/types.h>
#include <unistd.h>
+#define ZIC_VERSION '2'
+
+typedef int_fast64_t zic_t;
+
+#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
+#define ZIC_MAX_ABBR_LEN_WO_WARN 6
+#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
+
#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
/*
** On some ancient hosts, predicates like `isspace(C)' are defined
-** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
+** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
** which says they are defined only if C == ((unsigned char) C) || C == EOF.
** Neither the C Standard nor POSIX require that `isascii' exist.
** For portability, we check both ancient and modern requirements.
@@ -28,6 +41,11 @@ static const char rcsid[] =
#define isascii(x) 1
#endif
+#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
+#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
+
+#define end(cp) (strchr((cp), '\0'))
+
struct rule {
const char * r_filename;
int r_linenum;
@@ -36,6 +54,8 @@ struct rule {
int r_loyear; /* for example, 1986 */
int r_hiyear; /* for example, 1986 */
const char * r_yrtype;
+ int r_lowasnum;
+ int r_hiwasnum;
int r_month; /* 0..11 */
@@ -52,7 +72,7 @@ struct rule {
const char * r_abbrvar; /* variable part of abbreviation */
int r_todo; /* a rule to do (used in outzone) */
- time_t r_temp; /* used in outzone */
+ zic_t r_temp; /* used in outzone */
};
/*
@@ -78,73 +98,81 @@ struct zone {
int z_nrules;
struct rule z_untilrule;
- time_t z_untiltime;
+ zic_t z_untiltime;
};
-static void addtt P((time_t starttime, int type));
-static int addtype P((long gmtoff, const char * abbr, int isdst,
- int ttisstd, int ttisgmt));
-static void leapadd P((time_t t, int positive, int rolling, int count));
-static void adjleap P((void));
-static void associate P((void));
-static int ciequal P((const char * ap, const char * bp));
-static void convert P((long val, char * buf));
-static void dolink P((const char * fromfile, const char * tofile));
-static void doabbr P((char * abbr, const char * format,
- const char * letters, int isdst));
-static void eat P((const char * name, int num));
-static void eats P((const char * name, int num,
- const char * rname, int rnum));
-static long eitol P((int i));
-static void error P((const char * message));
-static char ** getfields P((char * buf));
-static long gethms P((const char * string, const char * errstrng,
- int signable));
-static void infile P((const char * filename));
-static void inleap P((char ** fields, int nfields));
-static void inlink P((char ** fields, int nfields));
-static void inrule P((char ** fields, int nfields));
-static int inzcont P((char ** fields, int nfields));
-static int inzone P((char ** fields, int nfields));
-static int inzsub P((char ** fields, int nfields, int iscont));
-static int itsabbr P((const char * abbr, const char * word));
-static int itsdir P((const char * name));
-static int lowerit P((int c));
-static char * memcheck P((char * tocheck));
-static int mkdirs P((char * filename));
-static void newabbr P((const char * abbr));
-static long oadd P((long t1, long t2));
-static void outzone P((const struct zone * zp, int ntzones));
-static void puttzcode P((long code, FILE * fp));
-static int rcomp P((const void * leftp, const void * rightp));
-static time_t rpytime P((const struct rule * rp, int wantedy));
-static void rulesub P((struct rule * rp,
+static void addtt(zic_t starttime, int type);
+static int addtype(long gmtoff, const char * abbr, int isdst,
+ int ttisstd, int ttisgmt);
+static void leapadd(zic_t t, int positive, int rolling, int count);
+static void adjleap(void);
+static void associate(void);
+static int ciequal(const char * ap, const char * bp);
+static void convert(long val, char * buf);
+static void convert64(zic_t val, char * buf);
+static void dolink(const char * fromfield, const char * tofield);
+static void doabbr(char * abbr, const char * format,
+ const char * letters, int isdst, int doquotes);
+static void eat(const char * name, int num);
+static void eats(const char * name, int num,
+ const char * rname, int rnum);
+static long eitol(int i);
+static void error(const char * message);
+static char ** getfields(char * buf);
+static long gethms(const char * string, const char * errstrng,
+ int signable);
+static void infile(const char * filename);
+static void inleap(char ** fields, int nfields);
+static void inlink(char ** fields, int nfields);
+static void inrule(char ** fields, int nfields);
+static int inzcont(char ** fields, int nfields);
+static int inzone(char ** fields, int nfields);
+static int inzsub(char ** fields, int nfields, int iscont);
+static int is32(zic_t x);
+static int itsabbr(const char * abbr, const char * word);
+static int itsdir(const char * name);
+static int lowerit(int c);
+static char * memcheck(char * tocheck);
+static int mkdirs(char * filename);
+static void newabbr(const char * abbr);
+static long oadd(long t1, long t2);
+static void outzone(const struct zone * zp, int ntzones);
+static void puttzcode(long code, FILE * fp);
+static void puttzcode64(zic_t code, FILE * fp);
+static int rcomp(const void * leftp, const void * rightp);
+static zic_t rpytime(const struct rule * rp, int wantedy);
+static void rulesub(struct rule * rp,
const char * loyearp, const char * hiyearp,
const char * typep, const char * monthp,
- const char * dayp, const char * timep));
-static void setboundaries P((void));
-static void setgroup P((gid_t *flag, const char *name));
-static void setuser P((uid_t *flag, const char *name));
-static time_t tadd P((time_t t1, long t2));
-static void usage P((void));
-static void writezone P((const char * name));
-static int yearistype P((int year, const char * type));
-
-#if !(HAVE_STRERROR - 0)
-static char * strerror P((int));
-#endif /* !(HAVE_STRERROR - 0) */
+ const char * dayp, const char * timep);
+static int stringoffset(char * result, long offset);
+static int stringrule(char * result, const struct rule * rp,
+ long dstoff, long gmtoff);
+static void stringzone(char * result,
+ const struct zone * zp, int ntzones);
+static void setboundaries(void);
+static void setgroup(gid_t *flag, const char *name);
+static void setuser(uid_t *flag, const char *name);
+static zic_t tadd(zic_t t1, long t2);
+static void usage(FILE *stream, int status);
+static void writezone(const char * name, const char * string);
+static int yearistype(int year, const char * type);
static int charcnt;
static int errors;
static const char * filename;
static int leapcnt;
+static int leapseen;
+static int leapminyear;
+static int leapmaxyear;
static int linenum;
-static time_t max_time;
+static int max_abbrvar_len;
+static int max_format_len;
+static zic_t max_time;
static int max_year;
-static int max_year_representable;
-static time_t min_time;
+static zic_t min_time;
static int min_year;
-static int min_year_representable;
+static zic_t min_time;
static int noise;
static const char * rfilename;
static int rlinenum;
@@ -253,8 +281,8 @@ struct lookup {
const int l_value;
};
-static struct lookup const * byword P((const char * string,
- const struct lookup * lp));
+static struct lookup const * byword(const char * string,
+ const struct lookup * lp);
static struct lookup const line_codes[] = {
{ "Rule", LC_RULE },
@@ -331,7 +359,7 @@ static const int len_years[2] = {
};
static struct attype {
- time_t at;
+ zic_t at;
unsigned char type;
} attypes[TZ_MAX_TIMES];
static long gmtoffs[TZ_MAX_TYPES];
@@ -340,7 +368,7 @@ static unsigned char abbrinds[TZ_MAX_TYPES];
static char ttisstds[TZ_MAX_TYPES];
static char ttisgmts[TZ_MAX_TYPES];
static char chars[TZ_MAX_CHARS];
-static time_t trans[TZ_MAX_LEAPS];
+static zic_t trans[TZ_MAX_LEAPS];
static long corr[TZ_MAX_LEAPS];
static char roll[TZ_MAX_LEAPS];
@@ -366,19 +394,6 @@ char * const ptr;
** Error handling.
*/
-#if !(HAVE_STRERROR - 0)
-static char *
-strerror(errnum)
-int errnum;
-{
- extern char * sys_errlist[];
- extern int sys_nerr;
-
- return (errnum > 0 && errnum <= sys_nerr) ?
- sys_errlist[errnum] : _("Unknown system error");
-}
-#endif /* !(HAVE_STRERROR - 0) */
-
static void
eats(name, num, rname, rnum)
const char * const name;
@@ -432,12 +447,14 @@ const char * const string;
}
static void
-usage P((void))
-{
- (void) fprintf(stderr, "%s\n%s\n",
-_("usage: zic [--version] [-s] [-v] [-l localtime] [-p posixrules] [-d directory]"),
-_(" [-L leapseconds] [-y yearistype] [filename ... ]"));
- (void) exit(EXIT_FAILURE);
+usage(FILE *stream, int status)
+ {
+ (void) fprintf(stream, _("usage is zic \
+[ --version ] [--help] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
+\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
+\n\
+Report bugs to tz@elsie.nci.nih.gov.\n"));
+ exit(status);
}
static const char * psxrules;
@@ -445,7 +462,6 @@ static const char * lcltime;
static const char * directory;
static const char * leapsec;
static const char * yitcommand;
-static int sflag = FALSE;
static int Dflag;
static uid_t uflag = (uid_t)-1;
static gid_t gflag = (gid_t)-1;
@@ -464,21 +480,28 @@ char * argv[];
#ifdef unix
(void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
#endif /* defined unix */
-#if HAVE_GETTEXT - 0
- (void) setlocale(LC_MESSAGES, "");
+#if HAVE_GETTEXT
+ (void) setlocale(LC_ALL, "");
#ifdef TZ_DOMAINDIR
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
#endif /* defined TEXTDOMAINDIR */
(void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
+ if (TYPE_BIT(zic_t) < 64) {
+ (void) fprintf(stderr, "zic: %s\n",
+ _("wild compilation-time specification of zic_t"));
+ exit(EXIT_FAILURE);
+ }
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
errx(EXIT_SUCCESS, "%s", elsieid);
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(stdout, EXIT_SUCCESS);
}
while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
switch (c) {
default:
- usage();
+ usage(stderr, EXIT_FAILURE);
case 'D':
Dflag = 1;
break;
@@ -537,11 +560,11 @@ _("more than one -L option specified"));
noise = TRUE;
break;
case 's':
- sflag = TRUE;
+ (void) printf("zic: -s ignored\n");
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
- usage(); /* usage message by request */
+ usage(stderr, EXIT_FAILURE); /* usage message by request */
if (directory == NULL)
directory = TZDIR;
if (yitcommand == NULL)
@@ -557,7 +580,7 @@ _("more than one -L option specified"));
for (i = optind; i < argc; ++i)
infile(argv[i]);
if (errors)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
associate();
for (i = 0; i < nzones; i = j) {
/*
@@ -573,6 +596,11 @@ _("more than one -L option specified"));
for (i = 0; i < nlinks; ++i) {
eat(links[i].l_filename, links[i].l_linenum);
dolink(links[i].l_from, links[i].l_to);
+ if (noise)
+ for (j = 0; j < nlinks; ++j)
+ if (strcmp(links[i].l_to,
+ links[j].l_from) == 0)
+ warning(_("link to link"));
}
if (lcltime != NULL) {
eat("command line", 1);
@@ -586,26 +614,26 @@ _("more than one -L option specified"));
}
static void
-dolink(fromfile, tofile)
-const char * const fromfile;
-const char * const tofile;
+dolink(fromfield, tofield)
+const char * const fromfield;
+const char * const tofield;
{
register char * fromname;
register char * toname;
- if (fromfile[0] == '/')
- fromname = ecpyalloc(fromfile);
+ if (fromfield[0] == '/')
+ fromname = ecpyalloc(fromfield);
else {
fromname = ecpyalloc(directory);
fromname = ecatalloc(fromname, "/");
- fromname = ecatalloc(fromname, fromfile);
+ fromname = ecatalloc(fromname, fromfield);
}
- if (tofile[0] == '/')
- toname = ecpyalloc(tofile);
+ if (tofield[0] == '/')
+ toname = ecpyalloc(tofield);
else {
toname = ecpyalloc(directory);
toname = ecatalloc(toname, "/");
- toname = ecatalloc(toname, tofile);
+ toname = ecatalloc(toname, tofield);
}
/*
** We get to be careful here since
@@ -617,25 +645,30 @@ const char * const tofile;
int result;
if (mkdirs(toname) != 0)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
result = link(fromname, toname);
-#if (HAVE_SYMLINK - 0)
+#if HAVE_SYMLINK
if (result != 0 &&
- access(fromname, F_OK) == 0 &&
- !itsdir(fromname)) {
- const char *s = tofile;
- register char * symlinkcontents = NULL;
- while ((s = strchr(s+1, '/')) != NULL)
- symlinkcontents = ecatalloc(symlinkcontents, "../");
- symlinkcontents = ecatalloc(symlinkcontents, fromfile);
-
- result = symlink(symlinkcontents, toname);
- if (result == 0)
+ access(fromname, F_OK) == 0 &&
+ !itsdir(fromname)) {
+ const char *s = tofield;
+ register char * symlinkcontents = NULL;
+ while ((s = strchr(s+1, '/')) != NULL)
+ symlinkcontents =
+ ecatalloc(symlinkcontents,
+ "../");
+ symlinkcontents =
+ ecatalloc(symlinkcontents,
+ fromname);
+ result =
+ symlink(symlinkcontents,
+ toname);
+ if (result == 0)
warning(_("hard link failed, symbolic link used"));
- ifree(symlinkcontents);
+ ifree(symlinkcontents);
}
-#endif
+#endif /* HAVE_SYMLINK */
if (result != 0) {
err(EXIT_FAILURE, _("can't link from %s to %s"),
fromname, toname);
@@ -645,43 +678,17 @@ warning(_("hard link failed, symbolic link used"));
ifree(toname);
}
-#ifndef INT_MAX
-#define INT_MAX ((int) (((unsigned)~0)>>1))
-#endif /* !defined INT_MAX */
-
-#ifndef INT_MIN
-#define INT_MIN ((int) ~(((unsigned)~0)>>1))
-#endif /* !defined INT_MIN */
-
-/*
-** The tz file format currently allows at most 32-bit quantities.
-** This restriction should be removed before signed 32-bit values
-** wrap around in 2038, but unfortunately this will require a
-** change to the tz file format.
-*/
-
-#define MAX_BITS_IN_FILE 32
-#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)
+#define TIME_T_BITS_IN_FILE 64
static void
-setboundaries P((void))
+setboundaries (void)
{
- if (TYPE_SIGNED(time_t)) {
- min_time = ~ (time_t) 0;
- min_time <<= TIME_T_BITS_IN_FILE - 1;
- max_time = ~ (time_t) 0 - min_time;
- if (sflag)
- min_time = 0;
- } else {
- min_time = 0;
- max_time = 2 - sflag;
- max_time <<= TIME_T_BITS_IN_FILE - 1;
- --max_time;
- }
- min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
- max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
- min_year_representable = min_year;
- max_year_representable = max_year;
+ register int i;
+
+ min_time = -1;
+ for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
+ min_time *= 2;
+ max_time = -(min_time + 1);
}
static int
@@ -716,7 +723,7 @@ const void * cp2;
}
static void
-associate P((void))
+associate(void)
{
register struct zone * zp;
register struct rule * rp;
@@ -778,7 +785,7 @@ associate P((void))
*/
eat(zp->z_filename, zp->z_linenum);
zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
- TRUE);
+ TRUE);
/*
** Note, though, that if there's no rule,
** a '%s' in the format is a bad thing.
@@ -788,7 +795,7 @@ associate P((void))
}
}
if (errors)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
static void
@@ -817,7 +824,7 @@ const char * name;
cp = strchr(buf, '\n');
if (cp == NULL) {
error(_("line too long"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
*cp = '\0';
fields = getfields(buf);
@@ -885,7 +892,8 @@ const char * string;
const char * const errstring;
const int signable;
{
- int hh, mm, ss, sign;
+ long hh;
+ int mm, ss, sign;
if (string == NULL || *string == '\0')
return 0;
@@ -895,27 +903,32 @@ const int signable;
sign = -1;
++string;
} else sign = 1;
- if (sscanf(string, scheck(string, "%d"), &hh) == 1)
+ if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
mm = ss = 0;
- else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
+ else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
ss = 0;
- else if (sscanf(string, scheck(string, "%d:%d:%d"),
+ else if (sscanf(string, scheck(string, "%ld:%d:%d"),
&hh, &mm, &ss) != 3) {
error(errstring);
return 0;
}
- if ((hh < 0 || hh >= HOURSPERDAY ||
+ if (hh < 0 ||
mm < 0 || mm >= MINSPERHOUR ||
- ss < 0 || ss > SECSPERMIN) &&
- !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {
+ ss < 0 || ss > SECSPERMIN) {
error(errstring);
return 0;
}
- if (noise && hh == HOURSPERDAY)
+ if (LONG_MAX / SECSPERHOUR < hh) {
+ error(_("time overflow"));
+ return 0;
+ }
+ if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
warning(_("24:00 not handled by pre-1998 versions of zic"));
- return eitol(sign) *
- (eitol(hh * MINSPERHOUR + mm) *
- eitol(SECSPERMIN) + eitol(ss));
+ if (noise && (hh > HOURSPERDAY ||
+ (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
+warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
+ return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
+ eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
}
static void
@@ -940,6 +953,8 @@ const int nfields;
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
r.r_name = ecpyalloc(fields[RF_NAME]);
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ if (max_abbrvar_len < strlen(r.r_abbrvar))
+ max_abbrvar_len = strlen(r.r_abbrvar);
rules = (struct rule *) (void *) erealloc((char *) rules,
(int) ((nrules + 1) * sizeof *rules));
rules[nrules++] = r;
@@ -1045,6 +1060,8 @@ const int iscont;
}
z.z_rule = ecpyalloc(fields[i_rule]);
z.z_format = ecpyalloc(fields[i_format]);
+ if (max_format_len < strlen(z.z_format))
+ max_format_len = strlen(z.z_format);
hasuntil = nfields > i_untilyear;
if (hasuntil) {
z.z_untilrule.r_filename = filename;
@@ -1065,7 +1082,9 @@ const int iscont;
zones[nzones - 1].z_untiltime > min_time &&
zones[nzones - 1].z_untiltime < max_time &&
zones[nzones - 1].z_untiltime >= z.z_untiltime) {
- error(_("Zone continuation line end time is not after end time of previous line"));
+ error(_(
+"Zone continuation line end time is not after end time of previous line"
+ ));
return FALSE;
}
}
@@ -1089,7 +1108,7 @@ const int nfields;
register int i, j;
int year, month, day;
long dayoff, tod;
- time_t t;
+ zic_t t;
if (nfields != LEAP_FIELDS) {
error(_("wrong number of fields on Leap line"));
@@ -1098,12 +1117,17 @@ const int nfields;
dayoff = 0;
cp = fields[LP_YEAR];
if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
- /*
- * Leapin' Lizards!
- */
- error(_("invalid leaping year"));
- return;
+ /*
+ ** Leapin' Lizards!
+ */
+ error(_("invalid leaping year"));
+ return;
}
+ if (!leapseen || leapmaxyear < year)
+ leapmaxyear = year;
+ if (!leapseen || leapminyear > year)
+ leapminyear = year;
+ leapseen = TRUE;
j = EPOCH_YEAR;
while (j != year) {
if (year > j) {
@@ -1133,7 +1157,7 @@ const int nfields;
return;
}
dayoff = oadd(dayoff, eitol(day - 1));
- if (dayoff < 0 && !TYPE_SIGNED(time_t)) {
+ if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
error(_("time before zero"));
return;
}
@@ -1145,7 +1169,7 @@ const int nfields;
error(_("time too large"));
return;
}
- t = (time_t) dayoff * SECSPERDAY;
+ t = (zic_t) dayoff * SECSPERDAY;
tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
cp = fields[LP_CORR];
{
@@ -1169,7 +1193,9 @@ const int nfields;
return;
}
if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
- error(_("illegal Rolling/Stationary field on Leap line"));
+ error(_(
+ "illegal Rolling/Stationary field on Leap line"
+ ));
return;
}
leapadd(tadd(t, tod), positive, lp->l_value, count);
@@ -1256,7 +1282,8 @@ const char * const timep;
*/
cp = loyearp;
lp = byword(cp, begin_years);
- if (lp != NULL) switch ((int) lp->l_value) {
+ rp->r_lowasnum = lp == NULL;
+ if (!rp->r_lowasnum) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_loyear = INT_MIN;
break;
@@ -1269,14 +1296,11 @@ const char * const timep;
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
error(_("invalid starting year"));
return;
- } else if (noise) {
- if (rp->r_loyear < min_year_representable)
- warning(_("starting year too low to be represented"));
- else if (rp->r_loyear > max_year_representable)
- warning(_("starting year too high to be represented"));
}
cp = hiyearp;
- if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
+ lp = byword(cp, end_years);
+ rp->r_hiwasnum = lp == NULL;
+ if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_hiyear = INT_MIN;
break;
@@ -1292,11 +1316,6 @@ const char * const timep;
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
error(_("invalid ending year"));
return;
- } else if (noise) {
- if (rp->r_loyear < min_year_representable)
- warning(_("ending year too low to be represented"));
- else if (rp->r_loyear > max_year_representable)
- warning(_("ending year too high to be represented"));
}
if (rp->r_loyear > rp->r_hiyear) {
error(_("starting year greater than ending year"));
@@ -1311,8 +1330,6 @@ const char * const timep;
}
rp->r_yrtype = ecpyalloc(typep);
}
- if (rp->r_loyear < min_year && rp->r_loyear > 0)
- min_year = rp->r_loyear;
/*
** Day work.
** Accept things such as:
@@ -1366,13 +1383,25 @@ const long val;
char * const buf;
{
register int i;
- register long shift;
+ register int shift;
for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
buf[i] = val >> shift;
}
static void
+convert64(val, buf)
+const zic_t val;
+char * const buf;
+{
+ register int i;
+ register int shift;
+
+ for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
+ buf[i] = val >> shift;
+}
+
+static void
puttzcode(val, fp)
const long val;
FILE * const fp;
@@ -1383,28 +1412,50 @@ FILE * const fp;
(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
}
+static void
+puttzcode64(val, fp)
+const zic_t val;
+FILE * const fp;
+{
+ char buf[8];
+
+ convert64(val, buf);
+ (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+}
+
static int
atcomp(avp, bvp)
-void * avp;
-void * bvp;
+const void * avp;
+const void * bvp;
{
- if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
- return -1;
- else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
- return 1;
- else return 0;
+ const zic_t a = ((const struct attype *) avp)->at;
+ const zic_t b = ((const struct attype *) bvp)->at;
+
+ return (a < b) ? -1 : (a > b);
+}
+
+static int
+is32(x)
+const zic_t x;
+{
+ return INT32_MIN <= x && x <= INT32_MAX;
}
static void
-writezone(name)
+writezone(name, string)
const char * const name;
+const char * const string;
{
- register FILE * fp;
- register int i, j;
- static char * fullname;
- static struct tzhead tzh;
- time_t ats[TZ_MAX_TIMES];
- unsigned char types[TZ_MAX_TIMES];
+ register FILE * fp;
+ register int i, j;
+ register int leapcnt32, leapi32;
+ register int timecnt32, timei32;
+ register int pass;
+ static char * fullname;
+ static const struct tzhead tzh0;
+ static struct tzhead tzh;
+ zic_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
/*
** Sort.
@@ -1427,14 +1478,13 @@ const char * const name;
while (fromi < timecnt && attypes[fromi].type == 0)
++fromi; /* handled by default rule */
for ( ; fromi < timecnt; ++fromi) {
- if (toi != 0
- && ((attypes[fromi].at
- + gmtoffs[attypes[toi - 1].type])
- <= (attypes[toi - 1].at
- + gmtoffs[toi == 1 ? 0
- : attypes[toi - 2].type]))) {
- attypes[toi - 1].type = attypes[fromi].type;
- continue;
+ if (toi != 0 && ((attypes[fromi].at +
+ gmtoffs[attypes[toi - 1].type]) <=
+ (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
+ : attypes[toi - 2].type]))) {
+ attypes[toi - 1].type =
+ attypes[fromi].type;
+ continue;
}
if (toi == 0 ||
attypes[toi - 1].type != attypes[fromi].type)
@@ -1449,6 +1499,36 @@ const char * const name;
ats[i] = attypes[i].at;
types[i] = attypes[i].type;
}
+ /*
+ ** Correct for leap seconds.
+ */
+ for (i = 0; i < timecnt; ++i) {
+ j = leapcnt;
+ while (--j >= 0)
+ if (ats[i] > trans[j] - corr[j]) {
+ ats[i] = tadd(ats[i], corr[j]);
+ break;
+ }
+ }
+ /*
+ ** Figure out 32-bit-limited starts and counts.
+ */
+ timecnt32 = timecnt;
+ timei32 = 0;
+ leapcnt32 = leapcnt;
+ leapi32 = 0;
+ while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+ --timecnt32;
+ while (timecnt32 > 0 && !is32(ats[timei32])) {
+ --timecnt32;
+ ++timei32;
+ }
+ while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+ --leapcnt32;
+ while (leapcnt32 > 0 && !is32(trans[leapi32])) {
+ --leapcnt32;
+ ++leapi32;
+ }
fullname = erealloc(fullname,
(int) (strlen(directory) + 1 + strlen(name) + 1));
(void) sprintf(fullname, "%s/%s", directory, name);
@@ -1461,70 +1541,154 @@ const char * const name;
if ((fp = fopen(fullname, "wb")) == NULL) {
if (mkdirs(fullname) != 0)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
if ((fp = fopen(fullname, "wb")) == NULL)
err(EXIT_FAILURE, _("can't create %s"), fullname);
}
- convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
- convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
- convert(eitol(leapcnt), tzh.tzh_leapcnt);
- convert(eitol(timecnt), tzh.tzh_timecnt);
- convert(eitol(typecnt), tzh.tzh_typecnt);
- convert(eitol(charcnt), tzh.tzh_charcnt);
- (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
-#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
- DO(tzh_magic);
- DO(tzh_reserved);
- DO(tzh_ttisgmtcnt);
- DO(tzh_ttisstdcnt);
- DO(tzh_leapcnt);
- DO(tzh_timecnt);
- DO(tzh_typecnt);
- DO(tzh_charcnt);
-#undef DO
- for (i = 0; i < timecnt; ++i) {
- j = leapcnt;
- while (--j >= 0)
- if (ats[i] >= trans[j]) {
- ats[i] = tadd(ats[i], corr[j]);
- break;
+ for (pass = 1; pass <= 2; ++pass) {
+ register int thistimei, thistimecnt;
+ register int thisleapi, thisleapcnt;
+ register int thistimelim, thisleaplim;
+ int writetype[TZ_MAX_TIMES];
+ int typemap[TZ_MAX_TYPES];
+ register int thistypecnt;
+ char thischars[TZ_MAX_CHARS];
+ char thischarcnt;
+ int indmap[TZ_MAX_CHARS];
+
+ if (pass == 1) {
+ thistimei = timei32;
+ thistimecnt = timecnt32;
+ thisleapi = leapi32;
+ thisleapcnt = leapcnt32;
+ } else {
+ thistimei = 0;
+ thistimecnt = timecnt;
+ thisleapi = 0;
+ thisleapcnt = leapcnt;
+ }
+ thistimelim = thistimei + thistimecnt;
+ thisleaplim = thisleapi + thisleapcnt;
+ for (i = 0; i < typecnt; ++i)
+ writetype[i] = thistimecnt == timecnt;
+ if (thistimecnt == 0) {
+ /*
+ ** No transition times fall in the current
+ ** (32- or 64-bit) window.
+ */
+ if (typecnt != 0)
+ writetype[typecnt - 1] = TRUE;
+ } else {
+ for (i = thistimei - 1; i < thistimelim; ++i)
+ if (i >= 0)
+ writetype[types[i]] = TRUE;
+ /*
+ ** For America/Godthab and Antarctica/Palmer
+ */
+ if (thistimei == 0)
+ writetype[0] = TRUE;
+ }
+ thistypecnt = 0;
+ for (i = 0; i < typecnt; ++i)
+ typemap[i] = writetype[i] ? thistypecnt++ : -1;
+ for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
+ indmap[i] = -1;
+ thischarcnt = 0;
+ for (i = 0; i < typecnt; ++i) {
+ register char * thisabbr;
+
+ if (!writetype[i])
+ continue;
+ if (indmap[abbrinds[i]] >= 0)
+ continue;
+ thisabbr = &chars[abbrinds[i]];
+ for (j = 0; j < thischarcnt; ++j)
+ if (strcmp(&thischars[j], thisabbr) == 0)
+ break;
+ if (j == thischarcnt) {
+ (void) strcpy(&thischars[(int) thischarcnt],
+ thisabbr);
+ thischarcnt += strlen(thisabbr) + 1;
}
- puttzcode((long) ats[i], fp);
- }
- if (timecnt > 0)
- (void) fwrite((void *) types, (size_t) sizeof types[0],
- (size_t) 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((void *) chars, (size_t) sizeof chars[0],
- (size_t) charcnt, fp);
- for (i = 0; i < leapcnt; ++i) {
- if (roll[i]) {
- if (timecnt == 0 || trans[i] < ats[0]) {
- j = 0;
- while (isdsts[j])
- if (++j >= typecnt) {
- j = 0;
- break;
- }
- } else {
- j = 1;
- while (j < timecnt && trans[i] >= ats[j])
- ++j;
- j = types[j - 1];
+ indmap[abbrinds[i]] = j;
+ }
+#define DO(field) (void) fwrite((void *) tzh.field, \
+ (size_t) sizeof tzh.field, (size_t) 1, fp)
+ tzh = tzh0;
+ (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
+ tzh.tzh_version[0] = ZIC_VERSION;
+ convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
+ convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
+ convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
+ convert(eitol(thistimecnt), tzh.tzh_timecnt);
+ convert(eitol(thistypecnt), tzh.tzh_typecnt);
+ convert(eitol(thischarcnt), tzh.tzh_charcnt);
+ DO(tzh_magic);
+ DO(tzh_version);
+ DO(tzh_reserved);
+ DO(tzh_ttisgmtcnt);
+ DO(tzh_ttisstdcnt);
+ DO(tzh_leapcnt);
+ DO(tzh_timecnt);
+ DO(tzh_typecnt);
+ DO(tzh_charcnt);
+#undef DO
+ for (i = thistimei; i < thistimelim; ++i)
+ if (pass == 1)
+ puttzcode((long) ats[i], fp);
+ else puttzcode64(ats[i], fp);
+ for (i = thistimei; i < thistimelim; ++i) {
+ unsigned char uc;
+
+ uc = typemap[types[i]];
+ (void) fwrite((void *) &uc,
+ (size_t) sizeof uc,
+ (size_t) 1,
+ fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i]) {
+ puttzcode(gmtoffs[i], fp);
+ (void) putc(isdsts[i], fp);
+ (void) putc((unsigned char) indmap[abbrinds[i]], fp);
}
- puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
- } else puttzcode((long) trans[i], fp);
- puttzcode((long) corr[i], fp);
- }
- for (i = 0; i < typecnt; ++i)
- (void) putc(ttisstds[i], fp);
- for (i = 0; i < typecnt; ++i)
- (void) putc(ttisgmts[i], fp);
+ if (thischarcnt != 0)
+ (void) fwrite((void *) thischars,
+ (size_t) sizeof thischars[0],
+ (size_t) thischarcnt, fp);
+ for (i = thisleapi; i < thisleaplim; ++i) {
+ register zic_t todo;
+
+ if (roll[i]) {
+ if (timecnt == 0 || trans[i] < ats[0]) {
+ j = 0;
+ while (isdsts[j])
+ if (++j >= typecnt) {
+ j = 0;
+ break;
+ }
+ } else {
+ j = 1;
+ while (j < timecnt &&
+ trans[i] >= ats[j])
+ ++j;
+ j = types[j - 1];
+ }
+ todo = tadd(trans[i], -gmtoffs[j]);
+ } else todo = trans[i];
+ if (pass == 1)
+ puttzcode((long) todo, fp);
+ else puttzcode64(todo, fp);
+ puttzcode(corr[i], fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i])
+ (void) putc(ttisstds[i], fp);
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i])
+ (void) putc(ttisgmts[i], fp);
+ }
+ (void) fprintf(fp, "\n%s\n", string);
if (ferror(fp) || fclose(fp))
errx(EXIT_FAILURE, _("error writing %s"), fullname);
if (chmod(fullname, mflag) < 0)
@@ -1537,21 +1701,223 @@ const char * const name;
}
static void
-doabbr(abbr, format, letters, isdst)
+doabbr(abbr, format, letters, isdst, doquotes)
char * const abbr;
const char * const format;
const char * const letters;
const int isdst;
+const int doquotes;
{
- if (strchr(format, '/') == NULL) {
+ register char * cp;
+ register char * slashp;
+ register int len;
+
+ slashp = strchr(format, '/');
+ if (slashp == NULL) {
if (letters == NULL)
(void) strcpy(abbr, format);
else (void) sprintf(abbr, format, letters);
- } else if (isdst)
- (void) strcpy(abbr, strchr(format, '/') + 1);
- else {
- (void) strcpy(abbr, format);
- *strchr(abbr, '/') = '\0';
+ } else if (isdst) {
+ (void) strcpy(abbr, slashp + 1);
+ } else {
+ if (slashp > format)
+ (void) strncpy(abbr, format,
+ (unsigned) (slashp - format));
+ abbr[slashp - format] = '\0';
+ }
+ if (!doquotes)
+ return;
+ for (cp = abbr; *cp != '\0'; ++cp)
+ if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
+ strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
+ break;
+ len = strlen(abbr);
+ if (len > 0 && *cp == '\0')
+ return;
+ abbr[len + 2] = '\0';
+ abbr[len + 1] = '>';
+ for ( ; len > 0; --len)
+ abbr[len] = abbr[len - 1];
+ abbr[0] = '<';
+}
+
+static void
+updateminmax(x)
+const int x;
+{
+ if (min_year > x)
+ min_year = x;
+ if (max_year < x)
+ max_year = x;
+}
+
+static int
+stringoffset(result, offset)
+char * result;
+long offset;
+{
+ register int hours;
+ register int minutes;
+ register int seconds;
+
+ result[0] = '\0';
+ if (offset < 0) {
+ (void) strcpy(result, "-");
+ offset = -offset;
+ }
+ seconds = offset % SECSPERMIN;
+ offset /= SECSPERMIN;
+ minutes = offset % MINSPERHOUR;
+ offset /= MINSPERHOUR;
+ hours = offset;
+ if (hours >= HOURSPERDAY) {
+ result[0] = '\0';
+ return -1;
+ }
+ (void) sprintf(end(result), "%d", hours);
+ if (minutes != 0 || seconds != 0) {
+ (void) sprintf(end(result), ":%02d", minutes);
+ if (seconds != 0)
+ (void) sprintf(end(result), ":%02d", seconds);
+ }
+ return 0;
+}
+
+static int
+stringrule(result, rp, dstoff, gmtoff)
+char * result;
+const struct rule * const rp;
+const long dstoff;
+const long gmtoff;
+{
+ register long tod;
+
+ result = end(result);
+ if (rp->r_dycode == DC_DOM) {
+ register int month, total;
+
+ if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
+ return -1;
+ total = 0;
+ for (month = 0; month < rp->r_month; ++month)
+ total += len_months[0][month];
+ (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
+ } else {
+ register int week;
+
+ if (rp->r_dycode == DC_DOWGEQ) {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
+ return -1;
+ } else if (rp->r_dycode == DC_DOWLEQ) {
+ if (rp->r_dayofmonth == len_months[1][rp->r_month])
+ week = 5;
+ else {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
+ return -1;
+ }
+ } else return -1; /* "cannot happen" */
+ (void) sprintf(result, "M%d.%d.%d",
+ rp->r_month + 1, week, rp->r_wday);
+ }
+ tod = rp->r_tod;
+ if (rp->r_todisgmt)
+ tod += gmtoff;
+ if (rp->r_todisstd && rp->r_stdoff == 0)
+ tod += dstoff;
+ if (tod < 0) {
+ result[0] = '\0';
+ return -1;
+ }
+ if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
+ (void) strcat(result, "/");
+ if (stringoffset(end(result), tod) != 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void
+stringzone(result, zpfirst, zonecount)
+char * result;
+const struct zone * const zpfirst;
+const int zonecount;
+{
+ register const struct zone * zp;
+ register struct rule * rp;
+ register struct rule * stdrp;
+ register struct rule * dstrp;
+ register int i;
+ register const char * abbrvar;
+
+ result[0] = '\0';
+ zp = zpfirst + zonecount - 1;
+ stdrp = dstrp = NULL;
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
+ continue;
+ if (rp->r_yrtype != NULL)
+ continue;
+ if (rp->r_stdoff == 0) {
+ if (stdrp == NULL)
+ stdrp = rp;
+ else return;
+ } else {
+ if (dstrp == NULL)
+ dstrp = rp;
+ else return;
+ }
+ }
+ if (stdrp == NULL && dstrp == NULL) {
+ /*
+ ** There are no rules running through "max".
+ ** Let's find the latest rule.
+ */
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
+ (rp->r_hiyear == stdrp->r_hiyear &&
+ rp->r_month > stdrp->r_month))
+ stdrp = rp;
+ }
+ if (stdrp != NULL && stdrp->r_stdoff != 0)
+ return; /* We end up in DST (a POSIX no-no). */
+ /*
+ ** Horrid special case: if year is 2037,
+ ** presume this is a zone handled on a year-by-year basis;
+ ** do not try to apply a rule to the zone.
+ */
+ if (stdrp != NULL && stdrp->r_hiyear == 2037)
+ return;
+ }
+ if (stdrp == NULL && zp->z_nrules != 0)
+ return;
+ abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
+ doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
+ if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ if (dstrp == NULL)
+ return;
+ doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
+ if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
+ if (stringoffset(end(result),
+ -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
}
}
@@ -1564,7 +1930,7 @@ const int zonecount;
register struct rule * rp;
register int i, j;
register int usestart, useuntil;
- register time_t starttime, untiltime;
+ register zic_t starttime, untiltime;
register long gmtoff;
register long stdoff;
register int year;
@@ -1572,8 +1938,17 @@ const int zonecount;
register int startttisstd;
register int startttisgmt;
register int type;
- char startbuf[BUFSIZ];
-
+ register char * startbuf;
+ register char * ab;
+ register char * envvar;
+ register int max_abbr_len;
+ register int max_envvar_len;
+
+ max_abbr_len = 2 + max_format_len + max_abbrvar_len;
+ max_envvar_len = 2 * max_abbr_len + 5 * 9;
+ startbuf = emalloc(max_abbr_len + 1);
+ ab = emalloc(max_abbr_len + 1);
+ envvar = emalloc(max_envvar_len + 1);
INITIALIZE(untiltime);
INITIALIZE(starttime);
/*
@@ -1583,11 +1958,57 @@ const int zonecount;
typecnt = 0;
charcnt = 0;
/*
- ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
+ ** Thanks to Earl Chew
** for noting the need to unconditionally initialize startttisstd.
*/
startttisstd = FALSE;
startttisgmt = FALSE;
+ min_year = max_year = EPOCH_YEAR;
+ if (leapseen) {
+ updateminmax(leapminyear);
+ updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
+ }
+ for (i = 0; i < zonecount; ++i) {
+ zp = &zpfirst[i];
+ if (i < zonecount - 1)
+ updateminmax(zp->z_untilrule.r_loyear);
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (rp->r_lowasnum)
+ updateminmax(rp->r_loyear);
+ if (rp->r_hiwasnum)
+ updateminmax(rp->r_hiyear);
+ }
+ }
+ /*
+ ** Generate lots of data if a rule can't cover all future times.
+ */
+ stringzone(envvar, zpfirst, zonecount);
+ if (noise && envvar[0] == '\0') {
+ register char * wp;
+
+wp = ecpyalloc(_("no POSIX environment variable for zone"));
+ wp = ecatalloc(wp, " ");
+ wp = ecatalloc(wp, zpfirst->z_name);
+ warning(wp);
+ ifree(wp);
+ }
+ if (envvar[0] == '\0') {
+ if (min_year >= INT_MIN + YEARSPERREPEAT)
+ min_year -= YEARSPERREPEAT;
+ else min_year = INT_MIN;
+ if (max_year <= INT_MAX - YEARSPERREPEAT)
+ max_year += YEARSPERREPEAT;
+ else max_year = INT_MAX;
+ }
+ /*
+ ** For the benefit of older systems,
+ ** generate data from 1900 through 2037.
+ */
+ if (min_year > 1900)
+ min_year = 1900;
+ if (max_year < 2037)
+ max_year = 2037;
for (i = 0; i < zonecount; ++i) {
/*
** A guess that may well be corrected later.
@@ -1605,7 +2026,7 @@ const int zonecount;
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
doabbr(startbuf, zp->z_format,
- (char *) NULL, stdoff != 0);
+ (char *) NULL, stdoff != 0, FALSE);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
@@ -1633,9 +2054,8 @@ const int zonecount;
}
for ( ; ; ) {
register int k;
- register time_t jtime, ktime;
+ register zic_t jtime, ktime;
register long offset;
- char buf[BUFSIZ];
INITIALIZE(ktime);
if (useuntil) {
@@ -1691,23 +2111,27 @@ const int zonecount;
stdoff);
doabbr(startbuf, zp->z_format,
rp->r_abbrvar,
- rp->r_stdoff != 0);
+ rp->r_stdoff != 0,
+ FALSE);
continue;
}
if (*startbuf == '\0' &&
- startoff == oadd(zp->z_gmtoff,
- stdoff)) {
- doabbr(startbuf, zp->z_format,
- rp->r_abbrvar,
- rp->r_stdoff != 0);
+ startoff == oadd(zp->z_gmtoff,
+ stdoff)) {
+ doabbr(startbuf,
+ zp->z_format,
+ rp->r_abbrvar,
+ rp->r_stdoff !=
+ 0,
+ FALSE);
}
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
- doabbr(buf, zp->z_format, rp->r_abbrvar,
- rp->r_stdoff != 0);
+ doabbr(ab, zp->z_format, rp->r_abbrvar,
+ rp->r_stdoff != 0, FALSE);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
- type = addtype(offset, buf, rp->r_stdoff != 0,
+ type = addtype(offset, ab, rp->r_stdoff != 0,
rp->r_todisstd, rp->r_todisgmt);
addtt(ktime, type);
}
@@ -1740,12 +2164,15 @@ error(_("can't determine time zone abbreviation to use just after until time"));
starttime = tadd(starttime, -gmtoff);
}
}
- writezone(zpfirst->z_name);
+ writezone(zpfirst->z_name, envvar);
+ ifree(startbuf);
+ ifree(ab);
+ ifree(envvar);
}
static void
addtt(starttime, type)
-const time_t starttime;
+const zic_t starttime;
int type;
{
if (starttime <= min_time ||
@@ -1764,7 +2191,7 @@ int type;
}
if (timecnt >= TZ_MAX_TIMES) {
error(_("too many transitions?!"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
attypes[timecnt].at = starttime;
attypes[timecnt].type = type;
@@ -1783,15 +2210,15 @@ const int ttisgmt;
if (isdst != TRUE && isdst != FALSE) {
error(_("internal error - addtype called with bad isdst"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
if (ttisstd != TRUE && ttisstd != FALSE) {
error(_("internal error - addtype called with bad ttisstd"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
if (ttisgmt != TRUE && ttisgmt != FALSE) {
error(_("internal error - addtype called with bad ttisgmt"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
/*
** See if there's already an entry for this zone type.
@@ -1810,7 +2237,11 @@ const int ttisgmt;
*/
if (typecnt >= TZ_MAX_TYPES) {
error(_("too many local time types"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
+ }
+ if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
+ error(_("UTC offset out of range"));
+ exit(EXIT_FAILURE);
}
gmtoffs[i] = gmtoff;
isdsts[i] = isdst;
@@ -1829,7 +2260,7 @@ const int ttisgmt;
static void
leapadd(t, positive, rolling, count)
-const time_t t;
+const zic_t t;
const int positive;
const int rolling;
int count;
@@ -1838,13 +2269,13 @@ int count;
if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
error(_("too many leap seconds"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
for (i = 0; i < leapcnt; ++i)
if (t <= trans[i]) {
if (t == trans[i]) {
error(_("repeated leap second moment"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
}
@@ -1862,7 +2293,7 @@ int count;
}
static void
-adjleap P((void))
+adjleap(void)
{
register int i;
register long last = 0;
@@ -1898,7 +2329,7 @@ const char * const type;
error(_("wild result from command execution"));
warnx(_("command was '%s', result was %d"), buf, result);
for ( ; ; )
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
static int
@@ -1979,8 +2410,9 @@ register char * cp;
emalloc((int) ((strlen(cp) + 1) * sizeof *array));
nsubs = 0;
for ( ; ; ) {
- while (isascii(*cp) && isspace((unsigned char) *cp))
- ++cp;
+ while (isascii((unsigned char) *cp) &&
+ isspace((unsigned char) *cp))
+ ++cp;
if (*cp == '\0' || *cp == '#')
break;
array[nsubs++] = dp = cp;
@@ -2014,17 +2446,17 @@ const long t2;
t = t1 + t2;
if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
error(_("time overflow"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
return t;
}
-static time_t
+static zic_t
tadd(t1, t2)
-const time_t t1;
+const zic_t t1;
const long t2;
{
- register time_t t;
+ register zic_t t;
if (t1 == max_time && t2 > 0)
return max_time;
@@ -2033,7 +2465,7 @@ const long t2;
t = t1 + t2;
if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
error(_("time overflow"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
return t;
}
@@ -2043,14 +2475,14 @@ const long t2;
** 1970, 00:00 LOCAL time - in that year that the rule refers to.
*/
-static time_t
+static zic_t
rpytime(rp, wantedy)
register const struct rule * const rp;
register const int wantedy;
{
register int y, m, i;
register long dayoff; /* with a nod to Margaret O. */
- register time_t t;
+ register zic_t t;
if (wantedy == INT_MIN)
return min_time;
@@ -2080,7 +2512,7 @@ register const int wantedy;
--i;
else {
error(_("use of 2/29 in non leap-year"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
--i;
@@ -2114,16 +2546,15 @@ register const int wantedy;
}
if (i < 0 || i >= len_months[isleap(y)][m]) {
if (noise)
- warning(_("rule goes past start/end of month--will not work with pre-2004 versions of zic"));
+ warning(_("rule goes past start/end of month--\
+will not work with pre-2004 versions of zic"));
}
}
- if (dayoff < 0 && !TYPE_SIGNED(time_t))
- return min_time;
if (dayoff < min_time / SECSPERDAY)
return min_time;
if (dayoff > max_time / SECSPERDAY)
return max_time;
- t = (time_t) dayoff * SECSPERDAY;
+ t = (zic_t) dayoff * SECSPERDAY;
return tadd(t, rp->r_tod);
}
@@ -2133,10 +2564,48 @@ const char * const string;
{
register int i;
+ if (strcmp(string, GRANDPARENTED) != 0) {
+ register const char * cp;
+ register char * wp;
+
+ /*
+ ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
+ ** optionally followed by a + or - and a number from 1 to 14.
+ */
+ cp = string;
+ wp = NULL;
+ while (isascii((unsigned char) *cp) &&
+ isalpha((unsigned char) *cp))
+ ++cp;
+ if (cp - string == 0)
+wp = _("time zone abbreviation lacks alphabetic at start");
+ if (noise && cp - string > 3)
+wp = _("time zone abbreviation has more than 3 alphabetics");
+ if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
+wp = _("time zone abbreviation has too many alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii((unsigned char) *cp) &&
+ isdigit((unsigned char) *cp))
+ if (*cp++ == '1' &&
+ *cp >= '0' && *cp <= '4')
+ ++cp;
+ }
+ if (*cp != '\0')
+wp = _("time zone abbreviation differs from POSIX standard");
+ if (wp != NULL) {
+ wp = ecpyalloc(wp);
+ wp = ecatalloc(wp, " (");
+ wp = ecatalloc(wp, string);
+ wp = ecatalloc(wp, ")");
+ warning(wp);
+ ifree(wp);
+ }
+ }
i = strlen(string) + 1;
if (charcnt + i > TZ_MAX_CHARS) {
error(_("too many, or too long, time zone abbreviations"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
(void) strcpy(&chars[charcnt], string);
charcnt += eitol(i);
@@ -2144,7 +2613,7 @@ const char * const string;
static int
mkdirs(argname)
-char * const argname;
+char * argname;
{
register char * name;
register char * cp;