OLD | NEW |
1 #include "time_impl.h" | 1 #include "time_impl.h" |
2 #include <stdint.h> | 2 #include <stdint.h> |
3 #include <limits.h> | 3 #include <limits.h> |
4 #include <stdlib.h> | 4 #include <stdlib.h> |
5 #include <string.h> | 5 #include <string.h> |
6 #include "libc.h" | 6 #include "libc.h" |
7 | 7 |
8 long __timezone = 0; | 8 long __timezone = 0; |
9 int __daylight = 0; | 9 int __daylight = 0; |
10 char *__tzname[2] = { 0, 0 }; | 10 char* __tzname[2] = {0, 0}; |
11 | 11 |
12 weak_alias(__timezone, timezone); | 12 weak_alias(__timezone, timezone); |
13 weak_alias(__daylight, daylight); | 13 weak_alias(__daylight, daylight); |
14 weak_alias(__tzname, tzname); | 14 weak_alias(__tzname, tzname); |
15 | 15 |
16 static char std_name[TZNAME_MAX+1]; | 16 static char std_name[TZNAME_MAX + 1]; |
17 static char dst_name[TZNAME_MAX+1]; | 17 static char dst_name[TZNAME_MAX + 1]; |
18 const char __gmt[] = "GMT"; | 18 const char __gmt[] = "GMT"; |
19 | 19 |
20 static int dst_off; | 20 static int dst_off; |
21 static int r0[5], r1[5]; | 21 static int r0[5], r1[5]; |
22 | 22 |
23 static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end; | 23 static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end; |
24 static size_t map_size; | 24 static size_t map_size; |
25 | 25 |
26 static char old_tz_buf[32]; | 26 static char old_tz_buf[32]; |
27 static char *old_tz = old_tz_buf; | 27 static char* old_tz = old_tz_buf; |
28 static size_t old_tz_size = sizeof old_tz_buf; | 28 static size_t old_tz_size = sizeof old_tz_buf; |
29 | 29 |
30 static volatile int lock[2]; | 30 static volatile int lock[2]; |
31 | 31 |
32 static int getint(const char **p) | 32 static int getint(const char** p) { |
33 { | 33 unsigned x; |
34 » unsigned x; | 34 for (x = 0; **p - '0' < 10U; (*p)++) |
35 » for (x=0; **p-'0'<10U; (*p)++) x = **p-'0' + 10*x; | 35 x = **p - '0' + 10 * x; |
36 » return x; | 36 return x; |
37 } | 37 } |
38 | 38 |
39 static int getoff(const char **p) | 39 static int getoff(const char** p) { |
40 { | 40 int neg = 0; |
41 » int neg = 0; | 41 if (**p == '-') { |
42 » if (**p == '-') { | 42 ++*p; |
43 » » ++*p; | 43 neg = 1; |
44 » » neg = 1; | 44 } else if (**p == '+') { |
45 » } else if (**p == '+') { | 45 ++*p; |
46 » » ++*p; | 46 } |
47 » } | 47 int off = 3600 * getint(p); |
48 » int off = 3600*getint(p); | 48 if (**p == ':') { |
49 » if (**p == ':') { | 49 ++*p; |
50 » » ++*p; | 50 off += 60 * getint(p); |
51 » » off += 60*getint(p); | 51 if (**p == ':') { |
52 » » if (**p == ':') { | 52 ++*p; |
53 » » » ++*p; | 53 off += getint(p); |
54 » » » off += getint(p); | 54 } |
55 » » } | 55 } |
56 » } | 56 return neg ? -off : off; |
57 » return neg ? -off : off; | 57 } |
58 } | 58 |
59 | 59 static void getrule(const char** p, int rule[5]) { |
60 static void getrule(const char **p, int rule[5]) | 60 int r = rule[0] = **p; |
61 { | 61 |
62 » int r = rule[0] = **p; | 62 if (r != 'M') { |
63 | 63 if (r == 'J') |
64 » if (r!='M') { | 64 ++*p; |
65 » » if (r=='J') ++*p; | 65 else |
66 » » else rule[0] = 0; | 66 rule[0] = 0; |
67 » » rule[1] = getint(p); | 67 rule[1] = getint(p); |
68 » } else { | 68 } else { |
69 » » ++*p; rule[1] = getint(p); | 69 ++*p; |
70 » » ++*p; rule[2] = getint(p); | 70 rule[1] = getint(p); |
71 » » ++*p; rule[3] = getint(p); | 71 ++*p; |
72 » } | 72 rule[2] = getint(p); |
73 | 73 ++*p; |
74 » if (**p=='/') { | 74 rule[3] = getint(p); |
75 » » ++*p; | 75 } |
76 » » rule[4] = getoff(p); | 76 |
77 » } else { | 77 if (**p == '/') { |
78 » » rule[4] = 7200; | 78 ++*p; |
79 » } | 79 rule[4] = getoff(p); |
80 } | 80 } else { |
81 | 81 rule[4] = 7200; |
82 static void getname(char *d, const char **p) | 82 } |
83 { | 83 } |
84 » int i; | 84 |
85 » if (**p == '<') { | 85 static void getname(char* d, const char** p) { |
86 » » ++*p; | 86 int i; |
87 » » for (i=0; **p!='>' && i<TZNAME_MAX; i++) | 87 if (**p == '<') { |
88 » » » d[i] = (*p)[i]; | 88 ++*p; |
89 » » ++*p; | 89 for (i = 0; **p != '>' && i < TZNAME_MAX; i++) |
90 » } else { | 90 d[i] = (*p)[i]; |
91 » » for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++) | 91 ++*p; |
92 » » » d[i] = (*p)[i]; | 92 } else { |
93 » } | 93 for (i = 0; ((*p)[i] | 32) - 'a' < 26U && i < TZNAME_MAX; i++) |
94 » *p += i; | 94 d[i] = (*p)[i]; |
95 » d[i] = 0; | 95 } |
| 96 *p += i; |
| 97 d[i] = 0; |
96 } | 98 } |
97 | 99 |
98 #define VEC(...) ((const unsigned char[]){__VA_ARGS__}) | 100 #define VEC(...) ((const unsigned char[]){__VA_ARGS__}) |
99 | 101 |
100 static uint32_t zi_read32(const unsigned char *z) | 102 static uint32_t zi_read32(const unsigned char* z) { |
101 { | 103 return (unsigned)z[0] << 24 | z[1] << 16 | z[2] << 8 | z[3]; |
102 » return (unsigned)z[0]<<24 | z[1]<<16 | z[2]<<8 | z[3]; | 104 } |
103 } | 105 |
104 | 106 static size_t zi_dotprod(const unsigned char* z, |
105 static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t
n) | 107 const unsigned char* v, |
106 { | 108 size_t n) { |
107 » size_t y; | 109 size_t y; |
108 » uint32_t x; | 110 uint32_t x; |
109 » for (y=0; n; n--, z+=4, v++) { | 111 for (y = 0; n; n--, z += 4, v++) { |
110 » » x = zi_read32(z); | 112 x = zi_read32(z); |
111 » » y += x * *v; | 113 y += x * *v; |
112 » } | 114 } |
113 » return y; | 115 return y; |
114 } | 116 } |
115 | 117 |
116 int __munmap(void *, size_t); | 118 int __munmap(void*, size_t); |
117 | 119 |
118 static void do_tzset() | 120 static void do_tzset() { |
119 { | 121 char buf[NAME_MAX + 25], *pathname = buf + 24; |
120 » char buf[NAME_MAX+25], *pathname=buf+24; | 122 const char* try |
121 » const char *try, *s, *p; | 123 , *s, *p; |
122 » const unsigned char *map = 0; | 124 const unsigned char* map = 0; |
123 » size_t i; | 125 size_t i; |
124 » static const char search[] = | 126 static const char search[] = |
125 » » "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; | 127 "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; |
126 | 128 |
127 » s = getenv("TZ"); | 129 s = getenv("TZ"); |
128 » if (!s) s = "/etc/localtime"; | 130 if (!s) |
129 » if (!*s) s = __gmt; | 131 s = "/etc/localtime"; |
130 | 132 if (!*s) |
131 » if (old_tz && !strcmp(s, old_tz)) return; | 133 s = __gmt; |
132 | 134 |
133 » if (zi) __munmap((void *)zi, map_size); | 135 if (old_tz && !strcmp(s, old_tz)) |
134 | 136 return; |
135 » /* Cache the old value of TZ to check if it has changed. Avoid | 137 |
136 » * free so as not to pull it into static programs. Growth | 138 if (zi) |
137 » * strategy makes it so free would have minimal benefit anyway. */ | 139 __munmap((void*)zi, map_size); |
138 » i = strlen(s); | 140 |
139 » if (i > PATH_MAX+1) s = __gmt, i = 3; | 141 /* Cache the old value of TZ to check if it has changed. Avoid |
140 » if (i >= old_tz_size) { | 142 * free so as not to pull it into static programs. Growth |
141 » » old_tz_size *= 2; | 143 * strategy makes it so free would have minimal benefit anyway. */ |
142 » » if (i >= old_tz_size) old_tz_size = i+1; | 144 i = strlen(s); |
143 » » if (old_tz_size > PATH_MAX+2) old_tz_size = PATH_MAX+2; | 145 if (i > PATH_MAX + 1) |
144 » » old_tz = malloc(old_tz_size); | 146 s = __gmt, i = 3; |
145 » } | 147 if (i >= old_tz_size) { |
146 » if (old_tz) memcpy(old_tz, s, i+1); | 148 old_tz_size *= 2; |
147 | 149 if (i >= old_tz_size) |
148 » /* Non-suid can use an absolute tzfile pathname or a relative | 150 old_tz_size = i + 1; |
149 » * pathame beginning with "."; in secure mode, only the | 151 if (old_tz_size > PATH_MAX + 2) |
150 » * standard path will be searched. */ | 152 old_tz_size = PATH_MAX + 2; |
151 » if (*s == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) { | 153 old_tz = malloc(old_tz_size); |
152 » » if (*s == ':') s++; | 154 } |
153 » » if (*s == '/' || *s == '.') { | 155 if (old_tz) |
154 » » » if (!libc.secure || !strcmp(s, "/etc/localtime")) | 156 memcpy(old_tz, s, i + 1); |
155 » » » » map = __map_file(s, &map_size); | 157 |
156 » » } else { | 158 /* Non-suid can use an absolute tzfile pathname or a relative |
157 » » » size_t l = strlen(s); | 159 * pathame beginning with "."; in secure mode, only the |
158 » » » if (l <= NAME_MAX && !strchr(s, '.')) { | 160 * standard path will be searched. */ |
159 » » » » memcpy(pathname, s, l+1); | 161 if (*s == ':' || ((p = strchr(s, '/')) && !memchr(s, ',', p - s))) { |
160 » » » » pathname[l] = 0; | 162 if (*s == ':') |
161 » » » » for (try=search; !map && *try; try+=l+1) { | 163 s++; |
162 » » » » » l = strlen(try); | 164 if (*s == '/' || *s == '.') { |
163 » » » » » memcpy(pathname-l, try, l); | 165 if (!libc.secure || !strcmp(s, "/etc/localtime")) |
164 » » » » » map = __map_file(pathname-l, &map_size); | 166 map = __map_file(s, &map_size); |
165 » » » » } | 167 } else { |
166 » » » } | 168 size_t l = strlen(s); |
167 » » } | 169 if (l <= NAME_MAX && !strchr(s, '.')) { |
168 » » if (!map) s = __gmt; | 170 memcpy(pathname, s, l + 1); |
169 » } | 171 pathname[l] = 0; |
170 » if (map && (map_size < 44 || memcmp(map, "TZif", 4))) { | 172 for (try = search; !map && *try; try += l + 1) { |
171 » » __munmap((void *)map, map_size); | 173 l = strlen(try); |
172 » » map = 0; | 174 memcpy(pathname - l, try, l); |
173 » » s = __gmt; | 175 map = __map_file(pathname - l, &map_size); |
174 » } | 176 } |
175 | 177 } |
176 » zi = map; | 178 } |
177 » if (map) { | 179 if (!map) |
178 » » int scale = 2; | 180 s = __gmt; |
179 » » if (sizeof(time_t) > 4 && map[4]=='2') { | 181 } |
180 » » » size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6); | 182 if (map && (map_size < 44 || memcmp(map, "TZif", 4))) { |
181 » » » trans = zi+skip+44+44; | 183 __munmap((void*)map, map_size); |
182 » » » scale++; | 184 map = 0; |
183 » » } else { | 185 s = __gmt; |
184 » » » trans = zi+44; | 186 } |
185 » » } | 187 |
186 » » index = trans + (zi_read32(trans-12) << scale); | 188 zi = map; |
187 » » types = index + zi_read32(trans-12); | 189 if (map) { |
188 » » abbrevs = types + 6*zi_read32(trans-8); | 190 int scale = 2; |
189 » » abbrevs_end = abbrevs + zi_read32(trans-4); | 191 if (sizeof(time_t) > 4 && map[4] == '2') { |
190 » » if (zi[map_size-1] == '\n') { | 192 size_t skip = zi_dotprod(zi + 20, VEC(1, 1, 8, 5, 6, 1), 6); |
191 » » » for (s = (const char *)zi+map_size-2; *s!='\n'; s--); | 193 trans = zi + skip + 44 + 44; |
192 » » » s++; | 194 scale++; |
193 » » } else { | 195 } else { |
194 » » » const unsigned char *p; | 196 trans = zi + 44; |
195 » » » __tzname[0] = __tzname[1] = 0; | 197 } |
196 » » » __daylight = __timezone = dst_off = 0; | 198 index = trans + (zi_read32(trans - 12) << scale); |
197 » » » for (i=0; i<5; i++) r0[i] = r1[i] = 0; | 199 types = index + zi_read32(trans - 12); |
198 » » » for (p=types; p<abbrevs; p+=6) { | 200 abbrevs = types + 6 * zi_read32(trans - 8); |
199 » » » » if (!p[4] && !__tzname[0]) { | 201 abbrevs_end = abbrevs + zi_read32(trans - 4); |
200 » » » » » __tzname[0] = (char *)abbrevs + p[5]; | 202 if (zi[map_size - 1] == '\n') { |
201 » » » » » __timezone = -zi_read32(p); | 203 for (s = (const char*)zi + map_size - 2; *s != '\n'; s--) |
202 » » » » } | 204 ; |
203 » » » » if (p[4] && !__tzname[1]) { | 205 s++; |
204 » » » » » __tzname[1] = (char *)abbrevs + p[5]; | 206 } else { |
205 » » » » » dst_off = -zi_read32(p); | 207 const unsigned char* p; |
206 » » » » » __daylight = 1; | 208 __tzname[0] = __tzname[1] = 0; |
207 » » » » } | 209 __daylight = __timezone = dst_off = 0; |
208 » » » } | 210 for (i = 0; i < 5; i++) |
209 » » » if (!__tzname[0]) __tzname[0] = __tzname[1]; | 211 r0[i] = r1[i] = 0; |
210 » » » if (!__tzname[0]) __tzname[0] = (char *)__gmt; | 212 for (p = types; p < abbrevs; p += 6) { |
211 » » » if (!__daylight) { | 213 if (!p[4] && !__tzname[0]) { |
212 » » » » __tzname[1] = __tzname[0]; | 214 __tzname[0] = (char*)abbrevs + p[5]; |
213 » » » » dst_off = __timezone; | 215 __timezone = -zi_read32(p); |
214 » » » } | 216 } |
215 » » » return; | 217 if (p[4] && !__tzname[1]) { |
216 » » } | 218 __tzname[1] = (char*)abbrevs + p[5]; |
217 » } | 219 dst_off = -zi_read32(p); |
218 | 220 __daylight = 1; |
219 » if (!s) s = __gmt; | 221 } |
220 » getname(std_name, &s); | 222 } |
221 » __tzname[0] = std_name; | 223 if (!__tzname[0]) |
222 » __timezone = getoff(&s); | 224 __tzname[0] = __tzname[1]; |
223 » getname(dst_name, &s); | 225 if (!__tzname[0]) |
224 » __tzname[1] = dst_name; | 226 __tzname[0] = (char*)__gmt; |
225 » if (dst_name[0]) { | 227 if (!__daylight) { |
226 » » __daylight = 1; | 228 __tzname[1] = __tzname[0]; |
227 » » if (*s == '+' || *s=='-' || *s-'0'<10U) | 229 dst_off = __timezone; |
228 » » » dst_off = getoff(&s); | 230 } |
229 » » else | 231 return; |
230 » » » dst_off = __timezone - 3600; | 232 } |
231 » } else { | 233 } |
232 » » __daylight = 0; | 234 |
233 » » dst_off = 0; | 235 if (!s) |
234 » } | 236 s = __gmt; |
235 | 237 getname(std_name, &s); |
236 » if (*s == ',') s++, getrule(&s, r0); | 238 __tzname[0] = std_name; |
237 » if (*s == ',') s++, getrule(&s, r1); | 239 __timezone = getoff(&s); |
| 240 getname(dst_name, &s); |
| 241 __tzname[1] = dst_name; |
| 242 if (dst_name[0]) { |
| 243 __daylight = 1; |
| 244 if (*s == '+' || *s == '-' || *s - '0' < 10U) |
| 245 dst_off = getoff(&s); |
| 246 else |
| 247 dst_off = __timezone - 3600; |
| 248 } else { |
| 249 __daylight = 0; |
| 250 dst_off = 0; |
| 251 } |
| 252 |
| 253 if (*s == ',') |
| 254 s++, getrule(&s, r0); |
| 255 if (*s == ',') |
| 256 s++, getrule(&s, r1); |
238 } | 257 } |
239 | 258 |
240 /* Search zoneinfo rules to find the one that applies to the given time, | 259 /* Search zoneinfo rules to find the one that applies to the given time, |
241 * and determine alternate opposite-DST-status rule that may be needed. */ | 260 * and determine alternate opposite-DST-status rule that may be needed. */ |
242 | 261 |
243 static size_t scan_trans(long long t, int local, size_t *alt) | 262 static size_t scan_trans(long long t, int local, size_t* alt) { |
244 { | 263 int scale = 3 - (trans == zi + 44); |
245 » int scale = 3 - (trans == zi+44); | 264 uint64_t x; |
246 » uint64_t x; | 265 int off = 0; |
247 » int off = 0; | 266 |
248 | 267 size_t a = 0, n = (index - trans) >> scale, m; |
249 » size_t a = 0, n = (index-trans)>>scale, m; | 268 |
250 | 269 if (!n) { |
251 » if (!n) { | 270 if (alt) |
252 » » if (alt) *alt = 0; | 271 *alt = 0; |
253 » » return 0; | 272 return 0; |
254 » } | 273 } |
255 | 274 |
256 » /* Binary search for 'most-recent rule before t'. */ | 275 /* Binary search for 'most-recent rule before t'. */ |
257 » while (n > 1) { | 276 while (n > 1) { |
258 » » m = a + n/2; | 277 m = a + n / 2; |
259 » » x = zi_read32(trans + (m<<scale)); | 278 x = zi_read32(trans + (m << scale)); |
260 » » if (scale == 3) x = x<<32 | zi_read32(trans + (m<<scale) + 4); | 279 if (scale == 3) |
261 » » else x = (int32_t)x; | 280 x = x << 32 | zi_read32(trans + (m << scale) + 4); |
262 » » if (local) off = (int32_t)zi_read32(types + 6 * index[m-1]); | 281 else |
263 » » if (t - off < (int64_t)x) { | 282 x = (int32_t)x; |
264 » » » n /= 2; | 283 if (local) |
265 » » } else { | 284 off = (int32_t)zi_read32(types + 6 * index[m - 1]); |
266 » » » a = m; | 285 if (t - off < (int64_t)x) { |
267 » » » n -= n/2; | 286 n /= 2; |
268 » » } | 287 } else { |
269 » } | 288 a = m; |
270 | 289 n -= n / 2; |
271 » /* First and last entry are special. First means to use lowest-index | 290 } |
272 » * non-DST type. Last means to apply POSIX-style rule if available. */ | 291 } |
273 » n = (index-trans)>>scale; | 292 |
274 » if (a == n-1) return -1; | 293 /* First and last entry are special. First means to use lowest-index |
275 » if (a == 0) { | 294 * non-DST type. Last means to apply POSIX-style rule if available. */ |
276 » » x = zi_read32(trans + (a<<scale)); | 295 n = (index - trans) >> scale; |
277 » » if (scale == 3) x = x<<32 | zi_read32(trans + (a<<scale) + 4); | 296 if (a == n - 1) |
278 » » else x = (int32_t)x; | 297 return -1; |
279 » » if (local) off = (int32_t)zi_read32(types + 6 * index[a-1]); | 298 if (a == 0) { |
280 » » if (t - off < (int64_t)x) { | 299 x = zi_read32(trans + (a << scale)); |
281 » » » for (a=0; a<(abbrevs-types)/6; a++) { | 300 if (scale == 3) |
282 » » » » if (types[6*a+4] != types[4]) break; | 301 x = x << 32 | zi_read32(trans + (a << scale) + 4); |
283 » » » } | 302 else |
284 » » » if (a == (abbrevs-types)/6) a = 0; | 303 x = (int32_t)x; |
285 » » » if (types[6*a+4]) { | 304 if (local) |
286 » » » » *alt = a; | 305 off = (int32_t)zi_read32(types + 6 * index[a - 1]); |
287 » » » » return 0; | 306 if (t - off < (int64_t)x) { |
288 » » » } else { | 307 for (a = 0; a < (abbrevs - types) / 6; a++) { |
289 » » » » *alt = 0; | 308 if (types[6 * a + 4] != types[4]) |
290 » » » » return a; | 309 break; |
291 » » » } | 310 } |
292 » » } | 311 if (a == (abbrevs - types) / 6) |
293 » } | 312 a = 0; |
294 | 313 if (types[6 * a + 4]) { |
295 » /* Try to find a neighboring opposite-DST-status rule. */ | 314 *alt = a; |
296 » if (alt) { | 315 return 0; |
297 » » if (a && types[6*index[a-1]+4] != types[6*index[a]+4]) | 316 } else { |
298 » » » *alt = index[a-1]; | 317 *alt = 0; |
299 » » else if (a+1<n && types[6*index[a+1]+4] != types[6*index[a]+4]) | 318 return a; |
300 » » » *alt = index[a+1]; | 319 } |
301 » » else | 320 } |
302 » » » *alt = index[a]; | 321 } |
303 » } | 322 |
304 | 323 /* Try to find a neighboring opposite-DST-status rule. */ |
305 » return index[a]; | 324 if (alt) { |
306 } | 325 if (a && types[6 * index[a - 1] + 4] != types[6 * index[a] + 4]) |
307 | 326 *alt = index[a - 1]; |
308 static int days_in_month(int m, int is_leap) | 327 else if (a + 1 < n && |
309 { | 328 types[6 * index[a + 1] + 4] != types[6 * index[a] + 4]) |
310 » if (m==2) return 28+is_leap; | 329 *alt = index[a + 1]; |
311 » else return 30+((0xad5>>(m-1))&1); | 330 else |
| 331 *alt = index[a]; |
| 332 } |
| 333 |
| 334 return index[a]; |
| 335 } |
| 336 |
| 337 static int days_in_month(int m, int is_leap) { |
| 338 if (m == 2) |
| 339 return 28 + is_leap; |
| 340 else |
| 341 return 30 + ((0xad5 >> (m - 1)) & 1); |
312 } | 342 } |
313 | 343 |
314 /* Convert a POSIX DST rule plus year to seconds since epoch. */ | 344 /* Convert a POSIX DST rule plus year to seconds since epoch. */ |
315 | 345 |
316 static long long rule_to_secs(const int *rule, int year) | 346 static long long rule_to_secs(const int* rule, int year) { |
317 { | 347 int is_leap; |
318 » int is_leap; | 348 long long t = __year_to_secs(year, &is_leap); |
319 » long long t = __year_to_secs(year, &is_leap); | 349 int x, m, n, d; |
320 » int x, m, n, d; | 350 if (rule[0] != 'M') { |
321 » if (rule[0]!='M') { | 351 x = rule[1]; |
322 » » x = rule[1]; | 352 if (rule[0] == 'J' && (x < 60 || !is_leap)) |
323 » » if (rule[0]=='J' && (x < 60 || !is_leap)) x--; | 353 x--; |
324 » » t += 86400 * x; | 354 t += 86400 * x; |
325 » } else { | 355 } else { |
326 » » m = rule[1]; | 356 m = rule[1]; |
327 » » n = rule[2]; | 357 n = rule[2]; |
328 » » d = rule[3]; | 358 d = rule[3]; |
329 » » t += __month_to_secs(m-1, is_leap); | 359 t += __month_to_secs(m - 1, is_leap); |
330 » » int wday = (int)((t + 4*86400) % (7*86400)) / 86400; | 360 int wday = (int)((t + 4 * 86400) % (7 * 86400)) / 86400; |
331 » » int days = d - wday; | 361 int days = d - wday; |
332 » » if (days < 0) days += 7; | 362 if (days < 0) |
333 » » if (n == 5 && days+28 >= days_in_month(m, is_leap)) n = 4; | 363 days += 7; |
334 » » t += 86400 * (days + 7*(n-1)); | 364 if (n == 5 && days + 28 >= days_in_month(m, is_leap)) |
335 » } | 365 n = 4; |
336 » t += rule[4]; | 366 t += 86400 * (days + 7 * (n - 1)); |
337 » return t; | 367 } |
| 368 t += rule[4]; |
| 369 return t; |
338 } | 370 } |
339 | 371 |
340 /* Determine the time zone in effect for a given time in seconds since the | 372 /* Determine the time zone in effect for a given time in seconds since the |
341 * epoch. It can be given in local or universal time. The results will | 373 * epoch. It can be given in local or universal time. The results will |
342 * indicate whether DST is in effect at the queried time, and will give both | 374 * indicate whether DST is in effect at the queried time, and will give both |
343 * the GMT offset for the active zone/DST rule and the opposite DST. This | 375 * the GMT offset for the active zone/DST rule and the opposite DST. This |
344 * enables a caller to efficiently adjust for the case where an explicit | 376 * enables a caller to efficiently adjust for the case where an explicit |
345 * DST specification mismatches what would be in effect at the time. */ | 377 * DST specification mismatches what would be in effect at the time. */ |
346 | 378 |
347 void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppo
ff, const char **zonename) | 379 void __secs_to_zone(long long t, |
348 { | 380 int local, |
349 » LOCK(lock); | 381 int* isdst, |
| 382 long* offset, |
| 383 long* oppoff, |
| 384 const char** zonename) { |
| 385 LOCK(lock); |
350 | 386 |
351 » do_tzset(); | 387 do_tzset(); |
352 | 388 |
353 » if (zi) { | 389 if (zi) { |
354 » » size_t alt, i = scan_trans(t, local, &alt); | 390 size_t alt, i = scan_trans(t, local, &alt); |
355 » » if (i != -1) { | 391 if (i != -1) { |
356 » » » *isdst = types[6*i+4]; | 392 *isdst = types[6 * i + 4]; |
357 » » » *offset = (int32_t)zi_read32(types+6*i); | 393 *offset = (int32_t)zi_read32(types + 6 * i); |
358 » » » *zonename = (const char *)abbrevs + types[6*i+5]; | 394 *zonename = (const char*)abbrevs + types[6 * i + 5]; |
359 » » » if (oppoff) *oppoff = (int32_t)zi_read32(types+6*alt); | 395 if (oppoff) |
360 » » » UNLOCK(lock); | 396 *oppoff = (int32_t)zi_read32(types + 6 * alt); |
361 » » » return; | 397 UNLOCK(lock); |
362 » » } | 398 return; |
363 » } | 399 } |
| 400 } |
364 | 401 |
365 » if (!__daylight) goto std; | 402 if (!__daylight) |
| 403 goto std; |
366 | 404 |
367 » /* FIXME: may be broken if DST changes right at year boundary? | 405 /* FIXME: may be broken if DST changes right at year boundary? |
368 » * Also, this could be more efficient.*/ | 406 * Also, this could be more efficient.*/ |
369 » long long y = t / 31556952 + 70; | 407 long long y = t / 31556952 + 70; |
370 » while (__year_to_secs(y, 0) > t) y--; | 408 while (__year_to_secs(y, 0) > t) |
371 » while (__year_to_secs(y+1, 0) < t) y++; | 409 y--; |
| 410 while (__year_to_secs(y + 1, 0) < t) |
| 411 y++; |
372 | 412 |
373 » long long t0 = rule_to_secs(r0, y); | 413 long long t0 = rule_to_secs(r0, y); |
374 » long long t1 = rule_to_secs(r1, y); | 414 long long t1 = rule_to_secs(r1, y); |
375 | 415 |
376 » if (t0 < t1) { | 416 if (t0 < t1) { |
377 » » if (!local) { | 417 if (!local) { |
378 » » » t0 += __timezone; | 418 t0 += __timezone; |
379 » » » t1 += dst_off; | 419 t1 += dst_off; |
380 » » } | 420 } |
381 » » if (t >= t0 && t < t1) goto dst; | 421 if (t >= t0 && t < t1) |
382 » » goto std; | 422 goto dst; |
383 » } else { | 423 goto std; |
384 » » if (!local) { | 424 } else { |
385 » » » t1 += __timezone; | 425 if (!local) { |
386 » » » t0 += dst_off; | 426 t1 += __timezone; |
387 » » } | 427 t0 += dst_off; |
388 » » if (t >= t1 && t < t0) goto std; | 428 } |
389 » » goto dst; | 429 if (t >= t1 && t < t0) |
390 » } | 430 goto std; |
| 431 goto dst; |
| 432 } |
391 std: | 433 std: |
392 » *isdst = 0; | 434 *isdst = 0; |
393 » *offset = -__timezone; | 435 *offset = -__timezone; |
394 » if (oppoff) *oppoff = -dst_off; | 436 if (oppoff) |
395 » *zonename = __tzname[0]; | 437 *oppoff = -dst_off; |
396 » UNLOCK(lock); | 438 *zonename = __tzname[0]; |
397 » return; | 439 UNLOCK(lock); |
| 440 return; |
398 dst: | 441 dst: |
399 » *isdst = 1; | 442 *isdst = 1; |
400 » *offset = -dst_off; | 443 *offset = -dst_off; |
401 » if (oppoff) *oppoff = -__timezone; | 444 if (oppoff) |
402 » *zonename = __tzname[1]; | 445 *oppoff = -__timezone; |
403 » UNLOCK(lock); | 446 *zonename = __tzname[1]; |
| 447 UNLOCK(lock); |
404 } | 448 } |
405 | 449 |
406 void __tzset() | 450 void __tzset() { |
407 { | 451 LOCK(lock); |
408 » LOCK(lock); | 452 do_tzset(); |
409 » do_tzset(); | 453 UNLOCK(lock); |
410 » UNLOCK(lock); | |
411 } | 454 } |
412 | 455 |
413 weak_alias(__tzset, tzset); | 456 weak_alias(__tzset, tzset); |
414 | 457 |
415 const char *__tm_to_tzname(const struct tm *tm) | 458 const char* __tm_to_tzname(const struct tm* tm) { |
416 { | 459 const void* p = tm->__tm_zone; |
417 » const void *p = tm->__tm_zone; | 460 LOCK(lock); |
418 » LOCK(lock); | 461 do_tzset(); |
419 » do_tzset(); | 462 if (p != __gmt && p != __tzname[0] && p != __tzname[1] && |
420 » if (p != __gmt && p != __tzname[0] && p != __tzname[1] && | 463 (!zi || (uintptr_t)p - (uintptr_t)abbrevs >= abbrevs_end - abbrevs)) |
421 » (!zi || (uintptr_t)p-(uintptr_t)abbrevs >= abbrevs_end - abbrevs)) | 464 p = ""; |
422 » » p = ""; | 465 UNLOCK(lock); |
423 » UNLOCK(lock); | 466 return p; |
424 » return p; | |
425 } | 467 } |
OLD | NEW |