Mail Archives: cygwin/2002/02/11/11:41:50
------_=_NextPart_000_01C1B31A.A9F59490
Content-Type: text/plain;
charset="iso-8859-1"
Hello,
I have the following problem, or misunderstandig(!) of TZ variable in
cygwin1.dll.
Problem (and my current solution)
When I do not set TZ to a valid value, all times will be showed as GMT (or
UTC) time.
The automatic generated TZ variable in localtime.cc will generate a name
from GetTimeZoneInformation.
When I test this algorithm in a program, the name will be invalid (longer
than 3 characters).
At the moment I have problems to rebuild the cygwin1.dll (make will make a
lot of things but I do find a simple make cygwin1.dll...)
Is it a good, bad, very bad idea to test the length of the name against 3 to
generate a TZ variable compatible with tzparse?
localtime.cc (not tested, because I was not able to build cygwin1.dll)
GetTimeZoneInformation(&tz);
(...)
for (src = tz.StandardName; *src; src++)
if (is_upper(*src)) *dst++ = *src;
/* not 3 characters for timezone _tzname[0] ?
happens for example in Win2000/NT german version
a) tz.StandardName is a WideChar String
b) is very long "Westeropaische Normalzeit"
generate a TZ variable relative to GMT-x
(if strlen of _tzname is not equal 3 , tzparse will
not accept the TZ variable!)
mkt */
if (strlen(cp) != 3) /* mkt */
{ /* mkt */
strcpy(cp, "GMT"); /* mkt */
dst = cp + 3; /* mkt */
} /* mkt */
(...) same for the daylight saving time with DST.
When I call this function as a separate routine win32_tzset (roughly written
in win32_tzset.c for my VC program and Cygwin-GNU ports) the TZ variable
will be understood and the correct times will be chown.
pdksh port with a call to win32_tzset to set TZ automatically from Windows
Control Panel:
pdksh $ echo $TZ
GMT-1DST-2,M3.5.0/2,M10.5.0/3
pdksh $ date
Mon Feb 11 17:35:54 2002
(yes this the current time)
bash-2.05a$ date
Mon Feb 11 16:36:25 2002
(no, this the UTC time)
<<win32_tzset.c>> <<localtime.cc>>
------_=_NextPart_000_01C1B31A.A9F59490
Content-Type: application/octet-stream;
name="win32_tzset.c"
Content-Disposition: attachment;
filename="win32_tzset.c"
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#ifdef __GNUC__
static long _dstbias=0;
#endif
void win32_tzset( void )
{
tzset();
if (((char*)getenv("TZ") == (char*)NULL) && (_timezone == 0))
{
TIME_ZONE_INFORMATION tzinfo;
DWORD tzstate;
int dstflag=0;
static char TZ[40];
char tmp_str[40];
long i,j,g,k;
/* printf("try to build up a TZ Variable from Windows Date Control Panel!\n"); */
if ( (tzstate = GetTimeZoneInformation( &tzinfo )) != 0xFFFFFFFF )
{
/*
* Must be very careful in determining whether or not DST is
* really in effect.
*/
if ( (tzstate == TIME_ZONE_ID_DAYLIGHT) &&
(tzinfo.DaylightDate.wMonth != 0) &&
(tzinfo.DaylightBias != 0) )
dstflag = 1;
else
/*
* When in doubt, assume standard time
*/
dstflag = 0;
}
else
dstflag = 0; /* When in doubt, assume standard time */
_timezone = tzinfo.Bias * 60L;
if ( tzinfo.StandardDate.wMonth != 0 )
_timezone += (tzinfo.StandardBias * 60L);
if ( (tzinfo.DaylightDate.wMonth != 0) &&
(tzinfo.DaylightBias != 0) )
{
_daylight = 1;
_dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) *
60L;
}
else
{
_daylight = 0;
_dstbias = 0;
}
_tzname[0] = "GMT";
_tzname[1] = "DST";
/* BUILD UP TZ STRING */
/* always relativ to GMT Time */
strcpy(TZ,"TZ=GMT"); /* probably UTC for Universal StandardTime */
if (_timezone > 0)
{
strcat(TZ,"+");
i=_timezone;
}
else
{
strcat(TZ,"-");
i=_timezone * -1;
}
j=i % 60L; /* Minutenausgleich */
g=j % 60L; /* Sekundenausgleich */
i=i / 3600L;
sprintf(tmp_str,"%ld", i);
strcat(TZ,tmp_str);
if (j | g)
{
sprintf(tmp_str,":%ld", j);
strcat(TZ,tmp_str);
}
if (g)
{
sprintf(tmp_str,":%ld", g);
strcat(TZ,tmp_str);
}
if (_daylight)
{
strcat(TZ,"DST"); /* DaylightSavingTime */
k=_timezone + _dstbias; /* absolut differenz */
if (k > 0)
{
strcat(TZ,"+");
i=k;
}
else
{
strcat(TZ,"-");
i=k * -1;
}
j=i % 60L; /* Minutenausgleich */
g=j % 60L; /* Sekundenausgleich */
i=i / 3600L;
sprintf(tmp_str,"%ld", i);
strcat(TZ,tmp_str);
if (j | g)
{
sprintf(tmp_str,":%ld", j);
strcat(TZ,tmp_str);
}
if (g)
{
sprintf(tmp_str,":%ld", g);
strcat(TZ,tmp_str);
}
/* when to switch DST on ?*/
sprintf(tmp_str,",M%d.%d.%d/%d",
tzinfo.DaylightDate.wMonth,
tzinfo.DaylightDate.wDay,
tzinfo.DaylightDate.wDayOfWeek
tzinfo.DaylightDate.wHour);
strcat(TZ,tmp_str);
if (tzinfo.DaylightDate.wMinute || tzinfo.DaylightDate.wSecond)
{
sprintf(tmp_str,",:%d", tzinfo.DaylightDate.wMinute);
strcat(TZ,tmp_str);
}
if (tzinfo.DaylightDate.wSecond)
{
sprintf(tmp_str,",:%d", tzinfo.DaylightDate.wSecond);
strcat(TZ,tmp_str);
}
/* when to switch DST off, back to StandardDate ?*/
sprintf(tmp_str,",M%d.%d.%d/%d",
tzinfo.StandardDate.wMonth,
tzinfo.StandardDate.wDay,
tzinfo.StandardDate.wDayOfWeek,
tzinfo.StandardDate.wHour);
strcat(TZ,tmp_str);
if (tzinfo.StandardDate.wMinute || tzinfo.StandardDate.wSecond)
{
sprintf(tmp_str,",:%d", tzinfo.StandardDate.wMinute);
strcat(TZ,tmp_str);
}
if (tzinfo.StandardDate.wSecond)
{
sprintf(tmp_str,",:%d", tzinfo.StandardDate.wSecond);
strcat(TZ,tmp_str);
}
}
/* printf("\nbuild up TZ string: TZ=%s\n", TZ); */
putenv(TZ);
setenv
}
tzset(); /* set to system & cygwin */
}
------_=_NextPart_000_01C1B31A.A9F59490
Content-Type: application/octet-stream;
name="localtime.cc"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="localtime.cc"
/*=0A=
** This file is in the public domain, so clarified as of=0A=
** 1996-06-05 by Arthur David Olson (arthur_david_olson AT nih DOT gov).=0A=
*/=0A=
/* Temporarily merged private.h and tzfile.h for ease of management - =
DJ */=0A=
=0A=
#include "winsup.h"=0A=
#include "cygerrno.h"=0A=
#include <windows.h>=0A=
#define lint=0A=
=0A=
#define USG_COMPAT=0A=
=0A=
#ifndef lint=0A=
#ifndef NOID=0A=
static char elsieid[] =3D "@(#)localtime.c 7.66";=0A=
#endif /* !defined NOID */=0A=
#endif /* !defined lint */=0A=
=0A=
/*=0A=
** Leap second handling from Bradley White (bww AT k DOT gp DOT cs DOT cmu DOT edu).=0A=
** POSIX-style TZ environment variable handling from Guy Harris=0A=
** (guy AT auspex DOT com).=0A=
*/=0A=
=0A=
/*LINTLIBRARY*/=0A=
=0A=
#ifndef PRIVATE_H=0A=
=0A=
#define PRIVATE_H=0A=
=0A=
/*=0A=
** This file is in the public domain, so clarified as of=0A=
** 1996-06-05 by Arthur David Olson (arthur_david_olson AT nih DOT gov).=0A=
*/=0A=
=0A=
/*=0A=
** This header is for use ONLY with the time conversion code.=0A=
** There is no guarantee that it will remain unchanged,=0A=
** or that it will remain at all.=0A=
** Do NOT copy it to any system include directory.=0A=
** Thank you!=0A=
*/=0A=
=0A=
/*=0A=
** ID=0A=
*/=0A=
=0A=
#ifndef lint=0A=
#ifndef NOID=0A=
static char privatehid[] =3D "@(#)private.h 7.48";=0A=
#endif /* !defined NOID */=0A=
#endif /* !defined lint */=0A=
=0A=
/*=0A=
** Defaults for preprocessor symbols.=0A=
** You can override these in your C compiler options, e.g. =
`-DHAVE_ADJTIME=3D0'.=0A=
*/=0A=
=0A=
#ifndef HAVE_ADJTIME=0A=
#define HAVE_ADJTIME 1=0A=
#endif /* !defined HAVE_ADJTIME */=0A=
=0A=
#ifndef HAVE_GETTEXT=0A=
#define HAVE_GETTEXT 0=0A=
#endif /* !defined HAVE_GETTEXT */=0A=
=0A=
#ifndef HAVE_SETTIMEOFDAY=0A=
#define HAVE_SETTIMEOFDAY 3=0A=
#endif /* !defined HAVE_SETTIMEOFDAY */=0A=
=0A=
#ifndef HAVE_STRERROR=0A=
#define HAVE_STRERROR 0=0A=
#endif /* !defined HAVE_STRERROR */=0A=
=0A=
#ifndef HAVE_SYMLINK=0A=
#define HAVE_SYMLINK 1=0A=
#endif /* !defined HAVE_SYMLINK */=0A=
=0A=
#ifndef HAVE_UNISTD_H=0A=
#define HAVE_UNISTD_H 1=0A=
#endif /* !defined HAVE_UNISTD_H */=0A=
=0A=
#ifndef HAVE_UTMPX_H=0A=
#define HAVE_UTMPX_H 0=0A=
#endif /* !defined HAVE_UTMPX_H */=0A=
=0A=
#ifndef LOCALE_HOME=0A=
#define LOCALE_HOME "/usr/lib/locale"=0A=
#endif /* !defined LOCALE_HOME */=0A=
=0A=
/*=0A=
** Nested includes=0A=
*/=0A=
=0A=
#include "sys/types.h" /* for time_t */=0A=
#include "stdio.h"=0A=
#include "limits.h" /* for CHAR_BIT */=0A=
#include "time.h"=0A=
#include "stdlib.h"=0A=
=0A=
#if HAVE_GETTEXT - 0=0A=
#include "libintl.h"=0A=
#endif /* HAVE_GETTEXT - 0 */=0A=
=0A=
#if HAVE_UNISTD_H - 0=0A=
#include "unistd.h" /* for F_OK and R_OK */=0A=
#endif /* HAVE_UNISTD_H - 0 */=0A=
=0A=
#if !(HAVE_UNISTD_H - 0)=0A=
#ifndef F_OK=0A=
#define F_OK 0=0A=
#endif /* !defined F_OK */=0A=
#ifndef R_OK=0A=
#define R_OK 4=0A=
#endif /* !defined R_OK */=0A=
#endif /* !(HAVE_UNISTD_H - 0) */=0A=
=0A=
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > =
UCHAR_MAX. */=0A=
#define is_digit(c) ((unsigned)(c) - '0' <=3D 9)=0A=
=0A=
/*=0A=
** Workarounds for compilers/systems.=0A=
*/=0A=
=0A=
/*=0A=
** SunOS 4.1.1 cc lacks const.=0A=
*/=0A=
=0A=
#ifndef const=0A=
#ifndef __STDC__=0A=
#define const=0A=
#endif /* !defined __STDC__ */=0A=
#endif /* !defined const */=0A=
=0A=
/*=0A=
** SunOS 4.1.1 cc lacks prototypes.=0A=
*/=0A=
=0A=
#ifndef P=0A=
#ifdef __STDC__=0A=
#define P(x) x=0A=
#endif /* defined __STDC__ */=0A=
#ifndef __STDC__=0A=
#define P(x) ()=0A=
#endif /* !defined __STDC__ */=0A=
#endif /* !defined P */=0A=
=0A=
/*=0A=
** SunOS 4.1.1 headers lack EXIT_SUCCESS.=0A=
*/=0A=
=0A=
#ifndef EXIT_SUCCESS=0A=
#define EXIT_SUCCESS 0=0A=
#endif /* !defined EXIT_SUCCESS */=0A=
=0A=
/*=0A=
** SunOS 4.1.1 headers lack EXIT_FAILURE.=0A=
*/=0A=
=0A=
#ifndef EXIT_FAILURE=0A=
#define EXIT_FAILURE 1=0A=
#endif /* !defined EXIT_FAILURE */=0A=
=0A=
/*=0A=
** SunOS 4.1.1 headers lack FILENAME_MAX.=0A=
*/=0A=
=0A=
#ifndef FILENAME_MAX=0A=
=0A=
#ifndef MAXPATHLEN=0A=
#ifdef unix=0A=
#include "sys/param.h"=0A=
#endif /* defined unix */=0A=
#endif /* !defined MAXPATHLEN */=0A=
=0A=
#ifdef MAXPATHLEN=0A=
#define FILENAME_MAX MAXPATHLEN=0A=
#endif /* defined MAXPATHLEN */=0A=
#ifndef MAXPATHLEN=0A=
#define FILENAME_MAX 1024 /* Pure guesswork */=0A=
#endif /* !defined MAXPATHLEN */=0A=
=0A=
#endif /* !defined FILENAME_MAX */=0A=
=0A=
/*=0A=
** SunOS 4.1.1 libraries lack remove.=0A=
*/=0A=
=0A=
#ifndef remove=0A=
extern int unlink P((const char * filename));=0A=
#define remove unlink=0A=
#endif /* !defined remove */=0A=
=0A=
/*=0A=
** Finally, some convenience items.=0A=
*/=0A=
=0A=
#ifndef TRUE=0A=
#define TRUE 1=0A=
#endif /* !defined TRUE */=0A=
=0A=
#ifndef FALSE=0A=
#define FALSE 0=0A=
#endif /* !defined FALSE */=0A=
=0A=
#ifndef TYPE_BIT=0A=
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)=0A=
#endif /* !defined TYPE_BIT */=0A=
=0A=
#ifndef TYPE_SIGNED=0A=
#define TYPE_SIGNED(type) (((type) -1) < 0)=0A=
#endif /* !defined TYPE_SIGNED */=0A=
=0A=
#ifndef INT_STRLEN_MAXIMUM=0A=
/*=0A=
** 302 / 1000 is log10(2.0) rounded up.=0A=
** Subtract one for the sign bit if the type is signed;=0A=
** add one for integer division truncation;=0A=
** add one more for a minus sign if the type is signed.=0A=
*/=0A=
#define INT_STRLEN_MAXIMUM(type) \=0A=
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + =
TYPE_SIGNED(type))=0A=
#endif /* !defined INT_STRLEN_MAXIMUM */=0A=
=0A=
/*=0A=
** INITIALIZE(x)=0A=
*/=0A=
=0A=
#ifndef GNUC_or_lint=0A=
#ifdef lint=0A=
#define GNUC_or_lint=0A=
#endif /* defined lint */=0A=
#ifndef lint=0A=
#ifdef __GNUC__=0A=
#define GNUC_or_lint=0A=
#endif /* defined __GNUC__ */=0A=
#endif /* !defined lint */=0A=
#endif /* !defined GNUC_or_lint */=0A=
=0A=
#ifndef INITIALIZE=0A=
#ifdef GNUC_or_lint=0A=
#define INITIALIZE(x) ((x) =3D 0)=0A=
#endif /* defined GNUC_or_lint */=0A=
#ifndef GNUC_or_lint=0A=
#define INITIALIZE(x)=0A=
#endif /* !defined GNUC_or_lint */=0A=
#endif /* !defined INITIALIZE */=0A=
=0A=
/*=0A=
** For the benefit of GNU folk...=0A=
** `_(MSGID)' uses the current locale's message library string for =
MSGID.=0A=
** The default is to use gettext if available, and use MSGID =
otherwise.=0A=
*/=0A=
=0A=
#ifndef _=0A=
#if HAVE_GETTEXT - 0=0A=
#define _(msgid) gettext(msgid)=0A=
#else /* !(HAVE_GETTEXT - 0) */=0A=
#define _(msgid) msgid=0A=
#endif /* !(HAVE_GETTEXT - 0) */=0A=
#endif /* !defined _ */=0A=
=0A=
#ifndef TZ_DOMAIN=0A=
#define TZ_DOMAIN "tz"=0A=
#endif /* !defined TZ_DOMAIN */=0A=
=0A=
/*=0A=
** UNIX was a registered trademark of UNIX System Laboratories in =
1993.=0A=
*/=0A=
=0A=
#endif /* !defined PRIVATE_H */=0A=
=0A=
#ifndef TZFILE_H=0A=
=0A=
#define TZFILE_H=0A=
=0A=
/*=0A=
** This file is in the public domain, so clarified as of=0A=
** 1996-06-05 by Arthur David Olson (arthur_david_olson AT nih DOT gov).=0A=
*/=0A=
=0A=
/*=0A=
** This header is for use ONLY with the time conversion code.=0A=
** There is no guarantee that it will remain unchanged,=0A=
** or that it will remain at all.=0A=
** Do NOT copy it to any system include directory.=0A=
** Thank you!=0A=
*/=0A=
=0A=
/*=0A=
** ID=0A=
*/=0A=
=0A=
#ifndef lint=0A=
#ifndef NOID=0A=
static char tzfilehid[] =3D "@(#)tzfile.h 7.14";=0A=
#endif /* !defined NOID */=0A=
#endif /* !defined lint */=0A=
=0A=
/*=0A=
** Information about time zone files.=0A=
*/=0A=
=0A=
#ifndef TZDIR=0A=
#define TZDIR "/usr/local/etc/zoneinfo" /* Time zone object file =
directory */=0A=
#endif /* !defined TZDIR */=0A=
=0A=
#ifndef TZDEFAULT=0A=
#define TZDEFAULT "localtime"=0A=
#endif /* !defined TZDEFAULT */=0A=
=0A=
#ifndef TZDEFRULES=0A=
#define TZDEFRULES "posixrules"=0A=
#endif /* !defined TZDEFRULES */=0A=
=0A=
/*=0A=
** Each file begins with. . .=0A=
*/=0A=
=0A=
#define TZ_MAGIC "TZif"=0A=
=0A=
struct tzhead {=0A=
char tzh_magic[4]; /* TZ_MAGIC */=0A=
char tzh_reserved[16]; /* reserved for future use */=0A=
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */=0A=
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */=0A=
char tzh_leapcnt[4]; /* coded number of leap seconds */=0A=
char tzh_timecnt[4]; /* coded number of transition times */=0A=
char tzh_typecnt[4]; /* coded number of local time types */=0A=
char tzh_charcnt[4]; /* coded number of abbr. chars */=0A=
};=0A=
=0A=
/*=0A=
** . . .followed by. . .=0A=
**=0A=
** tzh_timecnt (char [4])s coded transition times a la time(2)=0A=
** tzh_timecnt (unsigned char)s types of local time starting at =
above=0A=
** tzh_typecnt repetitions of=0A=
** one (char [4]) coded UTC offset in seconds=0A=
** one (unsigned char) used to set tm_isdst=0A=
** one (unsigned char) that's an abbreviation list index=0A=
** tzh_charcnt (char)s '\0'-terminated zone abbreviations=0A=
** tzh_leapcnt repetitions of=0A=
** one (char [4]) coded leap second transition times=0A=
** one (char [4]) total correction after above=0A=
** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition=0A=
** time is standard time, if FALSE,=0A=
** transition time is wall clock time=0A=
** if absent, transition times are=0A=
** assumed to be wall clock time=0A=
** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition=0A=
** time is UTC, if FALSE,=0A=
** transition time is local time=0A=
** if absent, transition times are=0A=
** assumed to be local time=0A=
*/=0A=
=0A=
/*=0A=
** In the current implementation, "tzset()" refuses to deal with files =
that=0A=
** exceed any of the limits below.=0A=
*/=0A=
=0A=
#ifndef TZ_MAX_TIMES=0A=
/*=0A=
** The TZ_MAX_TIMES value below is enough to handle a bit more than =
a=0A=
** year's worth of solar time (corrected daily to the nearest second) =
or=0A=
** 138 years of Pacific Presidential Election time=0A=
** (where there are three time zone transitions every fourth year).=0A=
*/=0A=
#define TZ_MAX_TIMES 370=0A=
#endif /* !defined TZ_MAX_TIMES */=0A=
=0A=
#ifndef TZ_MAX_TYPES=0A=
#ifndef NOSOLAR=0A=
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold =
*/=0A=
#endif /* !defined NOSOLAR */=0A=
#ifdef NOSOLAR=0A=
/*=0A=
** Must be at least 14 for Europe/Riga as of Jan 12 1995,=0A=
** as noted by Earl Chew <earl AT hpato DOT aus DOT hp DOT com>.=0A=
*/=0A=
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */=0A=
#endif /* !defined NOSOLAR */=0A=
#endif /* !defined TZ_MAX_TYPES */=0A=
=0A=
#ifndef TZ_MAX_CHARS=0A=
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters =
*/=0A=
/* (limited by what unsigned chars can hold) */=0A=
#endif /* !defined TZ_MAX_CHARS */=0A=
=0A=
#ifndef TZ_MAX_LEAPS=0A=
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections =
*/=0A=
#endif /* !defined TZ_MAX_LEAPS */=0A=
=0A=
#define SECSPERMIN 60=0A=
#define MINSPERHOUR 60=0A=
#define HOURSPERDAY 24=0A=
#define DAYSPERWEEK 7=0A=
#define DAYSPERNYEAR 365=0A=
#define DAYSPERLYEAR 366=0A=
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)=0A=
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)=0A=
#define MONSPERYEAR 12=0A=
=0A=
#define TM_SUNDAY 0=0A=
#define TM_MONDAY 1=0A=
#define TM_TUESDAY 2=0A=
#define TM_WEDNESDAY 3=0A=
#define TM_THURSDAY 4=0A=
#define TM_FRIDAY 5=0A=
#define TM_SATURDAY 6=0A=
=0A=
#define TM_JANUARY 0=0A=
#define TM_FEBRUARY 1=0A=
#define TM_MARCH 2=0A=
#define TM_APRIL 3=0A=
#define TM_MAY 4=0A=
#define TM_JUNE 5=0A=
#define TM_JULY 6=0A=
#define TM_AUGUST 7=0A=
#define TM_SEPTEMBER 8=0A=
#define TM_OCTOBER 9=0A=
#define TM_NOVEMBER 10=0A=
#define TM_DECEMBER 11=0A=
=0A=
#define TM_YEAR_BASE 1900=0A=
=0A=
#define EPOCH_YEAR 1970=0A=
#define EPOCH_WDAY TM_THURSDAY=0A=
=0A=
/*=0A=
** Accurate only for the past couple of centuries;=0A=
** that will probably do.=0A=
*/=0A=
=0A=
#define isleap(y) (((y) % 4) =3D=3D 0 && (((y) % 100) !=3D 0 || ((y) % =
400) =3D=3D 0))=0A=
=0A=
#ifndef USG=0A=
=0A=
/*=0A=
** Use of the underscored variants may cause problems if you move your =
code to=0A=
** certain System-V-based systems; for maximum portability, use the=0A=
** underscore-free variants. The underscored variants are provided =
for=0A=
** backward compatibility only; they may disappear from future versions =
of=0A=
** this file.=0A=
*/=0A=
=0A=
#define SECS_PER_MIN SECSPERMIN=0A=
#define MINS_PER_HOUR MINSPERHOUR=0A=
#define HOURS_PER_DAY HOURSPERDAY=0A=
#define DAYS_PER_WEEK DAYSPERWEEK=0A=
#define DAYS_PER_NYEAR DAYSPERNYEAR=0A=
#define DAYS_PER_LYEAR DAYSPERLYEAR=0A=
#define SECS_PER_HOUR SECSPERHOUR=0A=
#define SECS_PER_DAY SECSPERDAY=0A=
#define MONS_PER_YEAR MONSPERYEAR=0A=
=0A=
#endif /* !defined USG */=0A=
=0A=
#endif /* !defined TZFILE_H */=0A=
=0A=
#include "fcntl.h"=0A=
=0A=
/*=0A=
** SunOS 4.1.1 headers lack O_BINARY.=0A=
*/=0A=
=0A=
#ifdef O_BINARY=0A=
#define OPEN_MODE (O_RDONLY | O_BINARY)=0A=
#endif /* defined O_BINARY */=0A=
#ifndef O_BINARY=0A=
#define OPEN_MODE O_RDONLY=0A=
#endif /* !defined O_BINARY */=0A=
=0A=
#ifndef WILDABBR=0A=
/*=0A=
** Someone might make incorrect use of a time zone abbreviation:=0A=
** 1. They might reference tzname[0] before calling tzset =
(explicitly=0A=
** or implicitly).=0A=
** 2. They might reference tzname[1] before calling tzset =
(explicitly=0A=
** or implicitly).=0A=
** 3. They might reference tzname[1] after setting to a time zone=0A=
** in which Daylight Saving Time is never observed.=0A=
** 4. They might reference tzname[0] after setting to a time zone=0A=
** in which Standard Time is never observed.=0A=
** 5. They might reference tm.TM_ZONE after calling offtime.=0A=
** What's best to do in the above cases is open to debate;=0A=
** for now, we just set things up so that in any of the five cases=0A=
** WILDABBR is used. Another possibility: initialize tzname[0] to =
the=0A=
** string "tzname[0] used before set", and similarly for the other =
cases.=0A=
** And another: initialize tzname[0] to "ERA", with an explanation in =
the=0A=
** manual page of what this "time zone abbreviation" means (doing this =
so=0A=
** that tzname[0] has the "normal" length of three characters).=0A=
*/=0A=
#define WILDABBR " "=0A=
#endif /* !defined WILDABBR */=0A=
=0A=
static char wildabbr[] NO_COPY =3D WILDABBR;=0A=
=0A=
static char gmt[] NO_COPY =3D "GMT";=0A=
=0A=
struct ttinfo { /* time type information */=0A=
long tt_gmtoff; /* UTC offset in seconds */=0A=
int tt_isdst; /* used to set tm_isdst */=0A=
int tt_abbrind; /* abbreviation list index */=0A=
int tt_ttisstd; /* TRUE if transition is std time */=0A=
int tt_ttisgmt; /* TRUE if transition is UTC */=0A=
};=0A=
=0A=
struct lsinfo { /* leap second information */=0A=
time_t ls_trans; /* transition time */=0A=
long ls_corr; /* correction to apply */=0A=
};=0A=
=0A=
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))=0A=
=0A=
#ifdef TZNAME_MAX=0A=
#define MY_TZNAME_MAX TZNAME_MAX=0A=
#endif /* defined TZNAME_MAX */=0A=
#ifndef TZNAME_MAX=0A=
#define MY_TZNAME_MAX 255=0A=
#endif /* !defined TZNAME_MAX */=0A=
=0A=
struct state {=0A=
int leapcnt;=0A=
int timecnt;=0A=
int typecnt;=0A=
int charcnt;=0A=
time_t ats[TZ_MAX_TIMES];=0A=
unsigned char types[TZ_MAX_TIMES];=0A=
struct ttinfo ttis[TZ_MAX_TYPES];=0A=
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),=0A=
(2 * (MY_TZNAME_MAX + 1)))];=0A=
struct lsinfo lsis[TZ_MAX_LEAPS];=0A=
};=0A=
=0A=
struct rule {=0A=
int r_type; /* type of rule--see below */=0A=
int r_day; /* day number of rule */=0A=
int r_week; /* week number of rule */=0A=
int r_mon; /* month number of rule */=0A=
long r_time; /* transition time of rule */=0A=
};=0A=
=0A=
#define JULIAN_DAY 0 /* Jn - Julian day */=0A=
#define DAY_OF_YEAR 1 /* n - day of year */=0A=
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week =
*/=0A=
=0A=
/*=0A=
** Prototypes for static functions.=0A=
*/=0A=
=0A=
static long detzcode P((const char * codep));=0A=
static const char * getzname P((const char * strp));=0A=
static const char * getnum P((const char * strp, int * nump, int =
min,=0A=
int max));=0A=
static const char * getsecs P((const char * strp, long * secsp));=0A=
static const char * getoffset P((const char * strp, long * =
offsetp));=0A=
static const char * getrule P((const char * strp, struct rule * =
rulep));=0A=
static void gmtload P((struct state * sp));=0A=
static void gmtsub P((const time_t * timep, long offset,=0A=
struct tm * tmp));=0A=
static void localsub P((const time_t * timep, long offset,=0A=
struct tm * tmp));=0A=
static int increment_overflow P((int * number, int delta));=0A=
static int normalize_overflow P((int * tensptr, int * unitsptr,=0A=
int base));=0A=
static void settzname P((void));=0A=
static time_t time1 P((struct tm * tmp,=0A=
void(*funcp) P((const time_t *,=0A=
long, struct tm *)),=0A=
long offset));=0A=
static time_t time2 P((struct tm *tmp,=0A=
void(*funcp) P((const time_t *,=0A=
long, struct tm*)),=0A=
long offset, int * okayp));=0A=
static time_t time2sub P((struct tm *tmp,=0A=
void(*funcp) P((const time_t *,=0A=
long, struct tm*)),=0A=
long offset, int * okayp, int do_norm_secs));=0A=
static void timesub P((const time_t * timep, long offset,=0A=
const struct state * sp, struct tm * tmp));=0A=
static int tmcomp P((const struct tm * atmp,=0A=
const struct tm * btmp));=0A=
static time_t transtime P((time_t janfirst, int year,=0A=
const struct rule * rulep, long offset));=0A=
static int tzload P((const char * name, struct state * sp));=0A=
static int tzparse P((const char * name, struct state * sp,=0A=
int lastditch));=0A=
=0A=
#ifdef ALL_STATE=0A=
static struct state * lclptr;=0A=
static struct state * gmtptr;=0A=
#endif /* defined ALL_STATE */=0A=
=0A=
#ifndef ALL_STATE=0A=
static struct state lclmem;=0A=
static struct state gmtmem;=0A=
#define lclptr (&lclmem)=0A=
#define gmtptr (&gmtmem)=0A=
#endif /* State Farm */=0A=
=0A=
#ifndef TZ_STRLEN_MAX=0A=
#define TZ_STRLEN_MAX 255=0A=
#endif /* !defined TZ_STRLEN_MAX */=0A=
=0A=
static char lcl_TZname[TZ_STRLEN_MAX + 1];=0A=
static int lcl_is_set;=0A=
static int gmt_is_set;=0A=
=0A=
#define tzname _tzname=0A=
#undef _tzname=0A=
=0A=
char * tzname[2] =3D {=0A=
wildabbr,=0A=
wildabbr=0A=
};=0A=
=0A=
/*=0A=
** Section 4.12.3 of X3.159-1989 requires that=0A=
** Except for the strftime function, these functions [asctime,=0A=
** ctime, gmtime, localtime] return values in one of two static=0A=
** objects: a broken-down time structure and an array of char.=0A=
** Thanks to Paul Eggert (eggert AT twinsun DOT com) for noting this.=0A=
*/=0A=
=0A=
static struct tm tm;=0A=
=0A=
=0A=
/* These variables are initialized by tzset. The macro versions are=0A=
defined in time.h, and indirect through the __imp_ pointers. */=0A=
=0A=
#define timezone _timezone=0A=
#define daylight _daylight=0A=
#undef _timezone=0A=
#undef _daylight=0A=
=0A=
#ifdef USG_COMPAT=0A=
time_t timezone;=0A=
int daylight;=0A=
#endif /* defined USG_COMPAT */=0A=
=0A=
#ifdef ALTZONE=0A=
time_t altzone;=0A=
#endif /* defined ALTZONE */=0A=
=0A=
static long=0A=
detzcode(const char *codep)=0A=
{=0A=
register long result;=0A=
register int i;=0A=
=0A=
result =3D (codep[0] & 0x80) ? ~0L : 0L;=0A=
for (i =3D 0; i < 4; ++i)=0A=
result =3D (result << 8) | (codep[i] & 0xff);=0A=
return result;=0A=
}=0A=
=0A=
static void=0A=
settzname P((void))=0A=
{=0A=
register struct state * const sp =3D lclptr;=0A=
register int i;=0A=
=0A=
tzname[0] =3D wildabbr;=0A=
tzname[1] =3D wildabbr;=0A=
#ifdef USG_COMPAT=0A=
daylight =3D 0;=0A=
timezone =3D 0;=0A=
#endif /* defined USG_COMPAT */=0A=
#ifdef ALTZONE=0A=
altzone =3D 0;=0A=
#endif /* defined ALTZONE */=0A=
#ifdef ALL_STATE=0A=
if (sp =3D=3D NULL) {=0A=
tzname[0] =3D tzname[1] =3D gmt;=0A=
return;=0A=
}=0A=
#endif /* defined ALL_STATE */=0A=
for (i =3D 0; i < sp->typecnt; ++i) {=0A=
register const struct ttinfo * const ttisp =3D &sp->ttis[i];=0A=
=0A=
tzname[ttisp->tt_isdst] =3D=0A=
&sp->chars[ttisp->tt_abbrind];=0A=
#ifdef USG_COMPAT=0A=
if (ttisp->tt_isdst)=0A=
daylight =3D 1;=0A=
if (i =3D=3D 0 || !ttisp->tt_isdst)=0A=
timezone =3D -(ttisp->tt_gmtoff);=0A=
#endif /* defined USG_COMPAT */=0A=
#ifdef ALTZONE=0A=
if (i =3D=3D 0 || ttisp->tt_isdst)=0A=
altzone =3D -(ttisp->tt_gmtoff);=0A=
#endif /* defined ALTZONE */=0A=
}=0A=
/*=0A=
** And to get the latest zone names into tzname. . .=0A=
*/=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
register const struct ttinfo * const ttisp =3D=0A=
&sp->ttis[=0A=
sp->types[i]];=0A=
=0A=
tzname[ttisp->tt_isdst] =3D=0A=
&sp->chars[ttisp->tt_abbrind];=0A=
}=0A=
}=0A=
=0A=
#include "tz_posixrules.h"=0A=
=0A=
static int=0A=
tzload(const char *name, struct state *sp)=0A=
{=0A=
register const char * p;=0A=
register int i;=0A=
register int fid;=0A=
save_errno save;=0A=
=0A=
if (name =3D=3D NULL && (name =3D TZDEFAULT) =3D=3D NULL)=0A=
return -1;=0A=
{=0A=
register int doaccess;=0A=
/*=0A=
** Section 4.9.1 of the C standard says that=0A=
** "FILENAME_MAX expands to an integral constant expression=0A=
** that is the size needed for an array of char large enough=0A=
** to hold the longest file name string that the implementation=0A=
** guarantees can be opened."=0A=
*/=0A=
char fullname[FILENAME_MAX + 1];=0A=
=0A=
if (name[0] =3D=3D ':')=0A=
++name;=0A=
doaccess =3D name[0] =3D=3D '/';=0A=
if (!doaccess) {=0A=
if ((p =3D TZDIR) =3D=3D NULL)=0A=
return -1;=0A=
if ((strlen(p) + strlen(name) + 1) >=3D sizeof fullname)=0A=
return -1;=0A=
(void) strcpy(fullname, p);=0A=
(void) strcat(fullname, "/");=0A=
(void) strcat(fullname, name);=0A=
/*=0A=
** Set doaccess if '.' (as in "../") shows up in name.=0A=
*/=0A=
if (strchr(name, '.') !=3D NULL)=0A=
doaccess =3D TRUE;=0A=
name =3D fullname;=0A=
}=0A=
#if 0=0A=
if (doaccess && access(name, R_OK) !=3D 0)=0A=
return -1;=0A=
#endif=0A=
if ((fid =3D open(name, OPEN_MODE)) =3D=3D -1)=0A=
{=0A=
const char *base =3D strrchr(name, '/');=0A=
if (base)=0A=
base++;=0A=
else=0A=
base =3D name;=0A=
if (strcmp(base, "posixrules"))=0A=
return -1;=0A=
=0A=
/* We've got a built-in copy of posixrules just in case */=0A=
fid =3D -2;=0A=
}=0A=
}=0A=
{=0A=
struct tzhead * tzhp;=0A=
union {=0A=
struct tzhead tzhead;=0A=
char buf[sizeof *sp + sizeof *tzhp];=0A=
} u;=0A=
int ttisstdcnt;=0A=
int ttisgmtcnt;=0A=
=0A=
if (fid =3D=3D -2)=0A=
{=0A=
memcpy(u.buf, _posixrules_data, sizeof(_posixrules_data));=0A=
i =3D sizeof(_posixrules_data);=0A=
}=0A=
else=0A=
{=0A=
i =3D read(fid, u.buf, sizeof u.buf);=0A=
if (close(fid) !=3D 0)=0A=
return -1;=0A=
}=0A=
ttisstdcnt =3D (int) detzcode(u.tzhead.tzh_ttisgmtcnt);=0A=
ttisgmtcnt =3D (int) detzcode(u.tzhead.tzh_ttisstdcnt);=0A=
sp->leapcnt =3D (int) detzcode(u.tzhead.tzh_leapcnt);=0A=
sp->timecnt =3D (int) detzcode(u.tzhead.tzh_timecnt);=0A=
sp->typecnt =3D (int) detzcode(u.tzhead.tzh_typecnt);=0A=
sp->charcnt =3D (int) detzcode(u.tzhead.tzh_charcnt);=0A=
p =3D u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;=0A=
if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||=0A=
sp->typecnt <=3D 0 || sp->typecnt > TZ_MAX_TYPES ||=0A=
sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||=0A=
sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||=0A=
(ttisstdcnt !=3D sp->typecnt && ttisstdcnt !=3D 0) ||=0A=
(ttisgmtcnt !=3D sp->typecnt && ttisgmtcnt !=3D 0))=0A=
return -1;=0A=
if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */=0A=
sp->timecnt + /* types */=0A=
sp->typecnt * (4 + 2) + /* ttinfos */=0A=
sp->charcnt + /* chars */=0A=
sp->leapcnt * (4 + 4) + /* lsinfos */=0A=
ttisstdcnt + /* ttisstds */=0A=
ttisgmtcnt) /* ttisgmts */=0A=
return -1;=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
sp->ats[i] =3D detzcode(p);=0A=
p +=3D 4;=0A=
}=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
sp->types[i] =3D (unsigned char) *p++;=0A=
if (sp->types[i] >=3D sp->typecnt)=0A=
return -1;=0A=
}=0A=
for (i =3D 0; i < sp->typecnt; ++i) {=0A=
register struct ttinfo * ttisp;=0A=
=0A=
ttisp =3D &sp->ttis[i];=0A=
ttisp->tt_gmtoff =3D detzcode(p);=0A=
p +=3D 4;=0A=
ttisp->tt_isdst =3D (unsigned char) *p++;=0A=
if (ttisp->tt_isdst !=3D 0 && ttisp->tt_isdst !=3D 1)=0A=
return -1;=0A=
ttisp->tt_abbrind =3D (unsigned char) *p++;=0A=
if (ttisp->tt_abbrind < 0 ||=0A=
ttisp->tt_abbrind > sp->charcnt)=0A=
return -1;=0A=
}=0A=
for (i =3D 0; i < sp->charcnt; ++i)=0A=
sp->chars[i] =3D *p++;=0A=
sp->chars[i] =3D '\0'; /* ensure '\0' at end */=0A=
for (i =3D 0; i < sp->leapcnt; ++i) {=0A=
register struct lsinfo * lsisp;=0A=
=0A=
lsisp =3D &sp->lsis[i];=0A=
lsisp->ls_trans =3D detzcode(p);=0A=
p +=3D 4;=0A=
lsisp->ls_corr =3D detzcode(p);=0A=
p +=3D 4;=0A=
}=0A=
for (i =3D 0; i < sp->typecnt; ++i) {=0A=
register struct ttinfo * ttisp;=0A=
=0A=
ttisp =3D &sp->ttis[i];=0A=
if (ttisstdcnt =3D=3D 0)=0A=
ttisp->tt_ttisstd =3D FALSE;=0A=
else {=0A=
ttisp->tt_ttisstd =3D *p++;=0A=
if (ttisp->tt_ttisstd !=3D TRUE &&=0A=
ttisp->tt_ttisstd !=3D FALSE)=0A=
return -1;=0A=
}=0A=
}=0A=
for (i =3D 0; i < sp->typecnt; ++i) {=0A=
register struct ttinfo * ttisp;=0A=
=0A=
ttisp =3D &sp->ttis[i];=0A=
if (ttisgmtcnt =3D=3D 0)=0A=
ttisp->tt_ttisgmt =3D FALSE;=0A=
else {=0A=
ttisp->tt_ttisgmt =3D *p++;=0A=
if (ttisp->tt_ttisgmt !=3D TRUE &&=0A=
ttisp->tt_ttisgmt !=3D FALSE)=0A=
return -1;=0A=
}=0A=
}=0A=
}=0A=
return 0;=0A=
}=0A=
=0A=
static const int mon_lengths[2][MONSPERYEAR] =3D {=0A=
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },=0A=
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }=0A=
};=0A=
=0A=
static const int year_lengths[2] =3D {=0A=
DAYSPERNYEAR, DAYSPERLYEAR=0A=
};=0A=
=0A=
/*=0A=
** Given a pointer into a time zone string, scan until a character that =
is not=0A=
** a valid character in a zone name is found. Return a pointer to =
that=0A=
** character.=0A=
*/=0A=
=0A=
static const char *=0A=
getzname(const char *strp)=0A=
{=0A=
register char c;=0A=
=0A=
while ((c =3D *strp) !=3D '\0' && !is_digit(c) && c !=3D ',' && c !=3D =
'-' &&=0A=
c !=3D '+')=0A=
++strp;=0A=
return strp;=0A=
}=0A=
=0A=
/*=0A=
** Given a pointer into a time zone string, extract a number from that =
string.=0A=
** Check that the number is within a specified range; if it is not, =
return=0A=
** NULL.=0A=
** Otherwise, return a pointer to the first character not part of the =
number.=0A=
*/=0A=
=0A=
static const char *=0A=
getnum(const char *strp, int *nump, const int min, const int max)=0A=
{=0A=
register char c;=0A=
register int num;=0A=
=0A=
if (strp =3D=3D NULL || !is_digit(c =3D *strp))=0A=
return NULL;=0A=
num =3D 0;=0A=
do {=0A=
num =3D num * 10 + (c - '0');=0A=
if (num > max)=0A=
return NULL; /* illegal value */=0A=
c =3D *++strp;=0A=
} while (is_digit(c));=0A=
if (num < min)=0A=
return NULL; /* illegal value */=0A=
*nump =3D num;=0A=
return strp;=0A=
}=0A=
=0A=
/*=0A=
** Given a pointer into a time zone string, extract a number of =
seconds,=0A=
** in hh[:mm[:ss]] form, from the string.=0A=
** If any error occurs, return NULL.=0A=
** Otherwise, return a pointer to the first character not part of the =
number=0A=
** of seconds.=0A=
*/=0A=
=0A=
static const char *=0A=
getsecs(const char *strp, long *secsp)=0A=
{=0A=
int num;=0A=
=0A=
/*=0A=
** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like=0A=
** "M10.4.6/26", which does not conform to Posix,=0A=
** but which specifies the equivalent of=0A=
** ``02:00 on the first Sunday on or after 23 Oct''.=0A=
*/=0A=
strp =3D getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
*secsp =3D num * (long) SECSPERHOUR;=0A=
if (*strp =3D=3D ':') {=0A=
++strp;=0A=
strp =3D getnum(strp, &num, 0, MINSPERHOUR - 1);=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
*secsp +=3D num * SECSPERMIN;=0A=
if (*strp =3D=3D ':') {=0A=
++strp;=0A=
/* `SECSPERMIN' allows for leap seconds. */=0A=
strp =3D getnum(strp, &num, 0, SECSPERMIN);=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
*secsp +=3D num;=0A=
}=0A=
}=0A=
return strp;=0A=
}=0A=
=0A=
/*=0A=
** Given a pointer into a time zone string, extract an offset, in=0A=
** [+-]hh[:mm[:ss]] form, from the string.=0A=
** If any error occurs, return NULL.=0A=
** Otherwise, return a pointer to the first character not part of the =
time.=0A=
*/=0A=
=0A=
static const char *=0A=
getoffset(const char *strp, long *offsetp)=0A=
{=0A=
register int neg =3D 0;=0A=
=0A=
if (*strp =3D=3D '-') {=0A=
neg =3D 1;=0A=
++strp;=0A=
} else if (*strp =3D=3D '+')=0A=
++strp;=0A=
strp =3D getsecs(strp, offsetp);=0A=
if (strp =3D=3D NULL)=0A=
return NULL; /* illegal time */=0A=
if (neg)=0A=
*offsetp =3D -*offsetp;=0A=
return strp;=0A=
}=0A=
=0A=
/*=0A=
** Given a pointer into a time zone string, extract a rule in the =
form=0A=
** date[/time]. See POSIX section 8 for the format of "date" and =
"time".=0A=
** If a valid rule is not found, return NULL.=0A=
** Otherwise, return a pointer to the first character not part of the =
rule.=0A=
*/=0A=
=0A=
static const char *=0A=
getrule(const char *strp, struct rule *rulep)=0A=
{=0A=
if (*strp =3D=3D 'J') {=0A=
/*=0A=
** Julian day.=0A=
*/=0A=
rulep->r_type =3D JULIAN_DAY;=0A=
++strp;=0A=
strp =3D getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);=0A=
} else if (*strp =3D=3D 'M') {=0A=
/*=0A=
** Month, week, day.=0A=
*/=0A=
rulep->r_type =3D MONTH_NTH_DAY_OF_WEEK;=0A=
++strp;=0A=
strp =3D getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
if (*strp++ !=3D '.')=0A=
return NULL;=0A=
strp =3D getnum(strp, &rulep->r_week, 1, 5);=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
if (*strp++ !=3D '.')=0A=
return NULL;=0A=
strp =3D getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);=0A=
} else if (is_digit(*strp)) {=0A=
/*=0A=
** Day of year.=0A=
*/=0A=
rulep->r_type =3D DAY_OF_YEAR;=0A=
strp =3D getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);=0A=
} else return NULL; /* invalid format */=0A=
if (strp =3D=3D NULL)=0A=
return NULL;=0A=
if (*strp =3D=3D '/') {=0A=
/*=0A=
** Time specified.=0A=
*/=0A=
++strp;=0A=
strp =3D getsecs(strp, &rulep->r_time);=0A=
} else rulep->r_time =3D 2 * SECSPERHOUR; /* default =3D 2:00:00 */=0A=
return strp;=0A=
}=0A=
=0A=
/*=0A=
** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, =
the=0A=
** year, a rule, and the offset from UTC at the time that rule takes =
effect,=0A=
** calculate the Epoch-relative time that rule takes effect.=0A=
*/=0A=
=0A=
static time_t=0A=
transtime(const time_t janfirst, const int year, const struct rule =
*rulep,=0A=
long offset)=0A=
{=0A=
register int leapyear;=0A=
register time_t value;=0A=
register int i;=0A=
int d, m1, yy0, yy1, yy2, dow;=0A=
=0A=
INITIALIZE(value);=0A=
leapyear =3D isleap(year);=0A=
switch (rulep->r_type) {=0A=
=0A=
case JULIAN_DAY:=0A=
/*=0A=
** Jn - Julian day, 1 =3D=3D January 1, 60 =3D=3D March 1 even in =
leap=0A=
** years.=0A=
** In non-leap years, or if the day number is 59 or less, just=0A=
** add SECSPERDAY times the day number-1 to the time of=0A=
** January 1, midnight, to get the day.=0A=
*/=0A=
value =3D janfirst + (rulep->r_day - 1) * SECSPERDAY;=0A=
if (leapyear && rulep->r_day >=3D 60)=0A=
value +=3D SECSPERDAY;=0A=
break;=0A=
=0A=
case DAY_OF_YEAR:=0A=
/*=0A=
** n - day of year.=0A=
** Just add SECSPERDAY times the day number to the time of=0A=
** January 1, midnight, to get the day.=0A=
*/=0A=
value =3D janfirst + rulep->r_day * SECSPERDAY;=0A=
break;=0A=
=0A=
case MONTH_NTH_DAY_OF_WEEK:=0A=
/*=0A=
** Mm.n.d - nth "dth day" of month m.=0A=
*/=0A=
value =3D janfirst;=0A=
for (i =3D 0; i < rulep->r_mon - 1; ++i)=0A=
value +=3D mon_lengths[leapyear][i] * SECSPERDAY;=0A=
=0A=
/*=0A=
** Use Zeller's Congruence to get day-of-week of first day of=0A=
** month.=0A=
*/=0A=
m1 =3D (rulep->r_mon + 9) % 12 + 1;=0A=
yy0 =3D (rulep->r_mon <=3D 2) ? (year - 1) : year;=0A=
yy1 =3D yy0 / 100;=0A=
yy2 =3D yy0 % 100;=0A=
dow =3D ((26 * m1 - 2) / 10 +=0A=
1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;=0A=
if (dow < 0)=0A=
dow +=3D DAYSPERWEEK;=0A=
=0A=
/*=0A=
** "dow" is the day-of-week of the first day of the month. Get=0A=
** the day-of-month (zero-origin) of the first "dow" day of the=0A=
** month.=0A=
*/=0A=
d =3D rulep->r_day - dow;=0A=
if (d < 0)=0A=
d +=3D DAYSPERWEEK;=0A=
for (i =3D 1; i < rulep->r_week; ++i) {=0A=
if (d + DAYSPERWEEK >=3D=0A=
mon_lengths[leapyear][rulep->r_mon - 1])=0A=
break;=0A=
d +=3D DAYSPERWEEK;=0A=
}=0A=
=0A=
/*=0A=
** "d" is the day-of-month (zero-origin) of the day we want.=0A=
*/=0A=
value +=3D d * SECSPERDAY;=0A=
break;=0A=
}=0A=
=0A=
/*=0A=
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in=0A=
** question. To get the Epoch-relative time of the specified local=0A=
** time on that day, add the transition time and the current offset=0A=
** from UTC.=0A=
*/=0A=
return value + rulep->r_time + offset;=0A=
}=0A=
=0A=
/*=0A=
** Given a POSIX section 8-style TZ string, fill in the rule tables =
as=0A=
** appropriate.=0A=
*/=0A=
=0A=
static int=0A=
tzparse(const char *name, struct state *sp, const int lastditch)=0A=
{=0A=
const char * stdname;=0A=
const char * dstname;=0A=
size_t stdlen;=0A=
size_t dstlen;=0A=
long stdoffset;=0A=
long dstoffset;=0A=
register time_t * atp;=0A=
register unsigned char * typep;=0A=
register char * cp;=0A=
register int load_result;=0A=
=0A=
INITIALIZE(dstname);=0A=
stdname =3D name;=0A=
if (lastditch) {=0A=
stdlen =3D strlen(name); /* length of standard zone name */=0A=
name +=3D stdlen;=0A=
if (stdlen >=3D sizeof sp->chars)=0A=
stdlen =3D (sizeof sp->chars) - 1;=0A=
stdoffset =3D 0;=0A=
} else {=0A=
name =3D getzname(name);=0A=
stdlen =3D name - stdname;=0A=
if (stdlen < 3)=0A=
return -1;=0A=
if (*name =3D=3D '\0')=0A=
return -1;=0A=
name =3D getoffset(name, &stdoffset);=0A=
if (name =3D=3D NULL)=0A=
return -1;=0A=
}=0A=
load_result =3D tzload(TZDEFRULES, sp);=0A=
if (load_result !=3D 0)=0A=
sp->leapcnt =3D 0; /* so, we're off a little */=0A=
if (*name !=3D '\0') {=0A=
dstname =3D name;=0A=
name =3D getzname(name);=0A=
dstlen =3D name - dstname; /* length of DST zone name */=0A=
if (dstlen < 3)=0A=
return -1;=0A=
if (*name !=3D '\0' && *name !=3D ',' && *name !=3D ';') {=0A=
name =3D getoffset(name, &dstoffset);=0A=
if (name =3D=3D NULL)=0A=
return -1;=0A=
} else dstoffset =3D stdoffset - SECSPERHOUR;=0A=
if (*name =3D=3D ',' || *name =3D=3D ';') {=0A=
struct rule start;=0A=
struct rule end;=0A=
register int year;=0A=
register time_t janfirst;=0A=
time_t starttime;=0A=
time_t endtime;=0A=
=0A=
++name;=0A=
if ((name =3D getrule(name, &start)) =3D=3D NULL)=0A=
return -1;=0A=
if (*name++ !=3D ',')=0A=
return -1;=0A=
if ((name =3D getrule(name, &end)) =3D=3D NULL)=0A=
return -1;=0A=
if (*name !=3D '\0')=0A=
return -1;=0A=
sp->typecnt =3D 2; /* standard time and DST */=0A=
/*=0A=
** Two transitions per year, from EPOCH_YEAR to 2037.=0A=
*/=0A=
sp->timecnt =3D 2 * (2037 - EPOCH_YEAR + 1);=0A=
if (sp->timecnt > TZ_MAX_TIMES)=0A=
return -1;=0A=
sp->ttis[0].tt_gmtoff =3D -dstoffset;=0A=
sp->ttis[0].tt_isdst =3D 1;=0A=
sp->ttis[0].tt_abbrind =3D stdlen + 1;=0A=
sp->ttis[1].tt_gmtoff =3D -stdoffset;=0A=
sp->ttis[1].tt_isdst =3D 0;=0A=
sp->ttis[1].tt_abbrind =3D 0;=0A=
atp =3D sp->ats;=0A=
typep =3D sp->types;=0A=
janfirst =3D 0;=0A=
for (year =3D EPOCH_YEAR; year <=3D 2037; ++year) {=0A=
starttime =3D transtime(janfirst, year, &start,=0A=
stdoffset);=0A=
endtime =3D transtime(janfirst, year, &end,=0A=
dstoffset);=0A=
if (starttime > endtime) {=0A=
*atp++ =3D endtime;=0A=
*typep++ =3D 1; /* DST ends */=0A=
*atp++ =3D starttime;=0A=
*typep++ =3D 0; /* DST begins */=0A=
} else {=0A=
*atp++ =3D starttime;=0A=
*typep++ =3D 0; /* DST begins */=0A=
*atp++ =3D endtime;=0A=
*typep++ =3D 1; /* DST ends */=0A=
}=0A=
janfirst +=3D year_lengths[isleap(year)] *=0A=
SECSPERDAY;=0A=
}=0A=
} else {=0A=
register long theirstdoffset;=0A=
register long theirdstoffset;=0A=
register long theiroffset;=0A=
register int isdst;=0A=
register int i;=0A=
register int j;=0A=
=0A=
if (*name !=3D '\0')=0A=
return -1;=0A=
if (load_result !=3D 0)=0A=
return -1;=0A=
/*=0A=
** Initial values of theirstdoffset and theirdstoffset.=0A=
*/=0A=
theirstdoffset =3D 0;=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
j =3D sp->types[i];=0A=
if (!sp->ttis[j].tt_isdst) {=0A=
theirstdoffset =3D=0A=
-sp->ttis[j].tt_gmtoff;=0A=
break;=0A=
}=0A=
}=0A=
theirdstoffset =3D 0;=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
j =3D sp->types[i];=0A=
if (sp->ttis[j].tt_isdst) {=0A=
theirdstoffset =3D=0A=
-sp->ttis[j].tt_gmtoff;=0A=
break;=0A=
}=0A=
}=0A=
/*=0A=
** Initially we're assumed to be in standard time.=0A=
*/=0A=
isdst =3D FALSE;=0A=
theiroffset =3D theirstdoffset;=0A=
/*=0A=
** Now juggle transition times and types=0A=
** tracking offsets as you do.=0A=
*/=0A=
for (i =3D 0; i < sp->timecnt; ++i) {=0A=
j =3D sp->types[i];=0A=
sp->types[i] =3D sp->ttis[j].tt_isdst;=0A=
if (sp->ttis[j].tt_ttisgmt) {=0A=
/* No adjustment to transition time */=0A=
} else {=0A=
/*=0A=
** If summer time is in effect, and the=0A=
** transition time was not specified as=0A=
** standard time, add the summer time=0A=
** offset to the transition time;=0A=
** otherwise, add the standard time=0A=
** offset to the transition time.=0A=
*/=0A=
/*=0A=
** Transitions from DST to DDST=0A=
** will effectively disappear since=0A=
** POSIX provides for only one DST=0A=
** offset.=0A=
*/=0A=
if (isdst && !sp->ttis[j].tt_ttisstd) {=0A=
sp->ats[i] +=3D dstoffset -=0A=
theirdstoffset;=0A=
} else {=0A=
sp->ats[i] +=3D stdoffset -=0A=
theirstdoffset;=0A=
}=0A=
}=0A=
theiroffset =3D -sp->ttis[j].tt_gmtoff;=0A=
if (sp->ttis[j].tt_isdst)=0A=
theirdstoffset =3D theiroffset;=0A=
else theirstdoffset =3D theiroffset;=0A=
}=0A=
/*=0A=
** Finally, fill in ttis.=0A=
** ttisstd and ttisgmt need not be handled.=0A=
*/=0A=
sp->ttis[0].tt_gmtoff =3D -stdoffset;=0A=
sp->ttis[0].tt_isdst =3D FALSE;=0A=
sp->ttis[0].tt_abbrind =3D 0;=0A=
sp->ttis[1].tt_gmtoff =3D -dstoffset;=0A=
sp->ttis[1].tt_isdst =3D TRUE;=0A=
sp->ttis[1].tt_abbrind =3D stdlen + 1;=0A=
sp->typecnt =3D 2;=0A=
}=0A=
} else {=0A=
dstlen =3D 0;=0A=
sp->typecnt =3D 1; /* only standard time */=0A=
sp->timecnt =3D 0;=0A=
sp->ttis[0].tt_gmtoff =3D -stdoffset;=0A=
sp->ttis[0].tt_isdst =3D 0;=0A=
sp->ttis[0].tt_abbrind =3D 0;=0A=
}=0A=
sp->charcnt =3D stdlen + 1;=0A=
if (dstlen !=3D 0)=0A=
sp->charcnt +=3D dstlen + 1;=0A=
if ((size_t) sp->charcnt > sizeof sp->chars)=0A=
return -1;=0A=
cp =3D sp->chars;=0A=
(void) strncpy(cp, stdname, stdlen);=0A=
cp +=3D stdlen;=0A=
*cp++ =3D '\0';=0A=
if (dstlen !=3D 0) {=0A=
(void) strncpy(cp, dstname, dstlen);=0A=
*(cp + dstlen) =3D '\0';=0A=
}=0A=
return 0;=0A=
}=0A=
=0A=
static void=0A=
gmtload(struct state *sp)=0A=
{=0A=
if (tzload(gmt, sp) !=3D 0)=0A=
(void) tzparse(gmt, sp, TRUE);=0A=
}=0A=
=0A=
#ifndef STD_INSPIRED=0A=
/*=0A=
** A non-static declaration of tzsetwall in a system header file=0A=
** may cause a warning about this upcoming static declaration...=0A=
*/=0A=
static=0A=
#endif /* !defined STD_INSPIRED */=0A=
void=0A=
tzsetwall P((void))=0A=
{=0A=
if (lcl_is_set < 0)=0A=
return;=0A=
lcl_is_set =3D -1;=0A=
=0A=
#ifdef ALL_STATE=0A=
if (lclptr =3D=3D NULL) {=0A=
lclptr =3D (struct state *) malloc(sizeof *lclptr);=0A=
if (lclptr =3D=3D NULL) {=0A=
settzname(); /* all we can do */=0A=
return;=0A=
}=0A=
}=0A=
#endif /* defined ALL_STATE */=0A=
#if defined (_WIN32) || defined (__CYGWIN__)=0A=
#define is_upper(c) ((unsigned)(c) - 'A' <=3D 26)=0A=
{=0A=
TIME_ZONE_INFORMATION tz;=0A=
char buf[BUFSIZ];=0A=
char *cp, *dst;=0A=
wchar_t *src;=0A=
div_t d;=0A=
GetTimeZoneInformation(&tz);=0A=
dst =3D cp =3D buf;=0A=
=0A=
for (src =3D tz.StandardName; *src; src++)=0A=
if (is_upper(*src)) *dst++ =3D *src;=0A=
=0A=
/* not 3 characters for timezone _tzname[0] ? =0A=
happens for example in Win2000/NT german version=0A=
a) tz.StandardName is a WideChar String=0A=
b) is very long "Westeropaische Normalzeit"=0A=
generate a TZ variable relative to GMT-x=0A=
(if strlen of _tzname is not equal 3 , tzparse will =0A=
not accept the TZ variable!)=0A=
mkt */=0A=
if (strlen(cp) !=3D 3) /* mkt */=0A=
{ /* mkt */=0A=
strcpy(cp, "GMT"); /* mkt */=0A=
dst =3D cp + 3; /* mkt */=0A=
} /* mkt */=0A=
=0A=
if (cp =3D=3D dst)=0A=
{=0A=
/* In Asian Windows, tz.StandardName may not contain=0A=
the timezone name. */=0A=
strcpy(cp, wildabbr);=0A=
cp +=3D strlen(wildabbr);=0A=
}=0A=
else=0A=
cp =3D dst;=0A=
=0A=
if (=0A=
strcpy(cp,"GMT");=0A=
cp=3Dstrchr(cp, 0);=0A=
#endif =0A=
d =3D div(tz.Bias, 60); /* ??? mkt */=0A=
if ( tz.StandardDate.wMonth !=3D 0 ) /* ??? this seems to be =
the Microsoft compatible algorithm mkt */=0A=
d +=3D div(tz.StandardBias, 60); /* ??? mkt */=0A=
=0A=
sprintf(cp, "%d", d.quot);=0A=
if (d.rem)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", abs(d.rem));=0A=
if(tz.StandardDate.wMonth) {=0A=
cp =3D strchr(cp, 0);=0A=
dst =3D cp;=0A=
=0A=
for (src =3D tz.DaylightName; *src; src++)=0A=
if (is_upper(*src)) *dst++ =3D *src;=0A=
=0A=
/* not 3 characters for daylight timezone _tzname[1] ? =0A=
happens for example in Win2000/NT german version=0A=
a) tz.StandardName is a WideChar String=0A=
b) is very long "Westeropaische Sommerzeit"=0A=
generate a TZ variable relative to GMT-xDST-y=0A=
(if strlen of _tzname is not equal 3 , tzparse will =
=0A=
not accept the TZ variable!)=0A=
mkt */=0A=
if (strlen(cp) !=3D 3) /* mkt */=0A=
{ /* mkt */=0A=
strcpy(cp, "DST"); /* mkt */=0A=
dst =3D cp + 3; /* mkt */=0A=
} /* mkt */=0A=
=0A=
if (cp =3D=3D dst)=0A=
{=0A=
/* In Asian Windows, tz.StandardName may not contain=0A=
the daylight name. */=0A=
strcpy(buf, wildabbr);=0A=
cp +=3D strlen(wildabbr);=0A=
}=0A=
else=0A=
cp =3D dst;=0A=
=0A=
d =3D div(tz.Bias+tz.DaylightBias, 60);=0A=
sprintf(cp, "%d", d.quot);=0A=
if (d.rem)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", abs(d.rem));=0A=
cp =3D strchr(cp, 0);=0A=
sprintf(cp=3Dstrchr(cp, 0), ",M%d.%d.%d/%d",=0A=
tz.DaylightDate.wMonth,=0A=
tz.DaylightDate.wDay,=0A=
tz.DaylightDate.wDayOfWeek,=0A=
tz.DaylightDate.wHour);=0A=
if (tz.DaylightDate.wMinute || tz.DaylightDate.wSecond)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", tz.DaylightDate.wMinute);=0A=
if (tz.DaylightDate.wSecond)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", tz.DaylightDate.wSecond);=0A=
cp =3D strchr(cp, 0);=0A=
sprintf(cp=3Dstrchr(cp, 0), ",M%d.%d.%d/%d",=0A=
tz.StandardDate.wMonth,=0A=
tz.StandardDate.wDay,=0A=
tz.StandardDate.wDayOfWeek,=0A=
tz.StandardDate.wHour);=0A=
if (tz.StandardDate.wMinute || tz.StandardDate.wSecond)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", tz.StandardDate.wMinute);=0A=
if (tz.StandardDate.wSecond)=0A=
sprintf(cp=3Dstrchr(cp, 0), ":%d", tz.StandardDate.wSecond);=0A=
}=0A=
/* printf("TZ deduced as `%s'\n", buf); */=0A=
if (tzparse(buf, lclptr, FALSE) =3D=3D 0) {=0A=
settzname();=0A=
setenv("TZ", buf, 1);=0A=
return;=0A=
}=0A=
}=0A=
#endif=0A=
if (tzload((char *) NULL, lclptr) !=3D 0)=0A=
gmtload(lclptr);=0A=
settzname();=0A=
}=0A=
=0A=
extern "C" void=0A=
tzset P((void))=0A=
{=0A=
const char * name =3D getenv("TZ");=0A=
=0A=
if (name =3D=3D NULL) {=0A=
tzsetwall();=0A=
return;=0A=
}=0A=
=0A=
if (lcl_is_set > 0 && strcmp(lcl_TZname, name) =3D=3D 0)=0A=
return;=0A=
lcl_is_set =3D (strlen(name) < sizeof(lcl_TZname));=0A=
if (lcl_is_set)=0A=
(void) strcpy(lcl_TZname, name);=0A=
=0A=
#ifdef ALL_STATE=0A=
if (lclptr =3D=3D NULL) {=0A=
lclptr =3D (struct state *) malloc(sizeof *lclptr);=0A=
if (lclptr =3D=3D NULL) {=0A=
settzname(); /* all we can do */=0A=
return;=0A=
}=0A=
}=0A=
#endif /* defined ALL_STATE */=0A=
if (*name =3D=3D '\0') {=0A=
/*=0A=
** User wants it fast rather than right.=0A=
*/=0A=
lclptr->leapcnt =3D 0; /* so, we're off a little */=0A=
lclptr->timecnt =3D 0;=0A=
lclptr->ttis[0].tt_gmtoff =3D 0;=0A=
lclptr->ttis[0].tt_abbrind =3D 0;=0A=
(void) strcpy(lclptr->chars, gmt);=0A=
} else if (tzload(name, lclptr) !=3D 0) {=0A=
if (name[0] =3D=3D ':' || tzparse(name, lclptr, FALSE) !=3D 0)=0A=
(void) gmtload(lclptr);=0A=
}=0A=
settzname();=0A=
}=0A=
=0A=
/*=0A=
** The easy way to behave "as if no library function calls" =
localtime=0A=
** is to not call it--so we drop its guts into "localsub", which can =
be=0A=
** freely called. (And no, the PANS doesn't require the above =
behavior--=0A=
** but it *is* desirable.)=0A=
**=0A=
** The unused offset argument is for the benefit of mktime variants.=0A=
*/=0A=
=0A=
/*ARGSUSED*/=0A=
static void=0A=
localsub (const time_t * const timep,=0A=
const long offset,=0A=
struct tm * const tmp)=0A=
{=0A=
register struct state * sp;=0A=
register const struct ttinfo * ttisp;=0A=
register int i;=0A=
const time_t t =3D *timep;=0A=
=0A=
sp =3D lclptr;=0A=
#ifdef ALL_STATE=0A=
if (sp =3D=3D NULL) {=0A=
gmtsub(timep, offset, tmp);=0A=
return;=0A=
}=0A=
#endif /* defined ALL_STATE */=0A=
if (sp->timecnt =3D=3D 0 || t < sp->ats[0]) {=0A=
i =3D 0;=0A=
while (sp->ttis[i].tt_isdst)=0A=
if (++i >=3D sp->typecnt) {=0A=
i =3D 0;=0A=
break;=0A=
}=0A=
} else {=0A=
for (i =3D 1; i < sp->timecnt; ++i)=0A=
if (t < sp->ats[i])=0A=
break;=0A=
i =3D sp->types[i - 1];=0A=
}=0A=
ttisp =3D &sp->ttis[i];=0A=
/*=0A=
** To get (wrong) behavior that's compatible with System V Release =
2.0=0A=
** you'd replace the statement below with=0A=
** t +=3D ttisp->tt_gmtoff;=0A=
** timesub(&t, 0L, sp, tmp);=0A=
*/=0A=
timesub(&t, ttisp->tt_gmtoff, sp, tmp);=0A=
tmp->tm_isdst =3D ttisp->tt_isdst;=0A=
tzname[tmp->tm_isdst] =3D &sp->chars[ttisp->tt_abbrind];=0A=
#ifdef TM_ZONE=0A=
tmp->TM_ZONE =3D &sp->chars[ttisp->tt_abbrind];=0A=
#endif /* defined TM_ZONE */=0A=
}=0A=
=0A=
extern "C" struct tm *=0A=
localtime(const time_t *timep)=0A=
{=0A=
tzset();=0A=
localsub(timep, 0L, &tm);=0A=
return &tm;=0A=
}=0A=
=0A=
/*=0A=
* Re-entrant version of localtime=0A=
*/=0A=
extern "C" struct tm *=0A=
localtime_r(const time_t *timep, struct tm *tm)=0A=
{=0A=
localsub(timep, 0L, tm);=0A=
return tm;=0A=
}=0A=
=0A=
/*=0A=
** gmtsub is to gmtime as localsub is to localtime.=0A=
*/=0A=
=0A=
static void=0A=
gmtsub(const time_t *timep, const long offset, struct tm *tmp)=0A=
{=0A=
if (!gmt_is_set) {=0A=
gmt_is_set =3D TRUE;=0A=
#ifdef ALL_STATE=0A=
gmtptr =3D (struct state *) malloc(sizeof *gmtptr);=0A=
if (gmtptr !=3D NULL)=0A=
#endif /* defined ALL_STATE */=0A=
gmtload(gmtptr);=0A=
}=0A=
timesub(timep, offset, gmtptr, tmp);=0A=
#ifdef TM_ZONE=0A=
/*=0A=
** Could get fancy here and deliver something such as=0A=
** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,=0A=
** but this is no time for a treasure hunt.=0A=
*/=0A=
if (offset !=3D 0)=0A=
tmp->TM_ZONE =3D wildabbr;=0A=
else {=0A=
#ifdef ALL_STATE=0A=
if (gmtptr =3D=3D NULL)=0A=
tmp->TM_ZONE =3D gmt;=0A=
else tmp->TM_ZONE =3D gmtptr->chars;=0A=
#endif /* defined ALL_STATE */=0A=
#ifndef ALL_STATE=0A=
tmp->TM_ZONE =3D gmtptr->chars;=0A=
#endif /* State Farm */=0A=
}=0A=
#endif /* defined TM_ZONE */=0A=
}=0A=
=0A=
extern "C" struct tm *=0A=
gmtime(const time_t *timep)=0A=
{=0A=
gmtsub(timep, 0L, &tm);=0A=
return &tm;=0A=
}=0A=
=0A=
/*=0A=
* Re-entrant version of gmtime=0A=
*/=0A=
extern "C" struct tm *=0A=
gmtime_r(const time_t *timep, struct tm *tm)=0A=
{=0A=
gmtsub(timep, 0L, tm);=0A=
return tm;=0A=
}=0A=
=0A=
#ifdef STD_INSPIRED=0A=
=0A=
extern "C" struct tm *=0A=
offtime(const time_t *timep, const long offset)=0A=
{=0A=
gmtsub(timep, offset, &tm);=0A=
return &tm;=0A=
}=0A=
=0A=
#endif /* defined STD_INSPIRED */=0A=
=0A=
static void=0A=
timesub(const time_t *timep, const long offset, const struct state =
*sp,=0A=
struct tm *tmp)=0A=
{=0A=
register const struct lsinfo * lp;=0A=
register long days;=0A=
register long rem;=0A=
register int y;=0A=
register int yleap;=0A=
register const int * ip;=0A=
register long corr;=0A=
register int hit;=0A=
register int i;=0A=
=0A=
corr =3D 0;=0A=
hit =3D 0;=0A=
#ifdef ALL_STATE=0A=
i =3D (sp =3D=3D NULL) ? 0 : sp->leapcnt;=0A=
#endif /* defined ALL_STATE */=0A=
#ifndef ALL_STATE=0A=
i =3D sp->leapcnt;=0A=
#endif /* State Farm */=0A=
while (--i >=3D 0) {=0A=
lp =3D &sp->lsis[i];=0A=
if (*timep >=3D lp->ls_trans) {=0A=
if (*timep =3D=3D lp->ls_trans) {=0A=
hit =3D ((i =3D=3D 0 && lp->ls_corr > 0) ||=0A=
lp->ls_corr > sp->lsis[i - 1].ls_corr);=0A=
if (hit)=0A=
while (i > 0 &&=0A=
sp->lsis[i].ls_trans =3D=3D=0A=
sp->lsis[i - 1].ls_trans + 1 &&=0A=
sp->lsis[i].ls_corr =3D=3D=0A=
sp->lsis[i - 1].ls_corr + 1) {=0A=
++hit;=0A=
--i;=0A=
}=0A=
}=0A=
corr =3D lp->ls_corr;=0A=
break;=0A=
}=0A=
}=0A=
days =3D *timep / SECSPERDAY;=0A=
rem =3D *timep % SECSPERDAY;=0A=
#ifdef mc68k=0A=
if (*timep =3D=3D 0x80000000) {=0A=
/*=0A=
** A 3B1 muffs the division on the most negative number.=0A=
*/=0A=
days =3D -24855;=0A=
rem =3D -11648;=0A=
}=0A=
#endif /* defined mc68k */=0A=
rem +=3D (offset - corr);=0A=
while (rem < 0) {=0A=
rem +=3D SECSPERDAY;=0A=
--days;=0A=
}=0A=
while (rem >=3D SECSPERDAY) {=0A=
rem -=3D SECSPERDAY;=0A=
++days;=0A=
}=0A=
tmp->tm_hour =3D (int) (rem / SECSPERHOUR);=0A=
rem =3D rem % SECSPERHOUR;=0A=
tmp->tm_min =3D (int) (rem / SECSPERMIN);=0A=
/*=0A=
** A positive leap second requires a special=0A=
** representation. This uses "... ??:59:60" et seq.=0A=
*/=0A=
tmp->tm_sec =3D (int) (rem % SECSPERMIN) + hit;=0A=
tmp->tm_wday =3D (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);=0A=
if (tmp->tm_wday < 0)=0A=
tmp->tm_wday +=3D DAYSPERWEEK;=0A=
y =3D EPOCH_YEAR;=0A=
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)=0A=
while (days < 0 || days >=3D (long) year_lengths[yleap =3D isleap(y)]) =
{=0A=
register int newy;=0A=
=0A=
newy =3D y + days / DAYSPERNYEAR;=0A=
if (days < 0)=0A=
--newy;=0A=
days -=3D (newy - y) * DAYSPERNYEAR +=0A=
LEAPS_THRU_END_OF(newy - 1) -=0A=
LEAPS_THRU_END_OF(y - 1);=0A=
y =3D newy;=0A=
}=0A=
tmp->tm_year =3D y - TM_YEAR_BASE;=0A=
tmp->tm_yday =3D (int) days;=0A=
ip =3D mon_lengths[yleap];=0A=
for (tmp->tm_mon =3D 0; days >=3D (long) ip[tmp->tm_mon]; =
++(tmp->tm_mon))=0A=
days =3D days - (long) ip[tmp->tm_mon];=0A=
tmp->tm_mday =3D (int) (days + 1);=0A=
tmp->tm_isdst =3D 0;=0A=
#ifdef TM_GMTOFF=0A=
tmp->TM_GMTOFF =3D offset;=0A=
#endif /* defined TM_GMTOFF */=0A=
}=0A=
=0A=
extern "C" char *=0A=
ctime(const time_t *timep)=0A=
{=0A=
/*=0A=
** Section 4.12.3.2 of X3.159-1989 requires that=0A=
** The ctime function converts the calendar time pointed to by timer=0A=
** to local time in the form of a string. It is equivalent to=0A=
** asctime(localtime(timer))=0A=
*/=0A=
return asctime(localtime(timep));=0A=
}=0A=
=0A=
extern "C" char *=0A=
ctime_r(const time_t *timep, char *buf)=0A=
{=0A=
struct tm tm;=0A=
=0A=
return asctime_r(localtime_r(timep, &tm), buf);=0A=
}=0A=
=0A=
/*=0A=
** Adapted from code provided by Robert Elz, who writes:=0A=
** The "best" way to do mktime I think is based on an idea of Bob=0A=
** Kridle's (so its said...) from a long time ago.=0A=
** [kridle AT xinet DOT com as of 1996-01-16.]=0A=
** It does a binary search of the time_t space. Since time_t's are=0A=
** just 32 bits, its a max of 32 iterations (even at 64 bits it=0A=
** would still be very reasonable).=0A=
*/=0A=
=0A=
#ifndef WRONG=0A=
#define WRONG (-1)=0A=
#endif /* !defined WRONG */=0A=
=0A=
/*=0A=
** Simplified normalize logic courtesy Paul Eggert =
(eggert AT twinsun DOT com).=0A=
*/=0A=
=0A=
static int=0A=
increment_overflow(int *number, int delta)=0A=
{=0A=
int number0;=0A=
=0A=
number0 =3D *number;=0A=
*number +=3D delta;=0A=
return (*number < number0) !=3D (delta < 0);=0A=
}=0A=
=0A=
static int=0A=
normalize_overflow(int *tensptr, int *unitsptr, const int base)=0A=
{=0A=
register int tensdelta;=0A=
=0A=
tensdelta =3D (*unitsptr >=3D 0) ?=0A=
(*unitsptr / base) :=0A=
(-1 - (-1 - *unitsptr) / base);=0A=
*unitsptr -=3D tensdelta * base;=0A=
return increment_overflow(tensptr, tensdelta);=0A=
}=0A=
=0A=
static int=0A=
tmcomp(register const struct tm *atmp, register const struct tm =
*btmp)=0A=
{=0A=
register int result;=0A=
=0A=
if ((result =3D (atmp->tm_year - btmp->tm_year)) =3D=3D 0 &&=0A=
(result =3D (atmp->tm_mon - btmp->tm_mon)) =3D=3D 0 &&=0A=
(result =3D (atmp->tm_mday - btmp->tm_mday)) =3D=3D 0 &&=0A=
(result =3D (atmp->tm_hour - btmp->tm_hour)) =3D=3D 0 &&=0A=
(result =3D (atmp->tm_min - btmp->tm_min)) =3D=3D 0)=0A=
result =3D atmp->tm_sec - btmp->tm_sec;=0A=
return result;=0A=
}=0A=
=0A=
static time_t=0A=
time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct =
tm*)),=0A=
const long offset, int *okayp, const int do_norm_secs)=0A=
{=0A=
register const struct state * sp;=0A=
register int dir;=0A=
register int bits;=0A=
register int i, j ;=0A=
register int saved_seconds;=0A=
time_t newt;=0A=
time_t t;=0A=
struct tm yourtm, mytm;=0A=
=0A=
*okayp =3D FALSE;=0A=
yourtm =3D *tmp;=0A=
if (do_norm_secs) {=0A=
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,=0A=
SECSPERMIN))=0A=
return WRONG;=0A=
}=0A=
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, =
MINSPERHOUR))=0A=
return WRONG;=0A=
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, =
HOURSPERDAY))=0A=
return WRONG;=0A=
if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, =
MONSPERYEAR))=0A=
return WRONG;=0A=
/*=0A=
** Turn yourtm.tm_year into an actual year number for now.=0A=
** It is converted back to an offset from TM_YEAR_BASE later.=0A=
*/=0A=
if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))=0A=
return WRONG;=0A=
while (yourtm.tm_mday <=3D 0) {=0A=
if (increment_overflow(&yourtm.tm_year, -1))=0A=
return WRONG;=0A=
i =3D yourtm.tm_year + (1 < yourtm.tm_mon);=0A=
yourtm.tm_mday +=3D year_lengths[isleap(i)];=0A=
}=0A=
while (yourtm.tm_mday > DAYSPERLYEAR) {=0A=
i =3D yourtm.tm_year + (1 < yourtm.tm_mon);=0A=
yourtm.tm_mday -=3D year_lengths[isleap(i)];=0A=
if (increment_overflow(&yourtm.tm_year, 1))=0A=
return WRONG;=0A=
}=0A=
for ( ; ; ) {=0A=
i =3D mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];=0A=
if (yourtm.tm_mday <=3D i)=0A=
break;=0A=
yourtm.tm_mday -=3D i;=0A=
if (++yourtm.tm_mon >=3D MONSPERYEAR) {=0A=
yourtm.tm_mon =3D 0;=0A=
if (increment_overflow(&yourtm.tm_year, 1))=0A=
return WRONG;=0A=
}=0A=
}=0A=
if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))=0A=
return WRONG;=0A=
if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {=0A=
/*=0A=
** We can't set tm_sec to 0, because that might push the=0A=
** time below the minimum representable time.=0A=
** Set tm_sec to 59 instead.=0A=
** This assumes that the minimum representable time is=0A=
** not in the same minute that a leap second was deleted from,=0A=
** which is a safer assumption than using 58 would be.=0A=
*/=0A=
if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))=0A=
return WRONG;=0A=
saved_seconds =3D yourtm.tm_sec;=0A=
yourtm.tm_sec =3D SECSPERMIN - 1;=0A=
} else {=0A=
saved_seconds =3D yourtm.tm_sec;=0A=
yourtm.tm_sec =3D 0;=0A=
}=0A=
/*=0A=
** Divide the search space in half=0A=
** (this works whether time_t is signed or unsigned).=0A=
*/=0A=
bits =3D TYPE_BIT(time_t) - 1;=0A=
/*=0A=
** If time_t is signed, then 0 is just above the median,=0A=
** assuming two's complement arithmetic.=0A=
** If time_t is unsigned, then (1 << bits) is just above the =
median.=0A=
*/=0A=
t =3D TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);=0A=
for ( ; ; ) {=0A=
(*funcp)(&t, offset, &mytm);=0A=
dir =3D tmcomp(&mytm, &yourtm);=0A=
if (dir !=3D 0) {=0A=
if (bits-- < 0)=0A=
return WRONG;=0A=
if (bits < 0)=0A=
--t; /* may be needed if new t is minimal */=0A=
else if (dir > 0)=0A=
t -=3D ((time_t) 1) << bits;=0A=
else t +=3D ((time_t) 1) << bits;=0A=
continue;=0A=
}=0A=
if (yourtm.tm_isdst < 0 || mytm.tm_isdst =3D=3D yourtm.tm_isdst)=0A=
break;=0A=
/*=0A=
** Right time, wrong type.=0A=
** Hunt for right time, right type.=0A=
** It's okay to guess wrong since the guess=0A=
** gets checked.=0A=
*/=0A=
/*=0A=
** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.=0A=
*/=0A=
sp =3D (const struct state *)=0A=
(((void *) funcp =3D=3D (void *) localsub) ?=0A=
lclptr : gmtptr);=0A=
#ifdef ALL_STATE=0A=
if (sp =3D=3D NULL)=0A=
return WRONG;=0A=
#endif /* defined ALL_STATE */=0A=
for (i =3D sp->typecnt - 1; i >=3D 0; --i) {=0A=
if (sp->ttis[i].tt_isdst !=3D yourtm.tm_isdst)=0A=
continue;=0A=
for (j =3D sp->typecnt - 1; j >=3D 0; --j) {=0A=
if (sp->ttis[j].tt_isdst =3D=3D yourtm.tm_isdst)=0A=
continue;=0A=
newt =3D t + sp->ttis[j].tt_gmtoff -=0A=
sp->ttis[i].tt_gmtoff;=0A=
(*funcp)(&newt, offset, &mytm);=0A=
if (tmcomp(&mytm, &yourtm) !=3D 0)=0A=
continue;=0A=
if (mytm.tm_isdst !=3D yourtm.tm_isdst)=0A=
continue;=0A=
/*=0A=
** We have a match.=0A=
*/=0A=
t =3D newt;=0A=
goto label;=0A=
}=0A=
}=0A=
return WRONG;=0A=
}=0A=
label:=0A=
newt =3D t + saved_seconds;=0A=
if ((newt < t) !=3D (saved_seconds < 0))=0A=
return WRONG;=0A=
t =3D newt;=0A=
(*funcp)(&t, offset, tmp);=0A=
*okayp =3D TRUE;=0A=
return t;=0A=
}=0A=
=0A=
static time_t=0A=
time2(struct tm *tmp, void (*funcp) P((const time_t*, long, struct =
tm*)),=0A=
const long offset, int *okayp)=0A=
{=0A=
time_t t;=0A=
=0A=
/*=0A=
** First try without normalization of seconds=0A=
** (in case tm_sec contains a value associated with a leap second).=0A=
** If that fails, try with normalization of seconds.=0A=
*/=0A=
t =3D time2sub(tmp, funcp, offset, okayp, FALSE);=0A=
return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);=0A=
}=0A=
=0A=
static time_t=0A=
time1(struct tm *tmp, void (*funcp) P((const time_t *, long, struct tm =
*)),=0A=
const long offset)=0A=
{=0A=
register time_t t;=0A=
register const struct state * sp;=0A=
register int samei, otheri;=0A=
int okay;=0A=
=0A=
if (tmp->tm_isdst > 1)=0A=
tmp->tm_isdst =3D 1;=0A=
t =3D time2(tmp, funcp, offset, &okay);=0A=
#ifdef PCTS=0A=
/*=0A=
** PCTS code courtesy Grant Sullivan (grant AT osf DOT org).=0A=
*/=0A=
if (okay)=0A=
return t;=0A=
if (tmp->tm_isdst < 0)=0A=
tmp->tm_isdst =3D 0; /* reset to std and try again */=0A=
#endif /* defined PCTS */=0A=
#ifndef PCTS=0A=
if (okay || tmp->tm_isdst < 0)=0A=
return t;=0A=
#endif /* !defined PCTS */=0A=
/*=0A=
** We're supposed to assume that somebody took a time of one type=0A=
** and did some math on it that yielded a "struct tm" that's bad.=0A=
** We try to divine the type they started from and adjust to the=0A=
** type they need.=0A=
*/=0A=
/*=0A=
** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.=0A=
*/=0A=
sp =3D (const struct state *) (((void *) funcp =3D=3D (void *) =
localsub) ?=0A=
lclptr : gmtptr);=0A=
#ifdef ALL_STATE=0A=
if (sp =3D=3D NULL)=0A=
return WRONG;=0A=
#endif /* defined ALL_STATE */=0A=
for (samei =3D sp->typecnt - 1; samei >=3D 0; --samei) {=0A=
if (sp->ttis[samei].tt_isdst !=3D tmp->tm_isdst)=0A=
continue;=0A=
for (otheri =3D sp->typecnt - 1; otheri >=3D 0; --otheri) {=0A=
if (sp->ttis[otheri].tt_isdst =3D=3D tmp->tm_isdst)=0A=
continue;=0A=
tmp->tm_sec +=3D sp->ttis[otheri].tt_gmtoff -=0A=
sp->ttis[samei].tt_gmtoff;=0A=
tmp->tm_isdst =3D !tmp->tm_isdst;=0A=
t =3D time2(tmp, funcp, offset, &okay);=0A=
if (okay)=0A=
return t;=0A=
tmp->tm_sec -=3D sp->ttis[otheri].tt_gmtoff -=0A=
sp->ttis[samei].tt_gmtoff;=0A=
tmp->tm_isdst =3D !tmp->tm_isdst;=0A=
}=0A=
}=0A=
return WRONG;=0A=
}=0A=
=0A=
extern "C" time_t=0A=
mktime(struct tm *tmp)=0A=
{=0A=
tzset();=0A=
return time1(tmp, localsub, 0L);=0A=
}=0A=
=0A=
#ifdef STD_INSPIRED=0A=
=0A=
extern "C" time_t=0A=
timelocal(struct tm *tmp)=0A=
{=0A=
tmp->tm_isdst =3D -1; /* in case it wasn't initialized */=0A=
return mktime(tmp);=0A=
}=0A=
=0A=
extern "C" time_t=0A=
timegm(struct tm *tmp)=0A=
{=0A=
tmp->tm_isdst =3D 0;=0A=
return time1(tmp, gmtsub, 0L);=0A=
}=0A=
=0A=
extern "C" time_t=0A=
timeoff(struct tm *tmp, const long offset)=0A=
{=0A=
tmp->tm_isdst =3D 0;=0A=
return time1(tmp, gmtsub, offset);=0A=
}=0A=
=0A=
#endif /* defined STD_INSPIRED */=0A=
=0A=
#ifdef CMUCS=0A=
=0A=
/*=0A=
** The following is supplied for compatibility with=0A=
** previous versions of the CMUCS runtime library.=0A=
*/=0A=
=0A=
extern "C" long=0A=
gtime(struct tm *tmp)=0A=
{=0A=
const time_t t =3D mktime(tmp);=0A=
=0A=
if (t =3D=3D WRONG)=0A=
return -1;=0A=
return t;=0A=
}=0A=
=0A=
#endif /* defined CMUCS */=0A=
=0A=
/*=0A=
** XXX--is the below the right way to conditionalize??=0A=
*/=0A=
=0A=
#ifdef STD_INSPIRED=0A=
=0A=
/*=0A=
** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599=0A=
** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which=0A=
** is not the case if we are accounting for leap seconds.=0A=
** So, we provide the following conversion routines for use=0A=
** when exchanging timestamps with POSIX conforming systems.=0A=
*/=0A=
=0A=
static long=0A=
leapcorr(time_t *timep)=0A=
{=0A=
register struct state * sp;=0A=
register struct lsinfo * lp;=0A=
register int i;=0A=
=0A=
sp =3D lclptr;=0A=
i =3D sp->leapcnt;=0A=
while (--i >=3D 0) {=0A=
lp =3D &sp->lsis[i];=0A=
if (*timep >=3D lp->ls_trans)=0A=
return lp->ls_corr;=0A=
}=0A=
return 0;=0A=
}=0A=
=0A=
extern "C" time_t=0A=
time2posix(time_t t)=0A=
{=0A=
tzset();=0A=
return t - leapcorr(&t);=0A=
}=0A=
=0A=
extern "C" time_t=0A=
posix2time(time_t t)=0A=
{=0A=
time_t x;=0A=
time_t y;=0A=
=0A=
tzset();=0A=
/*=0A=
** For a positive leap second hit, the result=0A=
** is not unique. For a negative leap second=0A=
** hit, the corresponding time doesn't exist,=0A=
** so we return an adjacent second.=0A=
*/=0A=
x =3D t + leapcorr(&t);=0A=
y =3D x - leapcorr(&x);=0A=
if (y < t) {=0A=
do {=0A=
x++;=0A=
y =3D x - leapcorr(&x);=0A=
} while (y < t);=0A=
if (t !=3D y)=0A=
return x - 1;=0A=
} else if (y > t) {=0A=
do {=0A=
--x;=0A=
y =3D x - leapcorr(&x);=0A=
} while (y > t);=0A=
if (t !=3D y)=0A=
return x + 1;=0A=
}=0A=
return x;=0A=
}=0A=
=0A=
#endif /* defined STD_INSPIRED */=0A=
------_=_NextPart_000_01C1B31A.A9F59490
Content-Type: text/plain; charset=us-ascii
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
------_=_NextPart_000_01C1B31A.A9F59490--
- Raw text -