This source file includes following definitions.
- extend_abbrs
- tzalloc
- save_abbr
- tzfree
- getenv_TZ
- setenv_TZ
- change_env
- set_tz
- revert_tz
- localtime_rz
- mktime_z
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <config.h>
26
27 #include <time.h>
28
29 #include <errno.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "flexmember.h"
35 #include "idx.h"
36 #include "time-internal.h"
37
38
39
40 enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
41
42
43
44
45 enum { ABBR_SIZE_MIN = DEFAULT_MXFAST - offsetof (struct tm_zone, abbrs) };
46
47
48
49
50 static timezone_t const local_tz = (timezone_t) 1;
51
52
53
54
55 static void
56 extend_abbrs (char *abbrs, char const *abbr, size_t abbr_size)
57 {
58 memcpy (abbrs, abbr, abbr_size);
59 abbrs[abbr_size] = '\0';
60 }
61
62
63
64 timezone_t
65 tzalloc (char const *name)
66 {
67 size_t name_size = name ? strlen (name) + 1 : 0;
68 size_t abbr_size = name_size < ABBR_SIZE_MIN ? ABBR_SIZE_MIN : name_size + 1;
69 timezone_t tz = malloc (FLEXSIZEOF (struct tm_zone, abbrs, abbr_size));
70 if (tz)
71 {
72 tz->next = NULL;
73 #if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE
74 tz->tzname_copy[0] = tz->tzname_copy[1] = NULL;
75 #endif
76 tz->tz_is_set = !!name;
77 tz->abbrs[0] = '\0';
78 if (name)
79 extend_abbrs (tz->abbrs, name, name_size);
80 }
81 return tz;
82 }
83
84
85
86
87
88 static bool
89 save_abbr (timezone_t tz, struct tm *tm)
90 {
91 #if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME
92 char const *zone = NULL;
93 char *zone_copy = (char *) "";
94
95 # if HAVE_TZNAME
96 int tzname_index = -1;
97 # endif
98
99 # if HAVE_STRUCT_TM_TM_ZONE
100 zone = tm->tm_zone;
101 # endif
102
103 # if HAVE_TZNAME
104 if (! (zone && *zone) && 0 <= tm->tm_isdst)
105 {
106 tzname_index = tm->tm_isdst != 0;
107 zone = tzname[tzname_index];
108 }
109 # endif
110
111
112 if (!zone || ((char *) tm <= zone && zone < (char *) (tm + 1)))
113 return true;
114
115 if (*zone)
116 {
117 zone_copy = tz->abbrs;
118
119 while (strcmp (zone_copy, zone) != 0)
120 {
121 if (! (*zone_copy || (zone_copy == tz->abbrs && tz->tz_is_set)))
122 {
123 idx_t zone_size = strlen (zone) + 1;
124 if (zone_size < tz->abbrs + ABBR_SIZE_MIN - zone_copy)
125 extend_abbrs (zone_copy, zone, zone_size);
126 else
127 {
128 tz = tz->next = tzalloc (zone);
129 if (!tz)
130 return false;
131 tz->tz_is_set = 0;
132 zone_copy = tz->abbrs;
133 }
134 break;
135 }
136
137 zone_copy += strlen (zone_copy) + 1;
138 if (!*zone_copy && tz->next)
139 {
140 tz = tz->next;
141 zone_copy = tz->abbrs;
142 }
143 }
144 }
145
146
147 # if HAVE_STRUCT_TM_TM_ZONE
148 tm->tm_zone = zone_copy;
149 # else
150 if (0 <= tzname_index)
151 tz->tzname_copy[tzname_index] = zone_copy;
152 # endif
153 #endif
154
155 return true;
156 }
157
158
159 void
160 tzfree (timezone_t tz)
161 {
162 if (tz != local_tz)
163 while (tz)
164 {
165 timezone_t next = tz->next;
166 free (tz);
167 tz = next;
168 }
169 }
170
171
172
173
174 #ifndef getenv_TZ
175 static char *
176 getenv_TZ (void)
177 {
178 return getenv ("TZ");
179 }
180 #endif
181
182 #ifndef setenv_TZ
183 static int
184 setenv_TZ (char const *tz)
185 {
186 return tz ? setenv ("TZ", tz, 1) : unsetenv ("TZ");
187 }
188 #endif
189
190
191
192 static bool
193 change_env (timezone_t tz)
194 {
195 if (setenv_TZ (tz->tz_is_set ? tz->abbrs : NULL) != 0)
196 return false;
197 tzset ();
198 return true;
199 }
200
201
202
203
204
205 static timezone_t
206 set_tz (timezone_t tz)
207 {
208 char *env_tz = getenv_TZ ();
209 if (env_tz
210 ? tz->tz_is_set && strcmp (tz->abbrs, env_tz) == 0
211 : !tz->tz_is_set)
212 return local_tz;
213 else
214 {
215 timezone_t old_tz = tzalloc (env_tz);
216 if (!old_tz)
217 return old_tz;
218 if (! change_env (tz))
219 {
220 int saved_errno = errno;
221 tzfree (old_tz);
222 errno = saved_errno;
223 return NULL;
224 }
225 return old_tz;
226 }
227 }
228
229
230
231
232 static bool
233 revert_tz (timezone_t tz)
234 {
235 if (tz == local_tz)
236 return true;
237 else
238 {
239 int saved_errno = errno;
240 bool ok = change_env (tz);
241 if (!ok)
242 saved_errno = errno;
243 tzfree (tz);
244 errno = saved_errno;
245 return ok;
246 }
247 }
248
249
250 struct tm *
251 localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
252 {
253 #ifdef HAVE_LOCALTIME_INFLOOP_BUG
254
255
256
257
258
259
260
261 if (! (-67768038400665599 <= *t && *t <= 67768036191766798))
262 {
263 errno = EOVERFLOW;
264 return NULL;
265 }
266 #endif
267
268 if (!tz)
269 return gmtime_r (t, tm);
270 else
271 {
272 timezone_t old_tz = set_tz (tz);
273 if (old_tz)
274 {
275 bool abbr_saved = localtime_r (t, tm) && save_abbr (tz, tm);
276 if (revert_tz (old_tz) && abbr_saved)
277 return tm;
278 }
279 return NULL;
280 }
281 }
282
283
284 time_t
285 mktime_z (timezone_t tz, struct tm *tm)
286 {
287 if (!tz)
288 return timegm (tm);
289 else
290 {
291 timezone_t old_tz = set_tz (tz);
292 if (old_tz)
293 {
294 struct tm tm_1;
295 tm_1.tm_sec = tm->tm_sec;
296 tm_1.tm_min = tm->tm_min;
297 tm_1.tm_hour = tm->tm_hour;
298 tm_1.tm_mday = tm->tm_mday;
299 tm_1.tm_mon = tm->tm_mon;
300 tm_1.tm_year = tm->tm_year;
301 tm_1.tm_yday = -1;
302 tm_1.tm_isdst = tm->tm_isdst;
303 time_t t = mktime (&tm_1);
304 bool ok = 0 <= tm_1.tm_yday;
305 #if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME
306 ok = ok && save_abbr (tz, &tm_1);
307 #endif
308 if (revert_tz (old_tz) && ok)
309 {
310 *tm = tm_1;
311 return t;
312 }
313 }
314 return -1;
315 }
316 }