/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* from Arthur Olson's 6.1 */
/*LINTLIBRARY*/
#include <tzfile.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h> /* for NULL */
#include <fcntl.h>
#ifdef __STDC__
#define P(s) s
#else /* !defined __STDC__ */
/*
** Memory management functions
*/
extern char * calloc();
extern char * malloc();
/*
** Communication with the environment
*/
extern char * getenv();
#define ASTERISK *
#define const
#endif /* !defined __STDC__ */
#ifndef TRUE
#define FALSE 0
#endif /* !defined TRUE */
/*
** 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).
*/
};
struct state {
int timecnt;
int typecnt;
int charcnt;
unsigned char *types;
char *chars;
};
struct rule {
};
/*
** Prototypes for static functions.
*/
int max));
static void settzname P((void));
long offset));
int lastditch));
static int lcl_is_set;
static int gmt_is_set;
#ifdef S5EMUL
"GMT",
" ",
};
int daylight = 0;
#endif /* defined S5EMUL */
static long
const char * const codep;
{
register long result;
register int i;
result = 0;
for (i = 0; i < 4; ++i)
return result;
}
/*
** Free up existing items pointed to by the specified "state" structure,
** and allocate new ones of sizes specified by that "state" structure.
** Return 0 on success; return -1 and free all previously-allocated items
** on failure.
*/
static int
{
(unsigned)sizeof (time_t));
return -1;
(unsigned)sizeof (unsigned char));
return -1;
}
}
(unsigned)sizeof (struct ttinfo));
return -1;
}
(unsigned)sizeof (char));
return -1;
}
return 0;
}
/*
** Free all the items pointed to by the specified "state" structure (except for
** "chars", which might have other references to it), and zero out all the
** pointers to those items.
*/
static void
{
}
}
}
}
#ifdef S5EMUL
static void
{
register int i;
daylight = 0;
timezone = 0;
altzone = 0;
return;
daylight = 1;
}
/*
** And to get the latest zone names into tzname. . .
*/
}
}
#endif
/*
** Maximum size of a time zone file.
*/
TZ_MAX_TIMES * (4 + sizeof (char)) + \
TZ_MAX_CHARS * sizeof (char) + \
TZ_MAX_TYPES * sizeof (char))
static int
register const char * name;
{
register const char * p;
register int i;
register int fid;
return -1;
{
register int doaccess;
if (name[0] == ':')
++name;
if (!doaccess) {
return -1;
return -1;
/*
** Set doaccess if '.' (as in "../") shows up in name.
*/
}
return (0);
return -1;
return -1;
}
{
int leapcnt;
int ttisstdcnt;
return -1;
return -1;
if (i < sizeof *tzhp +
ttisstdcnt * sizeof (char))
return -1;
return -1;
p += 4;
}
return -1;
}
p += 4;
return -1;
ttisp->tt_abbrind = (unsigned char) *p++;
if (ttisp->tt_abbrind < 0 ||
return -1;
}
if (ttisstdcnt == 0)
else {
ttisp->tt_ttisstd = *p++;
return -1;
}
}
}
if (sp->last_tzload)
return 0;
}
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
};
/*
** 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.
** Support both quoted and unquoted timezones.
*/
static const char *
const char * strp;
int quoted;
{
unsigned char c;
if (quoted) {
while ((c = (unsigned char)*strp) != '\0' &&
++strp;
} else {
&& (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 *
register const char * strp;
int * const nump;
const int min;
const int max;
{
register char c;
register int num;
return NULL;
num = 0;
return NULL; /* illegal value */
++strp;
}
return NULL; /* illegal value */
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 *
register const char * strp;
long * const secsp;
{
int num;
return NULL;
if (*strp == ':') {
++strp;
return NULL;
if (*strp == ':') {
++strp;
return NULL;
}
}
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 *
register const char * strp;
long * const offsetp;
{
register int neg;
if (*strp == '-') {
neg = 1;
++strp;
neg = 0;
else return NULL; /* illegal offset */
return NULL; /* illegal time */
if (neg)
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 *
const char * strp;
{
if (*strp == 'J') {
/*
** Julian day.
*/
++strp;
} else if (*strp == 'M') {
/*
** Month, week, day.
*/
++strp;
return NULL;
if (*strp++ != '.')
return NULL;
return NULL;
if (*strp++ != '.')
return NULL;
/*
** Day of year.
*/
} else return NULL; /* invalid format */
return NULL;
if (*strp == '/') {
/*
** Time specified.
*/
++strp;
return strp;
}
/*
** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
** year, a rule, and the offset from GMT at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect.
*/
static time_t
const int year;
const long offset;
{
register int leapyear;
register int i;
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 += 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.
*/
break;
case MONTH_NTH_DAY_OF_WEEK:
/*
** Mm.n.d - nth "dth day" of month m.
*/
/*
** Use Zeller's Congruence to get day-of-week of first day of
** month.
*/
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.
*/
if (d < 0)
d += DAYSPERWEEK;
if (d + DAYSPERWEEK >=
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 GMT 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 GMT.
*/
}
/*
** Given a POSIX section 8-style TZ string, fill in the rule tables as
** appropriate.
*/
static int
const char * name;
const int lastditch;
{
const char * stdname;
const char * dstname;
int stdlen;
int dstlen;
long stdoffset;
long dstoffset;
unsigned char * typep;
char * cp;
if (lastditch) {
} else {
if (*name == '<') {
name++;
stdname++;
if (*name != '>') {
return (-1);
}
name++;
} else {
}
if (stdlen < 3)
return -1;
}
if (*name == '\0')
stdoffset = 0;
else {
return -1;
}
if (*name != '\0') {
if (*name == '<') {
name++;
dstname++;
if (*name != '>') {
return (-1);
}
name++;
} else {
}
if (dstlen < 3)
return -1;
return -1;
register int year;
++name;
return -1;
if (*name++ != ',')
return -1;
return -1;
if (*name != '\0')
return -1;
/*
** Two transitions per year, from EPOCH_YEAR to 2037.
*/
return -1;
return -1;
janfirst = 0;
*typep++ = 0; /* DST begins */
} else {
*typep++ = 0; /* DST begins */
}
janfirst +=
}
} else {
int sawstd;
int sawdst;
long stdfix;
long dstfix;
long oldfix;
int isdst;
register int i;
if (*name != '\0')
return -1;
return -1;
}
/*
** Discard zone abbreviations from file, and allocate
** space for the ones from TZ.
*/
(unsigned)sizeof (char));
/*
** Compute the difference between the real and
** prototype standard and summer time offsets
** from GMT, and put the real standard and summer
** time offsets into the rules in place of the
** prototype offsets.
*/
stdfix = 0;
dstfix = 0;
dstfix =
return -1;
} else {
stdfix =
return -1;
}
}
/*
** Make sure we have both standard and summer time.
*/
return -1;
/*
** Now correct the transition times by shifting
** them by the difference between the real and
** prototype offsets. Note that this difference
** can be different in standard and summer time;
** the prototype probably has a 1-hour difference
** between standard and summer time, but a different
** difference can be specified in TZ.
*/
/*
** 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.
*/
}
}
} else {
dstlen = 0;
return -1;
}
*cp++ = '\0';
if (dstlen != 0) {
}
return 0;
}
static void
{
}
void
{
lcl_is_set = TRUE;
#ifdef S5EMUL
settzname(); /* all we can do */
#endif
return;
}
}
#ifdef S5EMUL
settzname();
#endif
}
void
tzset()
{
register const char * name;
tzsetwall();
return;
}
lcl_is_set = TRUE;
#ifdef S5EMUL
settzname(); /* all we can do */
#endif
return;
}
}
if (*name == '\0') {
/*
** User wants it fast rather than right.
*/
return;
#ifdef S5EMUL
settzname();
#endif
}
/*
** The easy way to behave "as if no library function calls" localtime
** is to not call it--so we drop its guts into "localsub", which can be
** freely called. (And no, the PANS doesn't require the above behavior--
** but it *is* desirable.)
**
** The unused offset argument is for the benefit of mktime variants.
*/
/*ARGSUSED*/
static void
const long offset;
{
register int i;
if (!lcl_is_set)
tzset();
return;
}
i = 0;
i = 0;
break;
}
} else {
break;
}
#ifdef S5EMUL
#endif /* S5EMUL */
}
struct tm *
{
* base localtime calls this to initialize
* some things, so we'll do it here, too.
*/
return &tm;
}
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
static void
const long offset;
{
if (!gmt_is_set) {
gmt_is_set = TRUE;
}
/*
** Could get fancy here and deliver something such as
** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
if (offset != 0)
else {
}
}
struct tm *
{
return &tm;
}
struct tm *
const long offset;
{
return &tm;
}
static void
const long offset;
{
register long days;
register long rem;
register int y;
register int yleap;
register const int * ip;
while (rem < 0) {
rem += SECSPERDAY;
--days;
}
while (rem >= SECSPERDAY) {
rem -= SECSPERDAY;
++days;
}
y = EPOCH_YEAR;
if (days >= 0)
for ( ; ; ) {
break;
++y;
}
else do {
--y;
} while (days < 0);
}
/*
** 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. (mtxinu!kridle now).
** 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
#endif /* !defined WRONG */
static void
int * const tensptr;
int * const unitsptr;
const int base;
{
int tmp;
} else if (*unitsptr < 0) {
/* tmp has the range 0 to abs(*unitptr) -1 */
}
}
static int
{
register int result;
return result;
}
static time_t
void (* const funcp)();
const long offset;
int * const okayp;
{
register int dir;
register int bits;
register int i, j ;
register int saved_seconds;
time_t t;
}
}
}
for ( ; ; ) {
break;
}
}
/*
** Calculate the number of magnitude bits in a time_t
** (this works regardless of whether time_t is
** signed or unsigned, though lint complains if unsigned).
*/
;
/*
** If time_t is signed, then 0 is the median value,
** if time_t is unsigned, then 1 << bits is median.
*/
for ( ; ; ) {
if (dir != 0) {
if (bits-- < 0)
return WRONG;
if (bits < 0)
--t;
else if (dir > 0)
continue;
}
break;
/*
** Right time, wrong type.
** Hunt for right time, right type.
** It's okay to guess wrong since the guess
** gets checked.
*/
return WRONG;
continue;
continue;
continue;
continue;
/*
** We have a match.
*/
t = newt;
goto label;
}
}
return WRONG;
}
t += saved_seconds;
return t;
}
static time_t
void (* const funcp)();
const long offset;
{
register time_t t;
int okay;
return t;
/*
** 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.
*/
return WRONG;
continue;
continue;
if (okay)
return t;
}
}
return WRONG;
}
{
}
{
}
{
}
const long offset;
{
}