Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | #include |
2 | #include |
||
3 | #include |
||
4 | #include |
||
5 | #include |
||
6 | #include |
||
7 | #include |
||
8 | #include |
||
9 | #include |
||
10 | #include |
||
11 | #include "posixrul.h" |
||
12 | |||
13 | #define P(s) s |
||
14 | #define alloc_size_t size_t |
||
15 | #define qsort_size_t size_t |
||
16 | #define fread_size_t size_t |
||
17 | #define fwrite_size_t size_t |
||
18 | |||
19 | #define ACCESS_MODE O_RDONLY|O_BINARY |
||
20 | #define OPEN_MODE O_RDONLY|O_BINARY |
||
21 | |||
22 | static char WILDABBR[] = " "; |
||
23 | |||
24 | #ifndef TRUE |
||
25 | #define TRUE 1 |
||
26 | #define FALSE 0 |
||
27 | #endif /* !defined TRUE */ |
||
28 | |||
29 | static const char GMT[] = "GMT"; |
||
30 | |||
31 | struct ttinfo { /* time type information */ |
||
32 | long tt_gmtoff; /* GMT offset in seconds */ |
||
33 | int tt_isdst; /* used to set tm_isdst */ |
||
34 | int tt_abbrind; /* abbreviation list index */ |
||
35 | int tt_ttisstd; /* TRUE if transition is std time */ |
||
36 | }; |
||
37 | |||
38 | struct lsinfo { /* leap second information */ |
||
39 | time_t ls_trans; /* transition time */ |
||
40 | long ls_corr; /* correction to apply */ |
||
41 | }; |
||
42 | |||
43 | struct state { |
||
44 | int leapcnt; |
||
45 | int timecnt; |
||
46 | int typecnt; |
||
47 | int charcnt; |
||
48 | time_t ats[TZ_MAX_TIMES]; |
||
49 | unsigned char types[TZ_MAX_TIMES]; |
||
50 | struct ttinfo ttis[TZ_MAX_TYPES]; |
||
51 | char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? TZ_MAX_CHARS + 1 : sizeof GMT]; |
||
52 | struct lsinfo lsis[TZ_MAX_LEAPS]; |
||
53 | }; |
||
54 | |||
55 | struct rule { |
||
56 | int r_type; /* type of rule--see below */ |
||
57 | int r_day; /* day number of rule */ |
||
58 | int r_week; /* week number of rule */ |
||
59 | int r_mon; /* month number of rule */ |
||
60 | long r_time; /* transition time of rule */ |
||
61 | }; |
||
62 | |||
63 | #define JULIAN_DAY 0 /* Jn - Julian day */ |
||
64 | #define DAY_OF_YEAR 1 /* n - day of year */ |
||
65 | #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ |
||
66 | |||
67 | /* |
||
68 | ** Prototypes for static functions. |
||
69 | */ |
||
70 | |||
71 | static long detzcode P((const char * codep)); |
||
72 | static const char * getzname P((const char * strp)); |
||
73 | static const char * getnum P((const char * strp, int * nump, int min, |
||
74 | int max)); |
||
75 | static const char * getsecs P((const char * strp, long * secsp)); |
||
76 | static const char * getoffset P((const char * strp, long * offsetp)); |
||
77 | static const char * getrule P((const char * strp, struct rule * rulep)); |
||
78 | static void gmtload P((struct state * sp)); |
||
79 | static void gmtsub P((const time_t * timep, long offset, |
||
80 | struct tm * tmp)); |
||
81 | static void localsub P((const time_t * timep, long offset, |
||
82 | struct tm * tmp)); |
||
83 | static void normalize P((int * tensptr, int * unitsptr, int base)); |
||
84 | static void settzname P((void)); |
||
85 | static time_t time1 P((struct tm * tmp, void (* funcp)(const time_t * const, const long, struct tm * const), |
||
86 | long offset)); |
||
87 | static time_t time2 P((struct tm *tmp, void (* funcp)(const time_t * const, const long, struct tm * const), |
||
88 | long offset, int * okayp)); |
||
89 | static void timesub P((const time_t * timep, long offset, |
||
90 | const struct state * sp, struct tm * tmp)); |
||
91 | static int tmcomp P((const struct tm * atmp, |
||
92 | const struct tm * btmp)); |
||
93 | static time_t transtime P((time_t janfirst, int year, |
||
94 | const struct rule * rulep, long offset)); |
||
95 | static int tzparse P((const char * name, struct state * sp, |
||
96 | int lastditch)); |
||
97 | //static void tzsetwall(void); |
||
98 | |||
99 | #ifdef ALL_STATE |
||
100 | static struct state *lclptr; |
||
101 | static struct state *gmtptr; |
||
102 | #endif /* defined ALL_STATE */ |
||
103 | |||
104 | #ifndef ALL_STATE |
||
105 | static struct state lclmem; |
||
106 | static struct state gmtmem; |
||
107 | #define lclptr (&lclmem) |
||
108 | #define gmtptr (&gmtmem) |
||
109 | #endif /* State Farm */ |
||
110 | |||
111 | static int lcl_is_set; |
||
112 | static int gmt_is_set; |
||
113 | |||
114 | char * tzname[2] = { |
||
115 | WILDABBR, |
||
116 | WILDABBR |
||
117 | }; |
||
118 | |||
119 | static long |
||
120 | detzcode(const char * const codep) |
||
121 | { |
||
122 | long result; |
||
123 | int i; |
||
124 | |||
125 | result = 0; |
||
126 | for (i = 0; i < 4; ++i) |
||
127 | result = (result << 8) | (codep[i] & 0xff); |
||
128 | return result; |
||
129 | } |
||
130 | |||
131 | static void |
||
132 | settzname(void) |
||
133 | { |
||
134 | const struct state * const sp = lclptr; |
||
135 | int i; |
||
136 | |||
137 | tzname[0] = WILDABBR; |
||
138 | tzname[1] = WILDABBR; |
||
139 | #ifdef ALL_STATE |
||
140 | if (sp == NULL) |
||
141 | { |
||
142 | tzname[0] = tzname[1] = GMT; |
||
143 | return; |
||
144 | } |
||
145 | #endif /* defined ALL_STATE */ |
||
146 | for (i = 0; i < sp->typecnt; ++i) |
||
147 | { |
||
148 | register const struct ttinfo * const ttisp = &sp->ttis[i]; |
||
149 | |||
150 | tzname[ttisp->tt_isdst] = |
||
151 | unconst(&sp->chars[ttisp->tt_abbrind], char *); |
||
152 | #if 0 |
||
153 | if (ttisp->tt_isdst) |
||
154 | _daylight = 1; |
||
155 | if (i == 0 || !ttisp->tt_isdst) |
||
156 | _timezone = -(ttisp->tt_gmtoff); |
||
157 | if (i == 0 || ttisp->tt_isdst) |
||
158 | _altzone = -(ttisp->tt_gmtoff); |
||
159 | #endif |
||
160 | } |
||
161 | /* |
||
162 | ** And to get the latest zone names into tzname. . . |
||
163 | */ |
||
164 | for (i = 0; i < sp->timecnt; ++i) |
||
165 | { |
||
166 | const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]]; |
||
167 | |||
168 | tzname[ttisp->tt_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
||
169 | } |
||
170 | } |
||
171 | |||
172 | static const int mon_lengths[2][MONSPERYEAR] = { |
||
173 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
||
174 | { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } |
||
175 | }; |
||
176 | |||
177 | static const int year_lengths[2] = { |
||
178 | DAYSPERNYEAR, DAYSPERLYEAR |
||
179 | }; |
||
180 | |||
181 | /* |
||
182 | ** Given a pointer into a time zone string, scan until a character that is not |
||
183 | ** a valid character in a zone name is found. Return a pointer to that |
||
184 | ** character. |
||
185 | */ |
||
186 | |||
187 | static const char * |
||
188 | getzname(const char *strp) |
||
189 | { |
||
190 | char c; |
||
191 | |||
192 | while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && |
||
193 | c != '+') |
||
194 | ++strp; |
||
195 | return strp; |
||
196 | } |
||
197 | |||
198 | /* |
||
199 | ** Given a pointer into a time zone string, extract a number from that string. |
||
200 | ** Check that the number is within a specified range; if it is not, return |
||
201 | ** NULL. |
||
202 | ** Otherwise, return a pointer to the first character not part of the number. |
||
203 | */ |
||
204 | |||
205 | static const char * |
||
206 | getnum(const char *strp, int * const nump, const int min, const int max) |
||
207 | { |
||
208 | char c; |
||
209 | int num; |
||
210 | |||
211 | if (strp == NULL || !isdigit(*strp)) |
||
212 | return NULL; |
||
213 | num = 0; |
||
214 | while ((c = *strp) != '\0' && isdigit(c)) |
||
215 | { |
||
216 | num = num * 10 + (c - '0'); |
||
217 | if (num > max) |
||
218 | return NULL; |
||
219 | ++strp; |
||
220 | } |
||
221 | if (num < min) |
||
222 | return NULL; |
||
223 | *nump = num; |
||
224 | return strp; |
||
225 | } |
||
226 | |||
227 | /* |
||
228 | ** Given a pointer into a time zone string, extract a number of seconds, |
||
229 | ** in hh[:mm[:ss]] form, from the string. |
||
230 | ** If any error occurs, return NULL. |
||
231 | ** Otherwise, return a pointer to the first character not part of the number |
||
232 | ** of seconds. |
||
233 | */ |
||
234 | |||
235 | static const char * |
||
236 | getsecs(const char *strp, long * const secsp) |
||
237 | { |
||
238 | int num; |
||
239 | |||
240 | strp = getnum(strp, &num, 0, HOURSPERDAY); |
||
241 | if (strp == NULL) |
||
242 | return NULL; |
||
243 | *secsp = num * SECSPERHOUR; |
||
244 | if (*strp == ':') |
||
245 | { |
||
246 | ++strp; |
||
247 | strp = getnum(strp, &num, 0, MINSPERHOUR - 1); |
||
248 | if (strp == NULL) |
||
249 | return NULL; |
||
250 | *secsp += num * SECSPERMIN; |
||
251 | if (*strp == ':') |
||
252 | { |
||
253 | ++strp; |
||
254 | strp = getnum(strp, &num, 0, SECSPERMIN - 1); |
||
255 | if (strp == NULL) |
||
256 | return NULL; |
||
257 | *secsp += num; |
||
258 | } |
||
259 | } |
||
260 | return strp; |
||
261 | } |
||
262 | |||
263 | /* |
||
264 | ** Given a pointer into a time zone string, extract an offset, in |
||
265 | ** [+-]hh[:mm[:ss]] form, from the string. |
||
266 | ** If any error occurs, return NULL. |
||
267 | ** Otherwise, return a pointer to the first character not part of the time. |
||
268 | */ |
||
269 | |||
270 | static const char * |
||
271 | getoffset(const char *strp, long * const offsetp) |
||
272 | { |
||
273 | int neg; |
||
274 | |||
275 | if (*strp == '-') |
||
276 | { |
||
277 | neg = 1; |
||
278 | ++strp; |
||
279 | } |
||
280 | else if (isdigit(*strp) || *strp++ == '+') |
||
281 | neg = 0; |
||
282 | else |
||
283 | return NULL; /* illegal offset */ |
||
284 | strp = getsecs(strp, offsetp); |
||
285 | if (strp == NULL) |
||
286 | return NULL; /* illegal time */ |
||
287 | if (neg) |
||
288 | *offsetp = -*offsetp; |
||
289 | return strp; |
||
290 | } |
||
291 | |||
292 | /* |
||
293 | ** Given a pointer into a time zone string, extract a rule in the form |
||
294 | ** date[/time]. See POSIX section 8 for the format of "date" and "time". |
||
295 | ** If a valid rule is not found, return NULL. |
||
296 | ** Otherwise, return a pointer to the first character not part of the rule. |
||
297 | */ |
||
298 | |||
299 | static const char * |
||
300 | getrule(const char *strp, struct rule * const rulep) |
||
301 | { |
||
302 | if (*strp == 'J') |
||
303 | { |
||
304 | /* |
||
305 | ** Julian day. |
||
306 | */ |
||
307 | rulep->r_type = JULIAN_DAY; |
||
308 | ++strp; |
||
309 | strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); |
||
310 | } |
||
311 | else if (*strp == 'M') |
||
312 | { |
||
313 | /* |
||
314 | ** Month, week, day. |
||
315 | */ |
||
316 | rulep->r_type = MONTH_NTH_DAY_OF_WEEK; |
||
317 | ++strp; |
||
318 | strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); |
||
319 | if (strp == NULL) |
||
320 | return NULL; |
||
321 | if (*strp++ != '.') |
||
322 | return NULL; |
||
323 | strp = getnum(strp, &rulep->r_week, 1, 5); |
||
324 | if (strp == NULL) |
||
325 | return NULL; |
||
326 | if (*strp++ != '.') |
||
327 | return NULL; |
||
328 | strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); |
||
329 | } |
||
330 | else if (isdigit(*strp)) |
||
331 | { |
||
332 | /* |
||
333 | ** Day of year. |
||
334 | */ |
||
335 | rulep->r_type = DAY_OF_YEAR; |
||
336 | strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); |
||
337 | } |
||
338 | else |
||
339 | return NULL; /* invalid format */ |
||
340 | if (strp == NULL) |
||
341 | return NULL; |
||
342 | if (*strp == '/') |
||
343 | { |
||
344 | /* |
||
345 | ** Time specified. |
||
346 | */ |
||
347 | ++strp; |
||
348 | strp = getsecs(strp, &rulep->r_time); |
||
349 | } |
||
350 | else |
||
351 | rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ |
||
352 | return strp; |
||
353 | } |
||
354 | |||
355 | /* |
||
356 | ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the |
||
357 | ** year, a rule, and the offset from GMT at the time that rule takes effect, |
||
358 | ** calculate the Epoch-relative time that rule takes effect. |
||
359 | */ |
||
360 | |||
361 | static time_t |
||
362 | transtime(const time_t janfirst, const int year, const struct rule * const rulep, const long offset) |
||
363 | { |
||
364 | int leapyear; |
||
365 | time_t value=0; |
||
366 | int i; |
||
367 | int d, m1, yy0, yy1, yy2, dow; |
||
368 | |||
369 | leapyear = isleap(year); |
||
370 | switch (rulep->r_type) |
||
371 | { |
||
372 | |||
373 | case JULIAN_DAY: |
||
374 | /* |
||
375 | ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap |
||
376 | ** years. |
||
377 | ** In non-leap years, or if the day number is 59 or less, just |
||
378 | ** add SECSPERDAY times the day number-1 to the time of |
||
379 | ** January 1, midnight, to get the day. |
||
380 | */ |
||
381 | value = janfirst + (rulep->r_day - 1) * SECSPERDAY; |
||
382 | if (leapyear && rulep->r_day >= 60) |
||
383 | value += SECSPERDAY; |
||
384 | break; |
||
385 | |||
386 | case DAY_OF_YEAR: |
||
387 | /* |
||
388 | ** n - day of year. |
||
389 | ** Just add SECSPERDAY times the day number to the time of |
||
390 | ** January 1, midnight, to get the day. |
||
391 | */ |
||
392 | value = janfirst + rulep->r_day * SECSPERDAY; |
||
393 | break; |
||
394 | |||
395 | case MONTH_NTH_DAY_OF_WEEK: |
||
396 | /* |
||
397 | ** Mm.n.d - nth "dth day" of month m. |
||
398 | */ |
||
399 | value = janfirst; |
||
400 | for (i = 0; i < rulep->r_mon - 1; ++i) |
||
401 | value += mon_lengths[leapyear][i] * SECSPERDAY; |
||
402 | |||
403 | /* |
||
404 | ** Use Zeller's Congruence to get day-of-week of first day of |
||
405 | ** month. |
||
406 | */ |
||
407 | m1 = (rulep->r_mon + 9) % 12 + 1; |
||
408 | yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; |
||
409 | yy1 = yy0 / 100; |
||
410 | yy2 = yy0 % 100; |
||
411 | dow = ((26 * m1 - 2) / 10 + |
||
412 | 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; |
||
413 | if (dow < 0) |
||
414 | dow += DAYSPERWEEK; |
||
415 | |||
416 | /* |
||
417 | ** "dow" is the day-of-week of the first day of the month. Get |
||
418 | ** the day-of-month (zero-origin) of the first "dow" day of the |
||
419 | ** month. |
||
420 | */ |
||
421 | d = rulep->r_day - dow; |
||
422 | if (d < 0) |
||
423 | d += DAYSPERWEEK; |
||
424 | for (i = 1; i < rulep->r_week; ++i) |
||
425 | { |
||
426 | if (d + DAYSPERWEEK >= |
||
427 | mon_lengths[leapyear][rulep->r_mon - 1]) |
||
428 | break; |
||
429 | d += DAYSPERWEEK; |
||
430 | } |
||
431 | |||
432 | /* |
||
433 | ** "d" is the day-of-month (zero-origin) of the day we want. |
||
434 | */ |
||
435 | value += d * SECSPERDAY; |
||
436 | break; |
||
437 | } |
||
438 | |||
439 | /* |
||
440 | ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in |
||
441 | ** question. To get the Epoch-relative time of the specified local |
||
442 | ** time on that day, add the transition time and the current offset |
||
443 | ** from GMT. |
||
444 | */ |
||
445 | return value + rulep->r_time + offset; |
||
446 | } |
||
447 | |||
448 | /* |
||
449 | ** Given a POSIX section 8-style TZ string, fill in the rule tables as |
||
450 | ** appropriate. |
||
451 | */ |
||
452 | static int tzload (const char * name, struct state * sp) |
||
453 | { |
||
454 | return -1; |
||
455 | } |
||
456 | |||
457 | static int |
||
458 | tzparse(const char *name, struct state * const sp, const int lastditch) |
||
459 | { |
||
460 | const char * stdname; |
||
461 | const char * dstname=0; |
||
462 | int stdlen; |
||
463 | int dstlen; |
||
464 | long stdoffset; |
||
465 | long dstoffset; |
||
466 | time_t * atp; |
||
467 | unsigned char * typep; |
||
468 | char * cp; |
||
469 | int load_result; |
||
470 | |||
471 | stdname = name; |
||
472 | if (lastditch) |
||
473 | { |
||
474 | stdlen = strlen(name); /* length of standard zone name */ |
||
475 | name += stdlen; |
||
476 | if (stdlen >= sizeof sp->chars) |
||
477 | stdlen = (sizeof sp->chars) - 1; |
||
478 | } |
||
479 | else |
||
480 | { |
||
481 | name = getzname(name); |
||
482 | stdlen = name - stdname; |
||
483 | if (stdlen < 3) |
||
484 | return -1; |
||
485 | } |
||
486 | if (*name == '\0') |
||
487 | return -1; |
||
488 | else |
||
489 | { |
||
490 | name = getoffset(name, &stdoffset); |
||
491 | if (name == NULL) |
||
492 | return -1; |
||
493 | } |
||
494 | load_result = tzload(TZDEFRULES, sp); |
||
495 | if (load_result != 0) |
||
496 | sp->leapcnt = 0; /* so, we're off a little */ |
||
497 | if (*name != '\0') |
||
498 | { |
||
499 | dstname = name; |
||
500 | name = getzname(name); |
||
501 | dstlen = name - dstname; /* length of DST zone name */ |
||
502 | if (dstlen < 3) |
||
503 | return -1; |
||
504 | if (*name != '\0' && *name != ',' && *name != ';') |
||
505 | { |
||
506 | name = getoffset(name, &dstoffset); |
||
507 | if (name == NULL) |
||
508 | return -1; |
||
509 | } |
||
510 | else |
||
511 | dstoffset = stdoffset - SECSPERHOUR; |
||
512 | if (*name == ',' || *name == ';') |
||
513 | { |
||
514 | struct rule start; |
||
515 | struct rule end; |
||
516 | int year; |
||
517 | time_t janfirst; |
||
518 | time_t starttime; |
||
519 | time_t endtime; |
||
520 | |||
521 | ++name; |
||
522 | if ((name = getrule(name, &start)) == NULL) |
||
523 | return -1; |
||
524 | if (*name++ != ',') |
||
525 | return -1; |
||
526 | if ((name = getrule(name, &end)) == NULL) |
||
527 | return -1; |
||
528 | if (*name != '\0') |
||
529 | return -1; |
||
530 | sp->typecnt = 2; /* standard time and DST */ |
||
531 | /* |
||
532 | ** Two transitions per year, from EPOCH_YEAR to 2037. |
||
533 | */ |
||
534 | sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); |
||
535 | if (sp->timecnt > TZ_MAX_TIMES) |
||
536 | return -1; |
||
537 | sp->ttis[0].tt_gmtoff = -dstoffset; |
||
538 | sp->ttis[0].tt_isdst = 1; |
||
539 | sp->ttis[0].tt_abbrind = stdlen + 1; |
||
540 | sp->ttis[1].tt_gmtoff = -stdoffset; |
||
541 | sp->ttis[1].tt_isdst = 0; |
||
542 | sp->ttis[1].tt_abbrind = 0; |
||
543 | atp = sp->ats; |
||
544 | typep = sp->types; |
||
545 | janfirst = 0; |
||
546 | for (year = EPOCH_YEAR; year <= 2037; ++year) |
||
547 | { |
||
548 | starttime = transtime(janfirst, year, &start, |
||
549 | stdoffset); |
||
550 | endtime = transtime(janfirst, year, &end, |
||
551 | dstoffset); |
||
552 | if (starttime > endtime) |
||
553 | { |
||
554 | *atp++ = endtime; |
||
555 | *typep++ = 1; /* DST ends */ |
||
556 | *atp++ = starttime; |
||
557 | *typep++ = 0; /* DST begins */ |
||
558 | } |
||
559 | else |
||
560 | { |
||
561 | *atp++ = starttime; |
||
562 | *typep++ = 0; /* DST begins */ |
||
563 | *atp++ = endtime; |
||
564 | *typep++ = 1; /* DST ends */ |
||
565 | } |
||
566 | janfirst += |
||
567 | year_lengths[isleap(year)] * SECSPERDAY; |
||
568 | } |
||
569 | } |
||
570 | else |
||
571 | { |
||
572 | int sawstd; |
||
573 | int sawdst; |
||
574 | long stdfix; |
||
575 | long dstfix; |
||
576 | long oldfix; |
||
577 | int isdst; |
||
578 | int i; |
||
579 | |||
580 | if (*name != '\0') |
||
581 | return -1; |
||
582 | if (load_result != 0) |
||
583 | return -1; |
||
584 | /* |
||
585 | ** Compute the difference between the real and |
||
586 | ** prototype standard and summer time offsets |
||
587 | ** from GMT, and put the real standard and summer |
||
588 | ** time offsets into the rules in place of the |
||
589 | ** prototype offsets. |
||
590 | */ |
||
591 | sawstd = FALSE; |
||
592 | sawdst = FALSE; |
||
593 | stdfix = 0; |
||
594 | dstfix = 0; |
||
595 | for (i = 0; i < sp->typecnt; ++i) |
||
596 | { |
||
597 | if (sp->ttis[i].tt_isdst) |
||
598 | { |
||
599 | oldfix = dstfix; |
||
600 | dstfix = |
||
601 | sp->ttis[i].tt_gmtoff + dstoffset; |
||
602 | if (sawdst && (oldfix != dstfix)) |
||
603 | return -1; |
||
604 | sp->ttis[i].tt_gmtoff = -dstoffset; |
||
605 | sp->ttis[i].tt_abbrind = stdlen + 1; |
||
606 | sawdst = TRUE; |
||
607 | } |
||
608 | else |
||
609 | { |
||
610 | oldfix = stdfix; |
||
611 | stdfix = |
||
612 | sp->ttis[i].tt_gmtoff + stdoffset; |
||
613 | if (sawstd && (oldfix != stdfix)) |
||
614 | return -1; |
||
615 | sp->ttis[i].tt_gmtoff = -stdoffset; |
||
616 | sp->ttis[i].tt_abbrind = 0; |
||
617 | sawstd = TRUE; |
||
618 | } |
||
619 | } |
||
620 | /* |
||
621 | ** Make sure we have both standard and summer time. |
||
622 | */ |
||
623 | if (!sawdst || !sawstd) |
||
624 | return -1; |
||
625 | /* |
||
626 | ** Now correct the transition times by shifting |
||
627 | ** them by the difference between the real and |
||
628 | ** prototype offsets. Note that this difference |
||
629 | ** can be different in standard and summer time; |
||
630 | ** the prototype probably has a 1-hour difference |
||
631 | ** between standard and summer time, but a different |
||
632 | ** difference can be specified in TZ. |
||
633 | */ |
||
634 | isdst = FALSE; /* we start in standard time */ |
||
635 | for (i = 0; i < sp->timecnt; ++i) |
||
636 | { |
||
637 | const struct ttinfo * ttisp; |
||
638 | |||
639 | /* |
||
640 | ** If summer time is in effect, and the |
||
641 | ** transition time was not specified as |
||
642 | ** standard time, add the summer time |
||
643 | ** offset to the transition time; |
||
644 | ** otherwise, add the standard time offset |
||
645 | ** to the transition time. |
||
646 | */ |
||
647 | ttisp = &sp->ttis[sp->types[i]]; |
||
648 | sp->ats[i] += |
||
649 | (isdst && !ttisp->tt_ttisstd) ? |
||
650 | dstfix : stdfix; |
||
651 | isdst = ttisp->tt_isdst; |
||
652 | } |
||
653 | } |
||
654 | } |
||
655 | else |
||
656 | { |
||
657 | dstlen = 0; |
||
658 | sp->typecnt = 1; /* only standard time */ |
||
659 | sp->timecnt = 0; |
||
660 | sp->ttis[0].tt_gmtoff = -stdoffset; |
||
661 | sp->ttis[0].tt_isdst = 0; |
||
662 | sp->ttis[0].tt_abbrind = 0; |
||
663 | } |
||
664 | sp->charcnt = stdlen + 1; |
||
665 | if (dstlen != 0) |
||
666 | sp->charcnt += dstlen + 1; |
||
667 | if (sp->charcnt > sizeof sp->chars) |
||
668 | return -1; |
||
669 | cp = sp->chars; |
||
670 | (void) strncpy(cp, stdname, stdlen); |
||
671 | cp += stdlen; |
||
672 | *cp++ = '\0'; |
||
673 | if (dstlen != 0) |
||
674 | { |
||
675 | (void) strncpy(cp, dstname, dstlen); |
||
676 | *(cp + dstlen) = '\0'; |
||
677 | } |
||
678 | return 0; |
||
679 | } |
||
680 | |||
681 | static void |
||
682 | gmtload(struct state * const sp) |
||
683 | { |
||
684 | if (tzload(GMT, sp) != 0) |
||
685 | (void) tzparse(GMT, sp, TRUE); |
||
686 | } |
||
687 | |||
688 | void |
||
689 | tzset(void) |
||
690 | { |
||
691 | const char * name; |
||
692 | |||
693 | name = getenv("TZ"); |
||
694 | if (name == NULL) |
||
695 | { |
||
696 | tzsetwall(); |
||
697 | return; |
||
698 | } |
||
699 | lcl_is_set = TRUE; |
||
700 | #ifdef ALL_STATE |
||
701 | if (lclptr == NULL) |
||
702 | { |
||
703 | lclptr = (struct state *) malloc(sizeof *lclptr); |
||
704 | if (lclptr == NULL) |
||
705 | { |
||
706 | settzname(); /* all we can do */ |
||
707 | return; |
||
708 | } |
||
709 | } |
||
710 | #endif /* defined ALL_STATE */ |
||
711 | if (*name == '\0') |
||
712 | { |
||
713 | /* |
||
714 | ** User wants it fast rather than right. |
||
715 | */ |
||
716 | lclptr->leapcnt = 0; /* so, we're off a little */ |
||
717 | lclptr->timecnt = 0; |
||
718 | lclptr->ttis[0].tt_gmtoff = 0; |
||
719 | lclptr->ttis[0].tt_abbrind = 0; |
||
720 | (void) strcpy(lclptr->chars, GMT); |
||
721 | } |
||
722 | else if (tzload(name, lclptr) != 0) |
||
723 | if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) |
||
724 | gmtload(lclptr); |
||
725 | settzname(); |
||
726 | } |
||
727 | |||
728 | void |
||
729 | tzsetwall(void) |
||
730 | { |
||
731 | lcl_is_set = TRUE; |
||
732 | #ifdef ALL_STATE |
||
733 | if (lclptr == NULL) |
||
734 | { |
||
735 | lclptr = (struct state *) malloc(sizeof *lclptr); |
||
736 | if (lclptr == NULL) |
||
737 | { |
||
738 | settzname(); /* all we can do */ |
||
739 | return; |
||
740 | } |
||
741 | } |
||
742 | #endif /* defined ALL_STATE */ |
||
743 | if (tzload((char *) NULL, lclptr) != 0) |
||
744 | gmtload(lclptr); |
||
745 | settzname(); |
||
746 | } |
||
747 | |||
748 | /* |
||
749 | ** The easy way to behave "as if no library function calls" localtime |
||
750 | ** is to not call it--so we drop its guts into "localsub", which can be |
||
751 | ** freely called. (And no, the PANS doesn't require the above behavior-- |
||
752 | ** but it *is* desirable.) |
||
753 | ** |
||
754 | ** The unused offset argument is for the benefit of mktime variants. |
||
755 | */ |
||
756 | |||
757 | /*ARGSUSED*/ |
||
758 | static void |
||
759 | localsub(const time_t * const timep, const long offset, struct tm * const tmp) |
||
760 | { |
||
761 | const struct state * sp; |
||
762 | const struct ttinfo * ttisp; |
||
763 | int i; |
||
764 | const time_t t = *timep; |
||
765 | |||
766 | if (!lcl_is_set) |
||
767 | tzset(); |
||
768 | sp = lclptr; |
||
769 | #ifdef ALL_STATE |
||
770 | if (sp == NULL) |
||
771 | { |
||
772 | gmtsub(timep, offset, tmp); |
||
773 | return; |
||
774 | } |
||
775 | #endif /* defined ALL_STATE */ |
||
776 | if (sp->timecnt == 0 || t < sp->ats[0]) |
||
777 | { |
||
778 | i = 0; |
||
779 | while (sp->ttis[i].tt_isdst) |
||
780 | if (++i >= sp->typecnt) |
||
781 | { |
||
782 | i = 0; |
||
783 | break; |
||
784 | } |
||
785 | } |
||
786 | else |
||
787 | { |
||
788 | for (i = 1; i < sp->timecnt; ++i) |
||
789 | if (t < sp->ats[i]) |
||
790 | break; |
||
791 | i = sp->types[i - 1]; |
||
792 | } |
||
793 | ttisp = &sp->ttis[i]; |
||
794 | /* |
||
795 | ** To get (wrong) behavior that's compatible with System V Release 2.0 |
||
796 | ** you'd replace the statement below with |
||
797 | ** t += ttisp->tt_gmtoff; |
||
798 | ** timesub(&t, 0L, sp, tmp); |
||
799 | */ |
||
800 | timesub(&t, ttisp->tt_gmtoff, sp, tmp); |
||
801 | tmp->tm_isdst = ttisp->tt_isdst; |
||
802 | tzname[tmp->tm_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
||
803 | tmp->tm_zone = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
||
804 | } |
||
805 | |||
806 | struct tm * |
||
807 | localtime(const time_t * const timep) |
||
808 | { |
||
809 | static struct tm tm; |
||
810 | |||
811 | localsub(timep, 0L, &tm); |
||
812 | return &tm; |
||
813 | } |
||
814 | |||
815 | /* |
||
816 | ** gmtsub is to gmtime as localsub is to localtime. |
||
817 | */ |
||
818 | |||
819 | static void |
||
820 | gmtsub(const time_t * const timep, const long offset, struct tm * const tmp) |
||
821 | { |
||
822 | if (!gmt_is_set) |
||
823 | { |
||
824 | gmt_is_set = TRUE; |
||
825 | #ifdef ALL_STATE |
||
826 | gmtptr = (struct state *) malloc(sizeof *gmtptr); |
||
827 | if (gmtptr != NULL) |
||
828 | #endif /* defined ALL_STATE */ |
||
829 | gmtload(gmtptr); |
||
830 | } |
||
831 | timesub(timep, offset, gmtptr, tmp); |
||
832 | /* |
||
833 | ** Could get fancy here and deliver something such as |
||
834 | ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, |
||
835 | ** but this is no time for a treasure hunt. |
||
836 | */ |
||
837 | if (offset != 0) |
||
838 | tmp->tm_zone = WILDABBR; |
||
839 | else |
||
840 | { |
||
841 | #ifdef ALL_STATE |
||
842 | if (gmtptr == NULL) |
||
843 | tmp->TM_ZONE = GMT; |
||
844 | else |
||
845 | tmp->TM_ZONE = gmtptr->chars; |
||
846 | #endif /* defined ALL_STATE */ |
||
847 | #ifndef ALL_STATE |
||
848 | tmp->tm_zone = gmtptr->chars; |
||
849 | #endif /* State Farm */ |
||
850 | } |
||
851 | } |
||
852 | |||
853 | struct tm * |
||
854 | gmtime(const time_t * const timep) |
||
855 | { |
||
856 | static struct tm tm; |
||
857 | |||
858 | gmtsub(timep, 0L, &tm); |
||
859 | return &tm; |
||
860 | } |
||
861 | |||
862 | static void |
||
863 | timesub(const time_t * const timep, const long offset, const struct state * const sp, struct tm * const tmp) |
||
864 | { |
||
865 | const struct lsinfo * lp; |
||
866 | long days; |
||
867 | long rem; |
||
868 | int y; |
||
869 | int yleap; |
||
870 | const int * ip; |
||
871 | long corr; |
||
872 | int hit; |
||
873 | int i; |
||
874 | |||
875 | corr = 0; |
||
876 | hit = FALSE; |
||
877 | #ifdef ALL_STATE |
||
878 | i = (sp == NULL) ? 0 : sp->leapcnt; |
||
879 | #endif /* defined ALL_STATE */ |
||
880 | #ifndef ALL_STATE |
||
881 | i = sp->leapcnt; |
||
882 | #endif /* State Farm */ |
||
883 | while (--i >= 0) |
||
884 | { |
||
885 | lp = &sp->lsis[i]; |
||
886 | if (*timep >= lp->ls_trans) |
||
887 | { |
||
888 | if (*timep == lp->ls_trans) |
||
889 | hit = ((i == 0 && lp->ls_corr > 0) || |
||
890 | lp->ls_corr > sp->lsis[i - 1].ls_corr); |
||
891 | corr = lp->ls_corr; |
||
892 | break; |
||
893 | } |
||
894 | } |
||
895 | days = *timep / SECSPERDAY; |
||
896 | rem = *timep % SECSPERDAY; |
||
897 | #ifdef mc68k |
||
898 | if (*timep == 0x80000000) |
||
899 | { |
||
900 | /* |
||
901 | ** A 3B1 muffs the division on the most negative number. |
||
902 | */ |
||
903 | days = -24855; |
||
904 | rem = -11648; |
||
905 | } |
||
906 | #endif /* mc68k */ |
||
907 | rem += (offset - corr); |
||
908 | while (rem < 0) |
||
909 | { |
||
910 | rem += SECSPERDAY; |
||
911 | --days; |
||
912 | } |
||
913 | while (rem >= SECSPERDAY) |
||
914 | { |
||
915 | rem -= SECSPERDAY; |
||
916 | ++days; |
||
917 | } |
||
918 | tmp->tm_hour = (int) (rem / SECSPERHOUR); |
||
919 | rem = rem % SECSPERHOUR; |
||
920 | tmp->tm_min = (int) (rem / SECSPERMIN); |
||
921 | tmp->tm_sec = (int) (rem % SECSPERMIN); |
||
922 | if (hit) |
||
923 | /* |
||
924 | ** A positive leap second requires a special |
||
925 | ** representation. This uses "... ??:59:60". |
||
926 | */ |
||
927 | ++(tmp->tm_sec); |
||
928 | tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); |
||
929 | if (tmp->tm_wday < 0) |
||
930 | tmp->tm_wday += DAYSPERWEEK; |
||
931 | y = EPOCH_YEAR; |
||
932 | if (days >= 0) |
||
933 | for ( ; ; ) |
||
934 | { |
||
935 | yleap = isleap(y); |
||
936 | if (days < (long) year_lengths[yleap]) |
||
937 | break; |
||
938 | ++y; |
||
939 | days = days - (long) year_lengths[yleap]; |
||
940 | } |
||
941 | else |
||
942 | do { |
||
943 | --y; |
||
944 | yleap = isleap(y); |
||
945 | days = days + (long) year_lengths[yleap]; |
||
946 | } while (days < 0); |
||
947 | tmp->tm_year = y - TM_YEAR_BASE; |
||
948 | tmp->tm_yday = (int) days; |
||
949 | ip = mon_lengths[yleap]; |
||
950 | for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) |
||
951 | days = days - (long) ip[tmp->tm_mon]; |
||
952 | tmp->tm_mday = (int) (days + 1); |
||
953 | tmp->tm_isdst = 0; |
||
954 | tmp->tm_gmtoff = offset; |
||
955 | } |
||
956 | |||
957 | /* |
||
958 | ** A la X3J11 |
||
959 | */ |
||
960 | |||
961 | char * |
||
962 | asctime(const struct tm *timeptr) |
||
963 | { |
||
964 | static const char wday_name[DAYSPERWEEK][3] = { |
||
965 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
||
966 | }; |
||
967 | static const char mon_name[MONSPERYEAR][3] = { |
||
968 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
969 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
||
970 | }; |
||
971 | static char result[26]; |
||
972 | |||
973 | (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n", |
||
974 | wday_name[timeptr->tm_wday], |
||
975 | mon_name[timeptr->tm_mon], |
||
976 | timeptr->tm_mday, timeptr->tm_hour, |
||
977 | timeptr->tm_min, timeptr->tm_sec, |
||
978 | TM_YEAR_BASE + timeptr->tm_year); |
||
979 | return result; |
||
980 | } |
||
981 | |||
982 | char * |
||
983 | ctime(const time_t * const timep) |
||
984 | { |
||
985 | return asctime(localtime(timep)); |
||
986 | } |
||
987 | |||
988 | /* |
||
989 | ** Adapted from code provided by Robert Elz, who writes: |
||
990 | ** The "best" way to do mktime I think is based on an idea of Bob |
||
991 | ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). |
||
992 | ** It does a binary search of the time_t space. Since time_t's are |
||
993 | ** just 32 bits, its a max of 32 iterations (even at 64 bits it |
||
994 | ** would still be very reasonable). |
||
995 | */ |
||
996 | |||
997 | #ifndef WRONG |
||
998 | #define WRONG (-1) |
||
999 | #endif /* !defined WRONG */ |
||
1000 | |||
1001 | static void |
||
1002 | normalize(int * const tensptr, int * const unitsptr, const int base) |
||
1003 | { |
||
1004 | if (*unitsptr >= base) |
||
1005 | { |
||
1006 | *tensptr += *unitsptr / base; |
||
1007 | *unitsptr %= base; |
||
1008 | } |
||
1009 | else if (*unitsptr < 0) |
||
1010 | { |
||
1011 | --*tensptr; |
||
1012 | *unitsptr += base; |
||
1013 | if (*unitsptr < 0) |
||
1014 | { |
||
1015 | *tensptr -= 1 + (-*unitsptr) / base; |
||
1016 | *unitsptr = base - (-*unitsptr) % base; |
||
1017 | } |
||
1018 | } |
||
1019 | } |
||
1020 | |||
1021 | static int |
||
1022 | tmcomp(const struct tm * const atmp, const struct tm * const btmp) |
||
1023 | { |
||
1024 | int result; |
||
1025 | |||
1026 | if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && |
||
1027 | (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && |
||
1028 | (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && |
||
1029 | (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && |
||
1030 | (result = (atmp->tm_min - btmp->tm_min)) == 0) |
||
1031 | result = atmp->tm_sec - btmp->tm_sec; |
||
1032 | return result; |
||
1033 | } |
||
1034 | |||
1035 | static time_t |
||
1036 | time2(struct tm *tmp, void (*const funcp)(const time_t *const,const long,struct tm *), const long offset, int * const okayp) |
||
1037 | { |
||
1038 | const struct state * sp; |
||
1039 | int dir; |
||
1040 | int bits; |
||
1041 | int i, j ; |
||
1042 | int saved_seconds; |
||
1043 | time_t newt; |
||
1044 | time_t t; |
||
1045 | struct tm yourtm, mytm; |
||
1046 | |||
1047 | *okayp = FALSE; |
||
1048 | yourtm = *tmp; |
||
1049 | if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) |
||
1050 | normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); |
||
1051 | normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); |
||
1052 | normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); |
||
1053 | normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); |
||
1054 | while (yourtm.tm_mday <= 0) |
||
1055 | { |
||
1056 | --yourtm.tm_year; |
||
1057 | yourtm.tm_mday += |
||
1058 | year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; |
||
1059 | } |
||
1060 | for ( ; ; ) |
||
1061 | { |
||
1062 | i = mon_lengths[isleap(yourtm.tm_year + |
||
1063 | TM_YEAR_BASE)][yourtm.tm_mon]; |
||
1064 | if (yourtm.tm_mday <= i) |
||
1065 | break; |
||
1066 | yourtm.tm_mday -= i; |
||
1067 | if (++yourtm.tm_mon >= MONSPERYEAR) |
||
1068 | { |
||
1069 | yourtm.tm_mon = 0; |
||
1070 | ++yourtm.tm_year; |
||
1071 | } |
||
1072 | } |
||
1073 | saved_seconds = yourtm.tm_sec; |
||
1074 | yourtm.tm_sec = 0; |
||
1075 | /* |
||
1076 | ** Calculate the number of magnitude bits in a time_t |
||
1077 | ** (this works regardless of whether time_t is |
||
1078 | ** signed or unsigned, though lint complains if unsigned). |
||
1079 | */ |
||
1080 | for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) |
||
1081 | ; |
||
1082 | /* |
||
1083 | ** If time_t is signed, then 0 is the median value, |
||
1084 | ** if time_t is unsigned, then 1 << bits is median. |
||
1085 | */ |
||
1086 | t = (time_t) 1 << bits; |
||
1087 | for ( ; ; ) |
||
1088 | { |
||
1089 | (*funcp)(&t, offset, &mytm); |
||
1090 | dir = tmcomp(&mytm, &yourtm); |
||
1091 | if (dir != 0) |
||
1092 | { |
||
1093 | if (bits-- < 0) |
||
1094 | return WRONG; |
||
1095 | if (bits < 0) |
||
1096 | --t; |
||
1097 | else if (dir > 0) |
||
1098 | t -= (time_t) 1 << bits; |
||
1099 | else t += (time_t) 1 << bits; |
||
1100 | continue; |
||
1101 | } |
||
1102 | if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) |
||
1103 | break; |
||
1104 | /* |
||
1105 | ** Right time, wrong type. |
||
1106 | ** Hunt for right time, right type. |
||
1107 | ** It's okay to guess wrong since the guess |
||
1108 | ** gets checked. |
||
1109 | */ |
||
1110 | sp = (const struct state *) |
||
1111 | ((funcp == localsub) ? lclptr : gmtptr); |
||
1112 | #ifdef ALL_STATE |
||
1113 | if (sp == NULL) |
||
1114 | return WRONG; |
||
1115 | #endif /* defined ALL_STATE */ |
||
1116 | for (i = 0; i < sp->typecnt; ++i) |
||
1117 | { |
||
1118 | if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) |
||
1119 | continue; |
||
1120 | for (j = 0; j < sp->typecnt; ++j) |
||
1121 | { |
||
1122 | if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) |
||
1123 | continue; |
||
1124 | newt = t + sp->ttis[j].tt_gmtoff - |
||
1125 | sp->ttis[i].tt_gmtoff; |
||
1126 | (*funcp)(&newt, offset, &mytm); |
||
1127 | if (tmcomp(&mytm, &yourtm) != 0) |
||
1128 | continue; |
||
1129 | if (mytm.tm_isdst != yourtm.tm_isdst) |
||
1130 | continue; |
||
1131 | /* |
||
1132 | ** We have a match. |
||
1133 | */ |
||
1134 | t = newt; |
||
1135 | goto label; |
||
1136 | } |
||
1137 | } |
||
1138 | return WRONG; |
||
1139 | } |
||
1140 | label: |
||
1141 | t += saved_seconds; |
||
1142 | (*funcp)(&t, offset, tmp); |
||
1143 | *okayp = TRUE; |
||
1144 | return t; |
||
1145 | } |
||
1146 | |||
1147 | static time_t |
||
1148 | time1(struct tm * const tmp, void (*const funcp)(const time_t * const, const long, struct tm *), const long offset) |
||
1149 | { |
||
1150 | time_t t; |
||
1151 | const struct state * sp; |
||
1152 | int samei, otheri; |
||
1153 | int okay; |
||
1154 | |||
1155 | if (tmp->tm_isdst > 1) |
||
1156 | tmp->tm_isdst = 1; |
||
1157 | t = time2(tmp, funcp, offset, &okay); |
||
1158 | if (okay || tmp->tm_isdst < 0) |
||
1159 | return t; |
||
1160 | /* |
||
1161 | ** We're supposed to assume that somebody took a time of one type |
||
1162 | ** and did some math on it that yielded a "struct tm" that's bad. |
||
1163 | ** We try to divine the type they started from and adjust to the |
||
1164 | ** type they need. |
||
1165 | */ |
||
1166 | sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); |
||
1167 | #ifdef ALL_STATE |
||
1168 | if (sp == NULL) |
||
1169 | return WRONG; |
||
1170 | #endif /* defined ALL_STATE */ |
||
1171 | for (samei = 0; samei < sp->typecnt; ++samei) |
||
1172 | { |
||
1173 | if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) |
||
1174 | continue; |
||
1175 | for (otheri = 0; otheri < sp->typecnt; ++otheri) |
||
1176 | { |
||
1177 | if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) |
||
1178 | continue; |
||
1179 | tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - |
||
1180 | sp->ttis[samei].tt_gmtoff; |
||
1181 | tmp->tm_isdst = !tmp->tm_isdst; |
||
1182 | t = time2(tmp, funcp, offset, &okay); |
||
1183 | if (okay) |
||
1184 | return t; |
||
1185 | tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - |
||
1186 | sp->ttis[samei].tt_gmtoff; |
||
1187 | tmp->tm_isdst = !tmp->tm_isdst; |
||
1188 | } |
||
1189 | } |
||
1190 | return WRONG; |
||
1191 | } |
||
1192 | |||
1193 | time_t |
||
1194 | mktime(struct tm * tmp) |
||
1195 | { |
||
1196 | return time1(tmp, localsub, 0L); |
||
1197 | }>>>>>>><>><>>>><>><>=><=>=>=>>>>>>>>>>>>>=>>>>>>=>>>>>><>> |