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