]>
Commit | Line | Data |
---|---|---|
63ff2b84 MG |
1 | /* localtime.cc: Wrapper of NetBSD tzcode support for Cygwin. See README file. |
2 | ||
3 | This file is part of Cygwin. | |
4 | ||
5 | This software is a copyrighted work licensed under the terms of the | |
6 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
7 | details. */ | |
8 | ||
9 | #include "../winsup.h" | |
10 | #include "../sync.h" | |
11 | #include "../include/cygwin/version.h" | |
12 | #include "tz_posixrules.h" | |
13 | ||
14 | static NO_COPY muto tzset_guard; | |
15 | ||
16 | // Convert these NetBSD rwlock ops into Cygwin muto ops | |
17 | #define rwlock_wrlock(X) tzset_guard.init("tzset_guard")->acquire() | |
18 | #define rwlock_unlock(X) tzset_guard.release() | |
19 | ||
20 | // Set these NetBSD-related option #defines appropriately for Cygwin | |
21 | //#define STD_INSPIRED // early-include private.h below does this | |
22 | #define lint | |
23 | #define HAVE_POSIX_DECLS 0 | |
24 | #define USG_COMPAT 1 | |
25 | #define NO_ERROR_IN_DST_GAP | |
26 | #define state __state | |
27 | ||
28 | // Turn a specific known kind of const parameter into non-const | |
29 | #define __UNCONST(X) ((char *) (X)) | |
30 | ||
31 | // Turn off these NetBSD audit-related definitions | |
32 | #define __aconst | |
33 | #define _DIAGASSERT(X) | |
34 | ||
35 | // Supply this Cygwin-specific function in advance of its use in localtime.c | |
36 | static char * | |
37 | tzgetwintzi (char *wildabbr, char *outbuf) | |
38 | { | |
39 | TIME_ZONE_INFORMATION tzi; | |
40 | char *cp, *dst; | |
41 | wchar_t *wsrc; | |
42 | div_t d; | |
43 | ||
44 | GetTimeZoneInformation (&tzi); | |
45 | dst = cp = outbuf; | |
46 | for (wsrc = tzi.StandardName; *wsrc; wsrc++) | |
47 | if (*wsrc >= L'A' && *wsrc <= L'Z') | |
48 | *dst++ = *wsrc; | |
49 | if ((dst - cp) < 3) | |
50 | { | |
51 | /* In non-english Windows, converted tz.StandardName | |
52 | may not contain a valid standard timezone name. */ | |
53 | strcpy (cp, wildabbr); | |
54 | cp += strlen (wildabbr); | |
55 | } | |
56 | else | |
57 | cp = dst; | |
58 | d = div (tzi.Bias + tzi.StandardBias, 60); | |
59 | __small_sprintf (cp, "%d", d.quot); | |
60 | if (d.rem) | |
61 | __small_sprintf (cp = strchr (cp, 0), ":%d", abs (d.rem)); | |
62 | if (tzi.StandardDate.wMonth) | |
63 | { | |
64 | cp = strchr (cp, 0); | |
65 | dst = cp; | |
66 | for (wsrc = tzi.DaylightName; *wsrc; wsrc++) | |
67 | if (*wsrc >= L'A' && *wsrc <= L'Z') | |
68 | *dst++ = *wsrc; | |
69 | if ((dst - cp) < 3) | |
70 | { | |
71 | /* In non-english Windows, converted tz.DaylightName | |
72 | may not contain a valid daylight timezone name. */ | |
73 | strcpy (cp, wildabbr); | |
74 | cp += strlen (wildabbr); | |
75 | } | |
76 | else | |
77 | cp = dst; | |
78 | d = div (tzi.Bias + tzi.DaylightBias, 60); | |
79 | __small_sprintf (cp, "%d", d.quot); | |
80 | if (d.rem) | |
81 | __small_sprintf (cp = strchr (cp, 0), ":%d", abs (d.rem)); | |
82 | cp = strchr (cp, 0); | |
83 | __small_sprintf (cp = strchr (cp, 0), ",M%d.%d.%d/%d", | |
84 | tzi.DaylightDate.wMonth, | |
85 | tzi.DaylightDate.wDay, | |
86 | tzi.DaylightDate.wDayOfWeek, | |
87 | tzi.DaylightDate.wHour); | |
88 | if (tzi.DaylightDate.wMinute || tzi.DaylightDate.wSecond) | |
89 | __small_sprintf (cp = strchr (cp, 0), ":%d", | |
90 | tzi.DaylightDate.wMinute); | |
91 | if (tzi.DaylightDate.wSecond) | |
92 | __small_sprintf (cp = strchr (cp, 0), ":%d", | |
93 | tzi.DaylightDate.wSecond); | |
94 | cp = strchr (cp, 0); | |
95 | __small_sprintf (cp = strchr (cp, 0), ",M%d.%d.%d/%d", | |
96 | tzi.StandardDate.wMonth, | |
97 | tzi.StandardDate.wDay, | |
98 | tzi.StandardDate.wDayOfWeek, | |
99 | tzi.StandardDate.wHour); | |
100 | if (tzi.StandardDate.wMinute || tzi.StandardDate.wSecond) | |
101 | __small_sprintf (cp = strchr (cp, 0), ":%d", | |
102 | tzi.StandardDate.wMinute); | |
103 | if (tzi.StandardDate.wSecond) | |
104 | __small_sprintf (cp = strchr (cp, 0), ":%d", | |
105 | tzi.StandardDate.wSecond); | |
106 | } | |
107 | /* __small_printf ("TZ deduced as `%s'\n", outbuf); */ | |
108 | return outbuf; | |
109 | } | |
110 | ||
111 | // Get ready to wrap NetBSD's localtime.c | |
112 | #ifdef __cplusplus | |
113 | extern "C" { | |
114 | #endif | |
115 | ||
116 | // Pull these in early to catch any small issues before the real test | |
117 | #include "private.h" | |
118 | #include "tzfile.h" | |
119 | ||
120 | /* Some NetBSD differences were too difficult to work around.. | |
121 | so #include a patched copy of localtime.c rather than the NetBSD original. | |
122 | Here is a list of the patches... | |
123 | (1) fix an erroneous decl of tzdirslash size (flagged by g++) | |
124 | (2) add conditional call to Cygwin's tzgetwintzi() from tzsetlcl() | |
125 | (3) add Cygwin's historical "posixrules" support to tzloadbody() | |
126 | */ | |
127 | #include "localtime.c.patched" | |
128 | ||
129 | #ifdef __cplusplus | |
130 | } | |
131 | #endif | |
132 | ||
133 | // Don't forget these Cygwin-specific additions from this point to EOF | |
134 | EXPORT_ALIAS (tzset_unlocked, _tzset_unlocked) | |
135 | ||
136 | extern "C" long | |
137 | __cygwin_gettzoffset (const struct tm *tmp) | |
138 | { | |
139 | #ifdef TM_GMTOFF | |
140 | if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS) | |
141 | return tmp->TM_GMTOFF; | |
142 | #endif /* defined TM_GMTOFF */ | |
143 | __tzinfo_type *tz = __gettzinfo (); | |
144 | /* The sign of this is exactly opposite the envvar TZ. We | |
145 | could directly use the global _timezone for tm_isdst==0, | |
146 | but have to use __tzrule for daylight savings. */ | |
147 | long offset = -tz->__tzrule[tmp->tm_isdst > 0].offset; | |
148 | return offset; | |
149 | } | |
150 | ||
151 | extern "C" const char * | |
152 | __cygwin_gettzname (const struct tm *tmp) | |
153 | { | |
154 | #ifdef TM_ZONE | |
155 | if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS) | |
156 | return tmp->TM_ZONE; | |
157 | #endif | |
158 | return _tzname[tmp->tm_isdst > 0]; | |
159 | } |