Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6725 | siemargl | 1 | /* |
2 | Copyright (c) 1990-2001 Info-ZIP. All rights reserved. |
||
3 | |||
4 | See the accompanying file LICENSE, version 2000-Apr-09 or later |
||
5 | (the contents of which are also included in zip.h) for terms of use. |
||
6 | If, for some reason, all these files are missing, the Info-ZIP license |
||
7 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
8 | */ |
||
9 | /* Replacement time library functions, based on platform independent public |
||
10 | * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and |
||
11 | * mkgmtime from our own mktime.c in Zip. |
||
12 | * |
||
13 | * Contains: tzset() |
||
14 | * __tzset() |
||
15 | * gmtime() |
||
16 | * localtime() |
||
17 | * mktime() |
||
18 | * mkgmtime() |
||
19 | * GetPlatformLocalTimezone() [different versions] |
||
20 | */ |
||
21 | |||
22 | /* HISTORY/CHANGES |
||
23 | * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on |
||
24 | * to amiga/filedate.c, replacing GNU-based functions which had |
||
25 | * replaced time_lib.c, both having been rejected for licensing |
||
26 | * reasons. Support for timezone files and leap seconds was removed. |
||
27 | * |
||
28 | * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform |
||
29 | * independent, copied in mktime() and mkgmtime() from Zip, renamed |
||
30 | * locale_TZ as GetPlatformLocalTimezone(), for use as a generic |
||
31 | * hook by other platforms. |
||
32 | */ |
||
33 | |||
34 | #ifndef __timezone_c |
||
35 | #define __timezone_c |
||
36 | |||
37 | |||
38 | #include "zip.h" |
||
39 | #include "timezone.h" |
||
40 | #include |
||
41 | #include |
||
42 | |||
43 | #ifdef IZTZ_DEFINESTDGLOBALS |
||
44 | long timezone = 0; |
||
45 | int daylight = 0; |
||
46 | char *tzname[2]; |
||
47 | #endif |
||
48 | |||
49 | #ifndef IZTZ_GETLOCALETZINFO |
||
50 | # define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE) |
||
51 | #endif |
||
52 | |||
53 | int real_timezone_is_set = FALSE; /* set by tzset() */ |
||
54 | |||
55 | |||
56 | #define TZDEFRULESTRING ",M4.1.0,M10.5.0" |
||
57 | #define TZDEFAULT "EST5EDT" |
||
58 | |||
59 | #define SECSPERMIN 60 |
||
60 | #define MINSPERHOUR 60 |
||
61 | #define HOURSPERDAY 24 |
||
62 | #define DAYSPERWEEK 7 |
||
63 | #define DAYSPERNYEAR 365 |
||
64 | #define DAYSPERLYEAR 366 |
||
65 | #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) |
||
66 | #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) |
||
67 | #define MONSPERYEAR 12 |
||
68 | |||
69 | #define EPOCH_WDAY 4 /* Jan 1, 1970 was thursday */ |
||
70 | #define EPOCH_YEAR 1970 |
||
71 | #define TM_YEAR_BASE 1900 |
||
72 | #define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR) |
||
73 | #define LAST_GOOD_YEAR (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135)) |
||
74 | |||
75 | #define YDAYS(month, year) yr_days[leap(year)][month] |
||
76 | |||
77 | /* Nonzero if `y' is a leap year, else zero. */ |
||
78 | #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) |
||
79 | |||
80 | /* Number of leap years from EPOCH_YEAR to `y' (not including `y' itself). */ |
||
81 | #define _P4 ((EPOCH_YEAR / 4) * 4 + 1) |
||
82 | #define _P100 ((EPOCH_YEAR / 100) * 100 + 1) |
||
83 | #define _P400 ((EPOCH_YEAR / 400) * 400 + 1) |
||
84 | #define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400) |
||
85 | |||
86 | /* Length of month `m' (0 .. 11) */ |
||
87 | #define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \ |
||
88 | ((m) == 1 && leap(y))) |
||
89 | |||
90 | /* internal module-level constants */ |
||
91 | #ifndef IZ_MKTIME_ONLY |
||
92 | static ZCONST char gmt[] = "GMT"; |
||
93 | static ZCONST int mon_lengths[2][MONSPERYEAR] = { |
||
94 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
||
95 | { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } |
||
96 | }; |
||
97 | #endif /* !IZ_MKTIME_ONLY */ |
||
98 | static ZCONST int yr_days[2][MONSPERYEAR+1] = { |
||
99 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
||
100 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } |
||
101 | }; |
||
102 | #ifndef IZ_MKTIME_ONLY |
||
103 | static ZCONST int year_lengths[2] = { |
||
104 | DAYSPERNYEAR, DAYSPERLYEAR |
||
105 | }; |
||
106 | |||
107 | /* internal variables */ |
||
108 | static struct state statism; |
||
109 | |||
110 | |||
111 | /* prototypes of static functions */ |
||
112 | static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year, |
||
113 | ZCONST struct rule * ZCONST rulep, |
||
114 | ZCONST long offset)); |
||
115 | static void generate_transitions OF((register struct state * ZCONST sp, |
||
116 | ZCONST struct rule * ZCONST start, |
||
117 | ZCONST struct rule * ZCONST end)); |
||
118 | static ZCONST char *getzname OF((ZCONST char *strp)); |
||
119 | static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump, |
||
120 | ZCONST int min, ZCONST int max)); |
||
121 | static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp)); |
||
122 | static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp)); |
||
123 | static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep)); |
||
124 | static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp)); |
||
125 | |||
126 | |||
127 | static time_t transtime(janfirst, year, rulep, offset) |
||
128 | ZCONST time_t janfirst; |
||
129 | ZCONST int year; |
||
130 | ZCONST struct rule * ZCONST rulep; |
||
131 | ZCONST long offset; |
||
132 | { |
||
133 | register int leapyear; |
||
134 | register time_t value; |
||
135 | register int i; |
||
136 | int d, m1, yy0, yy1, yy2, dow; |
||
137 | |||
138 | value = 0; |
||
139 | leapyear = leap(year); |
||
140 | switch (rulep->r_type) { |
||
141 | |||
142 | case JULIAN_DAY: |
||
143 | /* |
||
144 | ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap |
||
145 | ** years. |
||
146 | ** In non-leap years, or if the day number is 59 or less, just |
||
147 | ** add SECSPERDAY times the day number-1 to the time of |
||
148 | ** January 1, midnight, to get the day. |
||
149 | */ |
||
150 | value = janfirst + (rulep->r_day - 1) * SECSPERDAY; |
||
151 | if (leapyear && rulep->r_day >= 60) |
||
152 | value += SECSPERDAY; |
||
153 | break; |
||
154 | |||
155 | case DAY_OF_YEAR: |
||
156 | /* |
||
157 | ** n - day of year. |
||
158 | ** Just add SECSPERDAY times the day number to the time of |
||
159 | ** January 1, midnight, to get the day. |
||
160 | */ |
||
161 | value = janfirst + rulep->r_day * SECSPERDAY; |
||
162 | break; |
||
163 | |||
164 | case MONTH_NTH_DAY_OF_WEEK: |
||
165 | /* |
||
166 | ** Mm.n.d - nth "dth day" of month m. |
||
167 | */ |
||
168 | value = janfirst; |
||
169 | /* |
||
170 | for (i = 0; i < rulep->r_mon - 1; ++i) |
||
171 | value += mon_lengths[leapyear][i] * SECSPERDAY; |
||
172 | */ |
||
173 | value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY; |
||
174 | |||
175 | /* |
||
176 | ** Use Zeller's Congruence to get day-of-week of first day of |
||
177 | ** month. |
||
178 | */ |
||
179 | m1 = (rulep->r_mon + 9) % 12 + 1; |
||
180 | yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; |
||
181 | yy1 = yy0 / 100; |
||
182 | yy2 = yy0 % 100; |
||
183 | dow = ((26 * m1 - 2) / 10 + |
||
184 | 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; |
||
185 | if (dow < 0) |
||
186 | dow += DAYSPERWEEK; |
||
187 | |||
188 | /* |
||
189 | ** "dow" is the day-of-week of the first day of the month. Get |
||
190 | ** the day-of-month (zero-origin) of the first "dow" day of the |
||
191 | ** month. |
||
192 | */ |
||
193 | d = rulep->r_day - dow; |
||
194 | if (d < 0) |
||
195 | d += DAYSPERWEEK; |
||
196 | for (i = 1; i < rulep->r_week; ++i) { |
||
197 | if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) |
||
198 | break; |
||
199 | d += DAYSPERWEEK; |
||
200 | } |
||
201 | |||
202 | /* |
||
203 | ** "d" is the day-of-month (zero-origin) of the day we want. |
||
204 | */ |
||
205 | value += d * SECSPERDAY; |
||
206 | break; |
||
207 | } |
||
208 | |||
209 | /* |
||
210 | ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in |
||
211 | ** question. To get the Epoch-relative time of the specified local |
||
212 | ** time on that day, add the transition time and the current offset |
||
213 | ** from UTC. |
||
214 | */ |
||
215 | return value + rulep->r_time + offset; |
||
216 | } |
||
217 | |||
218 | static void generate_transitions(sp, start, end) |
||
219 | register struct state * ZCONST sp; |
||
220 | ZCONST struct rule * ZCONST start; |
||
221 | ZCONST struct rule * ZCONST end; |
||
222 | { |
||
223 | register int year; |
||
224 | register time_t janfirst; |
||
225 | time_t starttime; |
||
226 | time_t endtime; |
||
227 | long stdoffset = -sp->ttis[0].tt_gmtoff; |
||
228 | long dstoffset = -sp->ttis[1].tt_gmtoff; |
||
229 | register time_t * atp; |
||
230 | register unsigned char * typep; |
||
231 | |||
232 | /* |
||
233 | ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR. |
||
234 | */ |
||
235 | sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1); |
||
236 | atp = sp->ats; |
||
237 | typep = sp->types; |
||
238 | janfirst = 0; |
||
239 | for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) { |
||
240 | starttime = transtime(janfirst, year, start, stdoffset); |
||
241 | endtime = transtime(janfirst, year, end, dstoffset); |
||
242 | if (starttime > endtime) { |
||
243 | *atp++ = endtime; |
||
244 | *typep++ = 0; /* DST ends */ |
||
245 | *atp++ = starttime; |
||
246 | *typep++ = 1; /* DST begins */ |
||
247 | } else { |
||
248 | *atp++ = starttime; |
||
249 | *typep++ = 1; /* DST begins */ |
||
250 | *atp++ = endtime; |
||
251 | *typep++ = 0; /* DST ends */ |
||
252 | } |
||
253 | janfirst += year_lengths[leap(year)] * SECSPERDAY; |
||
254 | } |
||
255 | } |
||
256 | |||
257 | static ZCONST char *getzname(strp) |
||
258 | ZCONST char *strp; |
||
259 | { |
||
260 | register char c; |
||
261 | |||
262 | while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && |
||
263 | c != '+') |
||
264 | ++strp; |
||
265 | return strp; |
||
266 | } |
||
267 | |||
268 | static ZCONST char *getnum(strp, nump, min, max) |
||
269 | ZCONST char *strp; |
||
270 | int * ZCONST nump; |
||
271 | ZCONST int min; |
||
272 | ZCONST int max; |
||
273 | { |
||
274 | register char c; |
||
275 | register int num; |
||
276 | |||
277 | if (strp == NULL || !isdigit(c = *strp)) |
||
278 | return NULL; |
||
279 | num = 0; |
||
280 | do { |
||
281 | num = num * 10 + (c - '0'); |
||
282 | if (num > max) |
||
283 | return NULL; /* illegal value */ |
||
284 | c = *++strp; |
||
285 | } while (isdigit(c)); |
||
286 | if (num < min) |
||
287 | return NULL; /* illegal value */ |
||
288 | *nump = num; |
||
289 | return strp; |
||
290 | } |
||
291 | |||
292 | static ZCONST char *getsecs(strp, secsp) |
||
293 | ZCONST char *strp; |
||
294 | long * ZCONST secsp; |
||
295 | { |
||
296 | int num; |
||
297 | |||
298 | /* |
||
299 | ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like |
||
300 | ** "M10.4.6/26", which does not conform to Posix, |
||
301 | ** but which specifies the equivalent of |
||
302 | ** ``02:00 on the first Sunday on or after 23 Oct''. |
||
303 | */ |
||
304 | strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); |
||
305 | if (strp == NULL) |
||
306 | return NULL; |
||
307 | *secsp = num * (long) SECSPERHOUR; |
||
308 | if (*strp == ':') { |
||
309 | ++strp; |
||
310 | strp = getnum(strp, &num, 0, MINSPERHOUR - 1); |
||
311 | if (strp == NULL) |
||
312 | return NULL; |
||
313 | *secsp += num * SECSPERMIN; |
||
314 | if (*strp == ':') { |
||
315 | ++strp; |
||
316 | /* `SECSPERMIN' allows for leap seconds. */ |
||
317 | strp = getnum(strp, &num, 0, SECSPERMIN); |
||
318 | if (strp == NULL) |
||
319 | return NULL; |
||
320 | *secsp += num; |
||
321 | } |
||
322 | } |
||
323 | return strp; |
||
324 | } |
||
325 | |||
326 | static ZCONST char *getoffset(strp, offsetp) |
||
327 | ZCONST char *strp; |
||
328 | long * ZCONST offsetp; |
||
329 | { |
||
330 | register int neg = 0; |
||
331 | |||
332 | if (*strp == '-') { |
||
333 | neg = 1; |
||
334 | ++strp; |
||
335 | } else if (*strp == '+') |
||
336 | ++strp; |
||
337 | strp = getsecs(strp, offsetp); |
||
338 | if (strp == NULL) |
||
339 | return NULL; /* illegal time */ |
||
340 | if (neg) |
||
341 | *offsetp = -*offsetp; |
||
342 | return strp; |
||
343 | } |
||
344 | |||
345 | static ZCONST char *getrule(strp, rulep) |
||
346 | ZCONST char *strp; |
||
347 | struct rule * ZCONST rulep; |
||
348 | { |
||
349 | if (*strp == 'J') { |
||
350 | /* |
||
351 | ** Julian day. |
||
352 | */ |
||
353 | rulep->r_type = JULIAN_DAY; |
||
354 | ++strp; |
||
355 | strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); |
||
356 | } else if (*strp == 'M') { |
||
357 | /* |
||
358 | ** Month, week, day. |
||
359 | */ |
||
360 | rulep->r_type = MONTH_NTH_DAY_OF_WEEK; |
||
361 | ++strp; |
||
362 | strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); |
||
363 | if (strp == NULL) |
||
364 | return NULL; |
||
365 | if (*strp++ != '.') |
||
366 | return NULL; |
||
367 | strp = getnum(strp, &rulep->r_week, 1, 5); |
||
368 | if (strp == NULL) |
||
369 | return NULL; |
||
370 | if (*strp++ != '.') |
||
371 | return NULL; |
||
372 | strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); |
||
373 | } else if (isdigit(*strp)) { |
||
374 | /* |
||
375 | ** Day of year. |
||
376 | */ |
||
377 | rulep->r_type = DAY_OF_YEAR; |
||
378 | strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); |
||
379 | } else return NULL; /* invalid format */ |
||
380 | if (strp == NULL) |
||
381 | return NULL; |
||
382 | if (*strp == '/') { |
||
383 | /* |
||
384 | ** Time specified. |
||
385 | */ |
||
386 | ++strp; |
||
387 | strp = getsecs(strp, &rulep->r_time); |
||
388 | } else |
||
389 | rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ |
||
390 | return strp; |
||
391 | } |
||
392 | |||
393 | static int Parse_TZ(name, sp) |
||
394 | ZCONST char *name; |
||
395 | register struct state * ZCONST sp; |
||
396 | { |
||
397 | ZCONST char * stdname; |
||
398 | ZCONST char * dstname; |
||
399 | size_t stdlen; |
||
400 | size_t dstlen; |
||
401 | long stdoffset; |
||
402 | long dstoffset; |
||
403 | register char * cp; |
||
404 | |||
405 | dstname = NULL; |
||
406 | stdname = name; |
||
407 | name = getzname(name); |
||
408 | stdlen = name - stdname; |
||
409 | if (stdlen < 3) |
||
410 | return -1; |
||
411 | if (*name == '\0') |
||
412 | return -1; |
||
413 | name = getoffset(name, &stdoffset); |
||
414 | if (name == NULL) |
||
415 | return -1; |
||
416 | if (*name != '\0') { |
||
417 | dstname = name; |
||
418 | name = getzname(name); |
||
419 | dstlen = name - dstname; /* length of DST zone name */ |
||
420 | if (dstlen < 3) |
||
421 | return -1; |
||
422 | if (*name != '\0' && *name != ',' && *name != ';') { |
||
423 | name = getoffset(name, &dstoffset); |
||
424 | if (name == NULL) |
||
425 | return -1; |
||
426 | } else |
||
427 | dstoffset = stdoffset - SECSPERHOUR; |
||
428 | if (*name == '\0') |
||
429 | name = TZDEFRULESTRING; |
||
430 | if (*name == ',' || *name == ';') { |
||
431 | struct rule start; |
||
432 | struct rule end; |
||
433 | |||
434 | ++name; |
||
435 | if ((name = getrule(name, &start)) == NULL) |
||
436 | return -1; |
||
437 | if (*name++ != ',') |
||
438 | return -1; |
||
439 | if ((name = getrule(name, &end)) == NULL) |
||
440 | return -1; |
||
441 | if (*name != '\0') |
||
442 | return -1; |
||
443 | sp->typecnt = 2; /* standard time and DST */ |
||
444 | sp->ttis[0].tt_gmtoff = -stdoffset; |
||
445 | sp->ttis[0].tt_isdst = 0; |
||
446 | sp->ttis[0].tt_abbrind = 0; |
||
447 | sp->ttis[1].tt_gmtoff = -dstoffset; |
||
448 | sp->ttis[1].tt_isdst = 1; |
||
449 | sp->ttis[1].tt_abbrind = stdlen + 1; |
||
450 | generate_transitions(sp, &start, &end); |
||
451 | } |
||
452 | } else { |
||
453 | dstlen = 0; |
||
454 | sp->typecnt = 1; /* only standard time */ |
||
455 | sp->timecnt = 0; |
||
456 | sp->ttis[0].tt_gmtoff = -stdoffset; |
||
457 | sp->ttis[0].tt_isdst = 0; |
||
458 | sp->ttis[0].tt_abbrind = 0; |
||
459 | } |
||
460 | sp->charcnt = stdlen + 1; |
||
461 | if (dstlen != 0) |
||
462 | sp->charcnt += dstlen + 1; |
||
463 | if ((size_t) sp->charcnt > sizeof(sp->chars)) |
||
464 | return -1; |
||
465 | cp = sp->chars; |
||
466 | (void) strncpy(cp, stdname, stdlen); |
||
467 | cp += stdlen; |
||
468 | *cp++ = '\0'; |
||
469 | if (dstlen != 0) { |
||
470 | (void) strncpy(cp, dstname, dstlen); |
||
471 | *(cp + dstlen) = '\0'; |
||
472 | } |
||
473 | return 0; |
||
474 | } |
||
475 | |||
476 | void tzset() |
||
477 | { |
||
478 | char *TZstring; |
||
479 | int dstfirst; |
||
480 | static char *old_TZstring = NULL; |
||
481 | |||
482 | TZstring = getenv("TZ"); /* read TZ envvar */ |
||
483 | if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring)) |
||
484 | /* do not repeatedly parse an unchanged TZ specification */ |
||
485 | return; |
||
486 | if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0) |
||
487 | || IZTZ_GETLOCALETZINFO(&statism, generate_transitions) |
||
488 | || Parse_TZ(gmt, &statism) == 0) { |
||
489 | daylight = statism.typecnt > 1; |
||
490 | dstfirst = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst; |
||
491 | timezone = -statism.ttis[dstfirst].tt_gmtoff; |
||
492 | tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind; |
||
493 | tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind; |
||
494 | real_timezone_is_set = TRUE; |
||
495 | if (TZstring) { |
||
496 | if (old_TZstring) |
||
497 | old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1); |
||
498 | else |
||
499 | old_TZstring = malloc(strlen(TZstring) + 1); |
||
500 | if (old_TZstring) |
||
501 | strcpy(old_TZstring, TZstring); |
||
502 | } |
||
503 | } else { |
||
504 | timezone = 0; /* default is GMT0 which means no offsets */ |
||
505 | daylight = 0; /* from local system time */ |
||
506 | real_timezone_is_set = FALSE; |
||
507 | if (old_TZstring) { |
||
508 | free(old_TZstring); |
||
509 | old_TZstring = NULL; |
||
510 | } |
||
511 | } |
||
512 | #ifdef IZTZ_SETLOCALTZINFO |
||
513 | /* Some SAS/C library functions, e.g. stat(), call library */ |
||
514 | /* __tzset() themselves. So envvar TZ *must* exist in order to */ |
||
515 | /* to get the right offset from GMT. XXX TRY HARD to fix this! */ |
||
516 | set_TZ(timezone, daylight); |
||
517 | #endif /* IZTZ_SETLOCALTZINFO */ |
||
518 | } |
||
519 | |||
520 | /* XXX Does this also help SAS/C library work? */ |
||
521 | void __tzset() |
||
522 | { |
||
523 | if (!real_timezone_is_set) tzset(); |
||
524 | } |
||
525 | |||
526 | static struct tm _tmbuf; |
||
527 | |||
528 | struct tm *gmtime(when) |
||
529 | ZCONST time_t *when; |
||
530 | { |
||
531 | long days = *when / SECSPERDAY; |
||
532 | long secs = *when % SECSPERDAY; |
||
533 | int isleap; |
||
534 | |||
535 | memset(&_tmbuf, 0, sizeof(_tmbuf)); /* get any nonstandard fields */ |
||
536 | _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7; |
||
537 | _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE; |
||
538 | isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE); |
||
539 | while (days >= year_lengths[isleap]) { |
||
540 | days -= year_lengths[isleap]; |
||
541 | _tmbuf.tm_year++; |
||
542 | isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE); |
||
543 | } |
||
544 | _tmbuf.tm_mon = 0; |
||
545 | _tmbuf.tm_yday = days; |
||
546 | while (days >= mon_lengths[isleap][_tmbuf.tm_mon]) |
||
547 | days -= mon_lengths[isleap][_tmbuf.tm_mon++]; |
||
548 | _tmbuf.tm_mday = days + 1; |
||
549 | _tmbuf.tm_isdst = 0; |
||
550 | _tmbuf.tm_sec = secs % SECSPERMIN; |
||
551 | _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN; |
||
552 | _tmbuf.tm_hour = secs / SECSPERHOUR; |
||
553 | return &_tmbuf; |
||
554 | } |
||
555 | |||
556 | struct tm *localtime(when) |
||
557 | ZCONST time_t *when; |
||
558 | { |
||
559 | time_t localwhen = *when; |
||
560 | int timetype; |
||
561 | struct tm *ret; |
||
562 | |||
563 | __tzset(); |
||
564 | if (statism.timecnt == 0 || localwhen < statism.ats[0]) |
||
565 | timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 && |
||
566 | !statism.ttis[1].tt_isdst; |
||
567 | else { |
||
568 | for (timetype = 1; timetype < statism.timecnt; ++timetype) |
||
569 | if (localwhen < statism.ats[timetype]) |
||
570 | break; |
||
571 | timetype = statism.types[timetype - 1]; |
||
572 | } |
||
573 | localwhen += statism.ttis[timetype].tt_gmtoff; |
||
574 | ret = gmtime(&localwhen); |
||
575 | ret->tm_isdst = statism.ttis[timetype].tt_isdst; |
||
576 | return ret; |
||
577 | } |
||
578 | |||
579 | #ifdef NEED__ISINDST |
||
580 | int _isindst(tb) |
||
581 | struct tm *tb; |
||
582 | { |
||
583 | time_t localt; /* time_t equivalent of given tm struct */ |
||
584 | time_t univt; /* assumed UTC value of given time */ |
||
585 | long tzoffset_adj; /* timezone-adjustment `remainder' */ |
||
586 | int bailout_cnt; /* counter of tries for tz correction */ |
||
587 | int timetype; |
||
588 | |||
589 | __tzset(); |
||
590 | |||
591 | /* when DST is unsupported in current timezone, DST is always off */ |
||
592 | if (statism.typecnt <= 1) return FALSE; |
||
593 | |||
594 | localt = mkgmtime(tb); |
||
595 | if (localt == (time_t)-1) |
||
596 | /* specified time is out-of-range, default to FALSE */ |
||
597 | return FALSE; |
||
598 | |||
599 | univt = localt - statism.ttis[0].tt_gmtoff; |
||
600 | bailout_cnt = 3; |
||
601 | do { |
||
602 | if (statism.timecnt == 0 || univt < statism.ats[0]) |
||
603 | timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 && |
||
604 | !statism.ttis[1].tt_isdst; |
||
605 | else { |
||
606 | for (timetype = 1; timetype < statism.timecnt; ++timetype) |
||
607 | if (univt < statism.ats[timetype]) |
||
608 | break; |
||
609 | timetype = statism.types[timetype - 1]; |
||
610 | } |
||
611 | if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff) |
||
612 | == 0L) |
||
613 | break; |
||
614 | univt += tzoffset_adj; |
||
615 | } while (--bailout_cnt > 0); |
||
616 | |||
617 | /* return TRUE when DST is active at given time */ |
||
618 | return (statism.ttis[timetype].tt_isdst); |
||
619 | } |
||
620 | #endif /* NEED__ISINDST */ |
||
621 | #endif /* !IZ_MKTIME_ONLY */ |
||
622 | |||
623 | /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT |
||
624 | of the local time and date in the exploded time structure `tm', |
||
625 | adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'. |
||
626 | If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of |
||
627 | tm_isdst is determined and returned. Otherwise, mktime() assumes this |
||
628 | field as valid; its information is used when converting local time |
||
629 | to UTC. |
||
630 | Return -1 if time in `tm' cannot be represented as time_t value. */ |
||
631 | |||
632 | time_t mktime(tm) |
||
633 | struct tm *tm; |
||
634 | { |
||
635 | struct tm *ltm; /* Local time. */ |
||
636 | time_t loctime; /* The time_t value of local time. */ |
||
637 | time_t then; /* The time to return. */ |
||
638 | long tzoffset_adj; /* timezone-adjustment `remainder' */ |
||
639 | int bailout_cnt; /* counter of tries for tz correction */ |
||
640 | int save_isdst; /* Copy of the tm->isdst input value */ |
||
641 | |||
642 | save_isdst = tm->tm_isdst; |
||
643 | loctime = mkgmtime(tm); |
||
644 | if (loctime == -1) { |
||
645 | tm->tm_isdst = save_isdst; |
||
646 | return (time_t)-1; |
||
647 | } |
||
648 | |||
649 | /* Correct for the timezone and any daylight savings time. |
||
650 | The correction is verified and repeated when not correct, to |
||
651 | take into account the rare case that a change to or from daylight |
||
652 | savings time occurs between when it is the time in `tm' locally |
||
653 | and when it is that time in Greenwich. After the second correction, |
||
654 | the "timezone & daylight" offset should be correct in all cases. To |
||
655 | be sure, we allow a third try, but then the loop is stopped. */ |
||
656 | bailout_cnt = 3; |
||
657 | then = loctime; |
||
658 | do { |
||
659 | ltm = localtime(&then); |
||
660 | if (ltm == (struct tm *)NULL || |
||
661 | (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L) |
||
662 | break; |
||
663 | then += tzoffset_adj; |
||
664 | } while (--bailout_cnt > 0); |
||
665 | |||
666 | if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) { |
||
667 | /* Signal failure if timezone adjustment did not converge. */ |
||
668 | tm->tm_isdst = save_isdst; |
||
669 | return (time_t)-1; |
||
670 | } |
||
671 | |||
672 | if (save_isdst >= 0) { |
||
673 | if (ltm->tm_isdst && !save_isdst) |
||
674 | { |
||
675 | if (then + 3600 < then) |
||
676 | then = (time_t)-1; |
||
677 | else |
||
678 | then += 3600; |
||
679 | } |
||
680 | else if (!ltm->tm_isdst && save_isdst) |
||
681 | { |
||
682 | if (then - 3600 > then) |
||
683 | then = (time_t)-1; |
||
684 | else |
||
685 | then -= 3600; |
||
686 | } |
||
687 | ltm->tm_isdst = save_isdst; |
||
688 | } |
||
689 | |||
690 | if (tm != ltm) /* `tm' may already point to localtime's internal storage */ |
||
691 | *tm = *ltm; |
||
692 | |||
693 | return then; |
||
694 | } |
||
695 | |||
696 | |||
697 | #ifndef NO_TIME_T_MAX |
||
698 | /* Provide default values for the upper limit of the time_t range. |
||
699 | These are the result of the decomposition into a `struct tm' for |
||
700 | the time value 0xFFFFFFFEL ( = (time_t)-2 ). |
||
701 | Note: `(time_t)-1' is reserved for "invalid time"! */ |
||
702 | # ifndef TM_YEAR_MAX |
||
703 | # define TM_YEAR_MAX 2106 |
||
704 | # endif |
||
705 | # ifndef TM_MON_MAX |
||
706 | # define TM_MON_MAX 1 /* February */ |
||
707 | # endif |
||
708 | # ifndef TM_MDAY_MAX |
||
709 | # define TM_MDAY_MAX 7 |
||
710 | # endif |
||
711 | # ifndef TM_HOUR_MAX |
||
712 | # define TM_HOUR_MAX 6 |
||
713 | # endif |
||
714 | # ifndef TM_MIN_MAX |
||
715 | # define TM_MIN_MAX 28 |
||
716 | # endif |
||
717 | # ifndef TM_SEC_MAX |
||
718 | # define TM_SEC_MAX 14 |
||
719 | # endif |
||
720 | #endif /* NO_TIME_T_MAX */ |
||
721 | |||
722 | /* Adjusts out-of-range values for `tm' field `tm_member'. */ |
||
723 | #define ADJUST_TM(tm_member, tm_carry, modulus) \ |
||
724 | if ((tm_member) < 0) { \ |
||
725 | tm_carry -= (1 - ((tm_member)+1) / (modulus)); \ |
||
726 | tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \ |
||
727 | } else if ((tm_member) >= (modulus)) { \ |
||
728 | tm_carry += (tm_member) / (modulus); \ |
||
729 | tm_member = (tm_member) % (modulus); \ |
||
730 | } |
||
731 | |||
732 | /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT |
||
733 | of the Greenwich Mean time and date in the exploded time structure `tm'. |
||
734 | This function does always put back normalized values into the `tm' struct, |
||
735 | parameter, including the calculated numbers for `tm->tm_yday', |
||
736 | `tm->tm_wday', and `tm->tm_isdst'. |
||
737 | Returns -1 if the time in the `tm' parameter cannot be represented |
||
738 | as valid `time_t' number. */ |
||
739 | |||
740 | time_t mkgmtime(tm) |
||
741 | struct tm *tm; |
||
742 | { |
||
743 | int years, months, days, hours, minutes, seconds; |
||
744 | |||
745 | years = tm->tm_year + TM_YEAR_BASE; /* year - 1900 -> year */ |
||
746 | months = tm->tm_mon; /* 0..11 */ |
||
747 | days = tm->tm_mday - 1; /* 1..31 -> 0..30 */ |
||
748 | hours = tm->tm_hour; /* 0..23 */ |
||
749 | minutes = tm->tm_min; /* 0..59 */ |
||
750 | seconds = tm->tm_sec; /* 0..61 in ANSI C. */ |
||
751 | |||
752 | ADJUST_TM(seconds, minutes, 60) |
||
753 | ADJUST_TM(minutes, hours, 60) |
||
754 | ADJUST_TM(hours, days, 24) |
||
755 | ADJUST_TM(months, years, 12) |
||
756 | if (days < 0) |
||
757 | do { |
||
758 | if (--months < 0) { |
||
759 | --years; |
||
760 | months = 11; |
||
761 | } |
||
762 | days += monthlen(months, years); |
||
763 | } while (days < 0); |
||
764 | else |
||
765 | while (days >= monthlen(months, years)) { |
||
766 | days -= monthlen(months, years); |
||
767 | if (++months >= 12) { |
||
768 | ++years; |
||
769 | months = 0; |
||
770 | } |
||
771 | } |
||
772 | |||
773 | /* Restore adjusted values in tm structure */ |
||
774 | tm->tm_year = years - TM_YEAR_BASE; |
||
775 | tm->tm_mon = months; |
||
776 | tm->tm_mday = days + 1; |
||
777 | tm->tm_hour = hours; |
||
778 | tm->tm_min = minutes; |
||
779 | tm->tm_sec = seconds; |
||
780 | |||
781 | /* Set `days' to the number of days into the year. */ |
||
782 | days += YDAYS(months, years); |
||
783 | tm->tm_yday = days; |
||
784 | |||
785 | /* Now calculate `days' to the number of days since Jan 1, 1970. */ |
||
786 | days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) + |
||
787 | (unsigned)(nleap (years)); |
||
788 | tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7; |
||
789 | tm->tm_isdst = 0; |
||
790 | |||
791 | if (years < EPOCH_YEAR) |
||
792 | return (time_t)-1; |
||
793 | |||
794 | #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX)) |
||
795 | #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX)) |
||
796 | if (years > TM_YEAR_MAX || |
||
797 | (years == TM_YEAR_MAX && |
||
798 | (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) || |
||
799 | (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) && |
||
800 | (hours > TM_HOUR_MAX || |
||
801 | (hours == TM_HOUR_MAX && |
||
802 | (minutes > TM_MIN_MAX || |
||
803 | (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) ))))))) |
||
804 | return (time_t)-1; |
||
805 | #endif |
||
806 | #endif |
||
807 | |||
808 | return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days + |
||
809 | SECSPERHOUR * (unsigned long)hours + |
||
810 | (unsigned long)(SECSPERMIN * minutes + seconds)); |
||
811 | } |
||
812 | |||
813 | #endif /* __timezone_c */>>>>>>>>>>=>>>>>>>=>>>>=>>>> |