8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbc / libc / gen / common / localtime.c
blobba4278f37eb054e3098d30fa6eb2ba4228b19333
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
28 /* from Arthur Olson's 6.1 */
30 /*LINTLIBRARY*/
32 #include <tzfile.h>
33 #include <time.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdio.h> /* for NULL */
37 #include <fcntl.h>
39 #include <sys/param.h> /* for MAXPATHLEN */
41 #undef FILENAME_MAX
42 #define FILENAME_MAX MAXPATHLEN
44 #ifdef __STDC__
46 #define P(s) s
48 #else /* !defined __STDC__ */
51 ** Memory management functions
54 extern char * calloc();
55 extern char * malloc();
58 ** Communication with the environment
61 extern char * getenv();
63 #define ASTERISK *
64 #define P(s) (/ASTERISK s ASTERISK/)
66 #define const
68 #endif /* !defined __STDC__ */
70 #ifndef TRUE
71 #define TRUE 1
72 #define FALSE 0
73 #endif /* !defined TRUE */
75 #define ACCESS_MODE O_RDONLY
77 #define OPEN_MODE O_RDONLY
80 ** Someone might make incorrect use of a time zone abbreviation:
81 ** 1. They might reference tzname[0] before calling tzset (explicitly
82 ** or implicitly).
83 ** 2. They might reference tzname[1] before calling tzset (explicitly
84 ** or implicitly).
85 ** 3. They might reference tzname[1] after setting to a time zone
86 ** in which Daylight Saving Time is never observed.
87 ** 4. They might reference tzname[0] after setting to a time zone
88 ** in which Standard Time is never observed.
89 ** 5. They might reference tm.TM_ZONE after calling offtime.
90 ** What's best to do in the above cases is open to debate;
91 ** for now, we just set things up so that in any of the five cases
92 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
93 ** string "tzname[0] used before set", and similarly for the other cases.
94 ** And another: initialize tzname[0] to "ERA", with an explanation in the
95 ** manual page of what this "time zone abbreviation" means (doing this so
96 ** that tzname[0] has the "normal" length of three characters).
98 static const char *WILDABBR = " ";
100 static const char *GMT = "GMT";
102 struct ttinfo { /* time type information */
103 long tt_gmtoff; /* GMT offset in seconds */
104 int tt_isdst; /* used to set tm_isdst */
105 int tt_abbrind; /* abbreviation list index */
106 int tt_ttisstd; /* TRUE if transition is std time */
109 struct state {
110 int timecnt;
111 int typecnt;
112 int charcnt;
113 time_t *ats;
114 unsigned char *types;
115 struct ttinfo *ttis;
116 char *chars;
117 char *last_tzload; /* name of file tzload() last opened */
120 struct rule {
121 int r_type; /* type of rule--see below */
122 int r_day; /* day number of rule */
123 int r_week; /* week number of rule */
124 int r_mon; /* month number of rule */
125 long r_time; /* transition time of rule */
128 #define JULIAN_DAY 0 /* Jn - Julian day */
129 #define DAY_OF_YEAR 1 /* n - day of year */
130 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
133 ** Prototypes for static functions.
136 static int allocall P((register struct state * sp));
137 static long detzcode P((const char * codep));
138 static void freeall P((register struct state * sp));
139 static const char * getzname P((const char * strp, const int i));
140 static const char * getnum P((const char * strp, int * nump, int min,
141 int max));
142 static const char * getsecs P((const char * strp, long * secsp));
143 static const char * getoffset P((const char * strp, long * offsetp));
144 static const char * getrule P((const char * strp, struct rule * rulep));
145 static void gmtload P((struct state * sp));
146 static void gmtsub P((const time_t * timep, long offset,
147 struct tm * tmp));
148 static void localsub P((const time_t * timep, long offset,
149 struct tm * tmp));
150 static void normalize P((int * tensptr, int * unitsptr, int base));
151 static void settzname P((void));
152 static time_t time1 P((struct tm * tmp, void (* funcp)(),
153 long offset));
154 static time_t time2 P((struct tm *tmp, void (* funcp)(),
155 long offset, int * okayp));
156 static void timesub P((const time_t * timep, long offset,
157 struct tm * tmp));
158 static int tmcomp P((const struct tm * atmp,
159 const struct tm * btmp));
160 static time_t transtime P((time_t janfirst, int year,
161 const struct rule * rulep, long offset));
162 static int tzload P((const char * name, struct state * sp));
163 static int tzparse P((const char * name, struct state * sp,
164 int lastditch));
166 static struct state * lclptr;
167 static struct state * gmtptr;
169 static int lcl_is_set;
170 static int gmt_is_set;
172 #ifdef S5EMUL
173 char * tzname[2] = {
174 "GMT",
175 " ",
178 time_t timezone = 0;
179 time_t altzone = 0;
180 int daylight = 0;
181 #endif /* defined S5EMUL */
183 static long
184 detzcode(codep)
185 const char * const codep;
187 register long result;
188 register int i;
190 result = 0;
191 for (i = 0; i < 4; ++i)
192 result = (result << 8) | (codep[i] & 0xff);
193 return result;
197 ** Free up existing items pointed to by the specified "state" structure,
198 ** and allocate new ones of sizes specified by that "state" structure.
199 ** Return 0 on success; return -1 and free all previously-allocated items
200 ** on failure.
202 static int
203 allocall(sp)
204 register struct state * const sp;
206 freeall(sp);
208 if (sp->timecnt != 0) {
209 sp->ats = (time_t *)calloc((unsigned)sp->timecnt,
210 (unsigned)sizeof (time_t));
211 if (sp->ats == NULL)
212 return -1;
213 sp->types =
214 (unsigned char *)calloc((unsigned)sp->timecnt,
215 (unsigned)sizeof (unsigned char));
216 if (sp->types == NULL) {
217 freeall(sp);
218 return -1;
221 sp->ttis =
222 (struct ttinfo *)calloc((unsigned)sp->typecnt,
223 (unsigned)sizeof (struct ttinfo));
224 if (sp->ttis == NULL) {
225 freeall(sp);
226 return -1;
228 sp->chars = (char *)calloc((unsigned)sp->charcnt + 1,
229 (unsigned)sizeof (char));
230 if (sp->chars == NULL) {
231 freeall(sp);
232 return -1;
234 return 0;
238 ** Free all the items pointed to by the specified "state" structure (except for
239 ** "chars", which might have other references to it), and zero out all the
240 ** pointers to those items.
242 static void
243 freeall(sp)
244 register struct state * const sp;
246 if (sp->ttis) {
247 free((char *)sp->ttis);
248 sp->ttis = 0;
250 if (sp->types) {
251 free((char *)sp->types);
252 sp->types = 0;
254 if (sp->ats) {
255 free((char *)sp->ats);
256 sp->ats = 0;
260 #ifdef S5EMUL
261 static void
262 settzname()
264 register const struct state * const sp = lclptr;
265 register int i;
267 tzname[0] = (char *)GMT;
268 tzname[1] = (char *)WILDABBR;
269 daylight = 0;
270 timezone = 0;
271 altzone = 0;
272 if (sp == NULL)
273 return;
274 for (i = 0; i < sp->typecnt; ++i) {
275 register const struct ttinfo * const ttisp = &sp->ttis[i];
277 tzname[ttisp->tt_isdst] =
278 (char *) &sp->chars[ttisp->tt_abbrind];
279 if (ttisp->tt_isdst)
280 daylight = 1;
281 if (i == 0 || !ttisp->tt_isdst)
282 timezone = -(ttisp->tt_gmtoff);
283 if (i == 0 || ttisp->tt_isdst)
284 altzone = -(ttisp->tt_gmtoff);
287 ** And to get the latest zone names into tzname. . .
289 for (i = 0; i < sp->timecnt; ++i) {
290 register const struct ttinfo * const ttisp =
291 &sp->ttis[sp->types[i]];
293 tzname[ttisp->tt_isdst] =
294 (char *) &sp->chars[ttisp->tt_abbrind];
297 #endif
300 ** Maximum size of a time zone file.
302 #define MAX_TZFILESZ (sizeof (struct tzhead) + \
303 TZ_MAX_TIMES * (4 + sizeof (char)) + \
304 TZ_MAX_TYPES * (4 + 2 * sizeof (char)) + \
305 TZ_MAX_CHARS * sizeof (char) + \
306 TZ_MAX_LEAPS * 2 * 4 + \
307 TZ_MAX_TYPES * sizeof (char))
309 static int
310 tzload(name, sp)
311 register const char * name;
312 register struct state * const sp;
314 register const char * p;
315 register int i;
316 register int fid;
318 if (name == NULL && (name = (const char *)TZDEFAULT) == NULL)
319 return -1;
321 register int doaccess;
322 char fullname[FILENAME_MAX + 1];
324 if (name[0] == ':')
325 ++name;
326 doaccess = name[0] == '/';
327 if (!doaccess) {
328 if ((p = TZDIR) == NULL)
329 return -1;
330 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
331 return -1;
332 (void) strcpy(fullname, p);
333 (void) strcat(fullname, "/");
334 (void) strcat(fullname, name);
336 ** Set doaccess if '.' (as in "../") shows up in name.
338 if (strchr(name, '.') != NULL)
339 doaccess = TRUE;
340 name = fullname;
342 if (sp->last_tzload && strcmp(sp->last_tzload, name) == 0)
343 return (0);
344 if (doaccess && access(name, ACCESS_MODE) != 0)
345 return -1;
346 if ((fid = open(name, OPEN_MODE)) == -1)
347 return -1;
350 register const struct tzhead * tzhp;
351 char buf[MAX_TZFILESZ];
352 int leapcnt;
353 int ttisstdcnt;
355 i = read(fid, buf, sizeof buf);
356 if (close(fid) != 0 || i < sizeof *tzhp)
357 return -1;
358 tzhp = (struct tzhead *) buf;
359 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
360 leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
361 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
362 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
363 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
364 if (leapcnt < 0 || leapcnt > TZ_MAX_LEAPS ||
365 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
366 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
367 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
368 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
369 return -1;
370 if (i < sizeof *tzhp +
371 sp->timecnt * (4 + sizeof (char)) +
372 sp->typecnt * (4 + 2 * sizeof (char)) +
373 sp->charcnt * sizeof (char) +
374 leapcnt * 2 * 4 +
375 ttisstdcnt * sizeof (char))
376 return -1;
377 if (allocall(sp) < 0)
378 return -1;
379 p = buf + sizeof *tzhp;
380 for (i = 0; i < sp->timecnt; ++i) {
381 sp->ats[i] = detzcode(p);
382 p += 4;
384 for (i = 0; i < sp->timecnt; ++i) {
385 sp->types[i] = (unsigned char) *p++;
386 if (sp->types[i] >= sp->typecnt)
387 return -1;
389 for (i = 0; i < sp->typecnt; ++i) {
390 register struct ttinfo * ttisp;
392 ttisp = &sp->ttis[i];
393 ttisp->tt_gmtoff = detzcode(p);
394 p += 4;
395 ttisp->tt_isdst = (unsigned char) *p++;
396 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
397 return -1;
398 ttisp->tt_abbrind = (unsigned char) *p++;
399 if (ttisp->tt_abbrind < 0 ||
400 ttisp->tt_abbrind > sp->charcnt)
401 return -1;
403 for (i = 0; i < sp->charcnt-1; ++i)
404 sp->chars[i] = *p++;
405 sp->chars[i] = '\0'; /* ensure '\0' at end */
406 p += (4 + 4) * leapcnt; /* skip leap seconds list */
407 for (i = 0; i < sp->typecnt; ++i) {
408 register struct ttinfo * ttisp;
410 ttisp = &sp->ttis[i];
411 if (ttisstdcnt == 0)
412 ttisp->tt_ttisstd = FALSE;
413 else {
414 ttisp->tt_ttisstd = *p++;
415 if (ttisp->tt_ttisstd != TRUE &&
416 ttisp->tt_ttisstd != FALSE)
417 return -1;
421 if (sp->last_tzload)
422 free(sp->last_tzload);
423 sp->last_tzload = strdup(name);
424 return 0;
427 static const int mon_lengths[2][MONSPERYEAR] = {
428 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
429 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
432 static const int year_lengths[2] = {
433 DAYSPERNYEAR, DAYSPERLYEAR
437 ** Given a pointer into a time zone string, scan until a character that is not
438 ** a valid character in a zone name is found. Return a pointer to that
439 ** character.
440 ** Support both quoted and unquoted timezones.
443 static const char *
444 getzname(strp, quoted)
445 const char * strp;
446 int quoted;
448 unsigned char c;
450 if (quoted) {
451 while ((c = (unsigned char)*strp) != '\0' &&
452 (isalnum(c) || (c == '+') || (c == '-')))
453 ++strp;
454 } else {
455 while ((c = (unsigned char)*strp) != '\0' && !isdigit(c)
456 && (c != ',') && (c != '-') && (c != '+'))
457 ++strp;
459 return strp;
463 ** Given a pointer into a time zone string, extract a number from that string.
464 ** Check that the number is within a specified range; if it is not, return
465 ** NULL.
466 ** Otherwise, return a pointer to the first character not part of the number.
469 static const char *
470 getnum(strp, nump, min, max)
471 register const char * strp;
472 int * const nump;
473 const int min;
474 const int max;
476 register char c;
477 register int num;
479 if (strp == NULL || !isdigit(*strp))
480 return NULL;
481 num = 0;
482 while ((c = *strp) != '\0' && isdigit(c)) {
483 num = num * 10 + (c - '0');
484 if (num > max)
485 return NULL; /* illegal value */
486 ++strp;
488 if (num < min)
489 return NULL; /* illegal value */
490 *nump = num;
491 return strp;
495 ** Given a pointer into a time zone string, extract a number of seconds,
496 ** in hh[:mm[:ss]] form, from the string.
497 ** If any error occurs, return NULL.
498 ** Otherwise, return a pointer to the first character not part of the number
499 ** of seconds.
502 static const char *
503 getsecs(strp, secsp)
504 register const char * strp;
505 long * const secsp;
507 int num;
509 strp = getnum(strp, &num, 0, HOURSPERDAY);
510 if (strp == NULL)
511 return NULL;
512 *secsp = num * SECSPERHOUR;
513 if (*strp == ':') {
514 ++strp;
515 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
516 if (strp == NULL)
517 return NULL;
518 *secsp += num * SECSPERMIN;
519 if (*strp == ':') {
520 ++strp;
521 strp = getnum(strp, &num, 0, SECSPERMIN - 1);
522 if (strp == NULL)
523 return NULL;
524 *secsp += num;
527 return strp;
531 ** Given a pointer into a time zone string, extract an offset, in
532 ** [+-]hh[:mm[:ss]] form, from the string.
533 ** If any error occurs, return NULL.
534 ** Otherwise, return a pointer to the first character not part of the time.
537 static const char *
538 getoffset(strp, offsetp)
539 register const char * strp;
540 long * const offsetp;
542 register int neg;
544 if (*strp == '-') {
545 neg = 1;
546 ++strp;
547 } else if (isdigit(*strp) || *strp++ == '+')
548 neg = 0;
549 else return NULL; /* illegal offset */
550 strp = getsecs(strp, offsetp);
551 if (strp == NULL)
552 return NULL; /* illegal time */
553 if (neg)
554 *offsetp = -*offsetp;
555 return strp;
559 ** Given a pointer into a time zone string, extract a rule in the form
560 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
561 ** If a valid rule is not found, return NULL.
562 ** Otherwise, return a pointer to the first character not part of the rule.
565 static const char *
566 getrule(strp, rulep)
567 const char * strp;
568 register struct rule * const rulep;
570 if (*strp == 'J') {
572 ** Julian day.
574 rulep->r_type = JULIAN_DAY;
575 ++strp;
576 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
577 } else if (*strp == 'M') {
579 ** Month, week, day.
581 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
582 ++strp;
583 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
584 if (strp == NULL)
585 return NULL;
586 if (*strp++ != '.')
587 return NULL;
588 strp = getnum(strp, &rulep->r_week, 1, 5);
589 if (strp == NULL)
590 return NULL;
591 if (*strp++ != '.')
592 return NULL;
593 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
594 } else if (isdigit(*strp)) {
596 ** Day of year.
598 rulep->r_type = DAY_OF_YEAR;
599 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
600 } else return NULL; /* invalid format */
601 if (strp == NULL)
602 return NULL;
603 if (*strp == '/') {
605 ** Time specified.
607 ++strp;
608 strp = getsecs(strp, &rulep->r_time);
609 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
610 return strp;
614 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
615 ** year, a rule, and the offset from GMT at the time that rule takes effect,
616 ** calculate the Epoch-relative time that rule takes effect.
619 static time_t
620 transtime(janfirst, year, rulep, offset)
621 const time_t janfirst;
622 const int year;
623 register const struct rule * const rulep;
624 const long offset;
626 register int leapyear;
627 register time_t value;
628 register int i;
629 int d, m1, yy0, yy1, yy2, dow;
631 leapyear = isleap(year);
632 switch (rulep->r_type) {
634 case JULIAN_DAY:
636 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
637 ** years.
638 ** In non-leap years, or if the day number is 59 or less, just
639 ** add SECSPERDAY times the day number-1 to the time of
640 ** January 1, midnight, to get the day.
642 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
643 if (leapyear && rulep->r_day >= 60)
644 value += SECSPERDAY;
645 break;
647 case DAY_OF_YEAR:
649 ** n - day of year.
650 ** Just add SECSPERDAY times the day number to the time of
651 ** January 1, midnight, to get the day.
653 value = janfirst + rulep->r_day * SECSPERDAY;
654 break;
656 case MONTH_NTH_DAY_OF_WEEK:
658 ** Mm.n.d - nth "dth day" of month m.
660 value = janfirst;
661 for (i = 0; i < rulep->r_mon - 1; ++i)
662 value += mon_lengths[leapyear][i] * SECSPERDAY;
665 ** Use Zeller's Congruence to get day-of-week of first day of
666 ** month.
668 m1 = (rulep->r_mon + 9) % 12 + 1;
669 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
670 yy1 = yy0 / 100;
671 yy2 = yy0 % 100;
672 dow = ((26 * m1 - 2) / 10 +
673 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
674 if (dow < 0)
675 dow += DAYSPERWEEK;
678 ** "dow" is the day-of-week of the first day of the month. Get
679 ** the day-of-month (zero-origin) of the first "dow" day of the
680 ** month.
682 d = rulep->r_day - dow;
683 if (d < 0)
684 d += DAYSPERWEEK;
685 for (i = 1; i < rulep->r_week; ++i) {
686 if (d + DAYSPERWEEK >=
687 mon_lengths[leapyear][rulep->r_mon - 1])
688 break;
689 d += DAYSPERWEEK;
693 ** "d" is the day-of-month (zero-origin) of the day we want.
695 value += d * SECSPERDAY;
696 break;
700 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
701 ** question. To get the Epoch-relative time of the specified local
702 ** time on that day, add the transition time and the current offset
703 ** from GMT.
705 return value + rulep->r_time + offset;
709 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
710 ** appropriate.
713 static int
714 tzparse(name, sp, lastditch)
715 const char * name;
716 struct state * const sp;
717 const int lastditch;
719 const char * stdname;
720 const char * dstname;
721 int stdlen;
722 int dstlen;
723 long stdoffset;
724 long dstoffset;
725 time_t * atp;
726 unsigned char * typep;
727 char * cp;
729 freeall(sp); /* */
730 stdname = name;
731 if (lastditch) {
732 stdlen = strlen(name); /* length of standard zone name */
733 name += stdlen;
734 if (stdlen >= sizeof sp->chars)
735 stdlen = (sizeof sp->chars) - 1;
736 } else {
737 if (*name == '<') {
738 name++;
739 stdname++;
740 name = getzname(name, 1);
741 if (*name != '>') {
742 return (-1);
744 stdlen = name - stdname;
745 name++;
746 } else {
747 name = getzname(name, 0);
748 stdlen = name - stdname;
750 if (stdlen < 3)
751 return -1;
753 if (*name == '\0')
754 stdoffset = 0;
755 else {
756 name = getoffset(name, &stdoffset);
757 if (name == NULL)
758 return -1;
760 if (*name != '\0') {
761 dstname = name;
762 if (*name == '<') {
763 name++;
764 dstname++;
765 name = getzname(name, 1);
766 if (*name != '>') {
767 return (-1);
769 dstlen = name - dstname;
770 name++;
771 } else {
772 name = getzname(name, 0);
773 dstlen = name - dstname;
775 if (dstlen < 3)
776 return -1;
777 if (*name != '\0' && *name != ',' && *name != ';') {
778 name = getoffset(name, &dstoffset);
779 if (name == NULL)
780 return -1;
781 } else dstoffset = stdoffset - SECSPERHOUR;
782 if (*name == ',' || *name == ';') {
783 struct rule start;
784 struct rule end;
785 register int year;
786 register time_t janfirst;
787 time_t starttime;
788 time_t endtime;
790 ++name;
791 if ((name = getrule(name, &start)) == NULL)
792 return -1;
793 if (*name++ != ',')
794 return -1;
795 if ((name = getrule(name, &end)) == NULL)
796 return -1;
797 if (*name != '\0')
798 return -1;
799 sp->typecnt = 2; /* standard time and DST */
801 ** Two transitions per year, from EPOCH_YEAR to 2037.
803 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
804 if (sp->timecnt > TZ_MAX_TIMES)
805 return -1;
806 sp->charcnt = stdlen + 1 + dstlen + 1;
807 if (allocall(sp) < 0)
808 return -1;
809 sp->ttis[0].tt_gmtoff = -dstoffset;
810 sp->ttis[0].tt_isdst = 1;
811 sp->ttis[0].tt_abbrind = stdlen + 1;
812 sp->ttis[1].tt_gmtoff = -stdoffset;
813 sp->ttis[1].tt_isdst = 0;
814 sp->ttis[1].tt_abbrind = 0;
815 atp = sp->ats;
816 typep = sp->types;
817 janfirst = 0;
818 for (year = EPOCH_YEAR; year <= 2037; ++year) {
819 starttime = transtime(janfirst, year, &start,
820 stdoffset);
821 endtime = transtime(janfirst, year, &end,
822 dstoffset);
823 if (starttime > endtime) {
824 *atp++ = endtime;
825 *typep++ = 1; /* DST ends */
826 *atp++ = starttime;
827 *typep++ = 0; /* DST begins */
828 } else {
829 *atp++ = starttime;
830 *typep++ = 0; /* DST begins */
831 *atp++ = endtime;
832 *typep++ = 1; /* DST ends */
834 janfirst +=
835 year_lengths[isleap(year)] * SECSPERDAY;
837 } else {
838 int sawstd;
839 int sawdst;
840 long stdfix;
841 long dstfix;
842 long oldfix;
843 int isdst;
844 register int i;
846 if (*name != '\0')
847 return -1;
848 if (tzload(TZDEFRULES, sp) != 0) {
849 freeall(sp);
850 return -1;
853 ** Discard zone abbreviations from file, and allocate
854 ** space for the ones from TZ.
856 free(sp->chars);
857 sp->charcnt = stdlen + 1 + dstlen + 1;
858 sp->chars = (char *)calloc((unsigned)sp->charcnt,
859 (unsigned)sizeof (char));
861 ** Compute the difference between the real and
862 ** prototype standard and summer time offsets
863 ** from GMT, and put the real standard and summer
864 ** time offsets into the rules in place of the
865 ** prototype offsets.
867 sawstd = FALSE;
868 sawdst = FALSE;
869 stdfix = 0;
870 dstfix = 0;
871 for (i = 0; i < sp->typecnt; ++i) {
872 if (sp->ttis[i].tt_isdst) {
873 oldfix = dstfix;
874 dstfix =
875 sp->ttis[i].tt_gmtoff + dstoffset;
876 if (sawdst && (oldfix != dstfix))
877 return -1;
878 sp->ttis[i].tt_gmtoff = -dstoffset;
879 sp->ttis[i].tt_abbrind = stdlen + 1;
880 sawdst = TRUE;
881 } else {
882 oldfix = stdfix;
883 stdfix =
884 sp->ttis[i].tt_gmtoff + stdoffset;
885 if (sawstd && (oldfix != stdfix))
886 return -1;
887 sp->ttis[i].tt_gmtoff = -stdoffset;
888 sp->ttis[i].tt_abbrind = 0;
889 sawstd = TRUE;
893 ** Make sure we have both standard and summer time.
895 if (!sawdst || !sawstd)
896 return -1;
898 ** Now correct the transition times by shifting
899 ** them by the difference between the real and
900 ** prototype offsets. Note that this difference
901 ** can be different in standard and summer time;
902 ** the prototype probably has a 1-hour difference
903 ** between standard and summer time, but a different
904 ** difference can be specified in TZ.
906 isdst = FALSE; /* we start in standard time */
907 for (i = 0; i < sp->timecnt; ++i) {
908 register const struct ttinfo * ttisp;
911 ** If summer time is in effect, and the
912 ** transition time was not specified as
913 ** standard time, add the summer time
914 ** offset to the transition time;
915 ** otherwise, add the standard time offset
916 ** to the transition time.
918 ttisp = &sp->ttis[sp->types[i]];
919 sp->ats[i] +=
920 (isdst && !ttisp->tt_ttisstd) ?
921 dstfix : stdfix;
922 isdst = ttisp->tt_isdst;
925 } else {
926 dstlen = 0;
927 sp->typecnt = 1; /* only standard time */
928 sp->timecnt = 0;
929 sp->charcnt = stdlen + 1;
930 if (allocall(sp) < 0)
931 return -1;
932 sp->ttis[0].tt_gmtoff = -stdoffset;
933 sp->ttis[0].tt_isdst = 0;
934 sp->ttis[0].tt_abbrind = 0;
936 cp = sp->chars;
937 (void) strncpy(cp, stdname, stdlen);
938 cp += stdlen;
939 *cp++ = '\0';
940 if (dstlen != 0) {
941 (void) strncpy(cp, dstname, dstlen);
942 *(cp + dstlen) = '\0';
944 return 0;
947 static void
948 gmtload(sp)
949 struct state * const sp;
951 if (tzload(GMT, sp) != 0)
952 (void) tzparse(GMT, sp, TRUE);
955 void
956 tzsetwall()
958 lcl_is_set = TRUE;
959 if (lclptr == NULL) {
960 lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr);
961 if (lclptr == NULL) {
962 #ifdef S5EMUL
963 settzname(); /* all we can do */
964 #endif
965 return;
968 if (tzload((char *) NULL, lclptr) != 0)
969 gmtload(lclptr);
970 #ifdef S5EMUL
971 settzname();
972 #endif
975 void
976 tzset()
978 register const char * name;
980 name = (const char *)getenv("TZ");
981 if (name == NULL) {
982 tzsetwall();
983 return;
985 lcl_is_set = TRUE;
986 if (lclptr == NULL) {
987 lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr);
988 if (lclptr == NULL) {
989 #ifdef S5EMUL
990 settzname(); /* all we can do */
991 #endif
992 return;
995 if (*name == '\0') {
997 ** User wants it fast rather than right.
999 lclptr->timecnt = 0;
1000 lclptr->typecnt = 1;
1001 lclptr->charcnt = sizeof GMT;
1002 if (allocall(lclptr) < 0)
1003 return;
1004 lclptr->ttis[0].tt_gmtoff = 0;
1005 lclptr->ttis[0].tt_abbrind = 0;
1006 (void) strcpy(lclptr->chars, GMT);
1007 } else if (tzload(name, lclptr) != 0)
1008 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1009 (void) tzparse(name, lclptr, TRUE);
1010 #ifdef S5EMUL
1011 settzname();
1012 #endif
1016 ** The easy way to behave "as if no library function calls" localtime
1017 ** is to not call it--so we drop its guts into "localsub", which can be
1018 ** freely called. (And no, the PANS doesn't require the above behavior--
1019 ** but it *is* desirable.)
1021 ** The unused offset argument is for the benefit of mktime variants.
1024 static struct tm tm;
1026 /*ARGSUSED*/
1027 static void
1028 localsub(timep, offset, tmp)
1029 const time_t * const timep;
1030 const long offset;
1031 struct tm * const tmp;
1033 register const struct state * sp;
1034 register const struct ttinfo * ttisp;
1035 register int i;
1036 const time_t t = *timep;
1038 if (!lcl_is_set)
1039 tzset();
1040 sp = lclptr;
1041 if (sp == NULL) {
1042 gmtsub(timep, offset, tmp);
1043 return;
1045 if (sp->timecnt == 0 || t < sp->ats[0]) {
1046 i = 0;
1047 while (sp->ttis[i].tt_isdst)
1048 if (++i >= sp->typecnt) {
1049 i = 0;
1050 break;
1052 } else {
1053 for (i = 1; i < sp->timecnt; ++i)
1054 if (t < sp->ats[i])
1055 break;
1056 i = sp->types[i - 1];
1058 ttisp = &sp->ttis[i];
1059 timesub(&t, ttisp->tt_gmtoff, tmp);
1060 tmp->tm_isdst = ttisp->tt_isdst;
1061 #ifdef S5EMUL
1062 tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
1063 #endif /* S5EMUL */
1064 tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
1067 struct tm *
1068 localtime(timep)
1069 const time_t * const timep;
1071 time_t temp_time = *(const time_t*)timep;
1073 _ltzset(&temp_time); /*
1074 * base localtime calls this to initialize
1075 * some things, so we'll do it here, too.
1077 localsub(timep, 0L, &tm);
1078 return &tm;
1082 ** gmtsub is to gmtime as localsub is to localtime.
1085 static void
1086 gmtsub(timep, offset, tmp)
1087 const time_t * const timep;
1088 const long offset;
1089 struct tm * const tmp;
1091 if (!gmt_is_set) {
1092 gmt_is_set = TRUE;
1093 gmtptr = (struct state *) calloc(1, (unsigned)sizeof *gmtptr);
1094 if (gmtptr != NULL)
1095 gmtload(gmtptr);
1097 timesub(timep, offset, tmp);
1099 ** Could get fancy here and deliver something such as
1100 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1101 ** but this is no time for a treasure hunt.
1103 if (offset != 0)
1104 tmp->tm_zone = (char *)WILDABBR;
1105 else {
1106 if (gmtptr == NULL)
1107 tmp->tm_zone = (char *)GMT;
1108 else tmp->tm_zone = gmtptr->chars;
1112 struct tm *
1113 gmtime(timep)
1114 const time_t * const timep;
1116 gmtsub(timep, 0L, &tm);
1117 return &tm;
1120 struct tm *
1121 offtime(timep, offset)
1122 const time_t * const timep;
1123 const long offset;
1125 gmtsub(timep, offset, &tm);
1126 return &tm;
1129 static void
1130 timesub(timep, offset, tmp)
1131 const time_t * const timep;
1132 const long offset;
1133 register struct tm * const tmp;
1135 register long days;
1136 register long rem;
1137 register int y;
1138 register int yleap;
1139 register const int * ip;
1141 days = *timep / SECSPERDAY;
1142 rem = *timep % SECSPERDAY;
1143 rem += offset;
1144 while (rem < 0) {
1145 rem += SECSPERDAY;
1146 --days;
1148 while (rem >= SECSPERDAY) {
1149 rem -= SECSPERDAY;
1150 ++days;
1152 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1153 rem = rem % SECSPERHOUR;
1154 tmp->tm_min = (int) (rem / SECSPERMIN);
1155 tmp->tm_sec = (int) (rem % SECSPERMIN);
1156 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1157 if (tmp->tm_wday < 0)
1158 tmp->tm_wday += DAYSPERWEEK;
1159 y = EPOCH_YEAR;
1160 if (days >= 0)
1161 for ( ; ; ) {
1162 yleap = isleap(y);
1163 if (days < (long) year_lengths[yleap])
1164 break;
1165 ++y;
1166 days = days - (long) year_lengths[yleap];
1168 else do {
1169 --y;
1170 yleap = isleap(y);
1171 days = days + (long) year_lengths[yleap];
1172 } while (days < 0);
1173 tmp->tm_year = y - TM_YEAR_BASE;
1174 tmp->tm_yday = (int) days;
1175 ip = mon_lengths[yleap];
1176 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1177 days = days - (long) ip[tmp->tm_mon];
1178 tmp->tm_mday = (int) (days + 1);
1179 tmp->tm_isdst = 0;
1180 tmp->tm_gmtoff = offset;
1184 ** Adapted from code provided by Robert Elz, who writes:
1185 ** The "best" way to do mktime I think is based on an idea of Bob
1186 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1187 ** It does a binary search of the time_t space. Since time_t's are
1188 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1189 ** would still be very reasonable).
1192 #ifndef WRONG
1193 #define WRONG (-1)
1194 #endif /* !defined WRONG */
1196 static void
1197 normalize(tensptr, unitsptr, base)
1198 int * const tensptr;
1199 int * const unitsptr;
1200 const int base;
1202 int tmp;
1204 if (*unitsptr >= base) {
1205 *tensptr += *unitsptr / base;
1206 *unitsptr %= base;
1207 } else if (*unitsptr < 0) {
1208 /* tmp has the range 0 to abs(*unitptr) -1 */
1209 tmp = -1 - (*unitsptr);
1210 *tensptr -= (tmp/base + 1);
1211 *unitsptr = (base - 1) - (tmp % base);
1215 static int
1216 tmcomp(atmp, btmp)
1217 register const struct tm * const atmp;
1218 register const struct tm * const btmp;
1220 register int result;
1222 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1223 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1224 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1225 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1226 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1227 result = atmp->tm_sec - btmp->tm_sec;
1228 return result;
1231 static time_t
1232 time2(tmp, funcp, offset, okayp)
1233 struct tm * const tmp;
1234 void (* const funcp)();
1235 const long offset;
1236 int * const okayp;
1238 register const struct state * sp;
1239 register int dir;
1240 register int bits;
1241 register int i, j ;
1242 register int saved_seconds;
1243 time_t newt;
1244 time_t t;
1245 struct tm yourtm, mytm;
1247 *okayp = FALSE;
1248 yourtm = *tmp;
1249 if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
1250 normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
1251 normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
1252 normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
1253 normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
1254 while (yourtm.tm_mday <= 0) {
1255 if (yourtm.tm_mon == 0) {
1256 yourtm.tm_mon = 12;
1257 --yourtm.tm_year;
1259 yourtm.tm_mday +=
1260 mon_lengths[isleap(yourtm.tm_year +
1261 TM_YEAR_BASE)][--yourtm.tm_mon];
1262 if (yourtm.tm_mon >= MONSPERYEAR) {
1263 yourtm.tm_mon = 0;
1264 --yourtm.tm_year;
1267 for ( ; ; ) {
1268 i = mon_lengths[isleap(yourtm.tm_year +
1269 TM_YEAR_BASE)][yourtm.tm_mon];
1270 if (yourtm.tm_mday <= i)
1271 break;
1272 yourtm.tm_mday -= i;
1273 if (++yourtm.tm_mon >= MONSPERYEAR) {
1274 yourtm.tm_mon = 0;
1275 ++yourtm.tm_year;
1278 saved_seconds = yourtm.tm_sec;
1279 yourtm.tm_sec = 0;
1281 ** Calculate the number of magnitude bits in a time_t
1282 ** (this works regardless of whether time_t is
1283 ** signed or unsigned, though lint complains if unsigned).
1285 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1288 ** If time_t is signed, then 0 is the median value,
1289 ** if time_t is unsigned, then 1 << bits is median.
1291 t = (t < 0) ? 0 : ((time_t) 1 << bits);
1292 for ( ; ; ) {
1293 (*funcp)(&t, offset, &mytm);
1294 dir = tmcomp(&mytm, &yourtm);
1295 if (dir != 0) {
1296 if (bits-- < 0)
1297 return WRONG;
1298 if (bits < 0)
1299 --t;
1300 else if (dir > 0)
1301 t -= (time_t) 1 << bits;
1302 else t += (time_t) 1 << bits;
1303 continue;
1305 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1306 break;
1308 ** Right time, wrong type.
1309 ** Hunt for right time, right type.
1310 ** It's okay to guess wrong since the guess
1311 ** gets checked.
1313 sp = (const struct state *)
1314 ((funcp == localsub) ? lclptr : gmtptr);
1315 if (sp == NULL)
1316 return WRONG;
1317 for (i = 0; i < sp->typecnt; ++i) {
1318 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1319 continue;
1320 for (j = 0; j < sp->typecnt; ++j) {
1321 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1322 continue;
1323 newt = t + sp->ttis[j].tt_gmtoff -
1324 sp->ttis[i].tt_gmtoff;
1325 (*funcp)(&newt, offset, &mytm);
1326 if (tmcomp(&mytm, &yourtm) != 0)
1327 continue;
1328 if (mytm.tm_isdst != yourtm.tm_isdst)
1329 continue;
1331 ** We have a match.
1333 t = newt;
1334 goto label;
1337 return WRONG;
1339 label:
1340 t += saved_seconds;
1341 (*funcp)(&t, offset, tmp);
1342 *okayp = TRUE;
1343 return t;
1346 static time_t
1347 time1(tmp, funcp, offset)
1348 struct tm * const tmp;
1349 void (* const funcp)();
1350 const long offset;
1352 register time_t t;
1353 register const struct state * sp;
1354 register int samei, otheri;
1355 int okay;
1358 if (tmp->tm_isdst > 1)
1359 tmp->tm_isdst = 1;
1360 t = time2(tmp, funcp, offset, &okay);
1361 if (okay || tmp->tm_isdst < 0)
1362 return t;
1364 ** We're supposed to assume that somebody took a time of one type
1365 ** and did some math on it that yielded a "struct tm" that's bad.
1366 ** We try to divine the type they started from and adjust to the
1367 ** type they need.
1369 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
1370 if (sp == NULL)
1371 return WRONG;
1372 for (samei = 0; samei < sp->typecnt; ++samei) {
1373 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1374 continue;
1375 for (otheri = 0; otheri < sp->typecnt; ++otheri) {
1376 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1377 continue;
1378 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1379 sp->ttis[samei].tt_gmtoff;
1380 tmp->tm_isdst = !tmp->tm_isdst;
1381 t = time2(tmp, funcp, offset, &okay);
1382 if (okay)
1383 return t;
1384 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1385 sp->ttis[samei].tt_gmtoff;
1386 tmp->tm_isdst = !tmp->tm_isdst;
1389 return WRONG;
1392 time_t
1393 mktime(tmp)
1394 struct tm * const tmp;
1396 return time1(tmp, localsub, 0L);
1399 time_t
1400 timelocal(tmp)
1401 struct tm * const tmp;
1403 tmp->tm_isdst = -1;
1404 return mktime(tmp);
1407 time_t
1408 timegm(tmp)
1409 struct tm * const tmp;
1411 return time1(tmp, gmtsub, 0L);
1414 time_t
1415 timeoff(tmp, offset)
1416 struct tm * const tmp;
1417 const long offset;
1420 return time1(tmp, gmtsub, offset);