Cygwin's wrapper around NetBSD's localtime.c. --- winsup/cygwin/tzcode/localtime.cc | 162 ++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 winsup/cygwin/tzcode/localtime.cc
diff --git a/winsup/cygwin/tzcode/localtime.cc b/winsup/cygwin/tzcode/localtime.cc new file mode 100644 index 000000000..9ea885ece --- /dev/null +++ b/winsup/cygwin/tzcode/localtime.cc @@ -0,0 +1,162 @@ +/* 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" + +// Set these NetBSD-related option #defines appropriately for Cygwin +//#define STD_INSPIRED // early-include private.h below does this +#define lint +#define USG_COMPAT 1 +#define NO_ERROR_IN_DST_GAP +#define state __state + +static NO_COPY muto tzset_guard; + +// Turn these NetBSD ops into the corresponding Cygwin ops +#define rwlock_wrlock(X) tzset_guard.init ("tzset_guard")->acquire () +#define rwlock_unlock(X) tzset_guard.release () + +// 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) + +// Get ready to enclose NetBSD's localtime.c +#ifdef __cplusplus +extern "C" { +#endif + +// Supply this Cygwin-specific function in advance of its use in localtime.c +static char * +tzgetwintz (char *wildabbr, char *outbuf) +{ + TIME_ZONE_INFORMATION tzi; + char *cp, *dst; + wchar_t *src; + div_t d; + + GetTimeZoneInformation (&tzi); + dst = cp = outbuf; + for (src = tzi.StandardName; *src; src++) + if (*src >= L'A' && *src <= L'Z') + *dst++ = *src; + 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 (src = tzi.DaylightName; *src; src++) + if (*src >= L'A' && *src <= L'Z') + *dst++ = *src; + 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 missing casts on all results of malloc() calls (flagged by g++) + (3) change all malloc() calls to analogous calloc() calls + (4) add conditional call to Cygwin's tzgetwintz() from tzsetlcl() + (5) add Cygwin's historical "posixrules" support to tzloadbody() + (6) enable defs of daylight, timezone, and tzname + (7) make def of __lclptr static to avoid exporting it +*/ +#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]; +} -- 2.21.0