2020-05-22 17:32:53 +08:00
|
|
|
/* localtime.cc: Wrapper of NetBSD tzcode support for Cygwin. See README file.
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2020-05-25 19:50:36 +08:00
|
|
|
#include "winsup.h"
|
|
|
|
#include "perprocess.h"
|
2020-05-22 17:32:53 +08:00
|
|
|
#include "tz_posixrules.h"
|
2020-05-25 19:50:36 +08:00
|
|
|
#include <cygwin/version.h>
|
|
|
|
#include <stdlib.h>
|
2020-10-05 20:50:13 +08:00
|
|
|
#include <sys/_tz_structs.h>
|
2020-05-22 17:32:53 +08:00
|
|
|
|
2020-05-25 19:50:36 +08:00
|
|
|
static NO_COPY SRWLOCK tzset_guard = SRWLOCK_INIT;
|
2020-05-22 17:32:53 +08:00
|
|
|
|
2020-05-25 19:50:36 +08:00
|
|
|
// Convert these NetBSD rwlock ops into SRWLocks
|
|
|
|
#define rwlock_wrlock(X) AcquireSRWLockExclusive(&tzset_guard)
|
|
|
|
#define rwlock_unlock(X) ReleaseSRWLockExclusive(&tzset_guard)
|
2020-05-22 17:32:53 +08:00
|
|
|
|
|
|
|
// Set these NetBSD-related option #defines appropriately for Cygwin
|
|
|
|
//#define STD_INSPIRED // early-include private.h below does this
|
|
|
|
#define lint
|
|
|
|
#define HAVE_POSIX_DECLS 0
|
|
|
|
#define USG_COMPAT 1
|
|
|
|
#define NO_ERROR_IN_DST_GAP
|
|
|
|
#define state __state
|
|
|
|
|
|
|
|
// Turn a specific known kind of const parameter into non-const
|
|
|
|
#define __UNCONST(X) ((char *) (X))
|
|
|
|
|
|
|
|
// Turn off these NetBSD audit-related definitions
|
|
|
|
#define __aconst
|
|
|
|
#define _DIAGASSERT(X)
|
|
|
|
|
|
|
|
// Supply this Cygwin-specific function in advance of its use in localtime.c
|
|
|
|
static char *
|
|
|
|
tzgetwintzi (char *wildabbr, char *outbuf)
|
|
|
|
{
|
|
|
|
TIME_ZONE_INFORMATION tzi;
|
|
|
|
char *cp, *dst;
|
|
|
|
wchar_t *wsrc;
|
|
|
|
div_t d;
|
|
|
|
|
|
|
|
GetTimeZoneInformation (&tzi);
|
|
|
|
dst = cp = outbuf;
|
|
|
|
for (wsrc = tzi.StandardName; *wsrc; wsrc++)
|
|
|
|
if (*wsrc >= L'A' && *wsrc <= L'Z')
|
|
|
|
*dst++ = *wsrc;
|
|
|
|
if ((dst - cp) < 3)
|
|
|
|
{
|
|
|
|
/* In non-english Windows, converted tz.StandardName
|
|
|
|
may not contain a valid standard timezone name. */
|
|
|
|
strcpy (cp, wildabbr);
|
|
|
|
cp += strlen (wildabbr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cp = dst;
|
|
|
|
d = div (tzi.Bias + tzi.StandardBias, 60);
|
|
|
|
__small_sprintf (cp, "%d", d.quot);
|
|
|
|
if (d.rem)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d", abs (d.rem));
|
|
|
|
if (tzi.StandardDate.wMonth)
|
|
|
|
{
|
|
|
|
cp = strchr (cp, 0);
|
|
|
|
dst = cp;
|
|
|
|
for (wsrc = tzi.DaylightName; *wsrc; wsrc++)
|
|
|
|
if (*wsrc >= L'A' && *wsrc <= L'Z')
|
|
|
|
*dst++ = *wsrc;
|
|
|
|
if ((dst - cp) < 3)
|
|
|
|
{
|
|
|
|
/* In non-english Windows, converted tz.DaylightName
|
|
|
|
may not contain a valid daylight timezone name. */
|
|
|
|
strcpy (cp, wildabbr);
|
|
|
|
cp += strlen (wildabbr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cp = dst;
|
|
|
|
d = div (tzi.Bias + tzi.DaylightBias, 60);
|
|
|
|
__small_sprintf (cp, "%d", d.quot);
|
|
|
|
if (d.rem)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d", abs (d.rem));
|
|
|
|
cp = strchr (cp, 0);
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ",M%d.%d.%d/%d",
|
|
|
|
tzi.DaylightDate.wMonth,
|
|
|
|
tzi.DaylightDate.wDay,
|
|
|
|
tzi.DaylightDate.wDayOfWeek,
|
|
|
|
tzi.DaylightDate.wHour);
|
|
|
|
if (tzi.DaylightDate.wMinute || tzi.DaylightDate.wSecond)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d",
|
|
|
|
tzi.DaylightDate.wMinute);
|
|
|
|
if (tzi.DaylightDate.wSecond)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d",
|
|
|
|
tzi.DaylightDate.wSecond);
|
|
|
|
cp = strchr (cp, 0);
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ",M%d.%d.%d/%d",
|
|
|
|
tzi.StandardDate.wMonth,
|
|
|
|
tzi.StandardDate.wDay,
|
|
|
|
tzi.StandardDate.wDayOfWeek,
|
|
|
|
tzi.StandardDate.wHour);
|
|
|
|
if (tzi.StandardDate.wMinute || tzi.StandardDate.wSecond)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d",
|
|
|
|
tzi.StandardDate.wMinute);
|
|
|
|
if (tzi.StandardDate.wSecond)
|
|
|
|
__small_sprintf (cp = strchr (cp, 0), ":%d",
|
|
|
|
tzi.StandardDate.wSecond);
|
|
|
|
}
|
|
|
|
/* __small_printf ("TZ deduced as `%s'\n", outbuf); */
|
|
|
|
return outbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pull these in early to catch any small issues before the real test
|
|
|
|
#include "private.h"
|
|
|
|
#include "tzfile.h"
|
|
|
|
|
|
|
|
/* Some NetBSD differences were too difficult to work around..
|
|
|
|
so #include a patched copy of localtime.c rather than the NetBSD original.
|
|
|
|
Here is a list of the patches...
|
|
|
|
(1) fix an erroneous decl of tzdirslash size (flagged by g++)
|
|
|
|
(2) add conditional call to Cygwin's tzgetwintzi() from tzsetlcl()
|
|
|
|
(3) add Cygwin's historical "posixrules" support to tzloadbody()
|
|
|
|
*/
|
2020-05-25 23:40:27 +08:00
|
|
|
#include "localtime.patched.c"
|
2020-05-22 17:32:53 +08:00
|
|
|
|
|
|
|
// Don't forget these Cygwin-specific additions from this point to EOF
|
|
|
|
EXPORT_ALIAS (tzset_unlocked, _tzset_unlocked)
|
|
|
|
|
2020-05-25 19:50:36 +08:00
|
|
|
long
|
2020-05-22 17:32:53 +08:00
|
|
|
__cygwin_gettzoffset (const struct tm *tmp)
|
|
|
|
{
|
|
|
|
#ifdef TM_GMTOFF
|
|
|
|
if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
|
2020-05-25 19:50:36 +08:00
|
|
|
return tmp->TM_GMTOFF;
|
2020-05-22 17:32:53 +08:00
|
|
|
#endif /* defined TM_GMTOFF */
|
|
|
|
__tzinfo_type *tz = __gettzinfo ();
|
|
|
|
/* The sign of this is exactly opposite the envvar TZ. We
|
|
|
|
could directly use the global _timezone for tm_isdst==0,
|
|
|
|
but have to use __tzrule for daylight savings. */
|
|
|
|
long offset = -tz->__tzrule[tmp->tm_isdst > 0].offset;
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2020-05-25 19:50:36 +08:00
|
|
|
const char *
|
2020-05-22 17:32:53 +08:00
|
|
|
__cygwin_gettzname (const struct tm *tmp)
|
|
|
|
{
|
|
|
|
#ifdef TM_ZONE
|
|
|
|
if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
|
|
|
|
return tmp->TM_ZONE;
|
|
|
|
#endif
|
|
|
|
return _tzname[tmp->tm_isdst > 0];
|
|
|
|
}
|