Index: lib/libc/time/README
===================================================================
RCS file: /cvsroot/src/lib/libc/time/README,v
retrieving revision 1.5
diff -u -r1.5 README
--- lib/libc/time/README 29 Jan 2002 12:40:33 -0000 1.5
+++ lib/libc/time/README 31 Dec 2009 20:52:24 -0000
@@ -1,4 +1,6 @@
-@(#)README 7.11
+@(#)README 8.3
+This file is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
"What time is it?" -- Richard Deacon as The King
"Any time you want it to be." -- Frank Baxter as The Scientist
@@ -52,8 +54,10 @@
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 +67,9 @@
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!
Index: lib/libc/time/Theory
===================================================================
RCS file: /cvsroot/src/lib/libc/time/Theory,v
retrieving revision 1.8
diff -u -r1.8 Theory
--- lib/libc/time/Theory 27 May 2004 20:39:49 -0000 1.8
+++ lib/libc/time/Theory 31 Dec 2009 20:52:24 -0000
@@ -1,6 +1,7 @@
# $NetBSD: Theory,v 1.8 2004/05/27 20:39:49 kleink Exp $
-@(#)Theory 7.15
-
+@(#)Theory 8.3
+This file is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
----- Outline -----
@@ -10,29 +11,29 @@
Calendrical issues
Time and time zones on Mars
-
----- 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
+
-Please send corrections to this web page to the
-time zone mailing list.
+This file is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
+Please send corrections to this web page to the
+time zone mailing list.
-The public-domain time zone database contains code and data
+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 Sources for Time Zone and Daylight Saving Time Data
-@(#)tz-link.htm 7.42
+@(#)tz-link.htm 8.22
The
tz databasetz or zoneinfo)
+to time zone
+boundaries, UTC offsets, and
+daylight-saving
+rules.
+This database (often called tz or zoneinfo)
is used by several implementations,
including
-the GNU C Library used in
-GNU/Linux,
+the
+GNU
+C Library used in
+GNU/Linux,
FreeBSD,
-NetBSD,
-OpenBSD,
-Cygwin,
-DJGPP,
-HP-UX,
-IRIX,
+NetBSD,
+OpenBSD,
+Cygwin,
+DJGPP,
+AIX,
Mac OS X,
OpenVMS,
-Solaris,
-Tru64, and
-UnixWare.
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, America/New_York
-represents most of the US eastern time zone;
-America/Indianapolis represents most of Indiana, which
-uses eastern time without daylight saving time (DST);
+represents most of the US eastern time zone;
+America/Phoenix represents most of Arizona, which
+uses mountain time without daylight saving time (DST);
America/Detroit represents most of Michigan, which uses
-eastern time but with different DST rules in 1975;
+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 TZ environment variable to
+Indiana, which switched from central to eastern time in 1991
+and switched back in 2006.
+To use the database on an extended POSIX
+implementation set the TZ environment variable to
the location's full name, e.g., TZ="America/New_York".
In the tz database's
-FTP distribution,
+FTP distribution
the code is in the file tzcodeC.tar.gz,
where C is the code's version;
similarly, the data are in tzdataD.tar.gz,
where D is the data's version.
-The following shell commands download
-these files to a GNU/Linux or similar host; see the downloaded
+The following shell commands download
+these files to a GNU/Linux or similar host;
+see the downloaded
README file for what to do next.
wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
gzip -dc tzcode*.tar.gz | tar -xf -
@@ -87,148 +107,238 @@
The data are by no means authoritative. If you find errors, please
send changes to the time zone
mailing list. You can also subscribe to the
-mailing list, retrieve the archive of old
+href="http://news.gmane.org/gmane.comp.time.tz">browse recent
+messages sent to the mailing list, subscribe to it,
+retrieve the full archive of old
messages (in gzip compressed format), or retrieve archived older versions of code
+href="ftp://munnari.oz.au/pub/oldtz">archived older versions of code
and data.
The Web has several other sources for time zone and daylight saving time data.
Here are some recent links that may be of interest.
Web pages using recent versions of the tz database
+
+These are listed roughly in ascending order of complexity and fanciness.
+
-- Date and Time Gateway
-is a text-based point-and-click interface to tables of current time
-throughout the world.
-- Fancier web interfaces, roughly in ascending order of complexity, include:
-
-- The Worldwide Holiday
-& Festival Site lists DST-related clock changes along with
-holidays.
-- The World Clock -
-Time Zones
-is a web interface to a time zone database derived from
-
tz's.
+- Date and Time Gateway
+lets you see the
TZ values directly.
+- Current
+Time in 1000 Places uses descriptions of the values.
+- Time Zone Converter
+uses a pulldown menu.
+- Complete
+timezone information for all countries displays tables of DST rules.
+
- The World Clock -
+Time Zones lets you sort zone names and convert times.
+- Graphical Display of
+Time Zones and Daylight Saving Times shows a graph of time
+difference versus time for any pair of locations.
+- The World Time Engine
+also contains data about time zone boundaries; it supports queries via place
+names and shows location maps.
Other time zone database formats
- The
Internet Calendaring and Scheduling Core Object Specification
-(iCalendar) specification published by the IETF
-Calendaring and Scheduling Working Group (calsch) covers time zone
-data; see its VTIMEZONE calendar component.
+(iCalendar), Internet RFC 2445, published by the (now-concluded) IETF
+Calendaring and Scheduling Working Group (calsch)
+covers time zone
+data; see its VTIMEZONE calendar component.
+The Calendaring and Scheduling
+Consortium is promoting further work in this area. iCalendar
+TIMEZONE Problems and Recommendations offers guidelines and
+recommendations for the use of VTIMEZONE and tz.
+- Extended Daylight
+Saving Time Links, Advisories and Changes lists vendor material on recent
+daylight saving time changes.
+- Timezone
+Registry and Service Recommendations discusses a
+strategy for defining and deploying a time zone
+registration process that would establish unique names for each
+version of each
tz zone, along with a polygonal
+representation of the geographical area corresponding to the
+zone.
- The www-rdf-calendar
-list discusses RDF-based calendar
+list discusses RDF-based calendar
and group scheduling systems, and has a workspace on time zone
data converted from
tz. An earlier schema was sketched out by Tim Berners-Lee.
-- XCal
-was a draft XML document type
-definition that corresponded to iCalendar.
+href="http://www.w3.org/2000/01/foo">schema was sketched out.
Other tz compilers
-- Vzic iCalendar
-Timezone Converter describes a program Vzic that compiles
+
- Vzic iCalendar
+Timezone Converter describes a C
+program that compiles
tz source into iCalendar-compatible VTIMEZONE files.
Vzic is freely
-available under the GNU
-General Public License (GPL).
+available under the GNU
+General Public License (GPL).
+- tziCal - tz
+database conversion utility is like Vzic, except for the .NET framework.
- DateTime::TimeZone
contains a script
parse_olson that compiles
tz source into Perl
modules. It is part of the Perl DateTime Project, which is freely
-available under both the GPL and the Perl Artistic
-License. DateTime::TimeZone also contains a script
+available under both the GPL and the Perl Artistic
+License. DateTime::TimeZone also contains a script
tests_from_zdump that generates test cases for each clock
transition in the tz database.
-- International Components for
-Unicode (ICU) contains a C/C++ library for internationalization that
-has a compiler from tz source into an ICU-specific format.
-ICU is freely available under a BSD-style license.
+- International Components for
+Unicode (ICU) contains C/C++ and Java
+libraries for internationalization that
+has a compiler from
tz source
+into an ICU-specific format.
+ICU is freely available under a
+BSD-style license.
- Joda Time - Java date
-and time API contains a class
+and time API
+contains a class
org.joda.time.tz.ZoneInfoCompiler that compiles
tz source into a Joda-specific binary format. Joda Time
-is freely available under a BSD-style license.
+is freely available under a BSD-style license.
+- PyTZ - Python Time
+Zone Library compiles
tz source into
+Python.
+It is freely available under a BSD-style license.
+- TZInfo - Ruby Timezone Library
+compiles
tz source into
+Ruby.
+It is freely available under the MIT license.
+- The Chronos Date/Time
+Library is a Smalltalk class
+library that compiles
tz source into a time zone repository whose format
+is either proprietary or an XML-encoded
+representation.
+- Starting with version 8.5, Tcl
+contains a developer-oriented parser that compiles tz
+source into text files, along with a runtime that can read those
+files. Tcl is freely available under a BSD-style
+license.
Other tz binary file readers
-- The GNU C Library
+
- The GNU C
+Library
has an independent, thread-safe implementation of
a
tz binary file reader.
This library is freely available under the
-GNU Lesser General Public License (LGPL),
-and is widely used in GNU/Linux systems.
-- ZoneInfo.java
+GNU Lesser General Public License
+(LGPL),
+and is widely used in GNU/Linux systems.
+- ZoneInfo.java
is a
tz binary file reader written in Java.
-It is freely available under the GNU LGPL.
-- Python time zones
-is a
tz binary file reader written in Python. It is freely available
-under a BSD-style license.
-
-Other tz-based time zone conversion software
-
+It is freely available under the LGPL.
+- Tcl, mentioned above, also contains a
+
tz binary file reader.
+
+Other tz-based time zone software
+
+- FoxClocks
+is an extension for Mozilla
+Toolkit applications like Firefox, Thunderbird, and
+Sunbird.
+It displays multiple clocks in the application window, and has a mapping
+interface to Google Earth.
+It is freely available under the GPL.
+- International
+clock (intclock) is a multi-timezone clock for
+GNU/Linux and similar systems. It is freely available
+under the GPL.
+- PublicDomain
+has a copy of a recent
tz database, accessed via a C# library. As its
+name suggests, it is in the public domain. Only current time stamps
+are well supported; historical data are compiled into the runtime but
+are not easily accessible.
- Sun Java releases since 1.4
-contain a copy of a recent tz database in a Java-specific
-format.
+contain a copy of a subset of a recent tz database in a
+Java-specific format.
+- Time Zone is
+a WordPress plugin. It is freely
+available under a BSD-style license.
- HyperCard
-time zones calculator is a HyperCard stack.
+href="http://veladg.com/velaterra.html">VelaTerra is
+a Mac OS X program. Its developers
+offer free
+licenses to tz contributors.
- World Time Explorer is a
+href="http://worldtimeexplorer.com/">World Time Explorer is a
Microsoft Windows program.
Other time zone databases
-- Atlas Query
-- Astrodienst is Astrodienst's Web version of Shanks's
+
- Atlas Query
+is Astrodienst's Web version of Shanks's
excellent time zone history atlases published in both computer and book form by computer
+and book form (one volume
+for the USA, and one for
+other locations) by Astro Communications Services.
- WORLDTIME: interactive atlas,
time info, public holidays
contains information on local time, sunrise and sunset,
and public holidays in several hundred cities around the world.
-- World Time Server
+
- World Time Server
is another time zone database.
- World Time Zones
-contains data from the Time Service Department of the US Naval Observatory
-(USNO), used as the source
+contains data from the Time Service Department of the
+US Naval Observatory, used as the source
for the
usno* files in the tz distribution.
-- Airlines, Airplanes
-and Airports lists current standard times for thousands of
-airports around the world. This seems to be derived from
-the Standard
-Schedules Information Manual (SSIM) of the
-the International Air Transport
-Association,
-which gives current time zone rules for
-all the airports served by commercial aviation.
+- The Standard
+Schedules Information Manual of the
+International Air Transport
+Association
+gives current time zone rules for airports served by commercial aviation.
+- Some Microsoft Windows versions contain time zone information in
+an undocumented format, with IDs that can be mapped to
TZ
+values using the Windows
+→ Tzid table maintained by the CLDR data mentioned
+below.
Maps
-- The United States Central
-Intelligence Agency (CIA) publishes a time
+
- The United States Central
+Intelligence Agency (CIA) publishes a time
zone map; the
Perry-Castañeda
@@ -238,37 +348,60 @@
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.
-- World timezones map with
-current time
+
- Current time around the world
+and standard time zones map of the world
has several fancy time zone maps; it covers Russia particularly well.
-The maps' pictorial quality is not quite as good as the CIA's
+The maps' pictorial quality is not quite as good as the
+CIA's
but the maps are more up to date.
Time zone boundaries
-- Time
+
- TZ timezone maps contains a shapefile of the
+
tz regions in the world.
+- Administrative Divisions
+of Countries ("Statoids") contains detailed lists of
+
tz-related zone subdivision data.
+- Time
zone boundaries for multizone countries summarizes legal
boundaries between time zones within countries.
- Manifold.net's Free Maps and
-GIS Data includes a Manifold-format map of world time zone
-boundaries distributed under the GPL. The GeoCommunity's International
-Time Zones publishes the same data in other formats.
-- The US Geological Survey's National Atlas of the United States
-publishes the Time
+GIS
+Data includes a Manifold-format map of
+world time zone boundaries distributed under the
+GPL.
+- The US Geological Survey's National Atlas of
+the United States
+publishes the Time
Zones of the United States in the public domain.
- The GeoCommunity lists several commercial sources for International
Time Zones and Time Zone Data.
+- A ship within the territorial
+waters of any nation uses that nation's time. In international
+waters, time zone boundaries are meridians 15° apart, except that
+UTC−12 and UTC+12 are each 7.5° wide and are separated by
+the 180° meridian (not by the International Date Line, which is
+for land and territorial waters only). A captain can change ship's
+clocks any time after entering a new time zone; midnight changes are
+common.
Civil time concepts and history
-- A Walk through Time
+
- A
+Walk through Time
surveys the evolution of timekeeping.
- About Daylight
-Saving Time - History, rationale, laws and dates
-is an overall history of DST.
+Saving Time - History, rationale, laws & dates
+is an overall history of DST.
+- Saving Time,
+Saving Energy discusses a primary justification for DST.
+- Who Knew? A Brief
+History of Daylight Saving Time summarizes some of the contentious
+history of DST.
- The
Time of Internet
describes time zones and daylight saving time,
@@ -277,20 +410,17 @@
- A History of
the International Date Line tells the story of the most important
time zone boundary.
-- Basic Time
+
- Basic Time
Zone Concepts discusses terminological issues behind time zones.
National histories of legal time
- Australia
-- The Community Relations Division of the New South Wales (NSW)
-Attorney General's Department maintains a history of
-daylight saving in NSW.
-- Austria
-- The Federal Office of Metrology and Surveying publishes a
-table of daylight saving time in Austria (in German).
+- The Parliamentary Library has commissioned research
+note on daylight saving time in Australia.
+The Bureau of Meteorology publishes a list of
+Implementation Dates of Daylight Savings Time within Australia.
- Belgium
- The Royal Observatory of Belgium maintains a table of Canada
- The Institute for National Measurement Standards publishes current
and some older information about Time
-Zones and Daylight Saving Time.
+href="http://inms-ienm.nrc-cnrc.gc.ca/time_services/daylight_saving_e.html">Time
+Zones & Daylight Saving Time.
- Chile
-- WebExhibits publishes a history of official time (in Spanish) originally
-written by the Chilean Hydrographic and Oceanographic Service.
+- The Chilean Hydrographic and Oceanographic Service publishes a history of
+official time (in Spanish).
- Germany
- The National Institute for Science and Technology maintains the Realisation of
Legal Time in Germany.
- Israel
- The Interior Ministry periodically issues announcements (in Hebrew).
- Mexico
- The Investigation and Analysis Service of the Mexican Library of
@@ -331,10 +460,15 @@
covers the history of local time in the Netherlands from ancient times.
- New Zealand
- The Department of Internal Affairs maintains a brief history about
-daylight saving. The privately-maintained Time Changes in
-New Zealand has more details.
+href="http://dia.govt.nz/diawebsite.nsf/wpg_URL/Resource-material-Information-We-Provide-About-Daylight-Saving">About
+Daylight Saving. The privately-maintained History of New Zealand
+time has more details.
+- Norway
+- The Norwegian Meteorological Institute lists
+Summer
+time in Norway (in Norwegian), citing the
+Institute of Theoretical Astrophysics, Oslo.
- Singapore
- Why
@@ -346,56 +480,86 @@
legal time in Britain discusses in detail the country
with perhaps the best-documented history of clock adjustments.
The National Physical Laboratory also maintains an archive
-of summer time dates.
+href="http://www.npl.co.uk/server.php?show=ConWebDoc.2714">Archive
+of Summer time dates.
Precision timekeeping
- The
+href="http://literature.agilent.com/litweb/pdf/5965-7984E.pdf">The
Science of Timekeeping is a thorough introduction
to the theory and practice of precision timekeeping.
-- NTP: The Network Time Protocol
+
- NTP: The Network
+Time Protocol
discusses how to synchronize clocks of
Internet hosts.
-- A
-Few Facts Concerning GMT, UT, and the RGO
-answers questions like "What is the difference between GMT and UTC?"
-- Astronomical
-Times explains more abstruse astronomical time scales like TT, TCG,
-and TDB.
-- The IAU's Standards Of Fundamental
-Astronomy (SOFA) initiative publishes Fortran code for converting
-among time scales like TAI, TDB, TT and UTC.
-- Basics of
+
- Timezone
+Options for DHCP
+(Internet RFC 4833)
+specifies a DHCP option for a server to configure
+a client's time zone and daylight saving settings automatically.
+- A Few
+Facts Concerning GMT, UT, and
+the RGO
+answers questions like "What is the
+difference between GMT and UTC?"
+- Astronomical
+Times explains more abstruse astronomical time scales like
+TDT,
+TCG, and
+TDB.
+Time
+Scales goes into more detail, particularly for historical variants.
+- The IAU's SOFA
+initiative publishes Fortran
+code for converting among time scales like
+TAI,
+TDB, TDT and
+UTC.
+- Basics of
Space Flight - Reference Systems - Time Conventions
briefly explains interplanetary space flight timekeeping.
- Technical
Notes on Mars Solar Time as Adopted by the Mars24 Sunclock briefly
-describes Mars Coordinated Time (MTC) and the diverse local time
+describes Mars Coordinated Time (MTC) and the
+diverse local time
scales used by each landed mission on Mars.
+- LeapSecond.com is
+dedicated not only to leap seconds but to precise time and frequency
+in general. It covers the state of the art in amateur timekeeping, and
+how the art has progressed over the past few decades.
- Bulletins
-maintained by the IERS EOP (PC) contains official publications of
+maintained by the
+IERS
+EOP
+(PC)
contains official publications of
the Earth Orientation Parameters Product Center of the
International Earth Rotation Service, the committee that decides
when leap seconds occur.
- The Leap
-Second Discussion List covers McCarthy and Klepczynski's proposal
-to discontinue leap seconds, published in GPS World 10, 11
-(1999-11), 50–57 and discussed further in R. A. Nelson et al.,
+href="http://six.pairlist.net/mailman/listinfo/leapsecs">Leap
+Second Discussion List covers McCarthy
+and Klepczynski's proposal to discontinue leap seconds,
+discussed further in
The
-leap second: its history and possible future,
-Metrologia
-38 (2001), 509–529.
-The
-Future of Leap Seconds catalogs information about this
+leap second: its history and possible future.
+The (now disbanded) AAS Leap Second
+Committee has solicited input on this proposal.
+The
+Future of Leap Seconds covers this
contentious issue.
Time notation
@@ -403,41 +567,82 @@
A Summary of
the International Standard Date and Time Notation 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
-ISO 8601:2000).
+summary of
+ISO
+8601:2004 -- Data elements and interchange formats -- Information
+interchange -- Representation of dates and times.
+
+XML
+Schema: Datatypes - dateTime specifies a format inspired by
+ISO 8601 that is in common use in XML data.
-Section 3.3 of Internet RFC 2822
+Internet
+Message Format (Internet RFC 2822) §3.3
specifies the time notation used in email and HTTP headers.
+href="ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt">HTTP
+headers.
-Internet RFC
-3339 specifies an ISO 8601 profile for use in new Internet
+Date and Time
+on the Internet: Timestamps (Internet RFC 3339)
+specifies an ISO 8601
+profile for use in new Internet
protocols.
-The
+Date & Time
+Formats on the Web surveys web- and Internet-oriented date and time
+formats.
+
+The
Best of Dates, the Worst of Dates covers many problems encountered
by software developers when handling dates and time stamps.
-
-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 POSIX the
-tz database contains English abbreviations for all time
-stamps but in many cases these are merely inventions of the database
+ The Unicode Common Locale Data Repository
+(CLDR) Project has localizations for time zone names,
+abbreviations, identifiers, and formats. For example, it contains
+French translations for "Eastern European Summer Time", "EEST", and
+"Bucharest". By-Type
+Chart: names.metazone shows these values for many locales.
+ICU contains a mechanism for using this data.
+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 POSIX the tz
+database contains English abbreviations for all time stamps but in
+many cases these are merely inventions of the database
maintainers.
+Numeric time zone abbreviations typically count hours east of
+UTC, e.g., +09 for Japan and
+-10 for Hawaii. However, the POSIX
+TZ environment variable uses the opposite convention. For
+example, one might use TZ="JST-9" and
+TZ="HST10" for Japan and Hawaii, respectively. If the
+tz database is available, it is usually better to use
+settings like TZ="Asia/Tokyo" and
+TZ="Pacific/Honolulu" instead, as this should avoid
+confusion, handle old time stamps better, and insulate you better from
+any future changes to the rules. One should never set
+POSIX TZ to a value like
+"GMT-9", though, since this would falsely claim that
+local time is nine hours ahead of UTC and the time zone
+is called "GMT".
Related indexes
- Time and the Arts
-- Open Directory -
+
- Open Directory -
Reference: Time
-- Google Directory - Reference > Time
-- Yahoo! Science > Measurements and Units > Time
+- Google Directory
+- Reference > Time
+- Yahoo!
+Directory > Science > Measurements and Units > Time
Index: lib/libc/time/tzfile.5
===================================================================
RCS file: /cvsroot/src/lib/libc/time/tzfile.5,v
retrieving revision 1.13
diff -u -r1.13 tzfile.5
--- lib/libc/time/tzfile.5 9 Mar 2009 19:24:27 -0000 1.13
+++ lib/libc/time/tzfile.5 31 Dec 2009 20:52:25 -0000
@@ -17,7 +17,9 @@
begin with the magic characters
.Dq TZif
to identify them as time zone information files,
-followed by sixteen bytes reserved for future use,
+followed by a character identifying the version of the file's format
+(as of 2005, either an ASCII NUL or a '2')
+followed by fifteen bytes containing zeroes reserved for future use,
followed by six four-byte values of type
.Fa long ,
written in a
@@ -65,7 +67,10 @@
transition time.
These values serve as indices into an array of
.Fa ttinfo
-structures that appears next in the file;
+.I ttinfo
+structures (with
+.I tzh_typecnt
+entries) that appears next in the file;
these structures are defined as follows:
.Bd -literal
struct ttinfo {
@@ -136,7 +141,20 @@
.Va tzh_timecnt
is zero or the time argument is less than the first transition time recorded
in the file.
+.PP
+For version-2-format time zone files,
+the above header and data is followed by a second header and data,
+identical in format except that
+eight bytes are used for each transition time or leap second time.
+After the second header and data comes a newline-enclosed,
+POSIX-TZ-environment-variable-style string for use in handling instants
+after the last transition time stored in the file
+(with nothing between the newlines if there is no POSIX representation for
+such instants).
.Sh SEE ALSO
.Xr ctime 3 ,
.Xr localtime 3 ,
.Xr time 3
+.\" @(#)tzfile.5 8.2
+.\" This file is in the public domain, so clarified as of
+.\" 1996-06-05 by Arthur David Olson.
Index: lib/libc/time/tzfile.h
===================================================================
RCS file: /cvsroot/src/lib/libc/time/tzfile.h,v
retrieving revision 1.8
diff -u -r1.8 tzfile.h
--- lib/libc/time/tzfile.h 22 Jan 1998 07:06:59 -0000 1.8
+++ lib/libc/time/tzfile.h 31 Dec 2009 20:52:25 -0000
@@ -5,7 +5,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.
*/
/*
@@ -23,7 +23,7 @@
#ifndef lint
#ifndef NOID
#if 0
-static char tzfilehid[] = "@(#)tzfile.h 7.14";
+static char tzfilehid[] = "@(#)tzfile.h 8.1";
#endif
#endif /* !defined NOID */
#endif /* !defined lint */
@@ -51,8 +51,9 @@
#define TZ_MAGIC "TZif"
struct tzhead {
- char tzh_magic[4]; /* TZ_MAGIC */
- char tzh_reserved[16]; /* reserved for future use */
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_version[1]; /* '\0' or '2' as of 2005 */
+ char tzh_reserved[15]; /* reserved--must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
@@ -87,18 +88,22 @@
*/
/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+*/
+
+/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
-/*
-** The TZ_MAX_TIMES value below is enough to handle a bit more than a
-** year's worth of solar time (corrected daily to the nearest second) or
-** 138 years of Pacific Presidential Election time
-** (where there are three time zone transitions every fourth year).
-*/
-#define TZ_MAX_TIMES 370
+#define TZ_MAX_TIMES 1200
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
@@ -108,7 +113,7 @@
#ifdef NOSOLAR
/*
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
-** as noted by Earl Chew .
+** as noted by Earl Chew.
*/
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif /* !defined NOSOLAR */
@@ -159,33 +164,20 @@
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
-/*
-** Accurate only for the past couple of centuries;
-** that will probably do.
-*/
-
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-#ifndef USG
-
/*
-** Use of the underscored variants may cause problems if you move your code to
-** certain System-V-based systems; for maximum portability, use the
-** underscore-free variants. The underscored variants are provided for
-** backward compatibility only; they may disappear from future versions of
-** this file.
-*/
-
-#define SECS_PER_MIN SECSPERMIN
-#define MINS_PER_HOUR MINSPERHOUR
-#define HOURS_PER_DAY HOURSPERDAY
-#define DAYS_PER_WEEK DAYSPERWEEK
-#define DAYS_PER_NYEAR DAYSPERNYEAR
-#define DAYS_PER_LYEAR DAYSPERLYEAR
-#define SECS_PER_HOUR SECSPERHOUR
-#define SECS_PER_DAY SECSPERDAY
-#define MONS_PER_YEAR MONSPERYEAR
+** Since everything in isleap is modulo 400 (or a factor of 400), we know that
+** isleap(y) == isleap(y % 400)
+** and so
+** isleap(a + b) == isleap((a + b) % 400)
+** or
+** isleap(a + b) == isleap(a % 400 + b % 400)
+** This is true even if % means modulo rather than Fortran remainder
+** (which is allowed by C89 but not C99).
+** We use this to avoid addition overflow problems.
+*/
-#endif /* !defined USG */
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#endif /* !defined TZFILE_H */
Index: lib/libc/time/tzselect.8
===================================================================
RCS file: /cvsroot/src/lib/libc/time/tzselect.8,v
retrieving revision 1.3
diff -u -r1.3 tzselect.8
--- lib/libc/time/tzselect.8 10 Nov 1999 20:32:31 -0000 1.3
+++ lib/libc/time/tzselect.8 31 Dec 2009 20:52:25 -0000
@@ -40,4 +40,6 @@
nonzero otherwise.
.SH "SEE ALSO"
newctime(3), tzfile(5), zdump(8), zic(8)
-.\" @(#)tzselect.8 1.3
+.\" @(#)tzselect.8 8.2
+.\" This file is in the public domain, so clarified as of
+.\" 2009-05-17 by Arthur David Olson.
Index: lib/libc/time/tzselect.ksh
===================================================================
RCS file: /cvsroot/src/lib/libc/time/tzselect.ksh,v
retrieving revision 1.5
diff -u -r1.5 tzselect.ksh
--- lib/libc/time/tzselect.ksh 10 Nov 1999 20:32:31 -0000 1.5
+++ lib/libc/time/tzselect.ksh 31 Dec 2009 20:52:25 -0000
@@ -2,12 +2,12 @@
#
# $NetBSD: tzselect.ksh,v 1.5 1999/11/10 20:32:31 kleink Exp $
#
-# '@(#)tzselect.ksh 1.7'
+VERSION='@(#)tzselect.ksh 8.2'
# Ask the user about the time zone, and output the resulting TZ value to stdout.
# Interact with the user via stderr and stdin.
-# Contributed by Paul Eggert .
+# Contributed by Paul Eggert.
# Porting notes:
#
@@ -47,6 +47,21 @@
exit 1
}
+if [ "$1" = "--help" ]; then
+ cat <
#ifndef lint
@@ -7,7 +11,7 @@
#endif /* !defined NOID */
#endif /* !defined lint */
-static char elsieid[] = "@(#)zdump.c 7.31";
+static char elsieid[] = "@(#)zdump.c 8.9";
/*
** This code has been made independent of the rest of the time
@@ -21,6 +25,19 @@
#include "time.h" /* for struct tm */
#include "stdlib.h" /* for exit, malloc, atoi */
#include
+#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
@@ -71,19 +88,32 @@
#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__ */
@@ -93,8 +123,7 @@
#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 */
@@ -106,34 +135,125 @@
*/
#ifndef _
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#define _(msgid) gettext(msgid)
-#else /* !(HAVE_GETTEXT - 0) */
-#define _(msgid) msgid
-#endif /* !(HAVE_GETTEXT - 0) */
+#else /* !HAVE_GETTEXT */
+#define _(msgid) __UNCONST(msgid)
+#endif /* !HAVE_GETTEXT */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
#define TZ_DOMAIN "tz"
#endif /* !defined TZ_DOMAIN */
-#ifndef P
-#define P(x) x
-#endif /* !defined P */
-
extern char ** environ;
-extern int getopt P((int argc, char * const argv[],
- const char * options));
+extern int getopt(int argc, char * const argv[],
+ const char * options);
extern char * optarg;
extern int optind;
-static const 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));
-int main P((int, char **));
+static time_t absolute_min_time;
+static time_t absolute_max_time;
static size_t longest;
static char * progname;
-static void show P((char * zone, time_t t, int v));
+static int warned;
+
+static const 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);
+int main(int, char **);
+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;
+}
+
+static void
+usage(const char *xprogname, FILE *stream, int status)
+{
+ (void) fprintf(stream,
+_("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n\
+\n\
+Report bugs to tz@elsie.nci.nih.gov.\n"),
+ xprogname, xprogname);
+ exit(status);
+}
int
main(argc, argv)
@@ -143,65 +263,79 @@
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
- (void) setlocale(LC_MESSAGES, "");
+ INITIALIZE(cutlotime);
+ INITIALIZE(cuthitime);
+#if HAVE_GETTEXT
+ (void) setlocale(LC_ALL, "");
#ifdef TZ_DOMAINDIR
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
-#endif /* defined(TEXTDOMAINDIR) */
+#endif /* defined TEXTDOMAINDIR */
(void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
progname = argv[0];
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
(void) printf("%s\n", elsieid);
- (void) exit(EXIT_SUCCESS);
+ exit(EXIT_SUCCESS);
+ } 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 != EOF && c != -1) ||
(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
- (void) fprintf(stderr,
-_("%s: usage is %s [ --version ] [ -v ] [ -c cutoff ] zonename ...\n"),
- argv[0], argv[0]);
- (void) exit(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;
+ usage(progname, stderr, EXIT_FAILURE);
+ }
+ 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));
@@ -226,43 +360,43 @@
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) strlcpy(buf, abbr(&tm), (sizeof buf));
+ 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) strlcpy(buf, abbr(&newtm),
- (sizeof buf));
+ 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;
@@ -272,37 +406,123 @@
err(EXIT_FAILURE, _("Error writing standard output"));
}
exit(EXIT_SUCCESS);
+ /* If exit fails to exit... */
+ return EXIT_FAILURE;
+}
- /* gcc -Wall pacifier */
- for ( ; ; )
- continue;
+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;
+
+ 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
-hunt(name, lot, hit)
-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) strlcpy(loab, abbr(&lotm), (sizeof loab));
- while ((hit - lot) >= 2) {
- t = lot / 2 + hit / 2;
+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 time_t
+hunt(char *name, time_t lot, time_t hit)
+{
+ 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 +531,7 @@
}
/*
-** 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 +539,14 @@
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 +558,36 @@
}
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 const char *
@@ -373,3 +602,84 @@
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));
+}
Index: lib/libc/time/zic.8
===================================================================
RCS file: /cvsroot/src/lib/libc/time/zic.8,v
retrieving revision 1.15
diff -u -r1.15 zic.8
--- lib/libc/time/zic.8 9 Mar 2009 19:24:27 -0000 1.15
+++ lib/libc/time/zic.8 31 Dec 2009 20:52:25 -0000
@@ -222,7 +222,12 @@
.El
.Pp
A zone line has the form
-.Dl Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]
+.sp
+.nf
+.ti +.5i
+.ta \w'Zone\0\0'u +\w'Australia/Adelaide\0\0'u +\w'GMTOFF\0\0'u +\w'RULES/SAVE\0\0'u +\w'FORMAT\0\0'u
+Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]]
+.sp
For example:
.Dl Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
The fields that make up a zone line are:
@@ -256,16 +261,17 @@
a slash
.Pq \&/
separates standard and daylight abbreviations.
-.It UNTIL
+.TP
+.B 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.
-.El
+fields of a rule; trailing fields can be omitted, and default to the
+earliest possible value for the missing fields.
+.IP
The next line must be a
.Dq continuation
line; this has the same form as a zone line except that the
@@ -273,11 +279,11 @@
.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
+.q until
+information in the previous line in the file used by the previous line.
+Continuation lines may contain
+.q until
+information, just as zone lines do, indicating that the next line is a further
continuation.
.Pp
A link line has the form
@@ -338,13 +344,81 @@
.Dq Rolling
if the leap second time given by the other fields should be interpreted as
local wall clock time.
-.El
-.Sh NOTES
+.SH "EXTENDED EXAMPLE"
+Here is an extended example of
+.I zic
+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,
+.IR zic
+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
.Pa /usr/share/zoneinfo
- standard directory used for created files
@@ -352,3 +426,6 @@
.Xr ctime 3 ,
.Xr tzfile 5 ,
.Xr zdump 8
+.\" @(#)zic.8 8.5
+.\" This file is in the public domain, so clarified as of
+.\" 2009-05-17 by Arthur David Olson.
Index: lib/libc/time/zic.c
===================================================================
RCS file: /cvsroot/src/lib/libc/time/zic.c,v
retrieving revision 1.24
diff -u -r1.24 zic.c
--- lib/libc/time/zic.c 23 Apr 2009 01:39:47 -0000 1.24
+++ lib/libc/time/zic.c 31 Dec 2009 20:52:25 -0000
@@ -1,4 +1,8 @@
/* $NetBSD: zic.c,v 1.24 2009/04/23 01:39:47 lukem Exp $ */
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
#include
#ifndef lint
@@ -7,12 +11,20 @@
#endif /* !defined NOID */
#endif /* !defined lint */
-static char elsieid[] = "@(#)zic.c 7.116";
+static char elsieid[] = "@(#)zic.c 8.20";
#include "private.h"
#include "locale.h"
#include "tzfile.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 */
+
#if HAVE_SYS_STAT_H
#include "sys/stat.h"
#endif
@@ -26,7 +38,7 @@
/*
** 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.
@@ -37,6 +49,11 @@
#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;
@@ -45,6 +62,8 @@
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 */
@@ -61,7 +80,7 @@
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 */
};
/*
@@ -87,80 +106,88 @@
int z_nrules;
struct rule z_untilrule;
- time_t z_untiltime;
+ zic_t z_untiltime;
};
-extern int getopt P((int argc, char * const argv[],
- const char * options));
-extern int link P((const char * fromname, const char * toname));
+extern int getopt(int argc, char * const argv[],
+ const char * options);
+extern int link(const char * fromname, const char * toname);
extern char * optarg;
extern int optind;
-static int atcomp P((const void *, const void *));
-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, int abbrlen, 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));
-int main P((int, char **));
-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 int, 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);
+int main(int, char **);
+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 time_t tadd P((time_t t1, long t2));
-static void usage P((void));
-static void warning P((const char * const));
-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 int,
+ const struct zone * zp, int ntzones);
+static void setboundaries(void);
+static zic_t tadd(zic_t t1, long t2);
+static void usage(FILE *stream, int status);
+static void warning(const char * const);
+static void writezone(const char * name, const char * string);
+static int yearistype(int year, const char * type);
+static int atcomp(const void *avp, const void *bvp);
+static void updateminmax(int x);
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 int noise;
static const char * rfilename;
static int rlinenum;
@@ -270,8 +297,8 @@
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 },
@@ -348,7 +375,7 @@
};
static struct attype {
- time_t at;
+ zic_t at;
unsigned char type;
} attypes[TZ_MAX_TIMES];
static long gmtoffs[TZ_MAX_TYPES];
@@ -357,7 +384,7 @@
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];
@@ -374,7 +401,7 @@
(void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
progname, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
return ptr;
}
@@ -388,19 +415,6 @@
** 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;
@@ -454,11 +468,15 @@
}
static void
-usage P((void))
+usage(FILE *stream, int status)
{
- (void) fprintf(stderr, _("%s: usage is %s [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
- progname, progname);
- (void) exit(EXIT_FAILURE);
+ (void) fprintf(stream, _("%s: usage is %s \
+[ --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"),
+ progname, progname);
+ exit(status);
}
static const char * psxrules;
@@ -466,7 +484,6 @@
static const char * directory;
static const char * leapsec;
static const char * yitcommand;
-static int sflag = FALSE;
int
main(argc, argv)
@@ -486,17 +503,24 @@
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
#endif /* defined TEXTDOMAINDIR */
(void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
progname = argv[0];
+ if (TYPE_BIT(zic_t) < 64) {
+ (void) fprintf(stderr, "%s: %s\n", progname,
+ _("wild compilation-time specification of zic_t"));
+ exit(EXIT_FAILURE);
+ }
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
(void) printf("%s\n", elsieid);
- (void) exit(EXIT_SUCCESS);
+ exit(EXIT_SUCCESS);
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(stdout, EXIT_SUCCESS);
}
while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
switch (c) {
default:
- usage();
+ usage(stderr, EXIT_FAILURE);
case 'd':
if (directory == NULL)
directory = optarg;
@@ -504,7 +528,7 @@
(void) fprintf(stderr,
_("%s: More than one -d option specified\n"),
progname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
case 'l':
@@ -514,7 +538,7 @@
(void) fprintf(stderr,
_("%s: More than one -l option specified\n"),
progname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
case 'p':
@@ -524,7 +548,7 @@
(void) fprintf(stderr,
_("%s: More than one -p option specified\n"),
progname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
case 'y':
@@ -534,7 +558,7 @@
(void) fprintf(stderr,
_("%s: More than one -y option specified\n"),
progname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
case 'L':
@@ -544,18 +568,18 @@
(void) fprintf(stderr,
_("%s: More than one -L option specified\n"),
progname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
break;
case 'v':
noise = TRUE;
break;
case 's':
- sflag = TRUE;
+ (void) printf("%s: -s ignored\n", progname);
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)
@@ -571,7 +595,7 @@
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) {
/*
@@ -587,6 +611,11 @@
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);
@@ -600,26 +629,26 @@
}
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
@@ -631,75 +660,54 @@
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) {
const char *e = strerror(errno);
(void) fprintf(stderr,
_("%s: Can't link from %s to %s: %s\n"),
progname, fromname, toname, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
ifree(fromname);
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
@@ -734,7 +742,7 @@
}
static void
-associate P((void))
+associate(void)
{
register struct zone * zp;
register struct rule * rp;
@@ -796,7 +804,7 @@
*/
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.
@@ -806,7 +814,7 @@
}
}
if (errors)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
static void
@@ -830,7 +838,7 @@
(void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
progname, name, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
wantcont = FALSE;
for (num = 1; ; ++num) {
@@ -840,7 +848,7 @@
cp = strchr(buf, '\n');
if (cp == NULL) {
error(_("line too long"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
*cp = '\0';
fields = getfields(buf);
@@ -884,7 +892,7 @@
(void) fprintf(stderr,
_("%s: panic: Invalid l_value %d\n"),
progname, lp->l_value);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
ifree((char *) fields);
@@ -892,14 +900,14 @@
if (ferror(fp)) {
(void) fprintf(stderr, _("%s: Error reading %s\n"),
progname, filename);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
if (fp != stdin && fclose(fp)) {
const char *e = strerror(errno);
(void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
progname, filename, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
if (wantcont)
error(_("expected continuation line not found"));
@@ -919,7 +927,8 @@
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;
@@ -929,27 +938,32 @@
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
@@ -974,6 +988,8 @@
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;
@@ -1079,6 +1095,8 @@
}
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;
@@ -1099,7 +1117,9 @@
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;
}
}
@@ -1123,7 +1143,7 @@
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"));
@@ -1132,12 +1152,17 @@
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) {
@@ -1167,7 +1192,7 @@
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;
}
@@ -1179,7 +1204,7 @@
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];
{
@@ -1203,7 +1228,9 @@
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);
@@ -1290,7 +1317,8 @@
*/
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;
@@ -1301,18 +1329,15 @@
(void) fprintf(stderr,
_("%s: panic: Invalid l_value %d\n"),
progname, lp->l_value);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
} 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;
@@ -1326,15 +1351,10 @@
(void) fprintf(stderr,
_("%s: panic: Invalid l_value %d\n"),
progname, lp->l_value);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
} 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"));
@@ -1349,8 +1369,6 @@
}
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:
@@ -1404,13 +1422,25 @@
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;
@@ -1421,28 +1451,50 @@
(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)
const void * avp;
const void * bvp;
{
- if (((const struct attype *) avp)->at < ((const struct attype *) bvp)->at)
- return -1;
- else if (((const struct attype *) avp)->at > ((const 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.
@@ -1465,14 +1517,13 @@
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)
@@ -1487,6 +1538,36 @@
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); /* XXX: sprintf is safe */
@@ -1498,104 +1579,391 @@
(void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
progname, fullname, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
if ((fp = fopen(fullname, "wb")) == NULL) {
if (mkdirs(fullname) != 0)
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
if ((fp = fopen(fullname, "wb")) == NULL) {
const char *e = strerror(errno);
(void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
progname, fullname, e);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
- 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);
+ 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;
+ }
+ 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 = 0; i < timecnt; ++i) {
- j = leapcnt;
- while (--j >= 0)
- if (ats[i] >= trans[j]) {
- ats[i] = tadd(ats[i], corr[j]);
- break;
+ 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) ats[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);
}
- 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];
- }
- 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);
+ (void) fprintf(fp, "\n%s\n", string);
if (ferror(fp) || fclose(fp)) {
(void) fprintf(stderr, _("%s: Error writing %s\n"),
progname, fullname);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
static void
-doabbr(abbr, abbrlen, format, letters, isdst)
+doabbr(abbr, abbrlen, format, letters, isdst, doquotes)
char * const abbr;
const int abbrlen;
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)strncpy(abbr, format, abbrlen - 1);
- else
- (void)snprintf(abbr, abbrlen, format, letters);
- } else if (isdst)
- (void)strncpy(abbr, strchr(format, '/') + 1, abbrlen - 1);
- else {
- (void)strncpy(abbr, format, abbrlen - 1);
- *strchr(abbr, '/') = '\0';
+ (void) strlcpy(abbr, format, abbrlen);
+ else (void) snprintf(abbr, abbrlen, format, letters);
+ } else if (isdst) {
+ (void) strlcpy(abbr, slashp + 1, abbrlen);
+ } 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, resultlen, zpfirst, zonecount)
+char * result;
+const int resultlen;
+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 || zp->z_stdoff != 0))
+ return;
+ abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
+ doabbr(result, resultlen, 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), resultlen - strlen(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;
}
}
@@ -1608,7 +1976,7 @@
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;
@@ -1616,8 +1984,17 @@
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);
/*
@@ -1627,11 +2004,57 @@
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, max_envvar_len+1, 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.
@@ -1648,8 +2071,8 @@
startoff = zp->z_gmtoff;
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
- doabbr(startbuf, sizeof startbuf, zp->z_format,
- (char *) NULL, stdoff != 0);
+ doabbr(startbuf, max_abbr_len + 1, zp->z_format,
+ (char *) NULL, stdoff != 0, FALSE);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
@@ -1677,9 +2100,8 @@
}
for ( ; ; ) {
register int k;
- register time_t jtime, ktime;
+ register zic_t jtime, ktime;
register long offset;
- char buf[BUFSIZ];
INITIALIZE(ktime);
if (useuntil) {
@@ -1733,27 +2155,32 @@
if (ktime < starttime) {
startoff = oadd(zp->z_gmtoff,
stdoff);
- doabbr(startbuf,sizeof startbuf,
+ doabbr(startbuf,
+ max_abbr_len + 1,
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,sizeof startbuf,
- zp->z_format,
- rp->r_abbrvar,
- rp->r_stdoff != 0);
+ startoff == oadd(zp->z_gmtoff,
+ stdoff)) {
+ doabbr(startbuf,
+ max_abbr_len + 1,
+ 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, sizeof buf, zp->z_format,
- rp->r_abbrvar, rp->r_stdoff != 0);
+ doabbr(ab, max_abbr_len+1, 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);
}
@@ -1764,7 +2191,7 @@
strchr(zp->z_format, '%') == NULL &&
strchr(zp->z_format, '/') == NULL)
(void)strncpy(startbuf, zp->z_format,
- sizeof(startbuf) - 1);
+ max_abbr_len + 1 - 1);
eat(zp->z_filename, zp->z_linenum);
if (*startbuf == '\0')
error(_("can't determine time zone abbreviation to use just after until time"));
@@ -1787,12 +2214,15 @@
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 ||
@@ -1811,7 +2241,7 @@
}
if (timecnt >= TZ_MAX_TIMES) {
error(_("too many transitions?!"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
attypes[timecnt].at = starttime;
attypes[timecnt].type = type;
@@ -1830,15 +2260,15 @@
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.
@@ -1857,7 +2287,11 @@
*/
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;
@@ -1876,7 +2310,7 @@
static void
leapadd(t, positive, rolling, count)
-const time_t t;
+const zic_t t;
const int positive;
const int rolling;
int count;
@@ -1885,13 +2319,13 @@
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;
}
@@ -1909,7 +2343,7 @@
}
static void
-adjleap P((void))
+adjleap(void)
{
register int i;
register long last = 0;
@@ -1946,7 +2380,7 @@
(void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
progname, buf, result);
for ( ; ; )
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
static int
@@ -2027,8 +2461,9 @@
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;
@@ -2038,7 +2473,12 @@
else while ((*dp = *cp++) != '"')
if (*dp != '\0')
++dp;
- else error(_("Odd number of quotation marks"));
+ else {
+ error(_(
+ "Odd number of quotation marks"
+ ));
+ exit(1);
+ }
} while (*cp != '\0' && *cp != '#' &&
(!isascii(*cp) || !isspace((unsigned char) *cp)));
if (isascii(*cp) && isspace((unsigned char) *cp))
@@ -2059,17 +2499,17 @@
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;
@@ -2078,7 +2518,7 @@
t = t1 + t2;
if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
error(_("time overflow"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
return t;
}
@@ -2088,14 +2528,14 @@
** 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;
@@ -2125,7 +2565,7 @@
--i;
else {
error(_("use of 2/29 in non leap-year"));
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
}
--i;
@@ -2159,16 +2599,15 @@
}
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);
}
@@ -2178,10 +2617,48 @@
{
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)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
charcnt += eitol(i);
@@ -2189,7 +2666,7 @@
static int
mkdirs(argname)
-char * const argname;
+char * argname;
{
register char * name;
register char * cp;
@@ -2245,7 +2722,7 @@
(void) fprintf(stderr,
_("%s: %d did not sign extend correctly\n"),
progname, i);
- (void) exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
return l;
}