- Move NCI generated files to arch-specific directories
[reactos.git] / reactos / lib / sdk / crt / time / ctime.c
1
2 // fix djdir
3
4 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
5 /* This file has been modified by DJ Delorie. These modifications are
6 ** Copyright (C) 1995 DJ Delorie, 24 Kirsten Ave, Rochester NH,
7 ** 03867-2954, USA.
8 */
9
10 /*
11 * Copyright (c) 1987, 1989 Regents of the University of California.
12 * All rights reserved.
13 *
14 * This code is derived from software contributed to Berkeley by
15 * Arthur David Olson of the National Cancer Institute.
16 *
17 * Redistribution and use in source and binary forms are permitted provided
18 * that: (1) source distributions retain this entire copyright notice and
19 * comment, and (2) distributions including binaries display the following
20 * acknowledgement: ``This product includes software developed by the
21 * University of California, Berkeley and its contributors'' in the
22 * documentation or other materials provided with the distribution and in
23 * all advertising materials mentioning features or use of this software.
24 * Neither the name of the University nor the names of its contributors may
25 * be used to endorse or promote products derived from this software without
26 * specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
28 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 */
31
32 /*
33 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
34 ** POSIX-style TZ environment variable handling from Guy Harris
35 ** (guy@auspex.com).
36 */
37
38 #include <precomp.h>
39
40 #include "tzfile.h"
41 #include "posixrul.h"
42
43 #ifdef __cplusplus
44 #define CPP_CONST const
45 #else
46 #define CPP_CONST
47 #endif
48
49 #define P(s) s
50 #define alloc_size_t size_t
51 #define qsort_size_t size_t
52 #define fread_size_t size_t
53 #define fwrite_size_t size_t
54
55 #define ACCESS_MODE O_RDONLY|O_BINARY
56 #define OPEN_MODE O_RDONLY|O_BINARY
57
58 /*
59 ** Someone might make incorrect use of a time zone abbreviation:
60 ** 1. They might reference tzname[0] before calling tzset (explicitly
61 ** or implicitly).
62 ** 2. They might reference tzname[1] before calling tzset (explicitly
63 ** or implicitly).
64 ** 3. They might reference tzname[1] after setting to a time zone
65 ** in which Daylight Saving Time is never observed.
66 ** 4. They might reference tzname[0] after setting to a time zone
67 ** in which Standard Time is never observed.
68 ** 5. They might reference tm.TM_ZONE after calling offtime.
69 ** What's best to do in the above cases is open to debate;
70 ** for now, we just set things up so that in any of the five cases
71 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
72 ** string "tzname[0] used before set", and similarly for the other cases.
73 ** And another: initialize tzname[0] to "ERA", with an explanation in the
74 ** manual page of what this "time zone abbreviation" means (doing this so
75 ** that tzname[0] has the "normal" length of three characters).
76 */
77
78 void _set_daylight_export(int);
79 void _set_timezone_export(int);
80
81
82 /* buffers must hold 64 characters! */
83 static char TZ_NAME[64] = "PST";
84 static char TZ_DST_NAME[64] = "PDT";
85
86 #ifndef TRUE
87 #define TRUE 1
88 #define FALSE 0
89 #endif /* !defined TRUE */
90
91 static const char GMT[] = "GMT";
92
93 struct ttinfo { /* time type information */
94 long tt_gmtoff; /* GMT offset in seconds */
95 int tt_isdst; /* used to set tm_isdst */
96 int tt_abbrind; /* abbreviation list index */
97 int tt_ttisstd; /* TRUE if transition is std time */
98 };
99
100 struct lsinfo { /* leap second information */
101 time_t ls_trans; /* transition time */
102 long ls_corr; /* correction to apply */
103 };
104
105 struct state {
106 int leapcnt;
107 int timecnt;
108 int typecnt;
109 int charcnt;
110 time_t ats[TZ_MAX_TIMES];
111 unsigned char types[TZ_MAX_TIMES];
112 struct ttinfo ttis[TZ_MAX_TYPES];
113 char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? TZ_MAX_CHARS + 1 : sizeof GMT];
114 struct lsinfo lsis[TZ_MAX_LEAPS];
115 };
116
117 struct rule {
118 int r_type; /* type of rule--see below */
119 int r_day; /* day number of rule */
120 int r_week; /* week number of rule */
121 int r_mon; /* month number of rule */
122 long r_time; /* transition time of rule */
123 };
124
125 #define JULIAN_DAY 0 /* Jn - Julian day */
126 #define DAY_OF_YEAR 1 /* n - day of year */
127 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
128
129 /*
130 ** Prototypes for static functions.
131 */
132 #if 0
133 static long detzcode P((const char * codep));
134 static const char * getzname P((const char * strp));
135 static const char * getnum P((const char * strp, int * nump, int min, int max));
136 static const char * getsecs P((const char * strp, long * secsp));
137 static const char * getoffset P((const char * strp, long * offsetp));
138 static const char * getrule P((const char * strp, struct rule * rulep));
139 static void gmtload P((struct state * sp));
140 static void gmtsub P((const time_t * timep, long offset, struct tm * tmp));
141 static void localsub P((const time_t * timep, long offset, struct tm * tmp));
142 static void normalize P((int * tensptr, int * unitsptr, int base));
143 static void settzname P((void));
144 static time_t time1 P((struct tm * tmp, void (* funcp)(const time_t * CPP_CONST, const long, struct tm * CPP_CONST), long offset));
145 static time_t time2 P((struct tm *tmp, void (* funcp)(const time_t * CPP_CONST, const long, struct tm * CPP_CONST), long offset, int * okayp));
146 static void timesub P((const time_t * timep, long offset, const struct state * sp, struct tm * tmp));
147 static int tmcomp P((const struct tm * atmp, const struct tm * btmp));
148 static time_t transtime P((time_t janfirst, int year, const struct rule * rulep, long offset));
149 static int tzload P((const char * name, struct state * sp));
150 static int tzparse P((const char * name, struct state * sp, int lastditch));
151 static void tzsetwall(void);
152
153 #else
154
155 static const char * getnum(const char * strp, int * CPP_CONST nump, const int min, const int max);
156 static void timesub(const time_t * CPP_CONST timep, const long offset, const struct state * CPP_CONST sp, struct tm * CPP_CONST tmp);
157 static time_t transtime(const time_t janfirst, const int year, const struct rule * CPP_CONST rulep, const long offset);
158 static void tzsetwall(void);
159
160 #endif
161
162 #ifdef ALL_STATE
163 static struct state *lclptr;
164 static struct state *gmtptr;
165 #endif /* defined ALL_STATE */
166
167 #ifndef ALL_STATE
168 static struct state lclmem;
169 static struct state gmtmem;
170 #define lclptr (&lclmem)
171 #define gmtptr (&gmtmem)
172 #endif /* State Farm */
173
174 static int lcl_is_set;
175 static int gmt_is_set;
176
177 char * _tzname[2] = {
178 TZ_NAME,
179 TZ_DST_NAME,
180 };
181
182 static long
183 detzcode(const char * CPP_CONST codep)
184 {
185 long result;
186 int i;
187
188 result = 0;
189 for (i = 0; i < 4; ++i)
190 result = (result << 8) | (codep[i] & 0xff);
191 return result;
192 }
193
194 static void
195 settzname(void)
196 {
197 const struct state * CPP_CONST sp = lclptr;
198 int i;
199
200 _tzname[0] = TZ_NAME;
201 _tzname[1] = TZ_DST_NAME;
202 #ifdef ALL_STATE
203 if (sp == NULL)
204 {
205 _tzname[0] = _tzname[1] = GMT;
206 return;
207 }
208 #endif /* defined ALL_STATE */
209 for (i = 0; i < sp->typecnt; ++i)
210 {
211 register const struct ttinfo * CPP_CONST ttisp = &sp->ttis[i];
212
213 _tzname[ttisp->tt_isdst] =
214 (char *)&sp->chars[ttisp->tt_abbrind];
215 #if 0
216 if (ttisp->tt_isdst) {
217 //_daylight = 1;
218 _set_daylight_export(1);
219 }
220 if (i == 0 || !ttisp->tt_isdst) {
221 //_timezone_dll = -(ttisp->tt_gmtoff);
222 _set_timezone_export(-(ttisp->tt_gmtoff));
223 }
224 if (i == 0 || ttisp->tt_isdst) {
225 _altzone = -(ttisp->tt_gmtoff);
226 }
227 #endif
228 }
229 /*
230 ** And to get the latest zone names into tzname. . .
231 */
232 for (i = 0; i < sp->timecnt; ++i)
233 {
234 const struct ttinfo * CPP_CONST ttisp = &sp->ttis[sp->types[i]];
235
236 _tzname[ttisp->tt_isdst] = (char *)&sp->chars[ttisp->tt_abbrind];
237 }
238 }
239
240 static char* tzdir(void)
241 {
242 static char dir[80]={0}, *cp;
243 if (dir[0] == 0)
244 {
245 if ((cp = getenv("TZDIR")))
246 {
247 strcpy(dir, cp);
248 }
249 else if ((cp = getenv("DJDIR")))
250 {
251 strcpy(dir, cp);
252 strcat(dir, "/zoneinfo");
253 }
254 else
255 strcpy(dir, "./");
256 }
257 return dir;
258 }
259
260 static int tzload(const char* name, struct state* CPP_CONST sp)
261 {
262 const char * p;
263 int i;
264 int fid;
265 char fullname[FILENAME_MAX + 1];
266 const struct tzhead * tzhp;
267 char buf[sizeof *sp + sizeof *tzhp];
268 int ttisstdcnt;
269
270 if (name == NULL && (name = TZDEFAULT) == NULL)
271 return -1;
272
273 if (name[0] == ':')
274 ++name;
275 if (name[0] != '/')
276 {
277 if ((p = tzdir()) == NULL)
278 return -1;
279 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
280 return -1;
281 strcpy(fullname, p);
282 strcat(fullname, "/");
283 strcat(fullname, name);
284 name = fullname;
285 }
286
287 if ((fid = _open(name, OPEN_MODE)) == -1)
288 {
289 const char *base = strrchr(name, '/');
290 if (base)
291 base++;
292 else
293 base = name;
294 if (strcmp(base, "posixrules"))
295 return -1;
296
297 /* We've got a built-in copy of posixrules just in case */
298 memcpy(buf, _posixrules_data, sizeof(_posixrules_data));
299 i = sizeof(_posixrules_data);
300 }
301 else
302 {
303 i = _read(fid, buf, sizeof buf);
304 if (_close(fid) != 0 || i < (int)sizeof *tzhp)
305 return -1;
306 }
307
308 tzhp = (struct tzhead *) buf;
309 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
310 sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
311 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
312 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
313 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
314 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
315 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
316 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
317 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
318 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
319 return -1;
320 if (i < (int)sizeof *tzhp +
321 sp->timecnt * (4 + (int)sizeof (char)) +
322 sp->typecnt * (4 + 2 * (int)sizeof (char)) +
323 sp->charcnt * (int)sizeof (char) +
324 sp->leapcnt * 2 * 4 +
325 ttisstdcnt * (int)sizeof (char))
326 return -1;
327 p = buf + sizeof *tzhp;
328 for (i = 0; i < sp->timecnt; ++i)
329 {
330 sp->ats[i] = detzcode(p);
331 p += 4;
332 }
333 for (i = 0; i < sp->timecnt; ++i)
334 {
335 sp->types[i] = (unsigned char) *p++;
336 if (sp->types[i] >= sp->typecnt)
337 return -1;
338 }
339 for (i = 0; i < sp->typecnt; ++i)
340 {
341 struct ttinfo * ttisp;
342
343 ttisp = &sp->ttis[i];
344 ttisp->tt_gmtoff = detzcode(p);
345 p += 4;
346 ttisp->tt_isdst = (unsigned char) *p++;
347 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
348 return -1;
349 ttisp->tt_abbrind = (unsigned char) *p++;
350 if (ttisp->tt_abbrind < 0 ||
351 ttisp->tt_abbrind > sp->charcnt)
352 return -1;
353 }
354 for (i = 0; i < sp->charcnt; ++i)
355 sp->chars[i] = *p++;
356 sp->chars[i] = '\0'; /* ensure '\0' at end */
357 for (i = 0; i < sp->leapcnt; ++i)
358 {
359 struct lsinfo * lsisp;
360
361 lsisp = &sp->lsis[i];
362 lsisp->ls_trans = detzcode(p);
363 p += 4;
364 lsisp->ls_corr = detzcode(p);
365 p += 4;
366 }
367 for (i = 0; i < sp->typecnt; ++i)
368 {
369 struct ttinfo * ttisp;
370
371 ttisp = &sp->ttis[i];
372 if (ttisstdcnt == 0)
373 ttisp->tt_ttisstd = FALSE;
374 else
375 {
376 ttisp->tt_ttisstd = *p++;
377 if (ttisp->tt_ttisstd != TRUE &&
378 ttisp->tt_ttisstd != FALSE)
379 return -1;
380 }
381 }
382 return 0;
383 }
384
385 static const int mon_lengths[2][MONSPERYEAR] = {
386 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
387 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
388 };
389
390 static const int year_lengths[2] = {
391 DAYSPERNYEAR, DAYSPERLYEAR
392 };
393
394 /*
395 ** Given a pointer into a time zone string, scan until a character that is not
396 ** a valid character in a zone name is found. Return a pointer to that
397 ** character.
398 */
399
400 static const char*
401 getzname(const char* strp)
402 {
403 char c;
404
405 while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
406 c != '+')
407 ++strp;
408 return strp;
409 }
410
411 /*
412 ** Given a pointer into a time zone string, extract a number from that string.
413 ** Check that the number is within a specified range; if it is not, return
414 ** NULL.
415 ** Otherwise, return a pointer to the first character not part of the number.
416 */
417
418 static const char*
419 getnum(const char* strp, int* CPP_CONST nump, const int min, const int max)
420 {
421 char c;
422 int num;
423
424 if (strp == NULL || !isdigit(*strp))
425 return NULL;
426 num = 0;
427 while ((c = *strp) != '\0' && isdigit(c))
428 {
429 num = num * 10 + (c - '0');
430 if (num > max)
431 return NULL;
432 ++strp;
433 }
434 if (num < min)
435 return NULL;
436 *nump = num;
437 return strp;
438 }
439
440 /*
441 ** Given a pointer into a time zone string, extract a number of seconds,
442 ** in hh[:mm[:ss]] form, from the string.
443 ** If any error occurs, return NULL.
444 ** Otherwise, return a pointer to the first character not part of the number
445 ** of seconds.
446 */
447
448 static const char *
449 getsecs(const char *strp, long * CPP_CONST secsp)
450 {
451 int num;
452
453 strp = getnum(strp, &num, 0, HOURSPERDAY);
454 if (strp == NULL)
455 return NULL;
456 *secsp = num * SECSPERHOUR;
457 if (*strp == ':')
458 {
459 ++strp;
460 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
461 if (strp == NULL)
462 return NULL;
463 *secsp += num * SECSPERMIN;
464 if (*strp == ':')
465 {
466 ++strp;
467 strp = getnum(strp, &num, 0, SECSPERMIN - 1);
468 if (strp == NULL)
469 return NULL;
470 *secsp += num;
471 }
472 }
473 return strp;
474 }
475
476 /*
477 ** Given a pointer into a time zone string, extract an offset, in
478 ** [+-]hh[:mm[:ss]] form, from the string.
479 ** If any error occurs, return NULL.
480 ** Otherwise, return a pointer to the first character not part of the time.
481 */
482
483 static const char *
484 getoffset(const char *strp, long * CPP_CONST offsetp)
485 {
486 int neg;
487
488 if (*strp == '-')
489 {
490 neg = 1;
491 ++strp;
492 }
493 else if (isdigit(*strp) || *strp++ == '+')
494 neg = 0;
495 else
496 return NULL; /* illegal offset */
497 strp = getsecs(strp, offsetp);
498 if (strp == NULL)
499 return NULL; /* illegal time */
500 if (neg)
501 *offsetp = -*offsetp;
502 return strp;
503 }
504
505 /*
506 ** Given a pointer into a time zone string, extract a rule in the form
507 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
508 ** If a valid rule is not found, return NULL.
509 ** Otherwise, return a pointer to the first character not part of the rule.
510 */
511
512 static const char *
513 getrule(const char *strp, struct rule * CPP_CONST rulep)
514 {
515 if (*strp == 'J')
516 {
517 /*
518 ** Julian day.
519 */
520 rulep->r_type = JULIAN_DAY;
521 ++strp;
522 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
523 }
524 else if (*strp == 'M')
525 {
526 /*
527 ** Month, week, day.
528 */
529 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
530 ++strp;
531 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
532 if (strp == NULL)
533 return NULL;
534 if (*strp++ != '.')
535 return NULL;
536 strp = getnum(strp, &rulep->r_week, 1, 5);
537 if (strp == NULL)
538 return NULL;
539 if (*strp++ != '.')
540 return NULL;
541 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
542 }
543 else if (isdigit(*strp))
544 {
545 /*
546 ** Day of year.
547 */
548 rulep->r_type = DAY_OF_YEAR;
549 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
550 }
551 else
552 return NULL; /* invalid format */
553 if (strp == NULL)
554 return NULL;
555 if (*strp == '/')
556 {
557 /*
558 ** Time specified.
559 */
560 ++strp;
561 strp = getsecs(strp, &rulep->r_time);
562 }
563 else
564 rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
565 return strp;
566 }
567
568 /*
569 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
570 ** year, a rule, and the offset from GMT at the time that rule takes effect,
571 ** calculate the Epoch-relative time that rule takes effect.
572 */
573
574 static time_t
575 transtime(const time_t janfirst, const int year, const struct rule * CPP_CONST rulep, const long offset)
576 {
577 int leapyear;
578 time_t value=0;
579 int i;
580 int d, m1, yy0, yy1, yy2, dow;
581
582 leapyear = isleap(year);
583 switch (rulep->r_type)
584 {
585
586 case JULIAN_DAY:
587 /*
588 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
589 ** years.
590 ** In non-leap years, or if the day number is 59 or less, just
591 ** add SECSPERDAY times the day number-1 to the time of
592 ** January 1, midnight, to get the day.
593 */
594 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
595 if (leapyear && rulep->r_day >= 60)
596 value += SECSPERDAY;
597 break;
598
599 case DAY_OF_YEAR:
600 /*
601 ** n - day of year.
602 ** Just add SECSPERDAY times the day number to the time of
603 ** January 1, midnight, to get the day.
604 */
605 value = janfirst + rulep->r_day * SECSPERDAY;
606 break;
607
608 case MONTH_NTH_DAY_OF_WEEK:
609 /*
610 ** Mm.n.d - nth "dth day" of month m.
611 */
612 value = janfirst;
613 for (i = 0; i < rulep->r_mon - 1; ++i)
614 value += mon_lengths[leapyear][i] * SECSPERDAY;
615
616 /*
617 ** Use Zeller's Congruence to get day-of-week of first day of
618 ** month.
619 */
620 m1 = (rulep->r_mon + 9) % 12 + 1;
621 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
622 yy1 = yy0 / 100;
623 yy2 = yy0 % 100;
624 dow = ((26 * m1 - 2) / 10 +
625 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
626 if (dow < 0)
627 dow += DAYSPERWEEK;
628
629 /*
630 ** "dow" is the day-of-week of the first day of the month. Get
631 ** the day-of-month (zero-origin) of the first "dow" day of the
632 ** month.
633 */
634 d = rulep->r_day - dow;
635 if (d < 0)
636 d += DAYSPERWEEK;
637 for (i = 1; i < rulep->r_week; ++i)
638 {
639 if (d + DAYSPERWEEK >=
640 mon_lengths[leapyear][rulep->r_mon - 1])
641 break;
642 d += DAYSPERWEEK;
643 }
644
645 /*
646 ** "d" is the day-of-month (zero-origin) of the day we want.
647 */
648 value += d * SECSPERDAY;
649 break;
650 }
651
652 /*
653 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
654 ** question. To get the Epoch-relative time of the specified local
655 ** time on that day, add the transition time and the current offset
656 ** from GMT.
657 */
658 return value + rulep->r_time + offset;
659 }
660
661 /*
662 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
663 ** appropriate.
664 */
665
666 static int
667 tzparse(const char *name, struct state * CPP_CONST sp, const int lastditch)
668 {
669 const char * stdname;
670 const char * dstname=0;
671 int stdlen;
672 int dstlen;
673 long stdoffset;
674 long dstoffset;
675 time_t * atp;
676 unsigned char * typep;
677 char * cp;
678 int load_result;
679
680 stdname = name;
681 if (lastditch)
682 {
683 stdlen = strlen(name); /* length of standard zone name */
684 name += stdlen;
685 if (stdlen >= (int)sizeof sp->chars)
686 stdlen = (int)(sizeof sp->chars) - 1;
687 }
688 else
689 {
690 name = getzname(name);
691 stdlen = name - stdname;
692 if (stdlen < 3)
693 return -1;
694 }
695 if (*name == '\0')
696 return -1;
697 else
698 {
699 name = getoffset(name, &stdoffset);
700 if (name == NULL)
701 return -1;
702 }
703 load_result = tzload(TZDEFRULES, sp);
704 if (load_result != 0)
705 sp->leapcnt = 0; /* so, we're off a little */
706 if (*name != '\0')
707 {
708 dstname = name;
709 name = getzname(name);
710 dstlen = name - dstname; /* length of DST zone name */
711 if (dstlen < 3)
712 return -1;
713 if (*name != '\0' && *name != ',' && *name != ';')
714 {
715 name = getoffset(name, &dstoffset);
716 if (name == NULL)
717 return -1;
718 }
719 else
720 dstoffset = stdoffset - SECSPERHOUR;
721 if (*name == ',' || *name == ';')
722 {
723 struct rule start;
724 struct rule end;
725 int year;
726 time_t janfirst;
727 time_t starttime;
728 time_t endtime;
729
730 ++name;
731 if ((name = getrule(name, &start)) == NULL)
732 return -1;
733 if (*name++ != ',')
734 return -1;
735 if ((name = getrule(name, &end)) == NULL)
736 return -1;
737 if (*name != '\0')
738 return -1;
739 sp->typecnt = 2; /* standard time and DST */
740 /*
741 ** Two transitions per year, from EPOCH_YEAR to 2037.
742 */
743 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
744 if (sp->timecnt > TZ_MAX_TIMES)
745 return -1;
746 sp->ttis[0].tt_gmtoff = -dstoffset;
747 sp->ttis[0].tt_isdst = 1;
748 sp->ttis[0].tt_abbrind = stdlen + 1;
749 sp->ttis[1].tt_gmtoff = -stdoffset;
750 sp->ttis[1].tt_isdst = 0;
751 sp->ttis[1].tt_abbrind = 0;
752 atp = sp->ats;
753 typep = sp->types;
754 janfirst = 0;
755 for (year = EPOCH_YEAR; year <= 2037; ++year)
756 {
757 starttime = transtime(janfirst, year, &start,
758 stdoffset);
759 endtime = transtime(janfirst, year, &end,
760 dstoffset);
761 if (starttime > endtime)
762 {
763 *atp++ = endtime;
764 *typep++ = 1; /* DST ends */
765 *atp++ = starttime;
766 *typep++ = 0; /* DST begins */
767 }
768 else
769 {
770 *atp++ = starttime;
771 *typep++ = 0; /* DST begins */
772 *atp++ = endtime;
773 *typep++ = 1; /* DST ends */
774 }
775 janfirst +=
776 year_lengths[isleap(year)] * SECSPERDAY;
777 }
778 }
779 else
780 {
781 int sawstd;
782 int sawdst;
783 long stdfix;
784 long dstfix;
785 long oldfix;
786 int isdst;
787 int i;
788
789 if (*name != '\0')
790 return -1;
791 if (load_result != 0)
792 return -1;
793 /*
794 ** Compute the difference between the real and
795 ** prototype standard and summer time offsets
796 ** from GMT, and put the real standard and summer
797 ** time offsets into the rules in place of the
798 ** prototype offsets.
799 */
800 sawstd = FALSE;
801 sawdst = FALSE;
802 stdfix = 0;
803 dstfix = 0;
804 for (i = 0; i < sp->typecnt; ++i)
805 {
806 if (sp->ttis[i].tt_isdst)
807 {
808 oldfix = dstfix;
809 dstfix =
810 sp->ttis[i].tt_gmtoff + dstoffset;
811 if (sawdst && (oldfix != dstfix))
812 return -1;
813 sp->ttis[i].tt_gmtoff = -dstoffset;
814 sp->ttis[i].tt_abbrind = stdlen + 1;
815 sawdst = TRUE;
816 }
817 else
818 {
819 oldfix = stdfix;
820 stdfix =
821 sp->ttis[i].tt_gmtoff + stdoffset;
822 if (sawstd && (oldfix != stdfix))
823 return -1;
824 sp->ttis[i].tt_gmtoff = -stdoffset;
825 sp->ttis[i].tt_abbrind = 0;
826 sawstd = TRUE;
827 }
828 }
829 /*
830 ** Make sure we have both standard and summer time.
831 */
832 if (!sawdst || !sawstd)
833 return -1;
834 /*
835 ** Now correct the transition times by shifting
836 ** them by the difference between the real and
837 ** prototype offsets. Note that this difference
838 ** can be different in standard and summer time;
839 ** the prototype probably has a 1-hour difference
840 ** between standard and summer time, but a different
841 ** difference can be specified in TZ.
842 */
843 isdst = FALSE; /* we start in standard time */
844 for (i = 0; i < sp->timecnt; ++i)
845 {
846 const struct ttinfo * ttisp;
847
848 /*
849 ** If summer time is in effect, and the
850 ** transition time was not specified as
851 ** standard time, add the summer time
852 ** offset to the transition time;
853 ** otherwise, add the standard time offset
854 ** to the transition time.
855 */
856 ttisp = &sp->ttis[sp->types[i]];
857 sp->ats[i] +=
858 (isdst && !ttisp->tt_ttisstd) ?
859 dstfix : stdfix;
860 isdst = ttisp->tt_isdst;
861 }
862 }
863 }
864 else
865 {
866 dstlen = 0;
867 sp->typecnt = 1; /* only standard time */
868 sp->timecnt = 0;
869 sp->ttis[0].tt_gmtoff = -stdoffset;
870 sp->ttis[0].tt_isdst = 0;
871 sp->ttis[0].tt_abbrind = 0;
872 }
873 sp->charcnt = stdlen + 1;
874 if (dstlen != 0)
875 sp->charcnt += dstlen + 1;
876 if (sp->charcnt > (int)sizeof sp->chars)
877 return -1;
878 cp = sp->chars;
879 (void) strncpy(cp, stdname, stdlen);
880 cp += stdlen;
881 *cp++ = '\0';
882 if (dstlen != 0)
883 {
884 (void) strncpy(cp, dstname, dstlen);
885 *(cp + dstlen) = '\0';
886 }
887 return 0;
888 }
889
890 static void
891 gmtload(struct state * CPP_CONST sp)
892 {
893 if (tzload(GMT, sp) != 0)
894 (void) tzparse(GMT, sp, TRUE);
895 }
896
897 /*
898 * @implemented
899 */
900 void
901 _tzset(void)
902 {
903 const char * name;
904
905 name = getenv("TZ");
906 if (name == NULL)
907 {
908 tzsetwall();
909 return;
910 }
911 lcl_is_set = TRUE;
912 #ifdef ALL_STATE
913 if (lclptr == NULL)
914 {
915 lclptr = (struct state *) malloc(sizeof *lclptr);
916 if (lclptr == NULL)
917 {
918 settzname(); /* all we can do */
919 return;
920 }
921 }
922 #endif /* defined ALL_STATE */
923 if (*name == '\0')
924 {
925 /*
926 ** User wants it fast rather than right.
927 */
928 lclptr->leapcnt = 0; /* so, we're off a little */
929 lclptr->timecnt = 0;
930 lclptr->ttis[0].tt_gmtoff = 0;
931 lclptr->ttis[0].tt_abbrind = 0;
932 (void) strcpy(lclptr->chars, GMT);
933 }
934 else if (tzload(name, lclptr) != 0)
935 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
936 gmtload(lclptr);
937 settzname();
938 }
939
940 void
941 tzsetwall(void)
942 {
943 lcl_is_set = TRUE;
944 #ifdef ALL_STATE
945 if (lclptr == NULL)
946 {
947 lclptr = (struct state *) malloc(sizeof *lclptr);
948 if (lclptr == NULL)
949 {
950 settzname(); /* all we can do */
951 return;
952 }
953 }
954 #endif /* defined ALL_STATE */
955 if (tzload((char *) NULL, lclptr) != 0)
956 gmtload(lclptr);
957 settzname();
958 }
959
960 /*
961 ** The easy way to behave "as if no library function calls" localtime
962 ** is to not call it--so we drop its guts into "localsub", which can be
963 ** freely called. (And no, the PANS doesn't require the above behavior--
964 ** but it *is* desirable.)
965 **
966 ** The unused offset argument is for the benefit of mktime variants.
967 */
968
969 /*ARGSUSED*/
970 static void
971 localsub(const time_t * CPP_CONST timep, const long offset, struct tm * CPP_CONST tmp)
972 {
973 const struct state * sp;
974 const struct ttinfo * ttisp;
975 int i;
976 const time_t t = *timep;
977
978 if (!lcl_is_set)
979 _tzset();
980 sp = lclptr;
981 #ifdef ALL_STATE
982 if (sp == NULL)
983 {
984 gmtsub(timep, offset, tmp);
985 return;
986 }
987 #endif /* defined ALL_STATE */
988 if (sp->timecnt == 0 || t < sp->ats[0])
989 {
990 i = 0;
991 while (sp->ttis[i].tt_isdst)
992 if (++i >= sp->typecnt)
993 {
994 i = 0;
995 break;
996 }
997 }
998 else
999 {
1000 for (i = 1; i < sp->timecnt; ++i)
1001 if (t < sp->ats[i])
1002 break;
1003 i = sp->types[i - 1];
1004 }
1005 ttisp = &sp->ttis[i];
1006 /*
1007 ** To get (wrong) behavior that's compatible with System V Release 2.0
1008 ** you'd replace the statement below with
1009 ** t += ttisp->tt_gmtoff;
1010 ** timesub(&t, 0L, sp, tmp);
1011 */
1012 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1013 tmp->tm_isdst = ttisp->tt_isdst;
1014 _tzname[tmp->tm_isdst] = (char *)&sp->chars[ttisp->tt_abbrind];
1015 #if 0
1016 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1017 tmp->tm_zone = (char *)&sp->chars[ttisp->tt_abbrind];
1018 #endif
1019 }
1020
1021 /*
1022 * @implemented
1023 */
1024 struct tm *
1025 localtime(const time_t * CPP_CONST timep)
1026 {
1027 static struct tm tm;
1028
1029 localsub(timep, 0L, &tm);
1030 return &tm;
1031 }
1032
1033 /*
1034 ** gmtsub is to gmtime as localsub is to localtime.
1035 */
1036
1037 static void
1038 gmtsub(const time_t * CPP_CONST timep, const long offset, struct tm * CPP_CONST tmp)
1039 {
1040 if (!gmt_is_set)
1041 {
1042 gmt_is_set = TRUE;
1043 #ifdef ALL_STATE
1044 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1045 if (gmtptr != NULL)
1046 #endif /* defined ALL_STATE */
1047 gmtload(gmtptr);
1048 }
1049 timesub(timep, offset, gmtptr, tmp);
1050 /*
1051 ** Could get fancy here and deliver something such as
1052 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1053 ** but this is no time for a treasure hunt.
1054 */
1055 #if 0
1056 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1057 if (offset != 0)
1058 tmp->tm_zone = TZ_NAME;
1059 else
1060 {
1061 #ifdef ALL_STATE
1062 if (gmtptr == NULL)
1063 tmp->TM_ZONE = GMT;
1064 else
1065 tmp->TM_ZONE = gmtptr->chars;
1066 #endif /* defined ALL_STATE */
1067 #ifndef ALL_STATE
1068 tmp->tm_zone = gmtptr->chars;
1069 #endif /* State Farm */
1070 }
1071 #endif /* if 0 */
1072 }
1073
1074 /*
1075 * @implemented
1076 */
1077 struct tm *
1078 gmtime(const time_t * CPP_CONST timep)
1079 {
1080 static struct tm tm;
1081
1082 gmtsub(timep, 0L, &tm);
1083 return &tm;
1084 }
1085
1086 static void
1087 timesub(const time_t * CPP_CONST timep, const long offset, const struct state * CPP_CONST sp, struct tm * CPP_CONST tmp)
1088 {
1089 const struct lsinfo * lp;
1090 long days;
1091 long rem;
1092 int y;
1093 int yleap;
1094 const int * ip;
1095 long corr;
1096 int hit;
1097 int i;
1098
1099 corr = 0;
1100 hit = FALSE;
1101 #ifdef ALL_STATE
1102 i = (sp == NULL) ? 0 : sp->leapcnt;
1103 #endif /* defined ALL_STATE */
1104 #ifndef ALL_STATE
1105 i = sp->leapcnt;
1106 #endif /* State Farm */
1107 while (--i >= 0)
1108 {
1109 lp = &sp->lsis[i];
1110 if (*timep >= lp->ls_trans)
1111 {
1112 if (*timep == lp->ls_trans)
1113 hit = ((i == 0 && lp->ls_corr > 0) ||
1114 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1115 corr = lp->ls_corr;
1116 break;
1117 }
1118 }
1119 days = *timep / SECSPERDAY;
1120 rem = *timep % SECSPERDAY;
1121 #ifdef mc68k
1122 if (*timep == 0x80000000)
1123 {
1124 /*
1125 ** A 3B1 muffs the division on the most negative number.
1126 */
1127 days = -24855;
1128 rem = -11648;
1129 }
1130 #endif /* mc68k */
1131 rem += (offset - corr);
1132 while (rem < 0)
1133 {
1134 rem += SECSPERDAY;
1135 --days;
1136 }
1137 while (rem >= SECSPERDAY)
1138 {
1139 rem -= SECSPERDAY;
1140 ++days;
1141 }
1142 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1143 rem = rem % SECSPERHOUR;
1144 tmp->tm_min = (int) (rem / SECSPERMIN);
1145 tmp->tm_sec = (int) (rem % SECSPERMIN);
1146 if (hit)
1147 /*
1148 ** A positive leap second requires a special
1149 ** representation. This uses "... ??:59:60".
1150 */
1151 ++(tmp->tm_sec);
1152 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1153 if (tmp->tm_wday < 0)
1154 tmp->tm_wday += DAYSPERWEEK;
1155 y = EPOCH_YEAR;
1156 if (days >= 0)
1157 for ( ; ; )
1158 {
1159 yleap = isleap(y);
1160 if (days < (long) year_lengths[yleap])
1161 break;
1162 ++y;
1163 days = days - (long) year_lengths[yleap];
1164 }
1165 else
1166 do {
1167 --y;
1168 yleap = isleap(y);
1169 days = days + (long) year_lengths[yleap];
1170 } while (days < 0);
1171 tmp->tm_year = y - TM_YEAR_BASE;
1172 tmp->tm_yday = (int) days;
1173 ip = mon_lengths[yleap];
1174 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1175 days = days - (long) ip[tmp->tm_mon];
1176 tmp->tm_mday = (int) (days + 1);
1177 tmp->tm_isdst = 0;
1178 #if 0
1179 /* tm_gmtoff doesnt exist in windows msvcrt -Gunnar */
1180 tmp->tm_gmtoff = offset;
1181 #endif
1182 }
1183
1184 /*
1185 ** A la X3J11
1186 */
1187
1188 /*
1189 * @implemented
1190 */
1191 char *
1192 asctime(const struct tm *timeptr)
1193 {
1194 static const char wday_name[DAYSPERWEEK][3] = {
1195 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1196 };
1197 static const char mon_name[MONSPERYEAR][3] = {
1198 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1199 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1200 };
1201 static char result[26];
1202
1203 (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
1204 wday_name[timeptr->tm_wday],
1205 mon_name[timeptr->tm_mon],
1206 timeptr->tm_mday, timeptr->tm_hour,
1207 timeptr->tm_min, timeptr->tm_sec,
1208 TM_YEAR_BASE + timeptr->tm_year);
1209 return result;
1210 }
1211
1212 /*
1213 * @implemented
1214 */
1215 char *
1216 ctime(const time_t * CPP_CONST timep)
1217 {
1218 return asctime(localtime(timep));
1219 }
1220
1221 /*
1222 ** Adapted from code provided by Robert Elz, who writes:
1223 ** The "best" way to do mktime I think is based on an idea of Bob
1224 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1225 ** It does a binary search of the time_t space. Since time_t's are
1226 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1227 ** would still be very reasonable).
1228 */
1229
1230 #ifndef WRONG
1231 #define WRONG (-1)
1232 #endif /* !defined WRONG */
1233
1234 static void
1235 normalize(int * CPP_CONST tensptr, int * CPP_CONST unitsptr, const int base)
1236 {
1237 if (*unitsptr >= base)
1238 {
1239 *tensptr += *unitsptr / base;
1240 *unitsptr %= base;
1241 }
1242 else if (*unitsptr < 0)
1243 {
1244 --*tensptr;
1245 *unitsptr += base;
1246 if (*unitsptr < 0)
1247 {
1248 *tensptr -= 1 + (-*unitsptr) / base;
1249 *unitsptr = base - (-*unitsptr) % base;
1250 }
1251 }
1252 }
1253
1254 static int
1255 tmcomp(const struct tm * CPP_CONST atmp, const struct tm * CPP_CONST btmp)
1256 {
1257 int result;
1258
1259 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1260 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1261 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1262 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1263 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1264 result = atmp->tm_sec - btmp->tm_sec;
1265 return result;
1266 }
1267
1268 static time_t
1269 time2(struct tm *tmp, void (*const funcp)(const time_t * CPP_CONST, const long, struct tm *), const long offset, int * CPP_CONST okayp)
1270 {
1271 const struct state * sp;
1272 int dir;
1273 int bits;
1274 int i, j ;
1275 int saved_seconds;
1276 time_t newt;
1277 time_t t;
1278 struct tm yourtm, mytm;
1279
1280 *okayp = FALSE;
1281 yourtm = *tmp;
1282 if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
1283 normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
1284 normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
1285 normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
1286 normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
1287 while (yourtm.tm_mday <= 0)
1288 {
1289 --yourtm.tm_year;
1290 yourtm.tm_mday +=
1291 year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1292 }
1293 for ( ; ; )
1294 {
1295 i = mon_lengths[isleap(yourtm.tm_year +
1296 TM_YEAR_BASE)][yourtm.tm_mon];
1297 if (yourtm.tm_mday <= i)
1298 break;
1299 yourtm.tm_mday -= i;
1300 if (++yourtm.tm_mon >= MONSPERYEAR)
1301 {
1302 yourtm.tm_mon = 0;
1303 ++yourtm.tm_year;
1304 }
1305 }
1306 saved_seconds = yourtm.tm_sec;
1307 yourtm.tm_sec = 0;
1308 /*
1309 ** Calculate the number of magnitude bits in a time_t
1310 ** (this works regardless of whether time_t is
1311 ** signed or unsigned, though lint complains if unsigned).
1312 */
1313 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1314 ;
1315 /*
1316 ** If time_t is signed, then 0 is the median value,
1317 ** if time_t is unsigned, then 1 << bits is median.
1318 */
1319 #ifdef _MSVCRT_LIB_
1320 t = (time_t) ((1 << bits) - 1);
1321 #else // TODO: FIXME: review which is correct
1322 t = (time_t) 1 << bits;
1323 #endif /*_MSVCRT_LIB_*/
1324
1325 for ( ; ; )
1326 {
1327 (*funcp)(&t, offset, &mytm);
1328 dir = tmcomp(&mytm, &yourtm);
1329 if (dir != 0)
1330 {
1331 if (bits-- < 0)
1332 return WRONG;
1333 if (bits < 0)
1334 --t;
1335 else if (dir > 0)
1336 t -= (time_t) 1 << bits;
1337 else t += (time_t) 1 << bits;
1338 continue;
1339 }
1340 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1341 break;
1342 /*
1343 ** Right time, wrong type.
1344 ** Hunt for right time, right type.
1345 ** It's okay to guess wrong since the guess
1346 ** gets checked.
1347 */
1348 sp = (const struct state *)
1349 ((funcp == localsub) ? lclptr : gmtptr);
1350 #ifdef ALL_STATE
1351 if (sp == NULL)
1352 return WRONG;
1353 #endif /* defined ALL_STATE */
1354 for (i = 0; i < sp->typecnt; ++i)
1355 {
1356 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1357 continue;
1358 for (j = 0; j < sp->typecnt; ++j)
1359 {
1360 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1361 continue;
1362 newt = t + sp->ttis[j].tt_gmtoff -
1363 sp->ttis[i].tt_gmtoff;
1364 (*funcp)(&newt, offset, &mytm);
1365 if (tmcomp(&mytm, &yourtm) != 0)
1366 continue;
1367 if (mytm.tm_isdst != yourtm.tm_isdst)
1368 continue;
1369 /*
1370 ** We have a match.
1371 */
1372 t = newt;
1373 goto label;
1374 }
1375 }
1376 return WRONG;
1377 }
1378 label:
1379 t += saved_seconds;
1380 (*funcp)(&t, offset, tmp);
1381 *okayp = TRUE;
1382 return t;
1383 }
1384
1385 static time_t
1386 time1(struct tm * CPP_CONST tmp, void (*const funcp)(const time_t * CPP_CONST, const long, struct tm *), const long offset)
1387 {
1388 time_t t;
1389 const struct state * sp;
1390 int samei, otheri;
1391 int okay;
1392
1393 if (tmp->tm_isdst > 1)
1394 tmp->tm_isdst = 1;
1395 t = time2(tmp, funcp, offset, &okay);
1396 if (okay || tmp->tm_isdst < 0)
1397 return t;
1398 /*
1399 ** We're supposed to assume that somebody took a time of one type
1400 ** and did some math on it that yielded a "struct tm" that's bad.
1401 ** We try to divine the type they started from and adjust to the
1402 ** type they need.
1403 */
1404 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
1405 #ifdef ALL_STATE
1406 if (sp == NULL)
1407 return WRONG;
1408 #endif /* defined ALL_STATE */
1409 for (samei = 0; samei < sp->typecnt; ++samei)
1410 {
1411 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1412 continue;
1413 for (otheri = 0; otheri < sp->typecnt; ++otheri)
1414 {
1415 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1416 continue;
1417 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1418 sp->ttis[samei].tt_gmtoff;
1419 tmp->tm_isdst = !tmp->tm_isdst;
1420 t = time2(tmp, funcp, offset, &okay);
1421 if (okay)
1422 return t;
1423 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1424 sp->ttis[samei].tt_gmtoff;
1425 tmp->tm_isdst = !tmp->tm_isdst;
1426 }
1427 }
1428 return WRONG;
1429 }
1430
1431 /*
1432 * @implemented
1433 */
1434 time_t
1435 mktime(struct tm * tmp)
1436 {
1437 return time1(tmp, localsub, 0L);
1438 }