Deleted Added
full compact
1#ifndef lint
2#ifndef NOID
3static char elsieid[] = "@(#)localtime.c 7.19";
4#endif /* !defined NOID */
5#endif /* !defined lint */
6
7/*
8** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
9** POSIX-style TZ environment variable handling from Guy Harris
10** (guy@auspex.com).
11*/
12
13/*LINTLIBRARY*/
14
15#include "private.h"
16#include "tzfile.h"
17#include "fcntl.h"
18
19#define ACCESS_MODE O_RDONLY
20
21#ifdef O_BINARY
22#define OPEN_MODE (O_RDONLY | O_BINARY)
23#endif /* defined O_BINARY */
24#ifndef O_BINARY
25#define OPEN_MODE O_RDONLY
26#endif /* !defined O_BINARY */
27
28#ifndef WILDABBR
29/*
30** Someone might make incorrect use of a time zone abbreviation:
31** 1. They might reference tzname[0] before calling tzset (explicitly
32** or implicitly).
33** 2. They might reference tzname[1] before calling tzset (explicitly
34** or implicitly).
35** 3. They might reference tzname[1] after setting to a time zone
36** in which Daylight Saving Time is never observed.
37** 4. They might reference tzname[0] after setting to a time zone
38** in which Standard Time is never observed.
39** 5. They might reference tm.TM_ZONE after calling offtime.
40** What's best to do in the above cases is open to debate;
41** for now, we just set things up so that in any of the five cases
42** WILDABBR is used. Another possibility: initialize tzname[0] to the
43** string "tzname[0] used before set", and similarly for the other cases.
44** And another: initialize tzname[0] to "ERA", with an explanation in the
45** manual page of what this "time zone abbreviation" means (doing this so
46** that tzname[0] has the "normal" length of three characters).
47*/
48#define WILDABBR " "
49#endif /* !defined WILDABBR */
50
51static const char GMT[] = "GMT";
52
53struct ttinfo { /* time type information */
54 long tt_gmtoff; /* GMT offset in seconds */
55 int tt_isdst; /* used to set tm_isdst */
56 int tt_abbrind; /* abbreviation list index */
57 int tt_ttisstd; /* TRUE if transition is std time */
58};
59
60struct lsinfo { /* leap second information */
61 time_t ls_trans; /* transition time */
62 long ls_corr; /* correction to apply */
63};
64
65#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))

--- 8 unchanged lines hidden (view full) ---

74struct state {
75 int leapcnt;
76 int timecnt;
77 int typecnt;
78 int charcnt;
79 time_t ats[TZ_MAX_TIMES];
80 unsigned char types[TZ_MAX_TIMES];
81 struct ttinfo ttis[TZ_MAX_TYPES];
82 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof GMT),
83 (2 * (MY_TZNAME_MAX + 1)))];
84 struct lsinfo lsis[TZ_MAX_LEAPS];
85};
86
87struct rule {
88 int r_type; /* type of rule--see below */
89 int r_day; /* day number of rule */
90 int r_week; /* week number of rule */

--- 20 unchanged lines hidden (view full) ---

111static void gmtsub P((const time_t * timep, long offset,
112 struct tm * tmp));
113static void localsub P((const time_t * timep, long offset,
114 struct tm * tmp));
115static int increment_overflow P((int * number, int delta));
116static int normalize_overflow P((int * tensptr, int * unitsptr,
117 int base));
118static void settzname P((void));
119static time_t time1 P((struct tm * tmp, void (* funcp)(),
120 long offset));
121static time_t time2 P((struct tm *tmp, void (* funcp)(),
122 long offset, int * okayp));
123static void timesub P((const time_t * timep, long offset,
124 const struct state * sp, struct tm * tmp));
125static int tmcomp P((const struct tm * atmp,
126 const struct tm * btmp));
127static time_t transtime P((time_t janfirst, int year,
128 const struct rule * rulep, long offset));
129static int tzload P((const char * name, struct state * sp));

--- 7 unchanged lines hidden (view full) ---

137
138#ifndef ALL_STATE
139static struct state lclmem;
140static struct state gmtmem;
141#define lclptr (&lclmem)
142#define gmtptr (&gmtmem)
143#endif /* State Farm */
144
145static int lcl_is_set;
146static int gmt_is_set;
147
148char * tzname[2] = {
149 WILDABBR,
150 WILDABBR
151};
152
153#ifdef USG_COMPAT
154time_t timezone = 0;
155int daylight = 0;
156#endif /* defined USG_COMPAT */
157
158#ifdef ALTZONE
159time_t altzone = 0;
160#endif /* defined ALTZONE */
161
162static long
163detzcode(codep)
164const char * const codep;
165{
166 register long result;
167 register int i;
168
169 result = 0;
170 for (i = 0; i < 4; ++i)
171 result = (result << 8) | (codep[i] & 0xff);
172 return result;
173}
174
175static void
176settzname()
177{
178 register const struct state * const sp = lclptr;
179 register int i;
180
181 tzname[0] = WILDABBR;
182 tzname[1] = WILDABBR;
183#ifdef USG_COMPAT
184 daylight = 0;
185 timezone = 0;
186#endif /* defined USG_COMPAT */
187#ifdef ALTZONE
188 altzone = 0;
189#endif /* defined ALTZONE */
190#ifdef ALL_STATE
191 if (sp == NULL) {
192 tzname[0] = tzname[1] = GMT;
193 return;
194 }
195#endif /* defined ALL_STATE */
196 for (i = 0; i < sp->typecnt; ++i) {
197 register const struct ttinfo * const ttisp = &sp->ttis[i];
198
199 tzname[ttisp->tt_isdst] =
200 (char *) &sp->chars[ttisp->tt_abbrind];
201#ifdef USG_COMPAT
202 if (ttisp->tt_isdst)
203 daylight = 1;
204 if (i == 0 || !ttisp->tt_isdst)
205 timezone = -(ttisp->tt_gmtoff);
206#endif /* defined USG_COMPAT */
207#ifdef ALTZONE
208 if (i == 0 || ttisp->tt_isdst)

--- 4 unchanged lines hidden (view full) ---

213 ** And to get the latest zone names into tzname. . .
214 */
215 for (i = 0; i < sp->timecnt; ++i) {
216 register const struct ttinfo * const ttisp =
217 &sp->ttis[
218 sp->types[i]];
219
220 tzname[ttisp->tt_isdst] =
221 (char *) &sp->chars[ttisp->tt_abbrind];
222 }
223}
224
225static int
226tzload(name, sp)
227register const char * name;
228register struct state * const sp;
229{
230 register const char * p;
231 register int i;
232 register int fid;
233
234 if (name == NULL && (name = TZDEFAULT) == NULL)
235 return -1;
236 {
237 register int doaccess;
238 char fullname[FILENAME_MAX + 1];
239
240 if (name[0] == ':')
241 ++name;
242 doaccess = name[0] == '/';
243 if (!doaccess) {
244 if ((p = TZDIR) == NULL)
245 return -1;

--- 4 unchanged lines hidden (view full) ---

250 (void) strcat(fullname, name);
251 /*
252 ** Set doaccess if '.' (as in "../") shows up in name.
253 */
254 if (strchr(name, '.') != NULL)
255 doaccess = TRUE;
256 name = fullname;
257 }
258 if (doaccess && access(name, ACCESS_MODE) != 0)
259 return -1;
260 if ((fid = open(name, OPEN_MODE)) == -1)
261 return -1;
262 }
263 {
264 register const struct tzhead * tzhp;
265 char buf[sizeof *sp + sizeof *tzhp];
266 int ttisstdcnt;
267
268 i = read(fid, buf, sizeof buf);
269 if (close(fid) != 0 || i < sizeof *tzhp)
270 return -1;
271 tzhp = (struct tzhead *) buf;
272 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
273 sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
274 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
275 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
276 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
277 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
278 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
279 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
280 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
281 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
282 return -1;
283 if (i < sizeof *tzhp +
284 sp->timecnt * (4 + sizeof (char)) +
285 sp->typecnt * (4 + 2 * sizeof (char)) +
286 sp->charcnt * sizeof (char) +
287 sp->leapcnt * 2 * 4 +
288 ttisstdcnt * sizeof (char))
289 return -1;
290 p = buf + sizeof *tzhp;
291 for (i = 0; i < sp->timecnt; ++i) {
292 sp->ats[i] = detzcode(p);
293 p += 4;
294 }
295 for (i = 0; i < sp->timecnt; ++i) {
296 sp->types[i] = (unsigned char) *p++;
297 if (sp->types[i] >= sp->typecnt)
298 return -1;

--- 32 unchanged lines hidden (view full) ---

331 ttisp->tt_ttisstd = FALSE;
332 else {
333 ttisp->tt_ttisstd = *p++;
334 if (ttisp->tt_ttisstd != TRUE &&
335 ttisp->tt_ttisstd != FALSE)
336 return -1;
337 }
338 }
339 }
340 return 0;
341}
342
343static const int mon_lengths[2][MONSPERYEAR] = {
344 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
345 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
346};

--- 62 unchanged lines hidden (view full) ---

409
410static const char *
411getsecs(strp, secsp)
412register const char * strp;
413long * const secsp;
414{
415 int num;
416
417 strp = getnum(strp, &num, 0, HOURSPERDAY);
418 if (strp == NULL)
419 return NULL;
420 *secsp = num * SECSPERHOUR;
421 if (*strp == ':') {
422 ++strp;
423 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
424 if (strp == NULL)
425 return NULL;
426 *secsp += num * SECSPERMIN;
427 if (*strp == ':') {
428 ++strp;
429 strp = getnum(strp, &num, 0, SECSPERMIN - 1);
430 if (strp == NULL)
431 return NULL;
432 *secsp += num;
433 }
434 }
435 return strp;
436}
437

--- 93 unchanged lines hidden (view full) ---

531register const struct rule * const rulep;
532const long offset;
533{
534 register int leapyear;
535 register time_t value;
536 register int i;
537 int d, m1, yy0, yy1, yy2, dow;
538
539 leapyear = isleap(year);
540 switch (rulep->r_type) {
541
542 case JULIAN_DAY:
543 /*
544 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
545 ** years.
546 ** In non-leap years, or if the day number is 59 or less, just

--- 74 unchanged lines hidden (view full) ---

621static int
622tzparse(name, sp, lastditch)
623const char * name;
624register struct state * const sp;
625const int lastditch;
626{
627 const char * stdname;
628 const char * dstname;
629 int stdlen;
630 int dstlen;
631 long stdoffset;
632 long dstoffset;
633 register time_t * atp;
634 register unsigned char * typep;
635 register char * cp;
636 register int load_result;
637
638 stdname = name;
639 if (lastditch) {
640 stdlen = strlen(name); /* length of standard zone name */
641 name += stdlen;
642 if (stdlen >= sizeof sp->chars)
643 stdlen = (sizeof sp->chars) - 1;
644 } else {
645 name = getzname(name);

--- 70 unchanged lines hidden (view full) ---

716 *typep++ = 0; /* DST begins */
717 *atp++ = endtime;
718 *typep++ = 1; /* DST ends */
719 }
720 janfirst += year_lengths[isleap(year)] *
721 SECSPERDAY;
722 }
723 } else {
724 int sawstd;
725 int sawdst;
726 long stdfix;
727 long dstfix;
728 long oldfix;
729 int isdst;
730 register int i;
731
732 if (*name != '\0')
733 return -1;
734 if (load_result != 0)
735 return -1;
736 /*
737 ** Compute the difference between the real and
738 ** prototype standard and summer time offsets
739 ** from GMT, and put the real standard and summer
740 ** time offsets into the rules in place of the
741 ** prototype offsets.
742 */
743 sawstd = FALSE;
744 sawdst = FALSE;
745 stdfix = 0;
746 dstfix = 0;
747 for (i = 0; i < sp->typecnt; ++i) {
748 if (sp->ttis[i].tt_isdst) {
749 oldfix = dstfix;
750 dstfix = sp->ttis[i].tt_gmtoff +
751 dstoffset;
752 if (sawdst && (oldfix != dstfix))
753 return -1;
754 sp->ttis[i].tt_gmtoff = -dstoffset;
755 sp->ttis[i].tt_abbrind = stdlen + 1;
756 sawdst = TRUE;
757 } else {
758 oldfix = stdfix;
759 stdfix = sp->ttis[i].tt_gmtoff +
760 stdoffset;
761 if (sawstd && (oldfix != stdfix))
762 return -1;
763 sp->ttis[i].tt_gmtoff = -stdoffset;
764 sp->ttis[i].tt_abbrind = 0;
765 sawstd = TRUE;
766 }
767 }
768 /*
769 ** Make sure we have both standard and summer time.
770 */
771 if (!sawdst || !sawstd)
772 return -1;
773 /*
774 ** Now correct the transition times by shifting
775 ** them by the difference between the real and
776 ** prototype offsets. Note that this difference
777 ** can be different in standard and summer time;
778 ** the prototype probably has a 1-hour difference
779 ** between standard and summer time, but a different
780 ** difference can be specified in TZ.
781 */
782 isdst = FALSE; /* we start in standard time */
783 for (i = 0; i < sp->timecnt; ++i) {
784 register const struct ttinfo * ttisp;
785
786 /*
787 ** If summer time is in effect, and the
788 ** transition time was not specified as
789 ** standard time, add the summer time
790 ** offset to the transition time;
791 ** otherwise, add the standard time offset
792 ** to the transition time.
793 */
794 ttisp = &sp->ttis[sp->types[i]];
795 sp->ats[i] +=
796 (isdst && !ttisp->tt_ttisstd) ?
797 dstfix : stdfix;
798 isdst = ttisp->tt_isdst;
799 }
800 }
801 } else {
802 dstlen = 0;
803 sp->typecnt = 1; /* only standard time */
804 sp->timecnt = 0;
805 sp->ttis[0].tt_gmtoff = -stdoffset;
806 sp->ttis[0].tt_isdst = 0;
807 sp->ttis[0].tt_abbrind = 0;

--- 13 unchanged lines hidden (view full) ---

821 }
822 return 0;
823}
824
825static void
826gmtload(sp)
827struct state * const sp;
828{
829 if (tzload(GMT, sp) != 0)
830 (void) tzparse(GMT, sp, TRUE);
831}
832
833#ifndef STD_INSPIRED
834static
835#endif /* !defined STD_INSPIRED */
836void
837tzsetwall()
838{
839 lcl_is_set = TRUE;
840#ifdef ALL_STATE
841 if (lclptr == NULL) {
842 lclptr = (struct state *) malloc(sizeof *lclptr);
843 if (lclptr == NULL) {
844 settzname(); /* all we can do */
845 return;
846 }
847 }
848#endif /* defined ALL_STATE */
849 if (tzload((char *) NULL, lclptr) != 0)
850 gmtload(lclptr);
851 settzname();
852}
853
854void
855tzset()
856{
857 register const char * name;
858
859 name = getenv("TZ");
860 if (name == NULL) {
861 tzsetwall();
862 return;
863 }
864 lcl_is_set = TRUE;
865#ifdef ALL_STATE
866 if (lclptr == NULL) {
867 lclptr = (struct state *) malloc(sizeof *lclptr);
868 if (lclptr == NULL) {
869 settzname(); /* all we can do */
870 return;
871 }
872 }
873#endif /* defined ALL_STATE */
874 if (*name == '\0') {
875 /*
876 ** User wants it fast rather than right.
877 */
878 lclptr->leapcnt = 0; /* so, we're off a little */
879 lclptr->timecnt = 0;
880 lclptr->ttis[0].tt_gmtoff = 0;
881 lclptr->ttis[0].tt_abbrind = 0;
882 (void) strcpy(lclptr->chars, GMT);
883 } else if (tzload(name, lclptr) != 0)
884 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
885 (void) gmtload(lclptr);
886 settzname();
887}
888
889/*
890** The easy way to behave "as if no library function calls" localtime

--- 6 unchanged lines hidden (view full) ---

897
898/*ARGSUSED*/
899static void
900localsub(timep, offset, tmp)
901const time_t * const timep;
902const long offset;
903struct tm * const tmp;
904{
905 register const struct state * sp;
906 register const struct ttinfo * ttisp;
907 register int i;
908 const time_t t = *timep;
909
910 if (!lcl_is_set)
911 tzset();
912 sp = lclptr;
913#ifdef ALL_STATE
914 if (sp == NULL) {
915 gmtsub(timep, offset, tmp);
916 return;
917 }
918#endif /* defined ALL_STATE */
919 if (sp->timecnt == 0 || t < sp->ats[0]) {

--- 13 unchanged lines hidden (view full) ---

933 /*
934 ** To get (wrong) behavior that's compatible with System V Release 2.0
935 ** you'd replace the statement below with
936 ** t += ttisp->tt_gmtoff;
937 ** timesub(&t, 0L, sp, tmp);
938 */
939 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
940 tmp->tm_isdst = ttisp->tt_isdst;
941 tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
942#ifdef TM_ZONE
943 tmp->TM_ZONE = (char *)&sp->chars[ttisp->tt_abbrind];
944#endif /* defined TM_ZONE */
945}
946
947struct tm *
948localtime(timep)
949const time_t * const timep;
950{
951 static struct tm tm;
952
953 localsub(timep, 0L, &tm);
954 return &tm;
955}
956
957/*
958** gmtsub is to gmtime as localsub is to localtime.
959*/
960

--- 14 unchanged lines hidden (view full) ---

975 timesub(timep, offset, gmtptr, tmp);
976#ifdef TM_ZONE
977 /*
978 ** Could get fancy here and deliver something such as
979 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
980 ** but this is no time for a treasure hunt.
981 */
982 if (offset != 0)
983 tmp->TM_ZONE = WILDABBR;
984 else {
985#ifdef ALL_STATE
986 if (gmtptr == NULL)
987 tmp->TM_ZONE = GMT;
988 else tmp->TM_ZONE = gmtptr->chars;
989#endif /* defined ALL_STATE */
990#ifndef ALL_STATE
991 tmp->TM_ZONE = gmtptr->chars;
992#endif /* State Farm */
993 }
994#endif /* defined TM_ZONE */
995}
996
997struct tm *
998gmtime(timep)
999const time_t * const timep;
1000{
1001 static struct tm tm;
1002
1003 gmtsub(timep, 0L, &tm);
1004 return &tm;
1005}
1006
1007#ifdef STD_INSPIRED
1008
1009struct tm *
1010offtime(timep, offset)
1011const time_t * const timep;
1012const long offset;
1013{
1014 static struct tm tm;
1015
1016 gmtsub(timep, offset, &tm);
1017 return &tm;
1018}
1019
1020#endif /* defined STD_INSPIRED */
1021
1022static void
1023timesub(timep, offset, sp, tmp)

--- 45 unchanged lines hidden (view full) ---

1069#ifdef mc68k
1070 if (*timep == 0x80000000) {
1071 /*
1072 ** A 3B1 muffs the division on the most negative number.
1073 */
1074 days = -24855;
1075 rem = -11648;
1076 }
1077#endif /* mc68k */
1078 rem += (offset - corr);
1079 while (rem < 0) {
1080 rem += SECSPERDAY;
1081 --days;
1082 }
1083 while (rem >= SECSPERDAY) {
1084 rem -= SECSPERDAY;
1085 ++days;

--- 36 unchanged lines hidden (view full) ---

1122 tmp->TM_GMTOFF = offset;
1123#endif /* defined TM_GMTOFF */
1124}
1125
1126char *
1127ctime(timep)
1128const time_t * const timep;
1129{
1130 return asctime(localtime(timep));
1131}
1132
1133/*
1134** Adapted from code provided by Robert Elz, who writes:
1135** The "best" way to do mktime I think is based on an idea of Bob
1136** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1137** It does a binary search of the time_t space. Since time_t's are

--- 9 unchanged lines hidden (view full) ---

1147** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1148*/
1149
1150static int
1151increment_overflow(number, delta)
1152int * number;
1153int delta;
1154{
1155 int number0;
1156
1157 number0 = *number;
1158 *number += delta;
1159 return (*number < number0) != (delta < 0);
1160}
1161
1162static int
1163normalize_overflow(tensptr, unitsptr, base)

--- 24 unchanged lines hidden (view full) ---

1188 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1189 result = atmp->tm_sec - btmp->tm_sec;
1190 return result;
1191}
1192
1193static time_t
1194time2(tmp, funcp, offset, okayp)
1195struct tm * const tmp;
1196void (* const funcp)();
1197const long offset;
1198int * const okayp;
1199{
1200 register const struct state * sp;
1201 register int dir;
1202 register int bits;
1203 register int i, j ;
1204 register int saved_seconds;

--- 128 unchanged lines hidden (view full) ---

1333 (*funcp)(&t, offset, tmp);
1334 *okayp = TRUE;
1335 return t;
1336}
1337
1338static time_t
1339time1(tmp, funcp, offset)
1340struct tm * const tmp;
1341void (* const funcp)();
1342const long offset;
1343{
1344 register time_t t;
1345 register const struct state * sp;
1346 register int samei, otheri;
1347 int okay;
1348
1349 if (tmp->tm_isdst > 1)

--- 46 unchanged lines hidden (view full) ---

1396 }
1397 return WRONG;
1398}
1399
1400time_t
1401mktime(tmp)
1402struct tm * const tmp;
1403{
1404 return time1(tmp, localsub, 0L);
1405}
1406
1407#ifdef STD_INSPIRED
1408
1409time_t
1410timelocal(tmp)
1411struct tm * const tmp;

--- 58 unchanged lines hidden (view full) ---

1470static long
1471leapcorr(timep)
1472time_t * timep;
1473{
1474 register struct state * sp;
1475 register struct lsinfo * lp;
1476 register int i;
1477
1478 if (!lcl_is_set)
1479 (void) tzset();
1480 sp = lclptr;
1481 i = sp->leapcnt;
1482 while (--i >= 0) {
1483 lp = &sp->lsis[i];
1484 if (*timep >= lp->ls_trans)
1485 return lp->ls_corr;
1486 }
1487 return 0;
1488}
1489
1490time_t
1491time2posix(t)
1492time_t t;
1493{
1494 return t - leapcorr(&t);
1495}
1496
1497time_t
1498posix2time(t)
1499time_t t;
1500{
1501 time_t x;
1502 time_t y;
1503
1504 /*
1505 ** For a positive leap second hit, the result
1506 ** is not unique. For a negative leap second
1507 ** hit, the corresponding time doesn't exist,
1508 ** so we return an adjacent second.
1509 */
1510 x = t + leapcorr(&t);
1511 y = x - leapcorr(&x);

--- 19 unchanged lines hidden ---