Index: vendor/tzcode/dist/usr.sbin/zic/README =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/README (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/README (revision 130777) @@ -1,66 +1,80 @@ -@(#)README 7.10 +@(#)README 7.11 "What time is it?" -- Richard Deacon as The King "Any time you want it to be." -- Frank Baxter as The Scientist (from the Bell System film "About Time") The 1989 update of the time zone package featured * POSIXization (including interpretation of POSIX-style TZ environment variables, provided by Guy Harris), * ANSIfication (including versions of "mktime" and "difftime"), * SVIDulation (an "altzone" variable) * MACHination (the "gtime" function) * corrections to some time zone data (including corrections to the rules for Great Britain and New Zealand) * reference data from the United States Naval Observatory for folks who want to do additional time zones * and the 1989 data for Saudi Arabia. (Since this code will be treated as "part of the implementation" in some places and as "part of the application" in others, there's no good way to name functions, such as timegm, that are not part of the proposed ANSI C standard; such functions have kept their old, underscore-free names in this update.) And the "dysize" function has disappeared; it was present to allow compilation of the "date" command on old BSD systems, and a version of "date" is now provided in the package. The "date" command is not created when you "make all" since it may lack options provided by the version distributed with your operating system, or may not interact with the system in the same way the native version does. Since POSIX frowns on correct leap second handling, the default behavior of the "zic" command (in the absence of a "-L" option) has been changed to omit leap second information from its output files. -Be sure to read the comments in "Makefile" and make any changes -needed to make things right for your system. +Here is a recipe for acquiring, building, installing, and testing the +tz distribution on a GNU/Linux or similar host. + + mkdir tz + cd tz + wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz' + gzip -dc tzcode*.tar.gz | tar -xf - + gzip -dc tzdata*.tar.gz | tar -xf - + +Be sure to read the comments in "Makefile" and make any changes needed +to make things right for your system, especially if you are using some +platform other than GNU/Linux. Then run the following commands, +substituting your desired installation directory for "$HOME/tzdir": + + make TOPDIR=$HOME/tzdir install + $HOME/tzdir/etc/zdump -v America/Los_Angeles 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: * give an idea of the variety of local time rules that have existed in the past and thus an idea of the variety that may be expected in the future; * provide a test of the generality of the local time rule description system. The information in the time zone data files is by no means authoritative; if you know that the rules are different from those in a file, by all means feel free to change file (and please send the changed version to tz@elsie.nci.nih.gov for use in the future). Europeans take note! Thanks to these Timezone Caballeros who've made major contributions to the time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz; Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales for testing work, and to Gwillim Law for checking local mean time data. None of them are responsible for remaining errors. Look in the ~ftp/pub directory of elsie.nci.nih.gov for updated versions of these files. Please send comments or information to tz@elsie.nci.nih.gov. Index: vendor/tzcode/dist/usr.sbin/zic/Theory =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/Theory (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/Theory (revision 130777) @@ -1,285 +1,552 @@ -@(#)Theory 7.6 +@(#)Theory 7.15 ----- Outline ----- Time and date functions Names of time zone regions Time zone abbreviations + Calendrical issues + Time and time zones on Mars ----- Time and date functions ----- These time and date functions are upwards compatible with POSIX.1, -an international standard for Unix-like systems. +an international standard for UNIX-like systems. As of this writing, the current edition of POSIX.1 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 POSIX.1 has the following properties and limitations. * In POSIX.1, time display in a process is controlled by the environment variable TZ. Unfortunately, the POSIX.1 TZ string takes a form that is hard to describe and is error-prone in practice. Also, POSIX.1 TZ strings can't deal with other (for example, Israeli) daylight saving time rules, or situations where more than two time zone abbreviations are used in an area. The POSIX.1 TZ string takes the following form: stdoffset[dst[offset],date[/time],date[/time]] where: - + std and dst are 3 or more characters specifying the standard and daylight saving time (DST) zone names. offset is of the form `[-]hh:[mm[:ss]]' and specifies the offset west of UTC. The default DST offset is one hour ahead of standard time. date[/time],date[/time] specifies the beginning and end of DST. If this is absent, the system supplies its own rules for DST, and these can differ from year to year; typically US DST rules are used. time takes the form `hh:[mm[:ss]]' and defaults to 02:00. date takes one of the following forms: Jn (1<=n<=365) origin-1 day number not counting February 29 n (0<=n<=365) origin-0 day number counting February 29 if present Mm.n.d (0[Sunday]<=d<=6[Saturday], 1<=n<=5, 1<=m<=12) for the dth day of week n of month m of the year, where week 1 is the first week in which day d appears, and `5' stands for the last week in which day d appears (which may be either the 4th or 5th week). * In POSIX.1, when a TZ value like "EST5EDT" is parsed, typically the current US DST rules are used, but this means that the US DST rules are compiled into each program that does time conversion. This means that when US time conversion rules change (as in the United States in 1987), all programs that do time conversion must be recompiled to ensure proper results. * In POSIX.1, there's no tamper-proof way for a process to learn the system's best idea of local wall clock. (This is important for applications that an administrator wants used only at certain times-- without regard to whether the user has fiddled the "TZ" environment variable. While an administrator can "do everything in UTC" to get around the problem, doing so is inconvenient and precludes handling daylight saving time shifts--as might be required to limit phone calls to off-peak hours.) * POSIX.1 requires that systems ignore leap seconds. These are the extensions that have been made to the POSIX.1 functions: * The "TZ" environment variable is used in generating the name of a file from which time zone information is read (or is interpreted a la POSIX); "TZ" is no longer constrained to be a three-letter time zone name followed by a number of hours and an optional three-letter daylight time zone name. The daylight saving time rules to be used for a particular time zone are encoded in the time zone file; the format of the file allows U.S., Australian, and other rules to be encoded, and allows for situations where more than two time zone abbreviations are used. It was recognized that allowing the "TZ" environment variable to take on values such as "America/New_York" might cause "old" programs (that expect "TZ" to have a certain form) to operate incorrectly; consideration was given to using some other environment variable (for example, "TIMEZONE") to hold the string used to generate the time zone information file name. In the end, however, it was decided to continue using "TZ": it is widely used for time zone purposes; separately maintaining both "TZ" and "TIMEZONE" seemed a nuisance; and systems where "new" forms of "TZ" might cause problems can simply use TZ values such as "EST5EDT" which can be used both by "new" programs (a la POSIX) and "old" programs (as zone names and offsets). * To handle places where more than two time zone abbreviations are used, the functions "localtime" and "gmtime" set tzname[tmp->tm_isdst] (where "tmp" is the value the function returns) to the time zone abbreviation to be used. This differs from POSIX.1, where the elements of tzname are only changed as a result of calls to tzset. * Since the "TZ" environment variable can now be used to control time conversion, the "daylight" and "timezone" variables are no longer needed. (These variables are defined and set by "tzset"; however, their values will not be used by "localtime.") * The "localtime" function has been set up to deliver correct results for near-minimum or near-maximum time_t values. (A comment in the source code tells how to get compatibly wrong results). * A function "tzsetwall" has been added to arrange for the system's best approximation to local wall clock time to be delivered by subsequent calls to "localtime." Source code for portable applications that "must" run on local wall clock time should call "tzsetwall();" if such code is moved to "old" systems that don't provide tzsetwall, you won't be able to generate an executable program. (These time zone functions also arrange for local wall clock time to be used if tzset is called--directly or indirectly--and there's no "TZ" environment variable; portable applications should not, however, rely on this behavior since it's not the way SVR2 systems behave.) * These functions can account for leap seconds, thanks to Bradley White (bww@k.cs.cmu.edu). Points of interest to folks with other systems: * This package is already part of many POSIX-compliant hosts, including BSD, HP, Linux, Network Appliance, SCO, SGI, and Sun. On such hosts, the primary use of this package is to update obsolete time zone rule tables. To do this, you may need to compile the time zone compiler `zic' supplied with this package instead of using the system `zic', since the format of zic's input changed slightly in late 1994, and many vendors still do not support the new input format. -* The Unix Version 7 "timezone" function is not present in this package; +* The UNIX Version 7 "timezone" function is not present in this package; it's impossible to reliably map timezone's arguments (a "minutes west of GMT" value and a "daylight saving time in effect" flag) to a time zone abbreviation, and we refuse to guess. Programs that in the past used the timezone function may now examine tzname[localtime(&clock)->tm_isdst] to learn the correct time zone abbreviation to use. Alternatively, use localtime(&clock)->tm_zone if this has been enabled. * The 4.2BSD gettimeofday function is not used in this package. This formerly let users obtain the current UTC offset and DST flag, but this functionality was removed in later versions of BSD. * In SVR2, time conversion fails for near-minimum or near-maximum time_t values when doing conversions for places that don't use UTC. This package takes care to do these conversions correctly. The functions that are conditionally compiled if STD_INSPIRED is defined should, at this point, be looked on primarily as food for thought. They are not in any sense "standard compatible"--some are not, in fact, specified in *any* standard. They do, however, represent responses of various authors to standardization proposals. Other time conversion proposals, in particular the one developed by folks at Hewlett Packard, offer a wider selection of functions that provide capabilities beyond those provided here. The absence of such functions from this package is not meant to discourage the development, standardization, or use of such functions. Rather, their absence reflects the decision to make this package contain valid extensions to POSIX.1, to ensure its broad acceptability. If more powerful time conversion functions can be standardized, so much the better. ----- Names of time zone rule files ----- -The names of this package's installed time zone rule files are chosen to -help minimize possible future incompatibilities due to political events. -Ordinarily, names of countries are not used, to avoid incompatibilities -when countries change their name (e.g. Zaire->Congo) or -when locations change countries (e.g. Hong Kong from UK colony to China). +The time zone rule file naming conventions attempt to strike a balance +among the following goals: + * Uniquely identify every national region where clocks have all + agreed since 1970. This is essential for the intended use: static + clocks keeping local civil time. + + * Indicate to humans as to where that region is. This simplifes use. + + * Be robust in the presence of political changes. This reduces the + number of updates and backward-compatibility hacks. For example, + names of countries are ordinarily not used, to avoid + incompatibilities when countries change their name + (e.g. Zaire->Congo) or when locations change countries + (e.g. Hong Kong from UK colony to China). + + * Be portable to a wide variety of implementations. + This promotes use of the technology. + + * Use a consistent naming convention over the entire world. + This simplifies both use and maintenance. + +This naming convention is not intended for use by inexperienced users +to select TZ values by themselves (though they can of course examine +and reuse existing settings). Distributors should provide +documentation and/or a simple selection interface that explains the +names; see the 'tzselect' program supplied with this distribution for +one example. + Names normally have the form AREA/LOCATION, where AREA is the name of a continent or ocean, and LOCATION is the name of a specific location within that region. North and South America share the same area, `America'. Typical names are `Africa/Cairo', `America/New_York', and `Pacific/Honolulu'. Here are the general rules used for choosing location names, in decreasing order of importance: - Use only valid Posix file names. Use only Ascii letters, digits, `.', - `-' and `_'. Do not exceed 14 characters or start with `-'. - E.g. prefer `Brunei' to `Bandar_Seri_Begawan'. + Use only valid POSIX file name components (i.e., the parts of + names other than `/'). Within a file name component, + use only ASCII letters, `.', `-' and `_'. Do not use + digits, as that might create an ambiguity with POSIX + TZ strings. A file name component must not exceed 14 + characters or start with `-'. E.g., prefer `Brunei' + to `Bandar_Seri_Begawan'. Include at least one location per time zone rule set per country. - One such location is enough. + One such location is enough. Use ISO 3166 (see the file + iso3166.tab) to help decide whether something is a country. If all the clocks in a country's region have agreed since 1970, don't bother to include more than one location even if subregions' clocks disagreed before 1970. Otherwise these tables would become annoyingly large. If a name is ambiguous, use a less ambiguous alternative; e.g. many cities are named San Jose and Georgetown, so prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'. Keep locations compact. Use cities or small islands, not countries or regions, so that any future time zone changes do not split locations into different time zones. E.g. prefer `Paris' to `France', since France has had multiple time zones. - Use traditional English spelling, e.g. prefer `Rome' to `Roma', and + Use mainstream English spelling, e.g. prefer `Rome' to `Roma', and prefer `Athens' to the true name (which uses Greek letters). - The Posix file name restrictions encourage this rule. + The POSIX file name restrictions encourage this rule. Use the most populous among locations in a country's time zone, e.g. prefer `Shanghai' to `Beijing'. Among locations with similar populations, pick the best-known location, e.g. prefer `Rome' to `Milan'. Use the singular form, e.g. prefer `Canary' to `Canaries'. Omit common suffixes like `_Islands' and `_City', unless that would lead to ambiguity. E.g. prefer `Cayman' to `Cayman_Islands' and `Guatemala' to `Guatemala_City', but prefer `Mexico_City' to `Mexico' because the country of Mexico has several time zones. Use `_' to represent a space. Omit `.' from abbreviations in names, e.g. prefer `St_Helena' to `St._Helena'. + Do not change established names if they only marginally + violate the above rules. For example, don't change + the existing name `Rome' to `Milan' merely because + Milan's population has grown to be somewhat greater + than Rome's. + If a name is changed, put its old spelling in the `backward' file. The file `zone.tab' lists the geographical locations used to name time zone rule files. Older versions of this package used a different naming scheme, and these older names are still supported. -See the file `backwards' for most of these older names +See the file `backward' for most of these older names (e.g. `US/Eastern' instead of `America/New_York'). The other old-fashioned names still supported are `WET', `CET', `MET', `EET' (see the file `europe'), and `Factory' (see the file `factory'). ----- Time zone abbreviations ----- When this package is installed, it generates time zone abbreviations like `EST' to be compatible with human tradition and POSIX.1. Here are the general rules used for choosing time zone abbreviations, in decreasing order of importance: - Use abbreviations that consist of 3 or more upper-case Ascii letters, - except use "___" for locations while uninhabited. - Posix.1 requires at least 3 characters, and the restriction to - upper-case Ascii letters follows most traditions. + Use abbreviations that consist of three or more ASCII letters. Previous editions of this database also used characters like ' ' and '?', but these characters have a special meaning to the shell and cause commands like set `date` - to have unexpected effects. In theory, the character set could - be !%./@A-Z^_a-z{}, but these tables use only upper-case - Ascii letters (and "___"). + to have unexpected effects. + Previous editions of this rule required upper-case letters, + but the Congressman who introduced Chamorro Standard Time + preferred "ChST", so the rule has been relaxed. + + This rule guarantees that all abbreviations could have + been specified by a POSIX.1 TZ string. POSIX.1 + requires at least three characters for an + abbreviation. POSIX.1-1996 says that an abbreviation + cannot start with ':', and cannot contain ',', '-', + '+', NUL, or a digit. Draft 7 of POSIX 1003.1-200x + changes this rule to say that an abbreviation can + contain only '-', '+', and alphanumeric characters in + the current locale. To be portable to both sets of + rules, an abbreviation must therefore use only ASCII + letters, as these are the only letters that are + alphabetic in all locales. + Use abbreviations that are in common use among English-speakers, e.g. `EST' for Eastern Standard Time in North America. We assume that applications translate them to other languages as part of the normal localization process; for example, a French application might translate `EST' to `HNE'. + For zones whose times are taken from a city's longitude, use the traditional xMT notation, e.g. `PMT' for Paris Mean Time. The only name like this in current use is `GMT'. + If there is no common English abbreviation, abbreviate the English translation of the usual phrase used by native speakers. If this is not available or is a phrase mentioning the country (e.g. ``Cape Verde Time''), then: When a country has a single or principal time zone region, append `T' to the country's ISO code, e.g. `CVT' for Cape Verde Time. For summer time append `ST'; for double summer time append `DST'; etc. When a country has multiple time zones, take the first three letters of an English place name identifying each zone and then append `T', `ST', etc. as before; e.g. `VLAST' for VLAdivostok Summer Time. + Use "zzz" for locations while uninhabited. The mnemonic is that + these locations are, in some sense, asleep. + Application writers should note that these abbreviations are ambiguous in practice: e.g. `EST' has a different meaning in Australia than it does in the United States. In new applications, it's often better to use numeric UTC offsets like `-0500' instead of time zone abbreviations like `EST'; this avoids the ambiguity. + + +----- Calendrical issues ----- + +Calendrical issues are a bit out of scope for a time zone database, +but they indicate the sort of problems that we would run into if we +extended the time zone database further into the past. An excellent +resource in this area is Nachum Dershowitz and Edward M. Reingold, + +Calendrical Calculations +, Cambridge University Press (1997). Other information and +sources are given below. They sometimes disagree. + + +France + +Gregorian calendar adopted 1582-12-20. +French Revolutionary calendar used 1793-11-24 through 1805-12-31, +and (in Paris only) 1871-05-06 through 1871-05-23. + + +Russia + +From Chris Carrier <72157.3334@CompuServe.COM> (1996-12-02): +On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar'' +with 30-day months plus 5 holidays, with a 5-day week. +On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the +Gregorian calendar while retaining the 6-day week; on 1940-06-27 it +reverted to the 7-day week. With the 6-day week the usual days +off were the 6th, 12th, 18th, 24th and 30th of the month. +(Source: Evitiar Zerubavel, _The Seven Day Circle_) + + +Mark Brader reported a similar story in "The Book of Calendars", edited +by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But: + +From: Petteri Sulonen (via Usenet) +Date: 14 Jan 1999 00:00:00 GMT +Message-ID: + +If your source is correct, how come documents between 1929 -- 1940 were +still dated using the conventional, Gregorian calendar? + +I can post a scan of a document dated December 1, 1934, signed by +Yenukidze, the secretary, on behalf of Kalinin, the President of the +Executive Committee of the Supreme Soviet, if you like. + + + +Sweden (and Finland) + +From: msb@sq.com (Mark Brader) + +Subject: Re: Gregorian reform -- a part of locale? + +Date: 1996-07-06 + +In 1700, Denmark made the transition from Julian to Gregorian. Sweden +decided to *start* a transition in 1700 as well, but rather than have one of +those unsightly calendar gaps :-), they simply decreed that the next leap +year after 1696 would be in 1744 -- putting the whole country on a calendar +different from both Julian and Gregorian for a period of 40 years. + +However, in 1704 something went wrong and the plan was not carried through; +they did, after all, have a leap year that year. And one in 1708. In 1712 +they gave it up and went back to Julian, putting 30 days in February that +year!... + +Then in 1753, Sweden made the transition to Gregorian in the usual manner, +getting there only 13 years behind the original schedule. + +(A previous posting of this story was challenged, and Swedish readers +produced the following references to support it: "Tiderakning och historia" +by Natanael Beckman (1924) and "Tid, en bok om tiderakning och +kalendervasen" by Lars-Olof Lode'n (no date was given).) + + +Grotefend's data + +From: "Michael Palmer" [with one obvious typo fixed] +Subject: Re: Gregorian Calendar (was Re: Another FHC related question +Newsgroups: soc.genealogy.german +Date: Tue, 9 Feb 1999 02:32:48 -800 +Message-ID: <199902091032.CAA09644@netcom10.netcom.com> + +The following is a(n incomplete) listing, arranged chronologically, of +European states, with the date they converted from the Julian to the +Gregorian calendar: + +04/15 Oct 1582 - Italy (with exceptions), Spain, Portugal, Poland (Roman + Catholics and Danzig only) +09/20 Dec 1582 - France, Lorraine + +21 Dec 1582/ + 01 Jan 1583 - Holland, Brabant, Flanders, Hennegau +10/21 Feb 1583 - bishopric of Liege (L"uttich) +13/24 Feb 1583 - bishopric of Augsburg +04/15 Oct 1583 - electorate of Trier +05/16 Oct 1583 - Bavaria, bishoprics of Freising, Eichstedt, Regensburg, + Salzburg, Brixen +13/24 Oct 1583 - Austrian Oberelsass and Breisgau +20/31 Oct 1583 - bishopric of Basel +02/13 Nov 1583 - duchy of J"ulich-Berg +02/13 Nov 1583 - electorate and city of K"oln +04/15 Nov 1583 - bishopric of W"urzburg +11/22 Nov 1583 - electorate of Mainz +16/27 Nov 1583 - bishopric of Strassburg and the margraviate of Baden +17/28 Nov 1583 - bishopric of M"unster and duchy of Cleve +14/25 Dec 1583 - Steiermark + +06/17 Jan 1584 - Austria and Bohemia +11/22 Jan 1584 - Luzern, Uri, Schwyz, Zug, Freiburg, Solothurn +12/23 Jan 1584 - Silesia and the Lausitz +22 Jan/ + 02 Feb 1584 - Hungary (legally on 21 Oct 1587) + Jun 1584 - Unterwalden +01/12 Jul 1584 - duchy of Westfalen + +16/27 Jun 1585 - bishopric of Paderborn + +14/25 Dec 1590 - Transylvania + +22 Aug/ + 02 Sep 1612 - duchy of Prussia + +13/24 Dec 1614 - Pfalz-Neuburg + + 1617 - duchy of Kurland (reverted to the Julian calendar in + 1796) + + 1624 - bishopric of Osnabr"uck + + 1630 - bishopric of Minden + +15/26 Mar 1631 - bishopric of Hildesheim + + 1655 - Kanton Wallis + +05/16 Feb 1682 - city of Strassburg + +18 Feb/ + 01 Mar 1700 - Protestant Germany (including Swedish possessions in + Germany), Denmark, Norway +30 Jun/ + 12 Jul 1700 - Gelderland, Zutphen +10 Nov/ + 12 Dec 1700 - Utrecht, Overijssel + +31 Dec 1700/ + 12 Jan 1701 - Friesland, Groningen, Z"urich, Bern, Basel, Geneva, + Turgau, and Schaffhausen + + 1724 - Glarus, Appenzell, and the city of St. Gallen + +01 Jan 1750 - Pisa and Florence + +02/14 Sep 1752 - Great Britain + +17 Feb/ + 01 Mar 1753 - Sweden + +1760-1812 - Graub"unden + +The Russian empire (including Finland and the Baltic states) did not +convert to the Gregorian calendar until the Soviet revolution of 1917. + +Source: H. Grotefend, _Taschenbuch der Zeitrechnung des deutschen +Mittelalters und der Neuzeit_, herausgegeben von Dr. O. Grotefend +(Hannover: Hahnsche Buchhandlung, 1941), pp. 26-28. + + +----- Time and time zones on Mars ----- + +Some people have adjusted their work schedules to fit Mars time. +Dozens of special Mars watches were built for Jet Propulsion +Laboratory workers who kept Mars time during the Mars Exploration +Rovers mission (2004). These timepieces look like normal Seikos and +Citizens but use Mars seconds rather than terrestrial seconds. + +A Mars solar day is called a "sol" and has a mean period equal to +about 24 hours 39 minutes 35.244 seconds in terrestrial time. It is +divided into a conventional 24-hour clock, so each Mars second equals +about 1.02749125 terrestrial seconds. + +The prime meridian of Mars goes through the center of the crater +Airy-0, named in honor of the British astronomer who built the +Greenwich telescope that defines Earth's prime meridian. Mean solar +time on the Mars prime meridian is called Mars Coordinated Time (MTC). + +Each landed mission on Mars has adopted a different reference for +solar time keeping, so there is no real standard for Mars time zones. +For example, the Mars Exploration Rover project (2004) defined two +time zones "Local Solar Time A" and "Local Solar Time B" for its two +missions, each zone designed so that its time equals local true solar +time at approximately the middle of the nominal mission. Such a "time +zone" is not particularly suited for any application other than the +mission itself. + +Many calendars have been proposed for Mars, but none have achieved +wide acceptance. Astronomers often use Mars Sol Date (MSD) which is a +sequential count of Mars solar days elapsed since about 1873-12-29 +12:00 GMT. + +The tz database does not currently support Mars time, but it is +documented here in the hopes that support will be added eventually. + +Sources: + +Michael Allison and Robert Schmunk, +"Technical Notes on Mars Solar Time as Adopted by the Mars24 Sunclock" + (2004-03-15). + +Jia-Rui Chong, "Workdays Fit for a Martian", Los Angeles Times +(2004-01-14), pp A1, A20-A21. Index: vendor/tzcode/dist/usr.sbin/zic/private.h =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/private.h (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/private.h (revision 130777) @@ -1,269 +1,294 @@ #ifndef PRIVATE_H #define PRIVATE_H /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ /* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. ** Do NOT copy it to any system include directory. ** Thank you! */ /* ** ID */ #ifndef lint #ifndef NOID -static char privatehid[] = "@(#)private.h 7.48"; +static char privatehid[] = "@(#)private.h 7.53"; #endif /* !defined NOID */ #endif /* !defined lint */ /* ** Defaults for preprocessor symbols. ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. */ #ifndef HAVE_ADJTIME #define HAVE_ADJTIME 1 #endif /* !defined HAVE_ADJTIME */ #ifndef HAVE_GETTEXT #define HAVE_GETTEXT 0 #endif /* !defined HAVE_GETTEXT */ +#ifndef HAVE_INCOMPATIBLE_CTIME_R +#define HAVE_INCOMPATIBLE_CTIME_R 0 +#endif /* !defined INCOMPATIBLE_CTIME_R */ + #ifndef HAVE_SETTIMEOFDAY #define HAVE_SETTIMEOFDAY 3 #endif /* !defined HAVE_SETTIMEOFDAY */ #ifndef HAVE_STRERROR -#define HAVE_STRERROR 0 +#define HAVE_STRERROR 1 #endif /* !defined HAVE_STRERROR */ #ifndef HAVE_SYMLINK #define HAVE_SYMLINK 1 #endif /* !defined HAVE_SYMLINK */ +#ifndef HAVE_SYS_STAT_H +#define HAVE_SYS_STAT_H 1 +#endif /* !defined HAVE_SYS_STAT_H */ + +#ifndef HAVE_SYS_WAIT_H +#define HAVE_SYS_WAIT_H 1 +#endif /* !defined HAVE_SYS_WAIT_H */ + #ifndef HAVE_UNISTD_H #define HAVE_UNISTD_H 1 #endif /* !defined HAVE_UNISTD_H */ #ifndef HAVE_UTMPX_H #define HAVE_UTMPX_H 0 #endif /* !defined HAVE_UTMPX_H */ #ifndef LOCALE_HOME #define LOCALE_HOME "/usr/lib/locale" #endif /* !defined LOCALE_HOME */ +#if HAVE_INCOMPATIBLE_CTIME_R +#define asctime_r _incompatible_asctime_r +#define ctime_r _incompatible_ctime_r +#endif /* HAVE_INCOMPATIBLE_CTIME_R */ + /* ** Nested includes */ #include "sys/types.h" /* for time_t */ #include "stdio.h" #include "errno.h" #include "string.h" #include "limits.h" /* for CHAR_BIT */ #include "time.h" #include "stdlib.h" #if HAVE_GETTEXT - 0 #include "libintl.h" #endif /* HAVE_GETTEXT - 0 */ +#if HAVE_SYS_WAIT_H - 0 +#include /* for WIFEXITED and WEXITSTATUS */ +#endif /* HAVE_SYS_WAIT_H - 0 */ + +#ifndef WIFEXITED +#define WIFEXITED(status) (((status) & 0xff) == 0) +#endif /* !defined WIFEXITED */ +#ifndef WEXITSTATUS +#define WEXITSTATUS(status) (((status) >> 8) & 0xff) +#endif /* !defined WEXITSTATUS */ + #if HAVE_UNISTD_H - 0 #include "unistd.h" /* for F_OK and R_OK */ #endif /* HAVE_UNISTD_H - 0 */ #if !(HAVE_UNISTD_H - 0) #ifndef F_OK #define F_OK 0 #endif /* !defined F_OK */ #ifndef R_OK #define R_OK 4 #endif /* !defined R_OK */ #endif /* !(HAVE_UNISTD_H - 0) */ /* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ #define is_digit(c) ((unsigned)(c) - '0' <= 9) /* ** Workarounds for compilers/systems. */ /* -** SunOS 4.1.1 cc lacks const. -*/ - -#ifndef const -#ifndef __STDC__ -#define const -#endif /* !defined __STDC__ */ -#endif /* !defined const */ - -/* ** SunOS 4.1.1 cc lacks prototypes. */ #ifndef P #ifdef __STDC__ #define P(x) x #endif /* defined __STDC__ */ #ifndef __STDC__ #define P(x) () #endif /* !defined __STDC__ */ #endif /* !defined P */ /* ** SunOS 4.1.1 headers lack EXIT_SUCCESS. */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif /* !defined EXIT_SUCCESS */ /* ** SunOS 4.1.1 headers lack EXIT_FAILURE. */ #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif /* !defined EXIT_FAILURE */ /* ** SunOS 4.1.1 headers lack FILENAME_MAX. */ #ifndef FILENAME_MAX #ifndef MAXPATHLEN #ifdef unix #include "sys/param.h" #endif /* defined unix */ #endif /* !defined MAXPATHLEN */ #ifdef MAXPATHLEN #define FILENAME_MAX MAXPATHLEN #endif /* defined MAXPATHLEN */ #ifndef MAXPATHLEN #define FILENAME_MAX 1024 /* Pure guesswork */ #endif /* !defined MAXPATHLEN */ #endif /* !defined FILENAME_MAX */ /* ** SunOS 4.1.1 libraries lack remove. */ #ifndef remove extern int unlink P((const char * filename)); #define remove unlink #endif /* !defined remove */ /* ** Some ancient errno.h implementations don't declare errno. ** But some newer errno.h implementations define it as a macro. ** Fix the former without affecting the latter. */ #ifndef errno extern int errno; #endif /* !defined errno */ /* ** Private function declarations. */ char * icalloc P((int nelem, int elsize)); char * icatalloc P((char * old, const char * new)); char * icpyalloc P((const char * string)); char * imalloc P((int n)); void * irealloc P((void * pointer, int size)); void icfree P((char * pointer)); void ifree P((char * pointer)); char * scheck P((const char *string, const char *format)); /* ** Finally, some convenience items. */ #ifndef TRUE #define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE #define FALSE 0 #endif /* !defined FALSE */ #ifndef TYPE_BIT #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #endif /* !defined TYPE_BIT */ #ifndef TYPE_SIGNED #define TYPE_SIGNED(type) (((type) -1) < 0) #endif /* !defined TYPE_SIGNED */ #ifndef INT_STRLEN_MAXIMUM /* ** 302 / 1000 is log10(2.0) rounded up. ** Subtract one for the sign bit if the type is signed; ** add one for integer division truncation; ** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ /* ** INITIALIZE(x) */ #ifndef GNUC_or_lint #ifdef lint #define GNUC_or_lint #endif /* defined lint */ #ifndef lint #ifdef __GNUC__ #define GNUC_or_lint #endif /* defined __GNUC__ */ #endif /* !defined lint */ #endif /* !defined GNUC_or_lint */ #ifndef INITIALIZE #ifdef GNUC_or_lint #define INITIALIZE(x) ((x) = 0) #endif /* defined GNUC_or_lint */ #ifndef GNUC_or_lint #define INITIALIZE(x) #endif /* !defined GNUC_or_lint */ #endif /* !defined INITIALIZE */ /* ** For the benefit of GNU folk... ** `_(MSGID)' uses the current locale's message library string for MSGID. ** The default is to use gettext if available, and use MSGID otherwise. */ #ifndef _ #if HAVE_GETTEXT - 0 #define _(msgid) gettext(msgid) #else /* !(HAVE_GETTEXT - 0) */ #define _(msgid) msgid #endif /* !(HAVE_GETTEXT - 0) */ #endif /* !defined _ */ #ifndef TZ_DOMAIN #define TZ_DOMAIN "tz" #endif /* !defined TZ_DOMAIN */ +#if HAVE_INCOMPATIBLE_CTIME_R +#undef asctime_r +#undef ctime_r +char *asctime_r P((struct tm const *, char *)); +char *ctime_r P((time_t const *, char *)); +#endif /* HAVE_INCOMPATIBLE_CTIME_R */ + /* -** UNIX was a registered trademark of UNIX System Laboratories in 1993. +** UNIX was a registered trademark of The Open Group in 2003. */ #endif /* !defined PRIVATE_H */ Index: vendor/tzcode/dist/usr.sbin/zic/tz-art.htm =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/tz-art.htm (nonexistent) +++ vendor/tzcode/dist/usr.sbin/zic/tz-art.htm (revision 130777) @@ -0,0 +1,278 @@ + + + + + +Time and the Arts + + +

Time and the Arts

+
+@(#)tz-art.htm 7.53 +
+

+Please send corrections to this web page to the +time zone mailing list.

+

+See also Sources for Time Zone and Daylight Saving Time Data.

+
+

+Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArtistKarrin Allyson
CDI Didn't Know About You
Copyright Date1993
LabelConcord Jazz, Inc.
IDCCD-4543
Track Time3:44
PersonnelKarrin Allyson, vocal; +Russ Long, piano; +Gerald Spaits, bass; +Todd Strait, drums
NotesCD notes "additional lyric by Karrin Allyson; +arranged by Russ Long and Karrin Allyson"
ADO Rating1 star
AMG Rating4 stars
Penguin Rating3.5 stars
 
ArtistKevin Mahogany
CDDouble Rainbow
Copyright Date1993
LabelEnja Records
IDENJ-7097 2
Track Time6:27
PersonnelKevin Mahogany, vocal; +Kenny Barron, piano; +Ray Drummond, bass; +Ralph Moore, tenor saxophone; +Lewis Nash, drums
ADO Rating1.5 stars
AMG Rating3 stars
Penguin Rating3 stars
 
ArtistJoe Williams
CDHere's to Life
Copyright Date1994
LabelTelarc International Corporation
IDCD-83357
Track Time3:58
PersonnelJoe Williams, vocal +The Robert Farnon [39 piece] Orchestra
NotesThis CD is also available as part of a 3-CD package from +Telarc, "Triple Play" (CD-83461)
ADO Ratingblack dot
AMG Rating2 stars
Penguin Rating3 stars
 
ArtistCharles Fambrough
CDKeeper of the Spirit
Copyright Date1995
LabelAudioQuest Music
IDAQ-CD1033
Track Time7:07
PersonnelCharles Fambrough, bass; +Joel Levine, tenor recorder; +Edward Simon, piano; +Lenny White, drums; +Marion Simon, percussion
NotesOn-line information and samples available at +http://wwmusic.com/~music/audioq/rel/1033.html
ADO Rating2 stars
AMG Ratingunrated
Penguin Rating3 stars
+
+

Also of note:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArtistHolly Cole Trio
CDBlame It On My Youth
Copyright Date1992
LabelManhattan
IDCDP 7 97349 2
Total Time37:45
PersonnelHolly Cole, voice; +Aaron Davis, piano; +David Piltch, string bass
NotesLyrical reference to "Eastern Standard Time" in +Tom Waits' "Purple Avenue"
ADO Rating2.5 stars
AMG Rating3 stars
Penguin Ratingunrated
 
ArtistMilt Hinton
CDOld Man Time
Copyright Date1990
LabelChiaroscuro
IDCR(D) 310
Total Time149:38 (two CDs)
PersonnelMilt Hinton, bass; +Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet; +Al Grey, trombone; +Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate, +clarinet and saxophone; +John Bunch, Red Richards, Norman Simmons, Derek Smith, +Ralph Sutton, piano; +Danny Barker, Al Casey, guitar; +Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams, +drums; +Lionel Hampton, vibraphone; +Cab Calloway, Joe Williams, vocal; +Buck Clayton, arrangements
Notestunes include Old Man Time, Time After Time, +Sometimes I'm Happy, +A Hot Time in the Old Town Tonight, +Four or Five Times, Now's the Time, +Time on My Hands, This Time It's Us, +and Good Time Charlie +On-line samples available at +http://www.chiaroscurojazz.com/albuminfo.php3?albumid=49
ADO Rating3 stars
AMG Rating4.5 stars
Penguin Rating3 stars
 
ArtistAlan Broadbent
CDPacific Standard Time
Copyright Date1995
LabelConcord Jazz, Inc.
IDCCD-4664
Total Time62:42
PersonnelAlan Broadbent, piano; +Putter Smith, Bass; +Frank Gibson, Jr., drums
NotesThe CD cover features an analemma for equation-of-time fans
ADO Rating1 star
AMG Rating4 stars
Penguin Rating3.5 stars
 
ArtistAnthony Braxton/Richard Teitelbaum
CDSilence/Time Zones
Copyright Date1996
LabelBlack Lion
IDBLCD 760221
Total Time72:58
PersonnelAnthony Braxton, sopranino and alto saxophones, +contrebasse clarinet, miscellaneous instruments; +Leo Smith, trumpet and miscellaneous instruments; +Leroy Jenkins, violin and miscellaneous instruments; +Richard Teitelbaum, modular moog and micromoog synthesizer
ADO Ratingblack dot
AMG Ratingunrated
 
ArtistJules Verne
BookLe Tour du Monde en Quatre-Vingts Jours +(Around the World in Eighty Days)
NotesWall-clock time plays a central role in the plot. +European readers of the 1870s clearly held the U.S. press in +deep contempt; the protagonists cross the U.S. without once +reading a paper. +An on-line French-language version of the book +"with illustrations from the original 1873 French-language edition" +is available at +http://fourmilab.ch/etexts/www/tdm80j +An on-line English-language translation of the book is available at +http://www.literature.org/Works/Jules-Verne/eighty
 
FilmBell Science - About Time
NotesThe Frank Baxter/Richard Deacon extravaganza +Information on ordering is available at +http://www.videoflicks.com/VF2/1035/1035893.ihtml
+
+
    +
  • +An episode of "The Adventures of Superman" entitled "The Mysterious +Cube," first aired 1958-02-24, had Superman convincing the controllers +of WWV to broadcast time signals five minutes ahead of actual time; +doing so got a crook trying to beat the statute of limitations to +emerge a bit too early from the titular enclosure. +
  • +
  • +The 1960s ITC television series "The Prisoner" included an episode +entitled "The Chimes of Big Ben" in which our protagonist tumbled to +the fraudulent nature of a Poland-to-England escape upon hearing "Big +Ben" chiming on Polish local time. +
  • +
  • +The series "Seinfeld" included an episode entitled "The Susie," first +broadcast 1997-02-13, in which Kramer decides that daylight saving time +isn't coming fast enough, so he sets his watch ahead an hour. +
  • +
  • +The syndicated comic strip "Dilbert" featured an all-too-rare example of +time zone humor on 1998-03-14. +
  • +
  • +Surrealist artist Guy Billout's work "Date Line" appeared on page 103 +of the 1999-11 Atlantic Monthly. +
  • +
  • +"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of Time +Magazine's 2002-11-11 issue; among other things, it proposed +year-round DST as a way of lessening wintertime despair. +
  • +
  • +The "20 Hours in America" episode of "The West Wing," first aired 2002-09-25, +saw White House staffers stranded in Indiana; they thought they had time to +catch Air Force One but were done in by intra-Indiana local time changes. +
  • +
  • +"In what time zone would you find New York City?" was a $200 question on +the 1999-11-13 United States airing of "Who Wants to Be a Millionaire?" +"In 1883, what industry led the movement to divide the U.S. into four time +zones?" was a $32,000 question on the 2001-05-23 United States airing of +"Who Wants to Be a Millionaire?" At this rate, the million-dollar time-zone +question should have been asked 2002-06-04. +
  • +
+
+
    +
  • +"We're been using the five-cent nickle in this country since 1492. +Now that's pretty near 100 years, daylight savings [sic]." +(Groucho Marx as Captain Spaulding in "Animal Crackers", 1930, +as noted by Will Fitzerald, wfitzgerald@ameritech.net) +
  • +
  • +"Good news." +"What did they do? Extend Daylight Saving Time year round?" +(Professional tanner George Hamilton, in dialog from a +May, 1999 episode of the syndicated television series "Baywatch") +
  • +
  • +"A fundamental belief held by Americans is that if you are on land, you +cannot be killed by a fish...So most Americans remain on land, believing +they're safe. Unfortunately, this belief—like so many myths, such as that +there's a reason for 'Daylight Saving Time'—is false." +(Dave Barry column, 2000-07-02) +
  • +
  • +"I once had sex for an hour and five minutes, but that was on the day +when you turn the clocks ahead." +(Garry Shandling, 52nd Annual Emmys, 2000-09-10) +
  • +
  • +"Would it impress you if I told you I invented Daylight Savings Time?" +("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of "Angel," +originally aired 2002-02-25) +
  • +
  • +"I thought you said Tulsa was a three hour flight." +"Well, you're forgetting about the time difference." +("Chandler" and "Joey" in dialog from the episode of "Friends" first +aired 2002-12-05) +
  • +
  • +"Is that a pertinent fact, +or are you trying to dazzle me with your command of time zones?" +(Kelsey Grammer as "Frasier Crane") +
  • +
  • +"Don't worry about the world coming to an end today. +It is already tomorrow in Australia." +(Charles M. Schulz, provided by Steve Summit) +
  • +
+ + Property changes on: vendor/tzcode/dist/usr.sbin/zic/tz-art.htm ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/tzcode/dist/usr.sbin/zic/tz-link.htm =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/tz-link.htm (nonexistent) +++ vendor/tzcode/dist/usr.sbin/zic/tz-link.htm (revision 130777) @@ -0,0 +1,443 @@ + + + + +Sources for Time Zone and Daylight Saving Time Data + + + + + + + + + + +

Sources for Time Zone and Daylight Saving Time Data

+
+@(#)tz-link.htm 7.42 +
+

+Please send corrections to this web page to the +time zone mailing list. +

+

The tz database

+

+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 tz or zoneinfo) +is used by several implementations, +including +the GNU C Library used in +GNU/Linux, +FreeBSD, +NetBSD, +OpenBSD, +Cygwin, +DJGPP, +HP-UX, +IRIX, +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); +America/Detroit represents most of Michigan, which uses +eastern time but with different DST rules in 1975; +and other entries represent smaller regions like Starke County, +Kentucky, which switched from central to eastern time in 1991. +To use the database, set the TZ environment variable to +the location's full name, e.g., TZ="America/New_York".

+

+In the tz database's +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 +README file for what to do next.

+
wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+gzip -dc tzcode*.tar.gz | tar -xf -
+gzip -dc tzdata*.tar.gz | tar -xf -
+
+

+The code lets you compile the tz source files into +machine-readable binary files, one for each location. It also lets +you read a tz binary file and interpret time stamps for that +location.

+

+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 +messages (in gzip compressed format), or retrieve 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

+ +

Other time zone database formats

+ +

Other tz compilers

+ +

Other tz binary file readers

+ +

Other tz-based time zone conversion software

+ +

Other time zone databases

+ +

Maps

+ +

Time zone boundaries

+ +

Civil time concepts and history

+ +

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).
+
Belgium
+
The Royal Observatory of Belgium maintains a table of time in Belgium (in Dutch).
+
Brazil
+
The Time Service Department of the National Observatory +records Brazil's daylight saving time decrees (in +Portuguese).
+
Canada
+
The Institute for National Measurement Standards publishes current +and some older information about Time +Zones and Daylight Saving Time.
+
Chile
+
WebExhibits publishes a history of official time (in Spanish) originally +written by the Chilean Hydrographic and Oceanographic Service.
+
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 +Congress has published a history of Mexican local time (in Spanish).
+
Malaysia
+
See Singapore below.
+
Netherlands
+
Legal time in the Netherlands (in Dutch) +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.
+
Singapore
+
Why +is Singapore in the "Wrong" Time Zone? details the +history of legal time in Singapore and Malaysia.
+
United Kingdom
+
History of +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.
+
+

Precision timekeeping

+ +

Time notation

+
    +
  • +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).
  • +
  • +Section 3.3 of Internet RFC 2822 +specifies the time notation used in email and HTTP headers.
  • +
  • +Internet RFC +3339 specifies an ISO 8601 profile for use in new Internet +protocols.
  • +
  • +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 +maintainers.
  • +
+

Related indexes

+ + + Property changes on: vendor/tzcode/dist/usr.sbin/zic/tz-link.htm ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/tzcode/dist/usr.sbin/zic/zdump.8 =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/zdump.8 (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/zdump.8 (revision 130777) @@ -1,39 +1,45 @@ .TH ZDUMP 8 .SH NAME zdump \- time zone dumper .SH SYNOPSIS .B zdump [ +.B \-\-version +] +[ .B \-v ] [ .B \-c cutoffyear ] [ zonename ... ] .SH DESCRIPTION .I Zdump prints the current time in each .I zonename named on the command line. .PP These options are available: .TP +.BI "\-\-version" +Output version information and exit. +.TP .B \-v For each .I zonename on the command line, print the time at the lowest possible time value, the time one day after the lowest possible time value, the times both one second before and exactly at each detected time discontinuity, the time at one day less than the highest possible time value, and the time at the highest possible time value, Each line ends with .B isdst=1 if the given time is Daylight Saving Time or .B isdst=0 otherwise. .TP .BI "\-c " cutoffyear Cut off the verbose output near the start of the given year. .SH "SEE ALSO" newctime(3), tzfile(5), zic(8) -.\" @(#)zdump.8 7.3 +.\" @(#)zdump.8 7.4 Index: vendor/tzcode/dist/usr.sbin/zic/zdump.c =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/zdump.c (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/zdump.c (revision 130777) @@ -1,372 +1,372 @@ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)zdump.c 7.28"; -#endif /* !defined NOID */ -#endif /* !defined lint */ +static char elsieid[] = "@(#)zdump.c 7.31"; /* ** This code has been made independent of the rest of the time ** conversion package to increase confidence in the verification it provides. ** You can use this code to help in verifying other implementations. */ #include "stdio.h" /* for stdout, stderr, perror */ #include "string.h" /* for strcpy */ #include "sys/types.h" /* for time_t */ #include "time.h" /* for struct tm */ #include "stdlib.h" /* for exit, malloc, atoi */ #ifndef MAX_STRING_LENGTH #define MAX_STRING_LENGTH 1024 #endif /* !defined MAX_STRING_LENGTH */ #ifndef TRUE #define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE #define FALSE 0 #endif /* !defined FALSE */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif /* !defined EXIT_SUCCESS */ #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif /* !defined EXIT_FAILURE */ #ifndef SECSPERMIN #define SECSPERMIN 60 #endif /* !defined SECSPERMIN */ #ifndef MINSPERHOUR #define MINSPERHOUR 60 #endif /* !defined MINSPERHOUR */ #ifndef SECSPERHOUR #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #endif /* !defined SECSPERHOUR */ #ifndef HOURSPERDAY #define HOURSPERDAY 24 #endif /* !defined HOURSPERDAY */ #ifndef EPOCH_YEAR #define EPOCH_YEAR 1970 #endif /* !defined EPOCH_YEAR */ #ifndef TM_YEAR_BASE #define TM_YEAR_BASE 1900 #endif /* !defined TM_YEAR_BASE */ #ifndef DAYSPERNYEAR #define DAYSPERNYEAR 365 #endif /* !defined DAYSPERNYEAR */ #ifndef isleap #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) #endif /* !defined isleap */ #if HAVE_GETTEXT - 0 #include "locale.h" /* for setlocale */ #include "libintl.h" #endif /* HAVE_GETTEXT - 0 */ #ifndef GNUC_or_lint #ifdef lint #define GNUC_or_lint #endif /* defined lint */ #ifndef lint #ifdef __GNUC__ #define GNUC_or_lint #endif /* defined __GNUC__ */ #endif /* !defined lint */ #endif /* !defined GNUC_or_lint */ #ifndef INITIALIZE #ifdef GNUC_or_lint #define INITIALIZE(x) ((x) = 0) #endif /* defined GNUC_or_lint */ #ifndef GNUC_or_lint #define INITIALIZE(x) #endif /* !defined GNUC_or_lint */ #endif /* !defined INITIALIZE */ /* ** For the benefit of GNU folk... ** `_(MSGID)' uses the current locale's message library string for MSGID. ** The default is to use gettext if available, and use MSGID otherwise. */ #ifndef _ #if HAVE_GETTEXT - 0 #define _(msgid) gettext(msgid) #else /* !(HAVE_GETTEXT - 0) */ #define _(msgid) msgid #endif /* !(HAVE_GETTEXT - 0) */ #endif /* !defined _ */ #ifndef TZ_DOMAIN #define TZ_DOMAIN "tz" #endif /* !defined TZ_DOMAIN */ #ifndef P #ifdef __STDC__ #define P(x) x #endif /* defined __STDC__ */ #ifndef __STDC__ #define P(x) () #endif /* !defined __STDC__ */ #endif /* !defined P */ extern char ** environ; extern int getopt P((int argc, char * const argv[], const char * options)); extern char * optarg; extern int optind; extern char * tzname[2]; static char * abbr P((struct tm * tmp)); static long delta P((struct tm * newp, struct tm * oldp)); static time_t hunt P((char * name, time_t lot, time_t hit)); static size_t longest; static char * progname; static void show P((char * zone, time_t t, int v)); int main(argc, argv) int argc; char * argv[]; { register int i; register int c; register int vflag; register char * cutoff; register int cutyear; register long cuttime; char ** fakeenv; time_t now; time_t t; time_t newt; time_t hibit; struct tm tm; struct tm newtm; INITIALIZE(cuttime); #if HAVE_GETTEXT - 0 (void) setlocale(LC_MESSAGES, ""); #ifdef TZ_DOMAINDIR (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); #endif /* defined(TEXTDOMAINDIR) */ (void) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT - 0 */ progname = argv[0]; + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "--version") == 0) { + (void) printf("%s\n", elsieid); + (void) exit(EXIT_SUCCESS); + } vflag = 0; cutoff = NULL; while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') if (c == 'v') vflag = 1; else cutoff = optarg; if ((c != EOF && c != -1) || (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { (void) fprintf(stderr, -_("%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n"), +_("%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; } (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) continue; fakeenv = (char **) malloc((size_t) ((i + 2) * sizeof *fakeenv)); if (fakeenv == NULL || (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) { (void) perror(progname); (void) exit(EXIT_FAILURE); } to = 0; (void) strcpy(fakeenv[to++], "TZ="); for (from = 0; environ[from] != NULL; ++from) if (strncmp(environ[from], "TZ=", 3) != 0) fakeenv[to++] = environ[from]; fakeenv[to] = NULL; environ = fakeenv; } for (i = optind; i < argc; ++i) { static char buf[MAX_STRING_LENGTH]; (void) strcpy(&fakeenv[0][3], argv[i]); if (!vflag) { show(argv[i], now, FALSE); continue; } /* ** Get lowest value of t. */ t = hibit; if (t > 0) /* time_t is unsigned */ t = 0; show(argv[i], t, TRUE); t += SECSPERHOUR * HOURSPERDAY; show(argv[i], t, TRUE); tm = *localtime(&t); (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); for ( ; ; ) { if (cutoff != NULL && t >= cuttime) break; newt = t + SECSPERHOUR * 12; if (cutoff != NULL && newt >= cuttime) break; if (newt <= t) break; newtm = *localtime(&newt); if (delta(&newtm, &tm) != (newt - t) || newtm.tm_isdst != tm.tm_isdst || strcmp(abbr(&newtm), buf) != 0) { newt = hunt(argv[i], t, newt); newtm = *localtime(&newt); (void) strncpy(buf, abbr(&newtm), (sizeof buf) - 1); } t = newt; tm = newtm; } /* ** Get highest value of t. */ t = ~((time_t) 0); if (t < 0) /* time_t is signed */ t &= ~hibit; t -= SECSPERHOUR * HOURSPERDAY; show(argv[i], t, TRUE); t += SECSPERHOUR * HOURSPERDAY; show(argv[i], t, TRUE); } if (fflush(stdout) || ferror(stdout)) { - (void) fprintf(stderr, _("%s: Error writing "), - argv[0]); - (void) perror(_("standard output")); + (void) fprintf(stderr, "%s: ", argv[0]); + (void) perror(_("Error writing standard output")); (void) exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); /* gcc -Wall pacifier */ for ( ; ; ) continue; } 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) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); while ((hit - lot) >= 2) { t = lot / 2 + hit / 2; if (t <= lot) ++t; else if (t >= hit) --t; tm = *localtime(&t); if (delta(&tm, &lotm) == (t - lot) && tm.tm_isdst == lotm.tm_isdst && strcmp(abbr(&tm), loab) == 0) { lot = t; lotm = tm; } else hit = t; } show(name, lot, TRUE); show(name, hit, TRUE); return hit; } /* ** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. */ static long delta(newp, oldp) struct tm * newp; struct tm * oldp; { long result; 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 += newp->tm_yday - oldp->tm_yday; result *= HOURSPERDAY; result += newp->tm_hour - oldp->tm_hour; result *= MINSPERHOUR; result += newp->tm_min - oldp->tm_min; result *= SECSPERMIN; result += newp->tm_sec - oldp->tm_sec; return result; } static void show(zone, t, v) char * zone; time_t t; int v; { 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); #ifdef TM_GMTOFF (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); #endif /* defined TM_GMTOFF */ } (void) printf("\n"); } static char * abbr(tmp) struct tm * tmp; { register char * result; static char nada; if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) return &nada; result = tzname[tmp->tm_isdst]; return (result == NULL) ? &nada : result; } Index: vendor/tzcode/dist/usr.sbin/zic/zic.8 =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/zic.8 (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/zic.8 (revision 130777) @@ -1,413 +1,424 @@ .TH ZIC 8 .SH NAME zic \- time zone compiler .SH SYNOPSIS .B zic [ +.B \-\-version +] +[ .B \-v ] [ .B \-d .I directory ] [ .B \-l .I localtime ] [ .B \-p .I posixrules ] [ .B \-L .I leapsecondfilename ] [ .B \-s ] [ .B \-y .I command ] [ .I filename \&... ] .SH DESCRIPTION .if t .ds lq `` .if t .ds rq '' .if n .ds lq \&"\" .if n .ds rq \&"\" .de q \\$3\*(lq\\$1\*(rq\\$2 .. .I Zic reads text from the file(s) named on the command line and creates the time conversion information files specified in this input. If a .I filename is .BR \- , the standard input is read. .PP These options are available: .TP +.BI "\-\-version" +Output version information and exit. +.TP .BI "\-d " directory Create time conversion information files in the named directory rather than in the standard directory named below. .TP .BI "\-l " timezone Use the given time zone as local time. .I Zic will act as if the input contained a link line of the form .sp .ti +.5i Link \fItimezone\fP localtime .TP .BI "\-p " timezone Use the given time zone's rules when handling POSIX-format time zone environment variables. .I Zic will act as if the input contained a link line of the form .sp .ti +.5i Link \fItimezone\fP posixrules .TP .BI "\-L " leapsecondfilename Read leap second information from the file with the given name. If this option is not used, no leap second information appears in output files. .TP .B \-v Complain if a year that appears in a data file is outside the range of years representable by .IR time (2) values. +Also complain if a time of 24:00 +(which cannot be handled by pre-1998 versions of +.IR zic ) +appears in the input. .TP .B \-s Limit time values stored in output files to values that are the same whether they're taken to be signed or unsigned. You can use this option to generate SVVS-compatible files. .TP .BI "\-y " command Use the given .I command rather than .B yearistype when checking year types (see below). .PP Input lines are made up of fields. Fields are separated from one another by any number of white space characters. Leading and trailing white space on input lines is ignored. An unquoted sharp character (#) in the input introduces a comment which extends to the end of the line the sharp character appears on. White space characters and sharp characters may be enclosed in double quotes (") if they're to be used as part of a field. Any line that is blank (after comment stripping) is ignored. Non-blank lines are expected to be of one of three types: rule lines, zone lines, and link lines. .PP A rule line has the form .nf .ti +.5i .ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'TYPE\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u .sp Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S .sp For example: .ti +.5i .sp Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D .sp .fi The fields that make up a rule line are: .TP "\w'LETTER/S'u" .B NAME Gives the (arbitrary) name of the set of rules this rule is part of. .TP .B FROM Gives the first year in which the rule applies. Any integer year can be supplied; the Gregorian calendar is assumed. The word .B minimum (or an abbreviation) means the minimum year representable as an integer. The word .B maximum (or an abbreviation) means the maximum year representable as an integer. Rules can describe times that are not representable as time values, with the unrepresentable times ignored; this allows rules to be portable among hosts with differing time value types. .TP .B TO Gives the final year in which the rule applies. In addition to .B minimum and .B maximum (as above), the word .B only (or an abbreviation) may be used to repeat the value of the .B FROM field. .TP .B TYPE Gives the type of year in which the rule applies. If .B TYPE is .B \- then the rule applies in all years between .B FROM and .B TO inclusive. If .B TYPE is something else, then .I zic executes the command .ti +.5i \fByearistype\fP \fIyear\fP \fItype\fP .br to check the type of a year: an exit status of zero is taken to mean that the year is of the given type; an exit status of one is taken to mean that the year is not of the given type. .TP .B IN Names the month in which the rule takes effect. Month names may be abbreviated. .TP .B ON Gives the day on which the rule takes effect. Recognized forms include: .nf .in +.5i .sp .ta \w'Sun<=25\0\0'u 5 the fifth of the month lastSun the last Sunday in the month lastMon the last Monday in the month Sun>=8 first Sunday on or after the eighth Sun<=25 last Sunday on or before the 25th .fi .in -.5i .sp Names of days of the week may be abbreviated or spelled out in full. Note that there must be no spaces within the .B ON field. .TP .B AT Gives the time of day at which the rule takes effect. Recognized forms include: .nf .in +.5i .sp .ta \w'1:28:13\0\0'u 2 time in hours 2:00 time in hours and minutes 15:00 24-hour format time (for times after noon) 1:28:14 time in hours, minutes, and seconds +\- equivalent to 0 .fi .in -.5i .sp where hour 0 is midnight at the start of the day, and hour 24 is midnight at the end of the day. Any of these forms may be followed by the letter .B w if the given time is local .q "wall clock" time, .B s if the given time is local .q standard time, or .B u (or .B g or .BR z ) if the given time is universal time; in the absence of an indicator, wall clock time is assumed. .TP .B SAVE Gives the amount of time to be added to local standard time when the rule is in effect. This field has the same format as the .B AT field (although, of course, the .B w and .B s suffixes are not used). .TP .B LETTER/S Gives the .q "variable part" (for example, the .q S or .q D in .q EST or .q EDT ) of time zone abbreviations to be used when this rule is in effect. If this field is .BR \- , the variable part is null. .PP A zone line has the form .sp .nf .ti +.5i .ta \w'Zone\0\0'u +\w'Australia/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 [UNTIL] .sp For example: .sp .ti +.5i Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00 .sp .fi The fields that make up a zone line are: .TP "\w'GMTOFF'u" .B NAME The name of the time zone. This is the name used in creating the time conversion information file for the zone. .TP .B GMTOFF The amount of time to add to UTC to get standard time in this zone. This field has the same format as the .B AT and .B SAVE fields of rule lines; begin the field with a minus sign if time must be subtracted from UTC. .TP .B RULES/SAVE The name of the rule(s) that apply in the time zone or, alternately, an amount of time to add to local standard time. If this field is .B \- then standard time always applies in the time zone. .TP .B FORMAT The format for time zone abbreviations in this time zone. The pair of characters .B %s is used to show where the .q "variable part" of the time zone abbreviation goes. Alternately, a slash (/) separates standard and daylight abbreviations. .TP .B UNTIL 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. .IP The next line must be a .q continuation line; this has the same form as a zone line except that the string .q Zone and the name are omitted, as the continuation line will place information starting at the time specified as the .B UNTIL field in the previous line in the file used by the previous line. Continuation lines may contain an .B UNTIL field, just as zone lines do, indicating that the next line is a further continuation. .PP A link line has the form .sp .nf .ti +.5i .ta \w'Link\0\0'u +\w'Europe/Istanbul\0\0'u Link LINK-FROM LINK-TO .sp For example: .sp .ti +.5i Link Europe/Istanbul Asia/Istanbul .sp .fi The .B LINK-FROM field should appear as the .B NAME field in some zone line; the .B LINK-TO field is used as an alternate name for that zone. .PP Except for continuation lines, lines may appear in any order in the input. .PP Lines in the file that describes leap seconds have the following form: .nf .ti +.5i .ta \w'Leap\0\0'u +\w'YEAR\0\0'u +\w'MONTH\0\0'u +\w'DAY\0\0'u +\w'HH:MM:SS\0\0'u +\w'CORR\0\0'u .sp Leap YEAR MONTH DAY HH:MM:SS CORR R/S .sp For example: .ti +.5i .sp Leap 1974 Dec 31 23:59:60 + S .sp .fi The .BR YEAR , .BR MONTH , .BR DAY , and .B HH:MM:SS fields tell when the leap second happened. The .B CORR field should be .q + if a second was added or .q - if a second was skipped. .\" There's no need to document the following, since it's impossible for more .\" than one leap second to be inserted or deleted at a time. .\" The C Standard is in error in suggesting the possibility. .\" See Terry J Quinn, The BIPM and the accurate measure of time, .\" Proc IEEE 79, 7 (July 1991), 894-905. .\" or .\" .q ++ .\" if two seconds were added .\" or .\" .q -- .\" if two seconds were skipped. The .B R/S field should be (an abbreviation of) .q Stationary if the leap second time given by the other fields should be interpreted as UTC or (an abbreviation of) .q Rolling if the leap second time given by the other fields should be interpreted as local wall clock time. .SH NOTE For areas with more than two types of local time, you may need to use local standard time in the .B AT field of the earliest transition time's rule to ensure that the earliest transition time recorded in the compiled file is correct. .SH FILE /usr/local/etc/zoneinfo standard directory used for created files .SH "SEE ALSO" newctime(3), tzfile(5), zdump(8) -.\" @(#)zic.8 7.18 +.\" @(#)zic.8 7.22 Index: vendor/tzcode/dist/usr.sbin/zic/zic.c =================================================================== --- vendor/tzcode/dist/usr.sbin/zic/zic.c (revision 130776) +++ vendor/tzcode/dist/usr.sbin/zic/zic.c (revision 130777) @@ -1,2210 +1,2236 @@ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)zic.c 7.96"; -#endif /* !defined NOID */ -#endif /* !defined lint */ +static char elsieid[] = "@(#)zic.c 7.116"; #include "private.h" #include "locale.h" #include "tzfile.h" -#ifdef unix -#include "sys/stat.h" /* for umask manifest constants */ -#endif /* defined unix */ +#if HAVE_SYS_STAT_H +#include "sys/stat.h" +#endif +#ifdef S_IRUSR +#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#else +#define MKDIR_UMASK 0755 +#endif + /* ** On some ancient hosts, predicates like `isspace(C)' are defined ** 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. ** If isascii is not defined, the isascii check succeeds trivially. */ #include "ctype.h" #ifndef isascii #define isascii(x) 1 #endif struct rule { const char * r_filename; int r_linenum; const char * r_name; int r_loyear; /* for example, 1986 */ int r_hiyear; /* for example, 1986 */ const char * r_yrtype; int r_month; /* 0..11 */ int r_dycode; /* see below */ int r_dayofmonth; int r_wday; long r_tod; /* time from midnight */ int r_todisstd; /* above is standard time if TRUE */ /* or wall clock time if FALSE */ int r_todisgmt; /* above is GMT if TRUE */ /* or local time if FALSE */ long r_stdoff; /* offset from standard time */ 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 */ }; /* ** r_dycode r_dayofmonth r_wday */ #define DC_DOM 0 /* 1..31 */ /* unused */ #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ struct zone { const char * z_filename; int z_linenum; const char * z_name; long z_gmtoff; const char * z_rule; const char * z_format; long z_stdoff; struct rule * z_rules; int z_nrules; struct rule z_untilrule; time_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 char * optarg; extern int optind; static void addtt P((time_t starttime, int type)); static int addtype P((long gmtoff, const char * abbr, int isdst, int ttisstd, int ttisgmt)); static void leapadd P((time_t t, int positive, int rolling, int count)); static void adjleap P((void)); static void associate P((void)); static int ciequal P((const char * ap, const char * bp)); static void convert P((long val, char * buf)); static void dolink P((const char * fromfile, const char * tofile)); static void doabbr P((char * abbr, const char * format, const char * letters, int isdst)); static void eat P((const char * name, int num)); static void eats P((const char * name, int num, const char * rname, int rnum)); static long eitol P((int i)); static void error P((const char * message)); static char ** getfields P((char * buf)); static long gethms P((const char * string, const char * errstrng, int signable)); static void infile P((const char * filename)); static void inleap P((char ** fields, int nfields)); static void inlink P((char ** fields, int nfields)); static void inrule P((char ** fields, int nfields)); static int inzcont P((char ** fields, int nfields)); static int inzone P((char ** fields, int nfields)); static int inzsub P((char ** fields, int nfields, int iscont)); static int itsabbr P((const char * abbr, const char * word)); static int itsdir P((const char * name)); static int lowerit P((int c)); static char * memcheck P((char * tocheck)); static int mkdirs P((char * filename)); static void newabbr P((const char * abbr)); static long oadd P((long t1, long t2)); static void outzone P((const struct zone * zp, int ntzones)); static void puttzcode P((long code, FILE * fp)); static int rcomp P((const void * leftp, const void * rightp)); static time_t rpytime P((const struct rule * rp, int wantedy)); static void rulesub P((struct rule * rp, 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 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) */ static int charcnt; static int errors; static const char * filename; static int leapcnt; static int linenum; static time_t max_time; static int max_year; static int max_year_representable; static time_t min_time; static int min_year; static int min_year_representable; static int noise; static const char * rfilename; static int rlinenum; static const char * progname; static int timecnt; static int typecnt; /* ** Line codes. */ #define LC_RULE 0 #define LC_ZONE 1 #define LC_LINK 2 #define LC_LEAP 3 /* ** Which fields are which on a Zone line. */ #define ZF_NAME 1 #define ZF_GMTOFF 2 #define ZF_RULE 3 #define ZF_FORMAT 4 #define ZF_TILYEAR 5 #define ZF_TILMONTH 6 #define ZF_TILDAY 7 #define ZF_TILTIME 8 #define ZONE_MINFIELDS 5 #define ZONE_MAXFIELDS 9 /* ** Which fields are which on a Zone continuation line. */ #define ZFC_GMTOFF 0 #define ZFC_RULE 1 #define ZFC_FORMAT 2 #define ZFC_TILYEAR 3 #define ZFC_TILMONTH 4 #define ZFC_TILDAY 5 #define ZFC_TILTIME 6 #define ZONEC_MINFIELDS 3 #define ZONEC_MAXFIELDS 7 /* ** Which files are which on a Rule line. */ #define RF_NAME 1 #define RF_LOYEAR 2 #define RF_HIYEAR 3 #define RF_COMMAND 4 #define RF_MONTH 5 #define RF_DAY 6 #define RF_TOD 7 #define RF_STDOFF 8 #define RF_ABBRVAR 9 #define RULE_FIELDS 10 /* ** Which fields are which on a Link line. */ #define LF_FROM 1 #define LF_TO 2 #define LINK_FIELDS 3 /* ** Which fields are which on a Leap line. */ #define LP_YEAR 1 #define LP_MONTH 2 #define LP_DAY 3 #define LP_TIME 4 #define LP_CORR 5 #define LP_ROLL 6 #define LEAP_FIELDS 7 /* ** Year synonyms. */ #define YR_MINIMUM 0 #define YR_MAXIMUM 1 #define YR_ONLY 2 static struct rule * rules; static int nrules; /* number of rules */ static struct zone * zones; static int nzones; /* number of zones */ struct link { const char * l_filename; int l_linenum; const char * l_from; const char * l_to; }; static struct link * links; static int nlinks; struct lookup { const char * l_word; const int l_value; }; static struct lookup const * byword P((const char * string, const struct lookup * lp)); static struct lookup const line_codes[] = { { "Rule", LC_RULE }, { "Zone", LC_ZONE }, { "Link", LC_LINK }, { "Leap", LC_LEAP }, { NULL, 0} }; static struct lookup const mon_names[] = { { "January", TM_JANUARY }, { "February", TM_FEBRUARY }, { "March", TM_MARCH }, { "April", TM_APRIL }, { "May", TM_MAY }, { "June", TM_JUNE }, { "July", TM_JULY }, { "August", TM_AUGUST }, { "September", TM_SEPTEMBER }, { "October", TM_OCTOBER }, { "November", TM_NOVEMBER }, { "December", TM_DECEMBER }, { NULL, 0 } }; static struct lookup const wday_names[] = { { "Sunday", TM_SUNDAY }, { "Monday", TM_MONDAY }, { "Tuesday", TM_TUESDAY }, { "Wednesday", TM_WEDNESDAY }, { "Thursday", TM_THURSDAY }, { "Friday", TM_FRIDAY }, { "Saturday", TM_SATURDAY }, { NULL, 0 } }; static struct lookup const lasts[] = { { "last-Sunday", TM_SUNDAY }, { "last-Monday", TM_MONDAY }, { "last-Tuesday", TM_TUESDAY }, { "last-Wednesday", TM_WEDNESDAY }, { "last-Thursday", TM_THURSDAY }, { "last-Friday", TM_FRIDAY }, { "last-Saturday", TM_SATURDAY }, { NULL, 0 } }; static struct lookup const begin_years[] = { { "minimum", YR_MINIMUM }, { "maximum", YR_MAXIMUM }, { NULL, 0 } }; static struct lookup const end_years[] = { { "minimum", YR_MINIMUM }, { "maximum", YR_MAXIMUM }, { "only", YR_ONLY }, { NULL, 0 } }; static struct lookup const leap_types[] = { { "Rolling", TRUE }, { "Stationary", FALSE }, { NULL, 0 } }; static const int len_months[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; static const int len_years[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; static struct attype { time_t at; unsigned char type; } attypes[TZ_MAX_TIMES]; static long gmtoffs[TZ_MAX_TYPES]; static char isdsts[TZ_MAX_TYPES]; static unsigned char abbrinds[TZ_MAX_TYPES]; static char ttisstds[TZ_MAX_TYPES]; static char ttisgmts[TZ_MAX_TYPES]; static char chars[TZ_MAX_CHARS]; static time_t trans[TZ_MAX_LEAPS]; static long corr[TZ_MAX_LEAPS]; static char roll[TZ_MAX_LEAPS]; /* ** Memory allocation. */ static char * memcheck(ptr) char * const ptr; { if (ptr == NULL) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, e); (void) exit(EXIT_FAILURE); } return ptr; } #define emalloc(size) memcheck(imalloc(size)) #define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) /* ** 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; const int num; const char * const rname; const int rnum; { filename = name; linenum = num; rfilename = rname; rlinenum = rnum; } static void eat(name, num) const char * const name; const int num; { eats(name, num, (char *) NULL, -1); } static void error(string) const char * const string; { /* ** Match the format of "cc" to allow sh users to ** zic ... 2>&1 | error -t "*" -v ** on BSD systems. */ (void) fprintf(stderr, _("\"%s\", line %d: %s"), filename, linenum, string); if (rfilename != NULL) (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), rfilename, rlinenum); (void) fprintf(stderr, "\n"); ++errors; } static void warning(string) const char * const string; { char * cp; cp = ecpyalloc(_("warning: ")); cp = ecatalloc(cp, string); error(cp); ifree(cp); --errors; } static void usage P((void)) { - (void) fprintf(stderr, _("%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"), + (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); } static const char * psxrules; static const char * lcltime; static const char * directory; static const char * leapsec; static const char * yitcommand; static int sflag = FALSE; int main(argc, argv) int argc; char * argv[]; { register int i; register int j; register int c; #ifdef unix (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); #endif /* defined unix */ #if HAVE_GETTEXT - 0 (void) setlocale(LC_MESSAGES, ""); #ifdef TZ_DOMAINDIR (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); #endif /* defined TEXTDOMAINDIR */ (void) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT - 0 */ progname = argv[0]; + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "--version") == 0) { + (void) printf("%s\n", elsieid); + (void) exit(EXIT_SUCCESS); + } while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1) switch (c) { default: usage(); case 'd': if (directory == NULL) directory = optarg; else { (void) fprintf(stderr, _("%s: More than one -d option specified\n"), progname); (void) exit(EXIT_FAILURE); } break; case 'l': if (lcltime == NULL) lcltime = optarg; else { (void) fprintf(stderr, _("%s: More than one -l option specified\n"), progname); (void) exit(EXIT_FAILURE); } break; case 'p': if (psxrules == NULL) psxrules = optarg; else { (void) fprintf(stderr, _("%s: More than one -p option specified\n"), progname); (void) exit(EXIT_FAILURE); } break; case 'y': if (yitcommand == NULL) yitcommand = optarg; else { (void) fprintf(stderr, _("%s: More than one -y option specified\n"), progname); (void) exit(EXIT_FAILURE); } break; case 'L': if (leapsec == NULL) leapsec = optarg; else { (void) fprintf(stderr, _("%s: More than one -L option specified\n"), progname); (void) exit(EXIT_FAILURE); } break; case 'v': noise = TRUE; break; case 's': sflag = TRUE; break; } if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) usage(); /* usage message by request */ if (directory == NULL) directory = TZDIR; if (yitcommand == NULL) yitcommand = "yearistype"; setboundaries(); if (optind < argc && leapsec != NULL) { infile(leapsec); adjleap(); } for (i = optind; i < argc; ++i) infile(argv[i]); if (errors) (void) exit(EXIT_FAILURE); associate(); for (i = 0; i < nzones; i = j) { /* ** Find the next non-continuation zone entry. */ for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) continue; outzone(&zones[i], j - i); } /* ** Make links. */ - for (i = 0; i < nlinks; ++i) + 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 (lcltime != NULL) + } + if (lcltime != NULL) { + eat("command line", 1); dolink(lcltime, TZDEFAULT); - if (psxrules != NULL) + } + if (psxrules != NULL) { + eat("command line", 1); dolink(psxrules, TZDEFRULES); + } return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } static void dolink(fromfile, tofile) const char * const fromfile; const char * const tofile; { register char * fromname; register char * toname; if (fromfile[0] == '/') fromname = ecpyalloc(fromfile); else { fromname = ecpyalloc(directory); fromname = ecatalloc(fromname, "/"); fromname = ecatalloc(fromname, fromfile); } if (tofile[0] == '/') toname = ecpyalloc(tofile); else { toname = ecpyalloc(directory); toname = ecatalloc(toname, "/"); toname = ecatalloc(toname, tofile); } /* ** We get to be careful here since ** there's a fair chance of root running us. */ if (!itsdir(toname)) (void) remove(toname); if (link(fromname, toname) != 0) { int result; if (mkdirs(toname) != 0) (void) exit(EXIT_FAILURE); + result = link(fromname, toname); -#if (HAVE_SYMLINK - 0) - if (result != 0) { - result = symlink(fromname, toname); +#if (HAVE_SYMLINK - 0) + 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) warning(_("hard link failed, symbolic link used")); + ifree(symlinkcontents); } #endif 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); } } 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) static void setboundaries P((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; } static int itsdir(name) const char * const name; { register char * myname; register int accres; myname = ecpyalloc(name); myname = ecatalloc(myname, "/."); accres = access(myname, F_OK); ifree(myname); return accres == 0; } /* ** Associate sets of rules with zones. */ /* ** Sort by rule name. */ static int rcomp(cp1, cp2) const void * cp1; const void * cp2; { return strcmp(((const struct rule *) cp1)->r_name, ((const struct rule *) cp2)->r_name); } static void associate P((void)) { register struct zone * zp; register struct rule * rp; register int base, out; register int i, j; if (nrules != 0) { (void) qsort((void *) rules, (size_t) nrules, (size_t) sizeof *rules, rcomp); for (i = 0; i < nrules - 1; ++i) { if (strcmp(rules[i].r_name, rules[i + 1].r_name) != 0) continue; if (strcmp(rules[i].r_filename, rules[i + 1].r_filename) == 0) continue; eat(rules[i].r_filename, rules[i].r_linenum); warning(_("same rule name in multiple files")); eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); warning(_("same rule name in multiple files")); for (j = i + 2; j < nrules; ++j) { if (strcmp(rules[i].r_name, rules[j].r_name) != 0) break; if (strcmp(rules[i].r_filename, rules[j].r_filename) == 0) continue; if (strcmp(rules[i + 1].r_filename, rules[j].r_filename) == 0) continue; break; } i = j - 1; } } for (i = 0; i < nzones; ++i) { zp = &zones[i]; zp->z_rules = NULL; zp->z_nrules = 0; } for (base = 0; base < nrules; base = out) { rp = &rules[base]; for (out = base + 1; out < nrules; ++out) if (strcmp(rp->r_name, rules[out].r_name) != 0) break; for (i = 0; i < nzones; ++i) { zp = &zones[i]; if (strcmp(zp->z_rule, rp->r_name) != 0) continue; zp->z_rules = rp; zp->z_nrules = out - base; } } for (i = 0; i < nzones; ++i) { zp = &zones[i]; if (zp->z_nrules == 0) { /* ** Maybe we have a local standard time offset. */ eat(zp->z_filename, zp->z_linenum); zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), TRUE); /* ** Note, though, that if there's no rule, ** a '%s' in the format is a bad thing. */ if (strchr(zp->z_format, '%') != 0) error(_("%s in ruleless zone")); } } if (errors) (void) exit(EXIT_FAILURE); } static void infile(name) const char * name; { register FILE * fp; register char ** fields; register char * cp; register const struct lookup * lp; register int nfields; register int wantcont; register int num; char buf[BUFSIZ]; if (strcmp(name, "-") == 0) { name = _("standard input"); fp = stdin; } else if ((fp = fopen(name, "r")) == NULL) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), progname, name, e); (void) exit(EXIT_FAILURE); } wantcont = FALSE; for (num = 1; ; ++num) { eat(name, num); if (fgets(buf, (int) sizeof buf, fp) != buf) break; cp = strchr(buf, '\n'); if (cp == NULL) { error(_("line too long")); (void) exit(EXIT_FAILURE); } *cp = '\0'; fields = getfields(buf); nfields = 0; while (fields[nfields] != NULL) { static char nada; if (strcmp(fields[nfields], "-") == 0) fields[nfields] = &nada; ++nfields; } if (nfields == 0) { /* nothing to do */ } else if (wantcont) { wantcont = inzcont(fields, nfields); } else { lp = byword(fields[0], line_codes); if (lp == NULL) error(_("input line of unknown type")); else switch ((int) (lp->l_value)) { case LC_RULE: inrule(fields, nfields); wantcont = FALSE; break; case LC_ZONE: wantcont = inzone(fields, nfields); break; case LC_LINK: inlink(fields, nfields); wantcont = FALSE; break; case LC_LEAP: if (name != leapsec) (void) fprintf(stderr, _("%s: Leap line in non leap seconds file %s\n"), progname, name); else inleap(fields, nfields); wantcont = FALSE; break; default: /* "cannot happen" */ (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) exit(EXIT_FAILURE); } } ifree((char *) fields); } if (ferror(fp)) { (void) fprintf(stderr, _("%s: Error reading %s\n"), progname, filename); (void) 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); } if (wantcont) error(_("expected continuation line not found")); } /* ** Convert a string of one of the forms ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss ** into a number of seconds. ** A null string maps to zero. ** Call error with errstring and return zero on errors. */ static long gethms(string, errstring, signable) const char * string; const char * const errstring; const int signable; { int hh, mm, ss, sign; if (string == NULL || *string == '\0') return 0; if (!signable) sign = 1; else if (*string == '-') { sign = -1; ++string; } else sign = 1; if (sscanf(string, scheck(string, "%d"), &hh) == 1) mm = ss = 0; else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) ss = 0; else if (sscanf(string, scheck(string, "%d:%d:%d"), &hh, &mm, &ss) != 3) { error(errstring); return 0; } if ((hh < 0 || hh >= HOURSPERDAY || mm < 0 || mm >= MINSPERHOUR || ss < 0 || ss > SECSPERMIN) && !(hh == HOURSPERDAY && mm == 0 && ss == 0)) { error(errstring); return 0; } + if (noise && hh == HOURSPERDAY) + warning(_("24:00 not handled by pre-1998 versions of zic")); return eitol(sign) * (eitol(hh * MINSPERHOUR + mm) * eitol(SECSPERMIN) + eitol(ss)); } static void inrule(fields, nfields) register char ** const fields; const int nfields; { static struct rule r; if (nfields != RULE_FIELDS) { error(_("wrong number of fields on Rule line")); return; } if (*fields[RF_NAME] == '\0') { error(_("nameless rule")); return; } r.r_filename = filename; r.r_linenum = linenum; r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); r.r_name = ecpyalloc(fields[RF_NAME]); r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); rules = (struct rule *) (void *) erealloc((char *) rules, (int) ((nrules + 1) * sizeof *rules)); rules[nrules++] = r; } static int inzone(fields, nfields) register char ** const fields; const int nfields; { register int i; static char * buf; if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { error(_("wrong number of fields on Zone line")); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); (void) sprintf(buf, _("\"Zone %s\" line and -l option are mutually exclusive"), TZDEFAULT); error(buf); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); (void) sprintf(buf, _("\"Zone %s\" line and -p option are mutually exclusive"), TZDEFRULES); error(buf); return FALSE; } for (i = 0; i < nzones; ++i) if (zones[i].z_name != NULL && strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { buf = erealloc(buf, (int) (132 + strlen(fields[ZF_NAME]) + strlen(zones[i].z_filename))); (void) sprintf(buf, _("duplicate zone name %s (file \"%s\", line %d)"), fields[ZF_NAME], zones[i].z_filename, zones[i].z_linenum); error(buf); return FALSE; } return inzsub(fields, nfields, FALSE); } static int inzcont(fields, nfields) register char ** const fields; const int nfields; { if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { error(_("wrong number of fields on Zone continuation line")); return FALSE; } return inzsub(fields, nfields, TRUE); } static int inzsub(fields, nfields, iscont) register char ** const fields; const int nfields; const int iscont; { register char * cp; static struct zone z; register int i_gmtoff, i_rule, i_format; register int i_untilyear, i_untilmonth; register int i_untilday, i_untiltime; register int hasuntil; if (iscont) { i_gmtoff = ZFC_GMTOFF; i_rule = ZFC_RULE; i_format = ZFC_FORMAT; i_untilyear = ZFC_TILYEAR; i_untilmonth = ZFC_TILMONTH; i_untilday = ZFC_TILDAY; i_untiltime = ZFC_TILTIME; z.z_name = NULL; } else { i_gmtoff = ZF_GMTOFF; i_rule = ZF_RULE; i_format = ZF_FORMAT; i_untilyear = ZF_TILYEAR; i_untilmonth = ZF_TILMONTH; i_untilday = ZF_TILDAY; i_untiltime = ZF_TILTIME; z.z_name = ecpyalloc(fields[ZF_NAME]); } z.z_filename = filename; z.z_linenum = linenum; z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); if ((cp = strchr(fields[i_format], '%')) != 0) { if (*++cp != 's' || strchr(cp, '%') != 0) { error(_("invalid abbreviation format")); return FALSE; } } z.z_rule = ecpyalloc(fields[i_rule]); z.z_format = ecpyalloc(fields[i_format]); hasuntil = nfields > i_untilyear; if (hasuntil) { z.z_untilrule.r_filename = filename; z.z_untilrule.r_linenum = linenum; rulesub(&z.z_untilrule, fields[i_untilyear], "only", "", (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", (nfields > i_untilday) ? fields[i_untilday] : "1", (nfields > i_untiltime) ? fields[i_untiltime] : "0"); z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); if (iscont && nzones > 0 && z.z_untiltime > min_time && z.z_untiltime < max_time && 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")); return FALSE; } } zones = (struct zone *) (void *) erealloc((char *) zones, (int) ((nzones + 1) * sizeof *zones)); zones[nzones++] = z; /* ** If there was an UNTIL field on this line, ** there's more information about the zone on the next line. */ return hasuntil; } static void inleap(fields, nfields) register char ** const fields; const int nfields; { register const char * cp; register const struct lookup * lp; register int i, j; int year, month, day; long dayoff, tod; time_t t; if (nfields != LEAP_FIELDS) { error(_("wrong number of fields on Leap line")); return; } dayoff = 0; cp = fields[LP_YEAR]; if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { /* * Leapin' Lizards! */ error(_("invalid leaping year")); return; } j = EPOCH_YEAR; while (j != year) { if (year > j) { i = len_years[isleap(j)]; ++j; } else { --j; i = -len_years[isleap(j)]; } dayoff = oadd(dayoff, eitol(i)); } if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { error(_("invalid month name")); return; } month = lp->l_value; j = TM_JANUARY; while (j != month) { i = len_months[isleap(year)][j]; dayoff = oadd(dayoff, eitol(i)); ++j; } cp = fields[LP_DAY]; if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || day <= 0 || day > len_months[isleap(year)][month]) { error(_("invalid day of month")); return; } dayoff = oadd(dayoff, eitol(day - 1)); if (dayoff < 0 && !TYPE_SIGNED(time_t)) { error(_("time before zero")); return; } - t = (time_t) dayoff * SECSPERDAY; - /* - ** Cheap overflow check. - */ - if (t / SECSPERDAY != dayoff) { - error(_("time overflow")); + if (dayoff < min_time / SECSPERDAY) { + error(_("time too small")); return; } + if (dayoff > max_time / SECSPERDAY) { + error(_("time too large")); + return; + } + t = (time_t) dayoff * SECSPERDAY; tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); cp = fields[LP_CORR]; { register int positive; int count; if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ positive = FALSE; count = 1; } else if (strcmp(cp, "--") == 0) { positive = FALSE; count = 2; } else if (strcmp(cp, "+") == 0) { positive = TRUE; count = 1; } else if (strcmp(cp, "++") == 0) { positive = TRUE; count = 2; } else { error(_("illegal CORRECTION field on Leap line")); return; } if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { error(_("illegal Rolling/Stationary field on Leap line")); return; } leapadd(tadd(t, tod), positive, lp->l_value, count); } } static void inlink(fields, nfields) register char ** const fields; const int nfields; { struct link l; if (nfields != LINK_FIELDS) { error(_("wrong number of fields on Link line")); return; } if (*fields[LF_FROM] == '\0') { error(_("blank FROM field on Link line")); return; } if (*fields[LF_TO] == '\0') { error(_("blank TO field on Link line")); return; } l.l_filename = filename; l.l_linenum = linenum; l.l_from = ecpyalloc(fields[LF_FROM]); l.l_to = ecpyalloc(fields[LF_TO]); links = (struct link *) (void *) erealloc((char *) links, (int) ((nlinks + 1) * sizeof *links)); links[nlinks++] = l; } static void rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) register struct rule * const rp; const char * const loyearp; const char * const hiyearp; const char * const typep; const char * const monthp; const char * const dayp; const char * const timep; { register const struct lookup * lp; register const char * cp; register char * dp; register char * ep; if ((lp = byword(monthp, mon_names)) == NULL) { error(_("invalid month name")); return; } rp->r_month = lp->l_value; rp->r_todisstd = FALSE; rp->r_todisgmt = FALSE; dp = ecpyalloc(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { case 's': /* Standard */ rp->r_todisstd = TRUE; rp->r_todisgmt = FALSE; *ep = '\0'; break; case 'w': /* Wall */ rp->r_todisstd = FALSE; rp->r_todisgmt = FALSE; *ep = '\0'; break; case 'g': /* Greenwich */ case 'u': /* Universal */ case 'z': /* Zulu */ rp->r_todisstd = TRUE; rp->r_todisgmt = TRUE; *ep = '\0'; break; } } rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); ifree(dp); /* ** Year work. */ cp = loyearp; lp = byword(cp, begin_years); if (lp != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: rp->r_loyear = INT_MIN; break; case YR_MAXIMUM: rp->r_loyear = INT_MAX; break; default: /* "cannot happen" */ (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) 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) { case YR_MINIMUM: rp->r_hiyear = INT_MIN; break; case YR_MAXIMUM: rp->r_hiyear = INT_MAX; break; case YR_ONLY: rp->r_hiyear = rp->r_loyear; break; default: /* "cannot happen" */ (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) 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(_("starting year too low to be represented")); + warning(_("ending year too low to be represented")); else if (rp->r_loyear > max_year_representable) - warning(_("starting year too high to be represented")); + warning(_("ending year too high to be represented")); } if (rp->r_loyear > rp->r_hiyear) { error(_("starting year greater than ending year")); return; } if (*typep == '\0') rp->r_yrtype = NULL; else { if (rp->r_loyear == rp->r_hiyear) { error(_("typed single year")); return; } rp->r_yrtype = ecpyalloc(typep); } if (rp->r_loyear < min_year && rp->r_loyear > 0) min_year = rp->r_loyear; /* ** Day work. ** Accept things such as: ** 1 ** last-Sunday ** Sun<=20 ** Sun>=7 */ dp = ecpyalloc(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { if ((ep = strchr(dp, '<')) != 0) rp->r_dycode = DC_DOWLEQ; else if ((ep = strchr(dp, '>')) != 0) rp->r_dycode = DC_DOWGEQ; else { ep = dp; rp->r_dycode = DC_DOM; } if (rp->r_dycode != DC_DOM) { *ep++ = 0; if (*ep++ != '=') { error(_("invalid day of month")); ifree(dp); return; } if ((lp = byword(dp, wday_names)) == NULL) { error(_("invalid weekday name")); ifree(dp); return; } rp->r_wday = lp->l_value; } if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || rp->r_dayofmonth <= 0 || (rp->r_dayofmonth > len_months[1][rp->r_month])) { error(_("invalid day of month")); ifree(dp); return; } } ifree(dp); } static void convert(val, buf) const long val; char * const buf; { register int i; register long shift; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) buf[i] = val >> shift; } static void puttzcode(val, fp) const long val; FILE * const fp; { char buf[4]; convert(val, buf); (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); } static int atcomp(avp, bvp) void * avp; void * bvp; { if (((struct attype *) avp)->at < ((struct attype *) bvp)->at) return -1; else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at) return 1; else return 0; } static void writezone(name) const char * const name; { 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]; /* ** Sort. */ if (timecnt > 1) (void) qsort((void *) attypes, (size_t) timecnt, (size_t) sizeof *attypes, atcomp); /* ** Optimize. */ { int fromi; int toi; toi = 0; fromi = 0; while (fromi < timecnt && attypes[fromi].at < min_time) ++fromi; if (isdsts[0] == 0) 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[toi - 1].type != attypes[fromi].type) attypes[toi++] = attypes[fromi]; } timecnt = toi; } /* ** Transfer. */ for (i = 0; i < timecnt; ++i) { ats[i] = attypes[i].at; types[i] = attypes[i].type; } fullname = erealloc(fullname, (int) (strlen(directory) + 1 + strlen(name) + 1)); (void) sprintf(fullname, "%s/%s", directory, name); /* ** Remove old file, if any, to snap links. */ if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"), progname, fullname, e); (void) exit(EXIT_FAILURE); } if ((fp = fopen(fullname, "wb")) == NULL) { if (mkdirs(fullname) != 0) (void) 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); } } convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); convert(eitol(typecnt), tzh.tzh_ttisstdcnt); convert(eitol(leapcnt), tzh.tzh_leapcnt); convert(eitol(timecnt), tzh.tzh_timecnt); convert(eitol(typecnt), tzh.tzh_typecnt); convert(eitol(charcnt), tzh.tzh_charcnt); (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); #define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp) DO(tzh_magic); DO(tzh_reserved); DO(tzh_ttisgmtcnt); DO(tzh_ttisstdcnt); DO(tzh_leapcnt); DO(tzh_timecnt); DO(tzh_typecnt); DO(tzh_charcnt); #undef DO for (i = 0; i < timecnt; ++i) { j = leapcnt; while (--j >= 0) if (ats[i] >= trans[j]) { ats[i] = tadd(ats[i], corr[j]); break; } puttzcode((long) ats[i], fp); } if (timecnt > 0) (void) fwrite((void *) types, (size_t) sizeof types[0], (size_t) timecnt, fp); for (i = 0; i < typecnt; ++i) { puttzcode((long) gmtoffs[i], fp); (void) putc(isdsts[i], fp); (void) putc(abbrinds[i], fp); } if (charcnt != 0) (void) fwrite((void *) chars, (size_t) sizeof chars[0], (size_t) charcnt, fp); for (i = 0; i < leapcnt; ++i) { if (roll[i]) { if (timecnt == 0 || trans[i] < ats[0]) { j = 0; while (isdsts[j]) if (++j >= typecnt) { j = 0; break; } } else { j = 1; while (j < timecnt && trans[i] >= ats[j]) ++j; j = types[j - 1]; } puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); } else puttzcode((long) trans[i], fp); puttzcode((long) corr[i], fp); } for (i = 0; i < typecnt; ++i) (void) putc(ttisstds[i], fp); for (i = 0; i < typecnt; ++i) (void) putc(ttisgmts[i], fp); if (ferror(fp) || fclose(fp)) { (void) fprintf(stderr, _("%s: Error writing %s\n"), progname, fullname); (void) exit(EXIT_FAILURE); } } static void doabbr(abbr, format, letters, isdst) char * const abbr; const char * const format; const char * const letters; const int isdst; { if (strchr(format, '/') == NULL) { if (letters == NULL) (void) strcpy(abbr, format); else (void) sprintf(abbr, format, letters); } else if (isdst) (void) strcpy(abbr, strchr(format, '/') + 1); else { (void) strcpy(abbr, format); *strchr(abbr, '/') = '\0'; } } static void outzone(zpfirst, zonecount) const struct zone * const zpfirst; const int zonecount; { register const struct zone * zp; register struct rule * rp; register int i, j; register int usestart, useuntil; register time_t starttime, untiltime; register long gmtoff; register long stdoff; register int year; register long startoff; register int startttisstd; register int startttisgmt; register int type; char startbuf[BUFSIZ]; INITIALIZE(untiltime); INITIALIZE(starttime); /* ** Now. . .finally. . .generate some useful data! */ timecnt = 0; typecnt = 0; charcnt = 0; /* - ** A guess that may well be corrected later. - */ - stdoff = 0; - /* ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) ** for noting the need to unconditionally initialize startttisstd. */ startttisstd = FALSE; startttisgmt = FALSE; for (i = 0; i < zonecount; ++i) { + /* + ** A guess that may well be corrected later. + */ + stdoff = 0; zp = &zpfirst[i]; usestart = i > 0 && (zp - 1)->z_untiltime > min_time; useuntil = i < (zonecount - 1); if (useuntil && zp->z_untiltime <= min_time) continue; gmtoff = zp->z_gmtoff; eat(zp->z_filename, zp->z_linenum); *startbuf = '\0'; startoff = zp->z_gmtoff; if (zp->z_nrules == 0) { stdoff = zp->z_stdoff; doabbr(startbuf, zp->z_format, (char *) NULL, stdoff != 0); type = addtype(oadd(zp->z_gmtoff, stdoff), startbuf, stdoff != 0, startttisstd, startttisgmt); if (usestart) { addtt(starttime, type); usestart = FALSE; - } - else if (stdoff != 0) + } else if (stdoff != 0) addtt(min_time, type); } else for (year = min_year; year <= max_year; ++year) { if (useuntil && year > zp->z_untilrule.r_hiyear) break; /* ** Mark which rules to do in the current year. ** For those to do, calculate rpytime(rp, year); */ for (j = 0; j < zp->z_nrules; ++j) { rp = &zp->z_rules[j]; eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); rp->r_todo = year >= rp->r_loyear && year <= rp->r_hiyear && yearistype(year, rp->r_yrtype); if (rp->r_todo) rp->r_temp = rpytime(rp, year); } for ( ; ; ) { register int k; register time_t jtime, ktime; register long offset; char buf[BUFSIZ]; INITIALIZE(ktime); if (useuntil) { /* ** Turn untiltime into UTC ** assuming the current gmtoff and ** stdoff values. */ untiltime = zp->z_untiltime; if (!zp->z_untilrule.r_todisgmt) untiltime = tadd(untiltime, -gmtoff); if (!zp->z_untilrule.r_todisstd) untiltime = tadd(untiltime, -stdoff); } /* ** Find the rule (of those to do, if any) ** that takes effect earliest in the year. */ k = -1; for (j = 0; j < zp->z_nrules; ++j) { rp = &zp->z_rules[j]; if (!rp->r_todo) continue; eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); offset = rp->r_todisgmt ? 0 : gmtoff; if (!rp->r_todisstd) offset = oadd(offset, stdoff); jtime = rp->r_temp; if (jtime == min_time || jtime == max_time) continue; jtime = tadd(jtime, -offset); if (k < 0 || jtime < ktime) { k = j; ktime = jtime; } } if (k < 0) break; /* go on to next year */ rp = &zp->z_rules[k]; rp->r_todo = FALSE; if (useuntil && ktime >= untiltime) break; stdoff = rp->r_stdoff; if (usestart && ktime == starttime) usestart = FALSE; if (usestart) { if (ktime < starttime) { startoff = oadd(zp->z_gmtoff, stdoff); doabbr(startbuf, zp->z_format, rp->r_abbrvar, rp->r_stdoff != 0); continue; } if (*startbuf == '\0' && startoff == oadd(zp->z_gmtoff, stdoff)) { doabbr(startbuf, zp->z_format, rp->r_abbrvar, rp->r_stdoff != 0); } } eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); doabbr(buf, zp->z_format, rp->r_abbrvar, rp->r_stdoff != 0); offset = oadd(zp->z_gmtoff, rp->r_stdoff); type = addtype(offset, buf, rp->r_stdoff != 0, rp->r_todisstd, rp->r_todisgmt); addtt(ktime, type); } } if (usestart) { if (*startbuf == '\0' && zp->z_format != NULL && strchr(zp->z_format, '%') == NULL && strchr(zp->z_format, '/') == NULL) (void) strcpy(startbuf, zp->z_format); eat(zp->z_filename, zp->z_linenum); if (*startbuf == '\0') error(_("can't determine time zone abbreviation to use just after until time")); else addtt(starttime, addtype(startoff, startbuf, startoff != zp->z_gmtoff, startttisstd, startttisgmt)); } /* ** Now we may get to set starttime for the next zone line. */ if (useuntil) { startttisstd = zp->z_untilrule.r_todisstd; startttisgmt = zp->z_untilrule.r_todisgmt; starttime = zp->z_untiltime; if (!startttisstd) starttime = tadd(starttime, -stdoff); if (!startttisgmt) starttime = tadd(starttime, -gmtoff); } } writezone(zpfirst->z_name); } static void addtt(starttime, type) const time_t starttime; int type; { if (starttime <= min_time || (timecnt == 1 && attypes[0].at < min_time)) { gmtoffs[0] = gmtoffs[type]; isdsts[0] = isdsts[type]; ttisstds[0] = ttisstds[type]; ttisgmts[0] = ttisgmts[type]; if (abbrinds[type] != 0) (void) strcpy(chars, &chars[abbrinds[type]]); abbrinds[0] = 0; charcnt = strlen(chars) + 1; typecnt = 1; timecnt = 0; type = 0; } if (timecnt >= TZ_MAX_TIMES) { error(_("too many transitions?!")); (void) exit(EXIT_FAILURE); } attypes[timecnt].at = starttime; attypes[timecnt].type = type; ++timecnt; } static int addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) const long gmtoff; const char * const abbr; const int isdst; const int ttisstd; const int ttisgmt; { register int i, j; if (isdst != TRUE && isdst != FALSE) { error(_("internal error - addtype called with bad isdst")); (void) exit(EXIT_FAILURE); } if (ttisstd != TRUE && ttisstd != FALSE) { error(_("internal error - addtype called with bad ttisstd")); (void) exit(EXIT_FAILURE); } if (ttisgmt != TRUE && ttisgmt != FALSE) { error(_("internal error - addtype called with bad ttisgmt")); (void) exit(EXIT_FAILURE); } /* ** See if there's already an entry for this zone type. ** If so, just return its index. */ for (i = 0; i < typecnt; ++i) { if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && strcmp(abbr, &chars[abbrinds[i]]) == 0 && ttisstd == ttisstds[i] && ttisgmt == ttisgmts[i]) return i; } /* ** There isn't one; add a new one, unless there are already too ** many. */ if (typecnt >= TZ_MAX_TYPES) { error(_("too many local time types")); (void) exit(EXIT_FAILURE); } gmtoffs[i] = gmtoff; isdsts[i] = isdst; ttisstds[i] = ttisstd; ttisgmts[i] = ttisgmt; for (j = 0; j < charcnt; ++j) if (strcmp(&chars[j], abbr) == 0) break; if (j == charcnt) newabbr(abbr); abbrinds[i] = j; ++typecnt; return i; } static void leapadd(t, positive, rolling, count) const time_t t; const int positive; const int rolling; int count; { register int i, j; if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { error(_("too many leap seconds")); (void) 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); } break; } do { for (j = leapcnt; j > i; --j) { trans[j] = trans[j - 1]; corr[j] = corr[j - 1]; roll[j] = roll[j - 1]; } trans[i] = t; corr[i] = positive ? 1L : eitol(-count); roll[i] = rolling; ++leapcnt; } while (positive && --count != 0); } static void adjleap P((void)) { register int i; register long last = 0; /* ** propagate leap seconds forward */ for (i = 0; i < leapcnt; ++i) { trans[i] = tadd(trans[i], last); last = corr[i] += last; } } static int yearistype(year, type) const int year; const char * const type; { static char * buf; int result; if (type == NULL || *type == '\0') return TRUE; buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); (void) sprintf(buf, "%s %d %s", yitcommand, year, type); result = system(buf); - if (result == 0) - return TRUE; - if (result == (1 << 8)) - return FALSE; + if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { + case 0: + return TRUE; + case 1: + return FALSE; + } error(_("Wild result from command execution")); (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), progname, buf, result); for ( ; ; ) (void) exit(EXIT_FAILURE); } static int lowerit(a) int a; { a = (unsigned char) a; return (isascii(a) && isupper(a)) ? tolower(a) : a; } static int ciequal(ap, bp) /* case-insensitive equality */ register const char * ap; register const char * bp; { while (lowerit(*ap) == lowerit(*bp++)) if (*ap++ == '\0') return TRUE; return FALSE; } static int itsabbr(abbr, word) register const char * abbr; register const char * word; { if (lowerit(*abbr) != lowerit(*word)) return FALSE; ++word; while (*++abbr != '\0') do { if (*word == '\0') return FALSE; } while (lowerit(*word++) != lowerit(*abbr)); return TRUE; } static const struct lookup * byword(word, table) register const char * const word; register const struct lookup * const table; { register const struct lookup * foundlp; register const struct lookup * lp; if (word == NULL || table == NULL) return NULL; /* ** Look for exact match. */ for (lp = table; lp->l_word != NULL; ++lp) if (ciequal(word, lp->l_word)) return lp; /* ** Look for inexact match. */ foundlp = NULL; for (lp = table; lp->l_word != NULL; ++lp) if (itsabbr(word, lp->l_word)) { if (foundlp == NULL) foundlp = lp; else return NULL; /* multiple inexact matches */ } return foundlp; } static char ** getfields(cp) register char * cp; { register char * dp; register char ** array; register int nsubs; if (cp == NULL) return NULL; array = (char **) (void *) emalloc((int) ((strlen(cp) + 1) * sizeof *array)); nsubs = 0; for ( ; ; ) { while (isascii(*cp) && isspace((unsigned char) *cp)) ++cp; if (*cp == '\0' || *cp == '#') break; array[nsubs++] = dp = cp; do { if ((*dp = *cp++) != '"') ++dp; else while ((*dp = *cp++) != '"') if (*dp != '\0') ++dp; else error(_("Odd number of quotation marks")); } while (*cp != '\0' && *cp != '#' && (!isascii(*cp) || !isspace((unsigned char) *cp))); if (isascii(*cp) && isspace((unsigned char) *cp)) ++cp; *dp = '\0'; } array[nsubs] = NULL; return array; } static long oadd(t1, t2) const long t1; const long t2; { register long t; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { error(_("time overflow")); (void) exit(EXIT_FAILURE); } return t; } static time_t tadd(t1, t2) const time_t t1; const long t2; { register time_t t; if (t1 == max_time && t2 > 0) return max_time; if (t1 == min_time && t2 < 0) return min_time; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { error(_("time overflow")); (void) exit(EXIT_FAILURE); } return t; } /* ** Given a rule, and a year, compute the date - in seconds since January 1, ** 1970, 00:00 LOCAL time - in that year that the rule refers to. */ static time_t rpytime(rp, wantedy) register 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; if (wantedy == INT_MIN) return min_time; if (wantedy == INT_MAX) return max_time; dayoff = 0; m = TM_JANUARY; y = EPOCH_YEAR; while (wantedy != y) { if (wantedy > y) { i = len_years[isleap(y)]; ++y; } else { --y; i = -len_years[isleap(y)]; } dayoff = oadd(dayoff, eitol(i)); } while (m != rp->r_month) { i = len_months[isleap(y)][m]; dayoff = oadd(dayoff, eitol(i)); ++m; } i = rp->r_dayofmonth; if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { if (rp->r_dycode == DC_DOWLEQ) --i; else { error(_("use of 2/29 in non leap-year")); (void) exit(EXIT_FAILURE); } } --i; dayoff = oadd(dayoff, eitol(i)); if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { register long wday; #define LDAYSPERWEEK ((long) DAYSPERWEEK) wday = eitol(EPOCH_WDAY); /* ** Don't trust mod of negative numbers. */ if (dayoff >= 0) wday = (wday + dayoff) % LDAYSPERWEEK; else { wday -= ((-dayoff) % LDAYSPERWEEK); if (wday < 0) wday += LDAYSPERWEEK; } while (wday != eitol(rp->r_wday)) if (rp->r_dycode == DC_DOWGEQ) { dayoff = oadd(dayoff, (long) 1); if (++wday >= LDAYSPERWEEK) wday = 0; ++i; } else { dayoff = oadd(dayoff, (long) -1); if (--wday < 0) wday = LDAYSPERWEEK - 1; --i; } if (i < 0 || i >= len_months[isleap(y)][m]) { - error(_("no day in month matches rule")); - (void) exit(EXIT_FAILURE); + if (noise) + 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; - /* - ** Cheap overflow check. - */ - if (t / SECSPERDAY != dayoff) - return (dayoff > 0) ? max_time : min_time; return tadd(t, rp->r_tod); } static void newabbr(string) const char * const string; { register int i; i = strlen(string) + 1; if (charcnt + i > TZ_MAX_CHARS) { error(_("too many, or too long, time zone abbreviations")); (void) exit(EXIT_FAILURE); } (void) strcpy(&chars[charcnt], string); charcnt += eitol(i); } static int mkdirs(argname) char * const argname; { register char * name; register char * cp; if (argname == NULL || *argname == '\0') return 0; cp = name = ecpyalloc(argname); while ((cp = strchr(cp + 1, '/')) != 0) { *cp = '\0'; #ifndef unix /* ** DOS drive specifier? */ if (isalpha((unsigned char) name[0]) && name[1] == ':' && name[2] == '\0') { *cp = '/'; continue; } #endif /* !defined unix */ if (!itsdir(name)) { /* ** It doesn't seem to exist, so we try to create it. ** Creation may fail because of the directory being ** created by some other multiprocessor, so we get ** to do extra checking. */ - if (mkdir(name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) { + if (mkdir(name, MKDIR_UMASK) != 0) { const char *e = strerror(errno); if (errno != EEXIST || !itsdir(name)) { (void) fprintf(stderr, _("%s: Can't create directory %s: %s\n"), progname, name, e); ifree(name); return -1; } } } *cp = '/'; } ifree(name); return 0; } static long eitol(i) const int i; { long l; l = i; if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { (void) fprintf(stderr, _("%s: %d did not sign extend correctly\n"), progname, i); (void) exit(EXIT_FAILURE); } return l; } /* -** UNIX was a registered trademark of UNIX System Laboratories in 1993. +** UNIX was a registered trademark of The Open Group in 2003. */