Standard Libraries for EDK II.

This set of three packages: AppPkg, StdLib, StdLibPrivateInternalFiles; contains the implementation of libraries based upon non-UEFI standards such as ISO/IEC-9899, the library portion of the C Language Standard, POSIX, etc.

AppPkg contains applications that make use of the standard libraries defined in the StdLib Package.

StdLib contains header (include) files and the implementations of the standard libraries.

StdLibPrivateInternalFiles contains files for the exclusive use of the library implementations in StdLib.  These files should never be directly referenced from applications or other code.


git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11600 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
darylm503
2011-04-27 21:42:16 +00:00
parent 98790d8148
commit 2aa62f2bc9
503 changed files with 67344 additions and 0 deletions

553
StdLib/LibC/Time/Theory.txt Normal file
View File

@@ -0,0 +1,553 @@
# $NetBSD: Theory,v 1.8 2004/05/27 20:39:49 kleink Exp $
@(#)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.
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;
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 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 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. 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 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.
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 `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 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.
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,
<a href="http://emr.cs.uiuc.edu/home/reingold/calendar-book/index.shtml">
Calendrical Calculations
</a>, 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: <Petteri.Sulonen-1401991626030001@lapin-kulta.in.helsinki.fi>
If your source is correct, how come documents between 1929 -- 1940 were
still dated using the conventional, Gregorian calendar?
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)
<a href="news:1996Jul6.012937.29190@sq.com">
Subject: Re: Gregorian reform -- a part of locale?
</a>
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" <mpalmer@netcom.com> [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"
<http://www.giss.nasa.gov/tools/mars24/help/notes.html> (2004-03-15).
Jia-Rui Chong, "Workdays Fit for a Martian", Los Angeles Times
(2004-01-14), pp A1, A20-A21.

780
StdLib/LibC/Time/Time.c Normal file
View File

@@ -0,0 +1,780 @@
/**
Definitions and Implementation for <time.h>.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Portions derived from the NIH time zone package file, localtime.c,
which contains the following notice:
This file is in the public domain, so clarified as of
1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp
**/
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/TimerLib.h>
#include <Library/BaseLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
//#include <Library/UefiRuntimeLib.h>
#include <LibConfig.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <reentrant.h>
#include "tzfile.h"
#include "TimeVals.h"
#include <MainData.h>
#include <extern.h> // Library/include/extern.h: Private to implementation
#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */
// Keep compiler quiet about casting from function to data pointers
#pragma warning ( disable : 4054 )
#endif /* defined(_MSC_VER) */
/* ####################### Private Data ################################# */
#if 0
static EFI_TIME TimeBuffer;
static UINT16 MonthOffs[12] = {
00,
31, 59, 90, 120,
151, 181, 212, 243,
273, 304, 334
};
static clock_t y2kOffs = 730485;
#endif
const int mon_lengths[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 }
};
const int year_lengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
static const char *wday_name[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char *mon_name[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static int gmt_is_set;
/* ############### Implementation Functions ############################ */
// Forward reference
static void
localsub(const time_t * const timep, const long offset, struct tm * const tmp);
clock_t
EFIAPI
__getCPS(void)
{
return gMD->ClocksPerSecond;
}
static void
timesub(
const time_t * const timep,
const long offset,
const struct state * const sp,
struct tm * const tmp
)
{
const struct lsinfo * lp;
time_t /*INTN*/ days;
time_t /*INTN*/ rem;
time_t /*INTN*/ y;
int yleap;
const int * ip;
time_t /*INTN*/ corr;
int hit;
int i;
corr = 0;
hit = 0;
#ifdef ALL_STATE
i = (sp == NULL) ? 0 : sp->leapcnt;
#endif /* defined ALL_STATE */
#ifndef ALL_STATE
i = sp->leapcnt;
#endif /* State Farm */
while (--i >= 0) {
lp = &sp->lsis[i];
if (*timep >= lp->ls_trans) {
if (*timep == lp->ls_trans) {
hit = ((i == 0 && lp->ls_corr > 0) ||
lp->ls_corr > sp->lsis[i - 1].ls_corr);
if (hit)
while (i > 0 &&
sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&
sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1 )
{
++hit;
--i;
}
}
corr = lp->ls_corr;
break;
}
}
days = *timep / SECSPERDAY;
rem = *timep % SECSPERDAY;
rem += (offset - corr);
while (rem < 0) {
rem += SECSPERDAY;
--days;
}
while (rem >= SECSPERDAY) {
rem -= SECSPERDAY;
++days;
}
tmp->tm_hour = (int) (rem / SECSPERHOUR);
rem = rem % SECSPERHOUR;
tmp->tm_min = (int) (rem / SECSPERMIN);
/*
** A positive leap second requires a special
** representation. This uses "... ??:59:60" et seq.
*/
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
if (tmp->tm_wday < 0)
tmp->tm_wday += DAYSPERWEEK;
y = EPOCH_YEAR;
while (days < 0 || days >= (LONG32) year_lengths[yleap = isleap(y)]) {
time_t /*INTN*/ newy;
newy = (y + days / DAYSPERNYEAR);
if (days < 0)
--newy;
days -= (newy - y) * DAYSPERNYEAR +
LEAPS_THRU_END_OF(newy - 1) -
LEAPS_THRU_END_OF(y - 1);
y = newy;
}
tmp->tm_year = (int)(y - TM_YEAR_BASE);
tmp->tm_yday = (int) days;
ip = mon_lengths[yleap];
for (tmp->tm_mon = 0; days >= (LONG32) ip[tmp->tm_mon]; ++(tmp->tm_mon))
days = days - (LONG32) ip[tmp->tm_mon];
tmp->tm_mday = (int) (days + 1);
tmp->tm_isdst = 0;
#ifdef TM_GMTOFF
tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */
}
/* ############### Time Manipulation Functions ########################## */
/** The clock function determines the processor time used.
@return The clock function returns the implementation<6F>s best
approximation to the processor time used by the program since the
beginning of an implementation-defined era related only to the
program invocation. To determine the time in seconds, the value
returned by the clock function should be divided by the value of
the macro CLOCKS_PER_SEC. If the processor time used is not
available or its value cannot be represented, the function
returns the value (clock_t)(-1).
On IA32 or X64 platforms, the value returned is the number of
CPU TimeStamp Counter ticks since the appliation started.
**/
clock_t
EFIAPI
clock(void)
{
clock_t temp;
#ifdef NT32dvm
temp = 0;
#else
temp = (clock_t)GetPerformanceCounter();
#endif /* NT32dvm */
return temp - gMD->AppStartTime;
}
/**
**/
double
EFIAPI
difftime(time_t time1, time_t time0)
{
return (double)(time1 - time0);
}
/*
** Adapted from code provided by Robert Elz, who writes:
** The "best" way to do mktime I think is based on an idea of Bob
** Kridle's (so its said...) from a long time ago.
** [kridle@xinet.com as of 1996-01-16.]
** It does a binary search of the time_t space. Since time_t's are
** just 32 bits, its a max of 32 iterations (even at 64 bits it
** would still be very reasonable).
*/
#ifndef WRONG
#define WRONG (-1)
#endif /* !defined WRONG */
/*
** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
*/
static int
increment_overflow(int * number, int delta)
{
int number0;
number0 = *number;
*number += delta;
return (*number < number0) != (delta < 0);
}
static int
normalize_overflow(int * const tensptr, int * const unitsptr, const int base)
{
register int tensdelta;
tensdelta = (*unitsptr >= 0) ?
(*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
*unitsptr -= tensdelta * base;
return increment_overflow(tensptr, tensdelta);
}
static int
tmcomp(const struct tm * const atmp, const struct tm * const btmp)
{
register int result;
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
(result = (atmp->tm_min - btmp->tm_min)) == 0)
result = atmp->tm_sec - btmp->tm_sec;
return result;
}
static time_t
time2sub(
struct tm * const tmp,
void (* const funcp)(const time_t*, long, struct tm*),
const long offset,
int * const okayp,
const int do_norm_secs
)
{
register const struct state * sp;
register int dir;
register int bits;
register int i, j ;
register int saved_seconds;
time_t newt;
time_t t;
struct tm yourtm, mytm;
*okayp = FALSE;
yourtm = *tmp; // Create a copy of tmp
if (do_norm_secs) {
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
SECSPERMIN))
return WRONG;
}
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
return WRONG;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
return WRONG;
if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
return WRONG;
/*
** Turn yourtm.tm_year into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
return WRONG;
while (yourtm.tm_mday <= 0) {
if (increment_overflow(&yourtm.tm_year, -1))
return WRONG;
i = yourtm.tm_year + (1 < yourtm.tm_mon);
yourtm.tm_mday += year_lengths[isleap(i)];
}
while (yourtm.tm_mday > DAYSPERLYEAR) {
i = yourtm.tm_year + (1 < yourtm.tm_mon);
yourtm.tm_mday -= year_lengths[isleap(i)];
if (increment_overflow(&yourtm.tm_year, 1))
return WRONG;
}
for ( ; ; ) {
i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
if (increment_overflow(&yourtm.tm_year, 1))
return WRONG;
}
}
if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
return WRONG;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
/*
** We can't set tm_sec to 0, because that might push the
** time below the minimum representable time.
** Set tm_sec to 59 instead.
** This assumes that the minimum representable time is
** not in the same minute that a leap second was deleted from,
** which is a safer assumption than using 58 would be.
*/
if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
return WRONG;
saved_seconds = yourtm.tm_sec;
yourtm.tm_sec = SECSPERMIN - 1;
} else {
saved_seconds = yourtm.tm_sec;
yourtm.tm_sec = 0;
}
/*
** Divide the search space in half
** (this works whether time_t is signed or unsigned).
*/
bits = TYPE_BIT(time_t) - 1;
/*
** Set t to the midpoint of our binary search.
**
** If time_t is signed, then 0 is just above the median,
** assuming two's complement arithmetic.
** If time_t is unsigned, then (1 << bits) is just above the median.
*/
t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
for ( ; ; ) {
(*funcp)(&t, offset, &mytm); // Convert t to broken-down time in mytm
dir = tmcomp(&mytm, &yourtm); // Is mytm larger, equal, or less than yourtm?
if (dir != 0) { // If mytm != yourtm...
if (bits-- < 0) // If we have exhausted all the bits..
return WRONG; // Return that we failed
if (bits < 0) // If on the last bit...
--t; /* may be needed if new t is minimal */
else if (dir > 0) // else if mytm > yourtm...
t -= ((time_t) 1) << bits; // subtract half the remaining time-space
else t += ((time_t) 1) << bits; // otherwise add half the remaining time-space
continue; // Repeat for the next half
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
break;
/*
** Right time, wrong type.
** Hunt for right time, right type.
** It's okay to guess wrong since the guess
** gets checked.
*/
/*
** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
*/
sp = (const struct state *)
(((void *) funcp == (void *) localsub) ?
lclptr : gmtptr);
#ifdef ALL_STATE
if (sp == NULL)
return WRONG;
#endif /* defined ALL_STATE */
for (i = sp->typecnt - 1; i >= 0; --i) {
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
continue;
for (j = sp->typecnt - 1; j >= 0; --j) {
if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
continue;
newt = t + sp->ttis[j].tt_gmtoff -
sp->ttis[i].tt_gmtoff;
(*funcp)(&newt, offset, &mytm);
if (tmcomp(&mytm, &yourtm) != 0)
continue;
if (mytm.tm_isdst != yourtm.tm_isdst)
continue;
/*
** We have a match.
*/
t = newt;
goto label;
}
}
return WRONG;
}
label:
newt = t + saved_seconds;
if ((newt < t) != (saved_seconds < 0))
return WRONG;
t = newt;
(*funcp)(&t, offset, tmp);
*okayp = TRUE;
return t;
}
static time_t
time2(struct tm * const tmp, void (* const funcp)(const time_t*, long, struct tm*),
const long offset, int * const okayp)
{
time_t t;
/*
** First try without normalization of seconds
** (in case tm_sec contains a value associated with a leap second).
** If that fails, try with normalization of seconds.
*/
t = time2sub(tmp, funcp, offset, okayp, FALSE);
return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
}
static time_t
time1(
struct tm * const tmp,
void (* const funcp)(const time_t *, long, struct tm *),
const long offset
)
{
register time_t t;
register const struct state * sp;
register int samei, otheri;
register int sameind, otherind;
register int i;
register int nseen;
int seen[TZ_MAX_TYPES];
int types[TZ_MAX_TYPES];
int okay;
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, funcp, offset, &okay);
#ifdef PCTS
/*
** PCTS code courtesy Grant Sullivan (grant@osf.org).
*/
if (okay)
return t;
if (tmp->tm_isdst < 0)
tmp->tm_isdst = 0; /* reset to std and try again */
#endif /* defined PCTS */
#ifndef PCTS
if (okay || tmp->tm_isdst < 0)
return t;
#endif /* !defined PCTS */
/*
** We're supposed to assume that somebody took a time of one type
** and did some math on it that yielded a "struct tm" that's bad.
** We try to divine the type they started from and adjust to the
** type they need.
*/
/*
** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
*/
sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
lclptr : gmtptr);
#ifdef ALL_STATE
if (sp == NULL)
return WRONG;
#endif /* defined ALL_STATE */
for (i = 0; i < sp->typecnt; ++i)
seen[i] = FALSE;
nseen = 0;
for (i = sp->timecnt - 1; i >= 0; --i)
if (!seen[sp->types[i]]) {
seen[sp->types[i]] = TRUE;
types[nseen++] = sp->types[i];
}
for (sameind = 0; sameind < nseen; ++sameind) {
samei = types[sameind];
if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
continue;
for (otherind = 0; otherind < nseen; ++otherind) {
otheri = types[otherind];
if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
continue;
tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -
sp->ttis[samei].tt_gmtoff);
tmp->tm_isdst = !tmp->tm_isdst;
t = time2(tmp, funcp, offset, &okay);
if (okay)
return t;
tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -
sp->ttis[samei].tt_gmtoff);
tmp->tm_isdst = !tmp->tm_isdst;
}
}
return WRONG;
}
/** The mktime function converts the broken-down time, expressed as local time,
in the structure pointed to by timeptr into a calendar time value with the
same encoding as that of the values returned by the time function. The
original values of the tm_wday and tm_yday components of the structure are
ignored, and the original values of the other components are not restricted
to the ranges indicated above. Thus, a positive or zero value for tm_isdst
causes the mktime function to presume initially that Daylight Saving Time,
respectively, is or is not in effect for the specified time. A negative
value causes it to attempt to determine whether Daylight Saving Time is in
effect for the specified time. On successful completion, the values of the
tm_wday and tm_yday components of the structure are set appropriately, and
the other components are set to represent the specified calendar time, but
with their values forced to the ranges indicated above; the final value of
tm_mday is not set until tm_mon and tm_year are determined.
@return The mktime function returns the specified calendar time encoded
as a value of type time_t. If the calendar time cannot be
represented, the function returns the value (time_t)(-1).
**/
time_t
EFIAPI
mktime(struct tm *timeptr)
{
/* From NetBSD */
time_t result;
rwlock_wrlock(&lcl_lock);
tzset();
result = time1(timeptr, &localsub, 0L);
rwlock_unlock(&lcl_lock);
return (result);
}
/** The time function determines the current calendar time. The encoding of
the value is unspecified.
@return The time function returns the implementation<6F>s best approximation
to the current calendar time. The value (time_t)(-1) is returned
if the calendar time is not available. If timer is not a null
pointer, the return value is also assigned to the object it
points to.
**/
time_t
EFIAPI
time(time_t *timer)
{
time_t CalTime;
EFI_STATUS Status;
EFI_TIME *ET;
struct tm *BT;
ET = &gMD->TimeBuffer;
BT = &gMD->BDTime;
// Get EFI Time
Status = gRT->GetTime( ET, NULL);
// Status = EfiGetTime( ET, NULL);
EFIerrno = Status;
if( Status != RETURN_SUCCESS) {
return (time_t)-1;
}
// Convert EFI time to broken-down time.
Efi2Tm( ET, BT);
// Convert to time_t
CalTime = mktime(&gMD->BDTime);
if( timer != NULL) {
*timer = CalTime;
}
return CalTime; // Return calendar time in microseconds
}
/* ################# Time Conversion Functions ########################## */
/*
Except for the strftime function, these functions each return a pointer to
one of two types of static objects: a broken-down time structure or an
array of char. Execution of any of the functions that return a pointer to
one of these object types may overwrite the information in any object of
the same type pointed to by the value returned from any previous call to
any of them. The implementation shall behave as if no other library
functions call these functions.
*/
/** The asctime function converts the broken-down time in the structure pointed
to by timeptr into a string in the form
Sun Sep 16 01:03:52 1973\n\0
using the equivalent of the following algorithm.
char *asctime(const struct tm *timeptr)
{
static const char wday_name[7][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][3] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];
sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
wday_name[timeptr->tm_wday],
mon_name[timeptr->tm_mon],
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
1900 + timeptr->tm_year);
return result;
}
@return The asctime function returns a pointer to the string.
**/
char *
EFIAPI
asctime(const struct tm *timeptr)
{
register const char * wn;
register const char * mn;
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
wn = "???";
else wn = wday_name[timeptr->tm_wday];
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
/*
** The X3J11-suggested format is
** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
** Since the .2 in 02.2d is ignored, we drop it.
*/
(void)snprintf(gMD->ASasctime,
sizeof (char[ASCTIME_BUFLEN]),
"%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
TM_YEAR_BASE + timeptr->tm_year);
return gMD->ASasctime;
}
/**
**/
char *
EFIAPI
ctime(const time_t *timer)
{
return asctime(localtime(timer));
}
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
static void
gmtsub(
const time_t * const timep,
const long offset,
struct tm * const tmp
)
{
#ifdef _REENTRANT
static mutex_t gmt_mutex = MUTEX_INITIALIZER;
#endif
mutex_lock(&gmt_mutex);
if (!gmt_is_set) {
gmt_is_set = TRUE;
#ifdef ALL_STATE
gmtptr = (struct state *) malloc(sizeof *gmtptr);
if (gmtptr != NULL)
#endif /* defined ALL_STATE */
gmtload(gmtptr);
}
mutex_unlock(&gmt_mutex);
timesub(timep, offset, gmtptr, tmp);
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
if (offset != 0)
tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);
else {
#ifdef ALL_STATE
if (gmtptr == NULL)
tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);
else tmp->TM_ZONE = gmtptr->chars;
#endif /* defined ALL_STATE */
#ifndef ALL_STATE
tmp->TM_ZONE = gmtptr->chars;
#endif /* State Farm */
}
#endif /* defined TM_ZONE */
}
/**
**/
struct tm *
EFIAPI
gmtime(const time_t *timer)
{
gmtsub(timer, 0L, &gMD->BDTime);
return &gMD->BDTime;
}
static void
localsub(const time_t * const timep, const long offset, struct tm * const tmp)
{
register struct state * sp;
register const struct ttinfo * ttisp;
register int i;
const time_t t = *timep;
sp = lclptr;
#ifdef ALL_STATE
if (sp == NULL) {
gmtsub(timep, offset, tmp);
return;
}
#endif /* defined ALL_STATE */
if (sp->timecnt == 0 || t < sp->ats[0]) {
i = 0;
while (sp->ttis[i].tt_isdst)
if (++i >= sp->typecnt) {
i = 0;
break;
}
} else {
for (i = 1; i < sp->timecnt; ++i)
if (t < sp->ats[i])
break;
i = sp->types[i - 1];
}
ttisp = &sp->ttis[i];
/*
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
*/
timesub(&t, ttisp->tt_gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->tt_isdst;
tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
#ifdef TM_ZONE
tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */
}
/**
**/
struct tm *
EFIAPI
localtime(const time_t *timer)
{
tzset();
localsub(timer, 0L, &gMD->BDTime);
return &gMD->BDTime;
}

53
StdLib/LibC/Time/Time.inf Normal file
View File

@@ -0,0 +1,53 @@
## @file
# Standard C library: Time implementations.
#
# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = LibTime
FILE_GUID = c5847038-ff75-4074-9e4c-c36a2eb398a5
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
LIBRARY_CLASS = LibTime
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
Time.c
ZoneProc.c
strftime.c
TimeEfi.c
[Packages]
StdLib/StdLib.dec
StdLibPrivateInternalFiles/DoNotUse.dec
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
UefiLib
TimerLib
BaseLib
UefiRuntimeServicesTableLib
################################################################
#
# The Build Options, below, are only used when building the C library.
# DO NOT use them when building your application!
# Nasty things could happen if you do.
#
[BuildOptions]
GCC:*_*_*_CC_FLAGS = -fno-strict-overflow -fno-builtin-strftime

View File

@@ -0,0 +1,48 @@
/** @file
Transformations between the EFI_TIME structure and struct tm or time_t.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <LibConfig.h>
#include <time.h>
#include "tzfile.h"
#include <MainData.h>
/* Convert an EFI_TIME structure into a C Standard tm structure. */
void
EFIAPI
Efi2Tm( EFI_TIME *ET, struct tm *BT)
{
// Convert EFI time to broken-down time.
BT->tm_year = ET->Year - TM_YEAR_BASE;
BT->tm_mon = ET->Month - 1; // BD time is zero based, EFI is 1 based
BT->tm_mday = ET->Day;
BT->tm_hour = ET->Hour;
BT->tm_min = ET->Minute;
BT->tm_sec = ET->Second;
BT->tm_isdst = -1;
BT->tm_zoneoff = ET->TimeZone;
BT->tm_daylight = ET->Daylight;
BT->tm_Nano = ET->Nanosecond;
}
/* Convert an EFI_TIME structure into a time_t value. */
time_t
EFIAPI
Efi2Time( EFI_TIME *EfiBDtime)
{
Efi2Tm( EfiBDtime, &gMD->BDTime);
return mktime( &gMD->BDTime);
}

117
StdLib/LibC/Time/TimeVals.h Normal file
View File

@@ -0,0 +1,117 @@
/** @file
Definitions private to the Implementation of <time.h>.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Portions derived from the NIH time zone package files,
which contain the following notice:
This file is in the public domain, so clarified as of
1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
**/
#ifndef _TIMEVAL_H
#define _TIMEVAL_H
extern struct state * lclptr;
extern struct state * gmtptr;
extern char * tzname[2];
extern const char gmt[4];
extern const char wildabbr[9];
extern const int year_lengths[2];
extern const int mon_lengths[2][MONSPERYEAR];
extern long int timezone;
extern int daylight;
#define EFI_UNSPECIFIED_TIMEZONE 0x07FF
/*
** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
** We default to US rules as of 1999-08-17.
** POSIX 1003.1 section 8.1.1 says that the default DST rules are
** implementation dependent; for historical reasons, US rules are a
** common default.
*/
#ifndef TZDEFRULESTRING
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
#endif
// Facilities for external time-zone definition files do not currently exist
#define NO_ZONEINFO_FILES
#define EPOCH_DAY 5
#define DAY_TO_uSEC 86400000000
/* Rule type values for the r_type member of a rule structure */
#define JULIAN_DAY 0 /* Jn - Julian day */
#define DAY_OF_YEAR 1 /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
#ifdef TZNAME_MAX
#define MY_TZNAME_MAX TZNAME_MAX
#endif /* defined TZNAME_MAX */
#ifndef TZNAME_MAX
#define MY_TZNAME_MAX 255
#endif /* !defined TZNAME_MAX */
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
#ifndef INITIALIZE
#define INITIALIZE(x) ((x) = 0)
#endif /* !defined INITIALIZE */
struct ttinfo { /* time type information */
LONG32 tt_gmtoff; /* UTC offset in seconds */
int tt_isdst; /* used to set tm_isdst */
int tt_abbrind; /* abbreviation list index */
int tt_ttisstd; /* TRUE if transition is std time */
int tt_ttisgmt; /* TRUE if transition is UTC */
};
struct lsinfo { /* leap second information */
time_t ls_trans; /* transition time */
LONG32 ls_corr; /* correction to apply */
};
struct state {
int leapcnt;
int timecnt;
int typecnt;
int charcnt;
time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))];
struct lsinfo lsis[TZ_MAX_LEAPS];
};
struct rule {
int r_type; /* type of rule--see below */
int r_day; /* day number of rule */
int r_week; /* week number of rule */
int r_mon; /* month number of rule */
LONG32 r_time; /* transition time of rule */
};
#define JULIAN_DAY 0 /* Jn - Julian day */
#define DAY_OF_YEAR 1 /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
__BEGIN_DECLS
extern void EFIAPI gmtload(struct state * const sp);
extern void EFIAPI tzset(void);
__END_DECLS
#endif /* _TIMEVAL_H */

830
StdLib/LibC/Time/ZoneProc.c Normal file
View File

@@ -0,0 +1,830 @@
/** @file
Time Zone processing.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Portions derived from the NIH time zone package file, localtime.c,
which contains the following notice:
This file is in the public domain, so clarified as of
1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp
**/
#include <LibConfig.h>
#include <sys/EfiSysCall.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tzfile.h"
#include "TimeVals.h"
#ifndef WILDABBR
/*
** Someone might make incorrect use of a time zone abbreviation:
** 1. They might reference tzname[0] before calling tzset (explicitly
** or implicitly).
** 2. They might reference tzname[1] before calling tzset (explicitly
** or implicitly).
** 3. They might reference tzname[1] after setting to a time zone
** in which Daylight Saving Time is never observed.
** 4. They might reference tzname[0] after setting to a time zone
** in which Standard Time is never observed.
** 5. They might reference tm.TM_ZONE after calling offtime.
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
*/
#define WILDABBR " "
#endif /* !defined WILDABBR */
const char wildabbr[9] = "WILDABBR";
const char gmt[4] = "GMT";
struct state * lclptr = NULL;
struct state * gmtptr = NULL;
#ifndef TZ_STRLEN_MAX
#define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set = 0;
//static int gmt_is_set = 0;
char * tzname[2] = {
(char *)__UNCONST(wildabbr),
(char *)__UNCONST(wildabbr)
};
long int timezone = 0;
int daylight = 0;
#ifndef NO_ZONEINFO_FILES
/** Get first 4 characters of codep as a 32-bit integer.
The first character of codep becomes the MSB of the resultant integer.
**/
static INT32
detzcode(const char * const codep)
{
register INT32 result;
/*
** The first character must be sign extended on systems with >32bit
** longs. This was solved differently in the master tzcode sources
** (the fix first appeared in tzcode95c.tar.gz). But I believe
** that this implementation is superior.
*/
#define SIGN_EXTEND_CHAR(x) ((signed char) x)
result = (SIGN_EXTEND_CHAR(codep[0]) << 24) \
| (codep[1] & 0xff) << 16 \
| (codep[2] & 0xff) << 8
| (codep[3] & 0xff);
return result;
}
#endif /* NO_ZONEINFO_FILES */
static void
settzname (void)
{
register struct state * const sp = lclptr;
register int i;
tzname[0] = (char *)__UNCONST(wildabbr);
tzname[1] = (char *)__UNCONST(wildabbr);
daylight = 0;
timezone = 0;
if (sp == NULL) {
tzname[0] = tzname[1] = (char *)__UNCONST(gmt);
return;
}
for (i = 0; i < sp->typecnt; ++i) {
register const struct ttinfo * const ttisp = &sp->ttis[i];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
if (ttisp->tt_isdst)
daylight = 1;
if (i == 0 || !ttisp->tt_isdst)
timezone = -(ttisp->tt_gmtoff);
}
/*
** And to get the latest zone names into tzname. . .
*/
for (i = 0; i < sp->timecnt; ++i) {
register const struct ttinfo * const ttisp =
&sp->ttis[ sp->types[i] ];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
}
}
/*
** Given a pointer into a time zone string, scan until a character that is not
** a valid character in a zone name is found. Return a pointer to that
** character.
*/
static const char *
getzname(register const char *strp)
{
register char c;
while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
c != '+')
++strp;
return strp;
}
/*
** Given a pointer into a time zone string, extract a number from that string.
** Check that the number is within a specified range; if it is not, return
** NULL.
** Otherwise, return a pointer to the first character not part of the number.
*/
static const char *
getnum(
register const char *strp,
int * const nump,
const int min,
const int max
)
{
register char c;
register int num;
if (strp == NULL || !is_digit(c = *strp))
return NULL;
num = 0;
do {
num = num * 10 + (c - '0');
if (num > max)
return NULL; /* illegal value */
c = *++strp;
} while (is_digit(c));
if (num < min)
return NULL; /* illegal value */
*nump = num;
return strp;
}
/*
** Given a pointer into a time zone string, extract a number of seconds,
** in hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the number
** of seconds.
*/
static const char *
getsecs(
register const char *strp,
LONG32 * const secsp
)
{
int num;
/*
** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
** "M10.4.6/26", which does not conform to Posix,
** but which specifies the equivalent of
** ``02:00 on the first Sunday on or after 23 Oct''.
*/
strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
if (strp == NULL)
return NULL;
*secsp = (long)(num * SECSPERHOUR);
if (*strp == ':') {
++strp;
strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
if (strp == NULL)
return NULL;
*secsp += num * SECSPERMIN;
if (*strp == ':') {
++strp;
/* `SECSPERMIN' allows for leap seconds. */
strp = getnum(strp, &num, 0, SECSPERMIN);
if (strp == NULL)
return NULL;
*secsp += num;
}
}
return strp;
}
/*
** Given a pointer into a time zone string, extract an offset, in
** [+-]hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the time.
*/
static const char *
getoffset(
register const char *strp,
LONG32 * const offsetp
)
{
register int neg = 0;
if (*strp == '-') {
neg = 1;
++strp;
} else if (*strp == '+')
++strp;
strp = getsecs(strp, offsetp);
if (strp == NULL)
return NULL; /* illegal time */
if (neg)
*offsetp = -*offsetp;
return strp;
}
/*
** Given a pointer into a time zone string, extract a rule in the form
** date[/time]. See POSIX section 8 for the format of "date" and "time".
** If a valid rule is not found, return NULL.
** Otherwise, return a pointer to the first character not part of the rule.
*/
static const char *
getrule(
const char *strp,
register struct rule * const rulep
)
{
if (*strp == 'J') {
/*
** Julian day.
*/
rulep->r_type = JULIAN_DAY;
++strp;
strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
} else if (*strp == 'M') {
/*
** Month, week, day.
*/
rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
++strp;
strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
if (strp == NULL)
return NULL;
if (*strp++ != '.')
return NULL;
strp = getnum(strp, &rulep->r_week, 1, 5);
if (strp == NULL)
return NULL;
if (*strp++ != '.')
return NULL;
strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
} else if (is_digit(*strp)) {
/*
** Day of year.
*/
rulep->r_type = DAY_OF_YEAR;
strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
} else return NULL; /* invalid format */
if (strp == NULL)
return NULL;
if (*strp == '/') {
/*
** Time specified.
*/
++strp;
strp = getsecs(strp, &rulep->r_time);
} else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
return strp;
}
static int
tzload(register const char *name, register struct state * const sp)
{
#ifndef NO_ZONEINFO_FILES
register const char * p;
register int i;
register int fid;
if (name == NULL && (name = TZDEFAULT) == NULL)
return -1;
{
register int doaccess;
/*
** Section 4.9.1 of the C standard says that
** "FILENAME_MAX expands to an integral constant expression
** that is the size needed for an array of char large enough
** to hold the longest file name string that the implementation
** guarantees can be opened."
*/
char fullname[FILENAME_MAX + 1];
if (name[0] == ':')
++name;
doaccess = name[0] == '/';
if (!doaccess) {
if ((p = TZDIR) == NULL)
return -1;
if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
return -1;
(void) strcpy(fullname, p); /* XXX strcpy is safe */
(void) strcat(fullname, "/"); /* XXX strcat is safe */
(void) strcat(fullname, name); /* XXX strcat is safe */
/*
** Set doaccess if '.' (as in "../") shows up in name.
*/
if (strchr(name, '.') != NULL)
doaccess = TRUE;
name = fullname;
}
if (doaccess && access(name, R_OK) != 0)
return -1;
/*
* XXX potential security problem here if user of a set-id
* program has set TZ (which is passed in as name) here,
* and uses a race condition trick to defeat the access(2)
* above.
*/
if ((fid = open(name, OPEN_MODE)) == -1)
return -1;
}
{
struct tzhead * tzhp;
union {
struct tzhead tzhead;
char buf[sizeof *sp + sizeof *tzhp];
} u;
int ttisstdcnt;
int ttisgmtcnt;
i = read(fid, u.buf, sizeof u.buf);
if (close(fid) != 0)
return -1;
ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
sp->timecnt + /* types */
sp->typecnt * (4 + 2) + /* ttinfos */
sp->charcnt + /* chars */
sp->leapcnt * (4 + 4) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */
return -1;
for (i = 0; i < sp->timecnt; ++i) {
sp->ats[i] = detzcode(p);
p += 4;
}
for (i = 0; i < sp->timecnt; ++i) {
sp->types[i] = (unsigned char) *p++;
if (sp->types[i] >= sp->typecnt)
return -1;
}
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
ttisp->tt_gmtoff = detzcode(p);
p += 4;
ttisp->tt_isdst = (unsigned char) *p++;
if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
return -1;
ttisp->tt_abbrind = (unsigned char) *p++;
if (ttisp->tt_abbrind < 0 ||
ttisp->tt_abbrind > sp->charcnt)
return -1;
}
for (i = 0; i < sp->charcnt; ++i)
sp->chars[i] = *p++;
sp->chars[i] = '\0'; /* ensure '\0' at end */
for (i = 0; i < sp->leapcnt; ++i) {
register struct lsinfo * lsisp;
lsisp = &sp->lsis[i];
lsisp->ls_trans = detzcode(p);
p += 4;
lsisp->ls_corr = detzcode(p);
p += 4;
}
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
if (ttisstdcnt == 0)
ttisp->tt_ttisstd = FALSE;
else {
ttisp->tt_ttisstd = *p++;
if (ttisp->tt_ttisstd != TRUE &&
ttisp->tt_ttisstd != FALSE)
return -1;
}
}
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
if (ttisgmtcnt == 0)
ttisp->tt_ttisgmt = FALSE;
else {
ttisp->tt_ttisgmt = *p++;
if (ttisp->tt_ttisgmt != TRUE &&
ttisp->tt_ttisgmt != FALSE)
return -1;
}
}
}
return 0;
#else /* ! NO_ZONEINFO_FILES */
return -1;
#endif
}
/*
** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
** year, a rule, and the offset from UTC at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect.
*/
static
time_t
transtime(
const time_t janfirst,
const int year,
const struct rule * const rulep,
const LONG32 offset
)
{
register int leapyear;
register time_t value;
register int i;
int d, m1, yy0, yy1, yy2, dow;
INITIALIZE(value);
leapyear = isleap(year);
switch (rulep->r_type) {
case JULIAN_DAY:
/*
** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
** years.
** In non-leap years, or if the day number is 59 or less, just
** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day.
*/
value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
if (leapyear && rulep->r_day >= 60)
value += SECSPERDAY;
break;
case DAY_OF_YEAR:
/*
** n - day of year.
** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day.
*/
value = janfirst + rulep->r_day * SECSPERDAY;
break;
case MONTH_NTH_DAY_OF_WEEK:
/*
** Mm.n.d - nth "dth day" of month m.
*/
value = janfirst;
for (i = 0; i < rulep->r_mon - 1; ++i)
value += mon_lengths[leapyear][i] * SECSPERDAY;
/*
** Use Zeller's Congruence to get day-of-week of first day of
** month.
*/
m1 = (rulep->r_mon + 9) % 12 + 1;
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
yy1 = yy0 / 100;
yy2 = yy0 % 100;
dow = ((26 * m1 - 2) / 10 +
1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
if (dow < 0)
dow += DAYSPERWEEK;
/*
** "dow" is the day-of-week of the first day of the month. Get
** the day-of-month (zero-origin) of the first "dow" day of the
** month.
*/
d = rulep->r_day - dow;
if (d < 0)
d += DAYSPERWEEK;
for (i = 1; i < rulep->r_week; ++i) {
if (d + DAYSPERWEEK >=
mon_lengths[leapyear][rulep->r_mon - 1])
break;
d += DAYSPERWEEK;
}
/*
** "d" is the day-of-month (zero-origin) of the day we want.
*/
value += d * SECSPERDAY;
break;
}
/*
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
** question. To get the Epoch-relative time of the specified local
** time on that day, add the transition time and the current offset
** from UTC.
*/
return value + rulep->r_time + offset;
}
/*
** Given a POSIX section 8-style TZ string, fill in the rule tables as
** appropriate.
*/
static int
tzparse(
const char * name,
struct state * const sp,
const int lastditch
)
{
const char *stdname;
const char *dstname;
size_t stdlen;
size_t dstlen;
LONG32 stdoffset;
LONG32 dstoffset;
time_t *atp;
unsigned char *typep;
char *cp;
int load_result;
dstname = NULL;
stdname = name;
if (lastditch) {
stdlen = strlen(name); /* length of standard zone name */
name += stdlen;
if (stdlen >= sizeof sp->chars)
stdlen = (sizeof sp->chars) - 1;
stdoffset = 0;
} else {
name = getzname(name);
stdlen = name - stdname;
if (stdlen < 3)
return -1;
if (*name == '\0')
return -1;
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
}
load_result = tzload(TZDEFRULES, sp);
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0') {
dstname = name;
name = getzname(name);
dstlen = name - dstname; /* length of DST zone name */
if (dstlen < 3)
return -1;
if (*name != '\0' && *name != ',' && *name != ';') {
name = getoffset(name, &dstoffset);
if (name == NULL)
return -1;
} else dstoffset = stdoffset - SECSPERHOUR;
if (*name == '\0' && load_result != 0)
name = TZDEFRULESTRING;
if (*name == ',' || *name == ';') {
struct rule start;
struct rule end;
register int year;
register time_t janfirst;
time_t starttime;
time_t endtime;
++name;
if ((name = getrule(name, &start)) == NULL)
return -1;
if (*name++ != ',')
return -1;
if ((name = getrule(name, &end)) == NULL)
return -1;
if (*name != '\0')
return -1;
sp->typecnt = 2; /* standard time and DST */
/*
** Two transitions per year, from EPOCH_YEAR to 2037.
*/
sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
if (sp->timecnt > TZ_MAX_TIMES)
return -1;
sp->ttis[0].tt_gmtoff = -dstoffset;
sp->ttis[0].tt_isdst = 1;
sp->ttis[0].tt_abbrind = (int)stdlen + 1;
sp->ttis[1].tt_gmtoff = -stdoffset;
sp->ttis[1].tt_isdst = 0;
sp->ttis[1].tt_abbrind = 0;
atp = sp->ats;
typep = sp->types;
janfirst = 0;
for (year = EPOCH_YEAR; year <= 2037; ++year) {
starttime = transtime(janfirst, year, &start,
stdoffset);
endtime = transtime(janfirst, year, &end,
dstoffset);
if (starttime > endtime) {
*atp++ = endtime;
*typep++ = 1; /* DST ends */
*atp++ = starttime;
*typep++ = 0; /* DST begins */
} else {
*atp++ = starttime;
*typep++ = 0; /* DST begins */
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
janfirst += year_lengths[isleap(year)] *
SECSPERDAY;
}
} else {
register LONG32 theirstdoffset;
register LONG32 theiroffset;
register int i;
register int j;
if (*name != '\0')
return -1;
/*
** Initial values of theirstdoffset
*/
theirstdoffset = 0;
for (i = 0; i < sp->timecnt; ++i) {
j = sp->types[i];
if (!sp->ttis[j].tt_isdst) {
theirstdoffset =
-sp->ttis[j].tt_gmtoff;
break;
}
}
/*
** Initially we're assumed to be in standard time.
*/
theiroffset = theirstdoffset;
/*
** Now juggle transition times and types
** tracking offsets as you do.
*/
for (i = 0; i < sp->timecnt; ++i) {
j = sp->types[i];
sp->types[i] = (unsigned char)sp->ttis[j].tt_isdst;
if (sp->ttis[j].tt_ttisgmt) {
/* No adjustment to transition time */
} else {
/*
** If summer time is in effect, and the
** transition time was not specified as
** standard time, add the summer time
** offset to the transition time;
** otherwise, add the standard time
** offset to the transition time.
*/
/*
** Transitions from DST to DDST
** will effectively disappear since
** POSIX provides for only one DST
** offset.
*/
sp->ats[i] += stdoffset -
theirstdoffset;
}
theiroffset = -sp->ttis[j].tt_gmtoff;
if (!sp->ttis[j].tt_isdst)
theirstdoffset = theiroffset;
}
/*
** Finally, fill in ttis.
** ttisstd and ttisgmt need not be handled.
*/
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = FALSE;
sp->ttis[0].tt_abbrind = 0;
sp->ttis[1].tt_gmtoff = -dstoffset;
sp->ttis[1].tt_isdst = TRUE;
sp->ttis[1].tt_abbrind = (int)stdlen + 1;
sp->typecnt = 2;
}
} else {
dstlen = 0;
sp->typecnt = 1; /* only standard time */
sp->timecnt = 0;
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = 0;
sp->ttis[0].tt_abbrind = 0;
}
sp->charcnt = (int)stdlen + 1;
if (dstlen != 0)
sp->charcnt += (int)dstlen + 1;
if ((size_t) sp->charcnt > sizeof sp->chars)
return -1;
cp = sp->chars;
(void) strncpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0) {
(void) strncpy(cp, dstname, dstlen);
*(cp + dstlen) = '\0';
}
return 0;
}
void
EFIAPI
gmtload(struct state * const sp)
{
if (tzload(gmt, sp) != 0)
(void) tzparse(gmt, sp, TRUE);
}
static void
tzsetwall(void)
{
if (lcl_is_set < 0)
return;
lcl_is_set = -1;
if (lclptr == NULL) {
lclptr = (struct state *) malloc(sizeof *lclptr);
if (lclptr == NULL) {
settzname(); /* all we can do */
return;
}
}
if (tzload((char *) NULL, lclptr) != 0)
gmtload(lclptr);
settzname();
}
void
EFIAPI
tzset(void)
{
register const char * name;
name = getenv("TZ");
if (name == NULL) {
tzsetwall();
return;
}
if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
return;
lcl_is_set = strlen(name) < sizeof lcl_TZname;
if (lcl_is_set)
(void)strncpyX(lcl_TZname, name, sizeof(lcl_TZname));
if (lclptr == NULL) {
lclptr = (struct state *) malloc(sizeof *lclptr);
if (lclptr == NULL) {
settzname(); /* all we can do */
return;
}
}
if (*name == '\0') {
/*
** User wants it fast rather than right.
*/
lclptr->leapcnt = 0; /* so, we're off a little */
lclptr->timecnt = 0;
lclptr->typecnt = 0;
lclptr->ttis[0].tt_isdst = 0;
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
(void)strncpyX(lclptr->chars, gmt, sizeof(lclptr->chars));
} else if (tzload(name, lclptr) != 0)
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
(void) gmtload(lclptr);
settzname();
}

602
StdLib/LibC/Time/strftime.c Normal file
View File

@@ -0,0 +1,602 @@
/** @file
Implementation of the strftime function for <time.h>.
Based on the UCB version with the ID appearing below.
This is ANSIish only when "multibyte character == plain character".
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Copyright (c) 1989, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
NetBSD: strftime.c,v 1.17.4.1 2007/08/21 20:08:21 liamjfoy Exp
**/
#include <LibConfig.h>
#include <sys/EfiCdefs.h>
#include "namespace.h"
#include <time.h>
#include "tzfile.h"
#include <TimeVals.h>
#include "fcntl.h"
#include "locale.h"
#include "sys/localedef.h"
#include <MainData.h>
/*
** We don't use these extensions in strftime operation even when
** supported by the local tzcode configuration. A strictly
** conforming C application may leave them in undefined state.
*/
#ifdef _LIBC
#undef TM_ZONE
#undef TM_GMTOFF
#endif
#define Locale _CurrentTimeLocale
static char * EFIAPI _add(const char *, char *, const char * const);
static char * EFIAPI _conv(const int, const char * const, char * const, const char * const);
static char * EFIAPI _fmt(const char *, const struct tm * const, char *, const char * const, int *);
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
#ifndef YEAR_2000_NAME
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */
#define IN_NONE 0
#define IN_SOME 1
#define IN_THIS 2
#define IN_ALL 3
size_t
EFIAPI
strftime(
char * __restrict s,
size_t maxsize,
const char * __restrict format,
const struct tm * __restrict timeptr
)
{
char * p;
int warn;
tzset();
warn = IN_NONE;
p = _fmt(((format == NULL) ? "%c" : format), timeptr, s, s + maxsize, &warn);
#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf(stderr, "\n");
if (format == NULL)
(void) fprintf(stderr, "NULL strftime format ");
else (void) fprintf(stderr, "strftime format \"%s\" ",
format);
(void) fprintf(stderr, "yields only two digits of years in ");
if (warn == IN_SOME)
(void) fprintf(stderr, "some locales");
else if (warn == IN_THIS)
(void) fprintf(stderr, "the current locale");
else (void) fprintf(stderr, "all locales");
(void) fprintf(stderr, "\n");
}
#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
return 0;
*p = '\0';
return p - s;
}
static char *
EFIAPI
_fmt(
const char * format,
const struct tm * const t,
char * pt,
const char * const ptlim,
int * warnp
)
{
for ( ; *format; ++format) {
if (*format == '%') {
label:
switch (*++format) {
case '\0':
--format;
break;
case 'A':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->day[t->tm_wday],
pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->abday[t->tm_wday],
pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->mon[t->tm_mon],
pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->abmon[t->tm_mon],
pt, ptlim);
continue;
case 'C':
/*
** %C used to do a...
** _fmt("%a %b %e %X %Y", t);
** ...whereas now POSIX 1003.2 calls for
** something completely different.
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
"%02d", pt, ptlim);
continue;
case 'c':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->d_t_fmt, t, pt, ptlim, &warn2);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
continue;
case 'E':
case 'O':
/*
** C99 locale modifiers.
** The sequences
** %Ec %EC %Ex %EX %Ey %EY
** %Od %oe %OH %OI %Om %OM
** %OS %Ou %OU %OV %Ow %OW %Oy
** are supposed to provide alternate
** representations.
*/
goto label;
case 'e':
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%02d", pt, ptlim);
continue;
case 'j':
pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
continue;
case 'k':
/*
** This used to be...
** _conv(t->tm_hour % 12 ?
** t->tm_hour % 12 : 12, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbins'
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv(t->tm_hour, "%2d", pt, ptlim);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
pt = _add("kitchen sink", pt, ptlim);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
/*
** This used to be...
** _conv(t->tm_hour, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbin's
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%2d", pt, ptlim);
continue;
case 'M':
pt = _conv(t->tm_min, "%02d", pt, ptlim);
continue;
case 'm':
pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
continue;
case 'n':
pt = _add("\n", pt, ptlim);
continue;
case 'p':
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
Locale->am_pm[1] :
Locale->am_pm[0],
pt, ptlim);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp);
continue;
case 'r':
pt = _fmt(Locale->t_fmt_ampm, t, pt, ptlim,
warnp);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
continue;
case 's':
{
struct tm tm;
char buf[INT_STRLEN_MAXIMUM(
time_t) + 1];
time_t mkt;
tm = *t;
mkt = mktime(&tm);
/* CONSTCOND */
if (TYPE_SIGNED(time_t))
(void) sprintf(buf, "%ld",
(long) mkt);
else (void) sprintf(buf, "%lu",
(unsigned long) mkt);
pt = _add(buf, pt, ptlim);
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
continue;
case 't':
pt = _add("\t", pt, ptlim);
continue;
case 'U':
pt = _conv((t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'u':
/*
** From Arnold Robbins' strftime version 3.0:
** "ISO 8601: Weekday as a decimal number
** [1 (Monday) - 7]"
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday,
"%d", pt, ptlim);
continue;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
**
** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
** "Week 01 of a year is per definition the first week which has the
** Thursday in this year, which is equivalent to the week which contains
** the fourth day of January. In other words, the first week of a new year
** is the week which has the majority of its days in the new year. Week 01
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
{
int year;
int yday;
int wday;
int w;
year = t->tm_year + TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int len;
int bot;
int top;
len = isleap(year) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
** What yday (-3 ... 3) does
** the ISO year begin on?
*/
bot = ((yday + 11 - wday) %
DAYSPERWEEK) - 3;
/*
** What yday does the NEXT
** ISO year begin on?
*/
top = bot -
(len % DAYSPERWEEK);
if (top < -3)
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
++year;
w = 1;
break;
}
if (yday >= bot) {
w = 1 + ((yday - bot) /
DAYSPERWEEK);
break;
}
--year;
yday += isleap(year) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
if ((w == 52
&& t->tm_mon == TM_JANUARY)
|| (w == 1
&& t->tm_mon == TM_DECEMBER))
w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = _conv(year % 100, "%02d",
pt, ptlim);
} else pt = _conv(year, "%04d",
pt, ptlim);
}
continue;
case 'v':
/*
** From Arnold Robbins' strftime version 3.0:
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
(t->tm_wday - 1) :
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = _fmt(Locale->t_fmt, t, pt, ptlim, warnp);
continue;
case 'x':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->d_fmt, t, pt, ptlim, &warn2);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'y':
*warnp = IN_ALL;
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
"%02d", pt, ptlim);
continue;
case 'Y':
pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE != NULL)
pt = _add(t->TM_ZONE, pt, ptlim);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst >= 0)
pt = _add(tzname[t->tm_isdst != 0],
pt, ptlim);
/*
** C99 says that %Z must be replaced by the
** empty string if the time zone is not
** determinable.
*/
continue;
case 'z':
{
int diff;
char const * sign;
if (t->tm_isdst < 0)
continue;
#ifdef TM_GMTOFF
diff = (int)t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
/*
** C99 says that the UTC offset must
** be computed by looking only at
** tm_isdst. This requirement is
** incorrect, since it means the code
** must rely on magic (in this case
** altzone and timezone), and the
** magic might not have the correct
** offset. Doing things correctly is
** tricky and requires disobeying C99;
** see GNU C strftime for details.
** For now, punt and conform to the
** standard, even though it's incorrect.
**
** C99 says that %z must be replaced by the
** empty string if the time zone is not
** determinable, so output nothing if the
** appropriate variables are not available.
*/
#ifndef STD_INSPIRED
if (t->tm_isdst == 0)
#ifdef USG_COMPAT
diff = -timezone;
#else /* !defined USG_COMPAT */
continue;
#endif /* !defined USG_COMPAT */
else
#ifdef ALTZONE
diff = -altzone;
#else /* !defined ALTZONE */
continue;
#endif /* !defined ALTZONE */
#else /* defined STD_INSPIRED */
{
struct tm tmp;
time_t lct, gct;
/*
** Get calendar time from t
** being treated as local.
*/
tmp = *t; /* mktime discards const */
lct = mktime(&tmp);
if (lct == (time_t)-1)
continue;
/*
** Get calendar time from t
** being treated as GMT.
**/
tmp = *t; /* mktime discards const */
gct = timegm(&tmp);
if (gct == (time_t)-1)
continue;
/* LINTED difference will fit int */
diff = (intmax_t)gct - (intmax_t)lct;
}
#endif /* defined STD_INSPIRED */
#endif /* !defined TM_GMTOFF */
if (diff < 0) {
sign = "-";
diff = -diff;
} else sign = "+";
pt = _add(sign, pt, ptlim);
diff /= 60;
pt = _conv((diff/60)*100 + diff%60,
"%04d", pt, ptlim);
}
continue;
#if 0
case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp);
continue;
#endif
case '%':
/*
** X311J/88-090 (4.12.3.5): if conversion char is
** undefined, behavior is undefined. Print out the
** character itself as printf(3) also does.
*/
default:
break;
}
}
if (pt == ptlim)
break;
*pt++ = *format;
}
return pt;
}
static char *
EFIAPI
_conv(
const int n,
const char * const format,
char * const pt,
const char * const ptlim
)
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(void) sprintf(buf, format, n);
return _add(buf, pt, ptlim);
}
static char *
EFIAPI
_add(
const char * str,
char * pt,
const char * const ptlim
)
{
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
return pt;
}

168
StdLib/LibC/Time/tzfile.h Normal file
View File

@@ -0,0 +1,168 @@
/** @file
Time Zone processing, declarations and macros.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Derived from the NIH time zone package file, tzfile.h, which contains the following notice:
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!
NetBSD: tzfile.h,v 1.8 1998/01/22 07:06:59 jtc Exp
**/
#ifndef TZFILE_H
#define TZFILE_H
/*
** Information about time zone files.
*/
#ifndef TZDIR /* Time zone object file directory */
#define TZDIR "/usr/share/zoneinfo"
#endif /* !defined TZDIR */
#ifndef TZDEFAULT
#define TZDEFAULT "/etc/localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
/*
** Each file begins with. . .
*/
#define TZ_MAGIC "TZif"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_reserved[16]; /* reserved for future use */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
char tzh_typecnt[4]; /* coded number of local time types */
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
** tzh_timecnt (char [4])s coded transition times a la time(2)
** tzh_timecnt (unsigned char)s types of local time starting at above
** tzh_typecnt repetitions of
** one (char [4]) coded UTC offset in seconds
** one (unsigned char) used to set tm_isdst
** one (unsigned char) that's an abbreviation list index
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
** time is standard time, if FALSE,
** transition time is wall clock time
** if absent, transition times are
** assumed to be wall clock time
** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
** time is UTC, if FALSE,
** transition time is local time
** if absent, transition times are
** assumed to be local time
*/
/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
/*
** The TZ_MAX_TIMES value below is enough to handle a bit more than a
** year's worth of solar time (corrected daily to the nearest second) or
** 138 years of Pacific Presidential Election time
** (where there are three time zone transitions every fourth year).
*/
#define TZ_MAX_TIMES 370
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
#ifndef NOSOLAR
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined NOSOLAR */
#ifdef NOSOLAR
/*
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
** as noted by Earl Chew <earl@hpato.aus.hp.com>.
*/
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif /* !defined NOSOLAR */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
/* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((LONG32)(SECSPERHOUR * HOURSPERDAY))
#define MONSPERYEAR 12
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_JANUARY 0
#define TM_FEBRUARY 1
#define TM_MARCH 2
#define TM_APRIL 3
#define TM_MAY 4
#define TM_JUNE 5
#define TM_JULY 6
#define TM_AUGUST 7
#define TM_SEPTEMBER 8
#define TM_OCTOBER 9
#define TM_NOVEMBER 10
#define TM_DECEMBER 11
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY // Use this for 32-bit time_t
//#define EPOCH_WDAY TM_SUNDAY // Use this for 64-bit time_t
/*
** Accurate only for the past couple of centuries;
** that will probably do.
*/
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#endif /* !defined TZFILE_H */