160 lines
4.7 KiB
C
160 lines
4.7 KiB
C
|
/* 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. */
|
||
|
|
||
|
#include "../winsup.h"
|
||
|
#include "../sync.h"
|
||
|
#include "../include/cygwin/version.h"
|
||
|
#include "tz_posixrules.h"
|
||
|
|
||
|
static NO_COPY muto tzset_guard;
|
||
|
|
||
|
// Convert these NetBSD rwlock ops into Cygwin muto ops
|
||
|
#define rwlock_wrlock(X) tzset_guard.init("tzset_guard")->acquire()
|
||
|
#define rwlock_unlock(X) tzset_guard.release()
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
// Get ready to wrap NetBSD's localtime.c
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
|
||
|
// 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()
|
||
|
*/
|
||
|
#include "localtime.c.patched"
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Don't forget these Cygwin-specific additions from this point to EOF
|
||
|
EXPORT_ALIAS (tzset_unlocked, _tzset_unlocked)
|
||
|
|
||
|
extern "C" long
|
||
|
__cygwin_gettzoffset (const struct tm *tmp)
|
||
|
{
|
||
|
#ifdef TM_GMTOFF
|
||
|
if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
|
||
|
return tmp->TM_GMTOFF;
|
||
|
#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;
|
||
|
}
|
||
|
|
||
|
extern "C" const char *
|
||
|
__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];
|
||
|
}
|