1 /*
2 		    Low Level Interface Library
3             Copyright 1983-2007 Green Hills Software,Inc.
4 
5  *  This program is the property of Green Hills Software, Inc,
6  *  its contents are proprietary information and no part of it
7  *  is to be disclosed to anyone except employees of Green Hills
8  *  Software, Inc., or as agreed in writing signed by the President
9  *  of Green Hills Software, Inc.
10 */
11 /* ind_gmtm.c: ANSI gmtime() facility. */
12 
13 #include <limits.h>
14 #include "indos.h"
15 #include "ind_thrd.h"
16 
17 #if defined(CROSSUNIX) || !defined(ANYUNIX)
18 
19 static const char mons[]={31,28,31,30,31,30,31,31,30,31,30};
20 /******************************************************************************/
21 /* #include <time.h>							      */
22 /* struct tm *gmtime(const time_t *timer);				      */
23 /*									      */
24 /*  gmtime returns a structure containing the current Greenwich Mean Time     */
25 /*  broken down into tm_year (current year - 1900), tm_mon (current month     */
26 /*  January=0), tm_mday (current day of month), tm_hour (current hour 24 hour */
27 /*  time), tm_min (current minute), and tm_sec (current second).              */
28 /*									      */
29 /*  timer is a pointer to a long containing the number of seconds since the   */
30 /*  Epoch (as set by time()).			                              */
31 /*									      */
32 /*  Return 0 if no time of day can be returned				      */
33 /*									      */
34 /*  NOT REENTRANT because it returns the address of a static buffer           */
35 /*  could be made reentrant if every call to gmtime allocated a new structure */
36 /******************************************************************************/
37 
38 #define SECS_IN_MIN	((time_t)60)
39 #define MINS_IN_HOUR	((time_t)60)
40 #define SECS_IN_HOUR	(MINS_IN_HOUR * SECS_IN_MIN)
41 #define HOURS_IN_DAY	((time_t)24)
42 #define SECS_IN_DAY	(HOURS_IN_DAY * SECS_IN_HOUR)
43 #define DAYS_IN_WEEK	((time_t)7)
44 
45 #define DAYS_IN_COMMON_YEAR	((time_t)365)
46 #define DAYS_IN_400_YEARS	(DAYS_IN_COMMON_YEAR * 400 + 97)
47 
gmtime_r(const time_t * timer,struct tm * result)48 struct tm *gmtime_r(const time_t *timer, struct tm *result) {
49 /*  If no other implementation provided, assume Epoch is 00:00:00 January 1,1970
50     as is true in UNIX.
51 */
52     time_t time_v = *timer;
53     int i, m, islpyr;
54     time_t y, t, s;
55 
56     if (time_v == (time_t)-1)
57 	return NULL;
58 
59 #if defined(MSW) || defined(MSDOS)
60     time_v -= 2209075200L;	/* convert to Epoch from MS-DOS */
61 #endif
62 
63     result->tm_isdst = 0;
64     /* Compute t as a Julian day number, where the Epoch is 0 */
65     /* and compute s as the seconds within the day */
66     t = time_v / SECS_IN_DAY;
67     s = time_v % SECS_IN_DAY;
68     if (s < 0) {
69 	s += SECS_IN_DAY;
70 	t--;
71     }
72 
73     /* hour, minute, second */
74     result->tm_hour = s / SECS_IN_HOUR;
75     s %= SECS_IN_HOUR;
76     result->tm_min = s / SECS_IN_MIN;
77     result->tm_sec = s % SECS_IN_MIN;
78 
79     /* January 1, 1970 was a Thursday. */
80     s = (t + 4) % DAYS_IN_WEEK;
81     if (s < 0) {
82 	s += DAYS_IN_WEEK;
83     }
84     result->tm_wday = s;
85 
86     /* If 1900 does not fall within range, things are very simple because */
87     /* every 4 years is a leap year. */
88     if (DAYS_IN_COMMON_YEAR * 69 > LONG_MAX / SECS_IN_DAY) {
89 	/* Adjust so that 0 is Dec 31, 1899, which is as though 0 is */
90 	/* Jan 1, 1900 and 1900 is a leap year.  This ensures that t is */
91 	/* positive and makes it as though every 4 years is a leap year. */
92 	/* (since t will not *actually* fall within 1900, we're fine) */
93 
94 	/* Thus, note that there were 17 leap days between Jan 1, 1900 and */
95 	/* Jan 1, 1970 */
96 	t += DAYS_IN_COMMON_YEAR * 70 + 18;
97 
98 	/* Compute y as the year, and t as the day within the year */
99 	y = t / (DAYS_IN_COMMON_YEAR * 4 + 1) * 4;
100 	t = t % (DAYS_IN_COMMON_YEAR * 4 + 1);
101 	if (t >= DAYS_IN_COMMON_YEAR + 1) {
102 	    y += (t - 1) / DAYS_IN_COMMON_YEAR;
103 	    t = (t - 1) % DAYS_IN_COMMON_YEAR;
104 	}
105 	islpyr = (y & 3) == 0;
106 	/* Note that we already adjusted so that 1900 is zero. */
107     } else {
108 	time_t century;
109 	/* Adjust to the beginning of a 400 year cycle, the year 2000 */
110 	/* There were 7 leap days between Jan 1, 1970 and Jan 1, 2000 */
111 	t -= DAYS_IN_COMMON_YEAR * 30 + 7;
112 
113 	/* Compute the century except for the low 2 bits, where 0 is 2000 */
114 	/* e.g., -4 is 1600 to 1999, 0 is 2000 to 2399, etc. */
115 	/* Adjust t so that the beginning of the 400 year cycle is 0 */
116 	century = t / DAYS_IN_400_YEARS * 4;
117 	t %= DAYS_IN_400_YEARS;
118 	if (t < 0) {
119 	    t += DAYS_IN_400_YEARS;
120 	    century -= 4;
121 	}
122 
123 	/* Add in the low 2 bits of the century and adjust t so that the */
124 	/* beginning of the century is 0, and so that all 4 year cycles have */
125 	/* an extra day in the first year.  That is, 366 is always the start */
126 	/* of the second year in the century, but some centuries have no day */
127 	/* 365. */
128 	if (t >= DAYS_IN_COMMON_YEAR * 100 + 25) {
129 	    century += (t - 1) / (DAYS_IN_COMMON_YEAR * 100 + 24);
130 	    t = (t - 1) % (DAYS_IN_COMMON_YEAR * 100 + 24);
131 	    if (t >= DAYS_IN_COMMON_YEAR) {
132 		t++;
133 	    }
134 	}
135 
136 	/* Compute y as the year within the century, and t as the day within */
137 	/* the year */
138 	y = t / (DAYS_IN_COMMON_YEAR * 4 + 1) * 4;
139 	t = t % (DAYS_IN_COMMON_YEAR * 4 + 1);
140 	if (t >= DAYS_IN_COMMON_YEAR + 1) {
141 	    y += (t - 1) / DAYS_IN_COMMON_YEAR;
142 	    t = (t - 1) % DAYS_IN_COMMON_YEAR;
143 	}
144 
145 	islpyr = (y & 3) == 0 && (y != 0 || (century & 3) == 0);
146 	/* Right now 2000 is 0, but we must return 1900 as 0. */
147 	y += (century + 1) * 100;
148 	/* If time_t is 64-bit, the year might not fit in an int, and we */
149 	/* must return NULL. */
150 	if (y != (int)y) {
151 	    return NULL;
152 	}
153     }
154     result->tm_year = y;
155     result->tm_yday = t;
156 
157     /* Increment to return an mday in the 1 to 31 range. */
158     t++;
159     for (i = 0; i < 11; i++) {
160 	m = mons[i];
161 	if (i == 1 && islpyr) {
162 	    m++;
163 	}
164 	if (t <= m)
165 	    break;
166 	t -= m;
167     }
168 
169     result->tm_mon  = i;
170     result->tm_mday = t;	/* we incremented the mday above */
171     return result;
172 }
173 
174 struct tm __ghs_static_gmtime_temp;
gmtime(const time_t * timer)175 struct tm *gmtime(const time_t *timer)
176 {
177 
178     struct tm *tmp = __ghs_GetThreadLocalStorageItem(__ghs_TLS_gmtime_temp);
179     if (tmp == NULL)
180 	tmp = &__ghs_static_gmtime_temp;
181     return(gmtime_r(timer, tmp));
182 }
183 #else
184 int _J_empty_file_illegal;
185 #endif	/* CROSSUNIX or !ANYUNIX */
186