]>
Commit | Line | Data |
---|---|---|
2aa62f2b | 1 | /**\r |
2 | Definitions and Implementation for <time.h>.\r | |
3 | \r | |
53e1e5c6 | 4 | Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r |
2aa62f2b | 5 | This program and the accompanying materials are licensed and made available under\r |
6 | the terms and conditions of the BSD License that accompanies this distribution.\r | |
7 | The full text of the license may be found at\r | |
8 | http://opensource.org/licenses/bsd-license.php.\r | |
9 | \r | |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
12 | \r | |
13 | Portions derived from the NIH time zone package file, localtime.c,\r | |
14 | which contains the following notice:\r | |
15 | \r | |
16 | This file is in the public domain, so clarified as of\r | |
17 | 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r | |
18 | \r | |
19 | NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp\r | |
20 | **/\r | |
21 | #include <Uefi.h>\r | |
22 | #include <Library/UefiLib.h>\r | |
23 | #include <Library/TimerLib.h>\r | |
24 | #include <Library/BaseLib.h>\r | |
25 | #include <Library/UefiRuntimeServicesTableLib.h>\r | |
26 | //#include <Library/UefiRuntimeLib.h>\r | |
27 | \r | |
28 | #include <LibConfig.h>\r | |
29 | \r | |
30 | #include <errno.h>\r | |
31 | #include <limits.h>\r | |
32 | #include <time.h>\r | |
33 | #include <reentrant.h>\r | |
34 | #include "tzfile.h"\r | |
35 | #include "TimeVals.h"\r | |
36 | #include <MainData.h>\r | |
37 | #include <extern.h> // Library/include/extern.h: Private to implementation\r | |
38 | \r | |
39 | #if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */\r | |
40 | // Keep compiler quiet about casting from function to data pointers\r | |
41 | #pragma warning ( disable : 4054 )\r | |
42 | #endif /* defined(_MSC_VER) */\r | |
43 | \r | |
44 | /* ####################### Private Data ################################# */\r | |
45 | \r | |
46 | #if 0\r | |
47 | static EFI_TIME TimeBuffer;\r | |
48 | \r | |
49 | static UINT16 MonthOffs[12] = {\r | |
50 | 00,\r | |
51 | 31, 59, 90, 120,\r | |
52 | 151, 181, 212, 243,\r | |
53 | 273, 304, 334\r | |
54 | };\r | |
55 | static clock_t y2kOffs = 730485;\r | |
56 | #endif\r | |
57 | \r | |
58 | const int mon_lengths[2][MONSPERYEAR] = {\r | |
59 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },\r | |
60 | { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }\r | |
61 | };\r | |
62 | \r | |
63 | const int year_lengths[2] = {\r | |
64 | DAYSPERNYEAR, DAYSPERLYEAR\r | |
65 | };\r | |
66 | \r | |
67 | \r | |
68 | static const char *wday_name[7] = {\r | |
69 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r | |
70 | };\r | |
71 | \r | |
72 | static const char *mon_name[12] = {\r | |
73 | "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r | |
74 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r | |
75 | };\r | |
76 | \r | |
77 | static int gmt_is_set;\r | |
78 | \r | |
79 | /* ############### Implementation Functions ############################ */\r | |
80 | // Forward reference\r | |
81 | static void\r | |
82 | localsub(const time_t * const timep, const long offset, struct tm * const tmp);\r | |
83 | \r | |
84 | clock_t\r | |
2aa62f2b | 85 | __getCPS(void)\r |
86 | {\r | |
87 | return gMD->ClocksPerSecond;\r | |
88 | }\r | |
89 | \r | |
90 | static void\r | |
91 | timesub(\r | |
92 | const time_t * const timep,\r | |
93 | const long offset,\r | |
94 | const struct state * const sp,\r | |
95 | struct tm * const tmp\r | |
96 | )\r | |
97 | {\r | |
98 | const struct lsinfo * lp;\r | |
99 | time_t /*INTN*/ days;\r | |
100 | time_t /*INTN*/ rem;\r | |
101 | time_t /*INTN*/ y;\r | |
102 | int yleap;\r | |
103 | const int * ip;\r | |
104 | time_t /*INTN*/ corr;\r | |
105 | int hit;\r | |
106 | int i;\r | |
107 | \r | |
108 | corr = 0;\r | |
109 | hit = 0;\r | |
110 | #ifdef ALL_STATE\r | |
111 | i = (sp == NULL) ? 0 : sp->leapcnt;\r | |
112 | #endif /* defined ALL_STATE */\r | |
113 | #ifndef ALL_STATE\r | |
114 | i = sp->leapcnt;\r | |
115 | #endif /* State Farm */\r | |
116 | while (--i >= 0) {\r | |
117 | lp = &sp->lsis[i];\r | |
118 | if (*timep >= lp->ls_trans) {\r | |
119 | if (*timep == lp->ls_trans) {\r | |
120 | hit = ((i == 0 && lp->ls_corr > 0) ||\r | |
121 | lp->ls_corr > sp->lsis[i - 1].ls_corr);\r | |
122 | if (hit)\r | |
123 | while (i > 0 &&\r | |
124 | sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&\r | |
125 | sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1 )\r | |
126 | {\r | |
127 | ++hit;\r | |
128 | --i;\r | |
129 | }\r | |
130 | }\r | |
131 | corr = lp->ls_corr;\r | |
132 | break;\r | |
133 | }\r | |
134 | }\r | |
135 | days = *timep / SECSPERDAY;\r | |
136 | rem = *timep % SECSPERDAY;\r | |
137 | rem += (offset - corr);\r | |
138 | while (rem < 0) {\r | |
139 | rem += SECSPERDAY;\r | |
140 | --days;\r | |
141 | }\r | |
142 | while (rem >= SECSPERDAY) {\r | |
143 | rem -= SECSPERDAY;\r | |
144 | ++days;\r | |
145 | }\r | |
146 | tmp->tm_hour = (int) (rem / SECSPERHOUR);\r | |
147 | rem = rem % SECSPERHOUR;\r | |
148 | tmp->tm_min = (int) (rem / SECSPERMIN);\r | |
149 | /*\r | |
150 | ** A positive leap second requires a special\r | |
151 | ** representation. This uses "... ??:59:60" et seq.\r | |
152 | */\r | |
153 | tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;\r | |
154 | tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);\r | |
155 | if (tmp->tm_wday < 0)\r | |
156 | tmp->tm_wday += DAYSPERWEEK;\r | |
157 | y = EPOCH_YEAR;\r | |
158 | while (days < 0 || days >= (LONG32) year_lengths[yleap = isleap(y)]) {\r | |
159 | time_t /*INTN*/ newy;\r | |
160 | \r | |
161 | newy = (y + days / DAYSPERNYEAR);\r | |
162 | if (days < 0)\r | |
163 | --newy;\r | |
164 | days -= (newy - y) * DAYSPERNYEAR +\r | |
165 | LEAPS_THRU_END_OF(newy - 1) -\r | |
166 | LEAPS_THRU_END_OF(y - 1);\r | |
167 | y = newy;\r | |
168 | }\r | |
169 | tmp->tm_year = (int)(y - TM_YEAR_BASE);\r | |
170 | tmp->tm_yday = (int) days;\r | |
171 | ip = mon_lengths[yleap];\r | |
172 | for (tmp->tm_mon = 0; days >= (LONG32) ip[tmp->tm_mon]; ++(tmp->tm_mon))\r | |
173 | days = days - (LONG32) ip[tmp->tm_mon];\r | |
174 | tmp->tm_mday = (int) (days + 1);\r | |
175 | tmp->tm_isdst = 0;\r | |
176 | #ifdef TM_GMTOFF\r | |
177 | tmp->TM_GMTOFF = offset;\r | |
178 | #endif /* defined TM_GMTOFF */\r | |
179 | }\r | |
180 | \r | |
181 | /* ############### Time Manipulation Functions ########################## */\r | |
182 | \r | |
2aa62f2b | 183 | /**\r |
184 | **/\r | |
185 | double\r | |
2aa62f2b | 186 | difftime(time_t time1, time_t time0)\r |
187 | {\r | |
188 | return (double)(time1 - time0);\r | |
189 | }\r | |
190 | \r | |
191 | /*\r | |
192 | ** Adapted from code provided by Robert Elz, who writes:\r | |
193 | ** The "best" way to do mktime I think is based on an idea of Bob\r | |
194 | ** Kridle's (so its said...) from a long time ago.\r | |
195 | ** [kridle@xinet.com as of 1996-01-16.]\r | |
196 | ** It does a binary search of the time_t space. Since time_t's are\r | |
197 | ** just 32 bits, its a max of 32 iterations (even at 64 bits it\r | |
198 | ** would still be very reasonable).\r | |
199 | */\r | |
200 | \r | |
201 | #ifndef WRONG\r | |
202 | #define WRONG (-1)\r | |
203 | #endif /* !defined WRONG */\r | |
204 | \r | |
205 | /*\r | |
206 | ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).\r | |
207 | */\r | |
208 | \r | |
209 | static int\r | |
210 | increment_overflow(int * number, int delta)\r | |
211 | {\r | |
212 | int number0;\r | |
213 | \r | |
214 | number0 = *number;\r | |
215 | *number += delta;\r | |
216 | return (*number < number0) != (delta < 0);\r | |
217 | }\r | |
218 | \r | |
219 | static int\r | |
220 | normalize_overflow(int * const tensptr, int * const unitsptr, const int base)\r | |
221 | {\r | |
222 | register int tensdelta;\r | |
223 | \r | |
224 | tensdelta = (*unitsptr >= 0) ?\r | |
225 | (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);\r | |
226 | *unitsptr -= tensdelta * base;\r | |
227 | return increment_overflow(tensptr, tensdelta);\r | |
228 | }\r | |
229 | \r | |
230 | static int\r | |
231 | tmcomp(const struct tm * const atmp, const struct tm * const btmp)\r | |
232 | {\r | |
233 | register int result;\r | |
234 | \r | |
235 | if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&\r | |
236 | (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&\r | |
237 | (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&\r | |
238 | (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&\r | |
239 | (result = (atmp->tm_min - btmp->tm_min)) == 0)\r | |
240 | result = atmp->tm_sec - btmp->tm_sec;\r | |
241 | return result;\r | |
242 | }\r | |
243 | \r | |
244 | static time_t\r | |
245 | time2sub(\r | |
246 | struct tm * const tmp,\r | |
247 | void (* const funcp)(const time_t*, long, struct tm*),\r | |
248 | const long offset,\r | |
249 | int * const okayp,\r | |
250 | const int do_norm_secs\r | |
251 | )\r | |
252 | {\r | |
253 | register const struct state * sp;\r | |
254 | register int dir;\r | |
255 | register int bits;\r | |
256 | register int i, j ;\r | |
257 | register int saved_seconds;\r | |
258 | time_t newt;\r | |
259 | time_t t;\r | |
260 | struct tm yourtm, mytm;\r | |
261 | \r | |
262 | *okayp = FALSE;\r | |
263 | yourtm = *tmp; // Create a copy of tmp\r | |
264 | if (do_norm_secs) {\r | |
265 | if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,\r | |
266 | SECSPERMIN))\r | |
267 | return WRONG;\r | |
268 | }\r | |
269 | if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))\r | |
270 | return WRONG;\r | |
271 | if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))\r | |
272 | return WRONG;\r | |
273 | if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))\r | |
274 | return WRONG;\r | |
275 | /*\r | |
276 | ** Turn yourtm.tm_year into an actual year number for now.\r | |
277 | ** It is converted back to an offset from TM_YEAR_BASE later.\r | |
278 | */\r | |
279 | if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))\r | |
280 | return WRONG;\r | |
281 | while (yourtm.tm_mday <= 0) {\r | |
282 | if (increment_overflow(&yourtm.tm_year, -1))\r | |
283 | return WRONG;\r | |
284 | i = yourtm.tm_year + (1 < yourtm.tm_mon);\r | |
285 | yourtm.tm_mday += year_lengths[isleap(i)];\r | |
286 | }\r | |
287 | while (yourtm.tm_mday > DAYSPERLYEAR) {\r | |
288 | i = yourtm.tm_year + (1 < yourtm.tm_mon);\r | |
289 | yourtm.tm_mday -= year_lengths[isleap(i)];\r | |
290 | if (increment_overflow(&yourtm.tm_year, 1))\r | |
291 | return WRONG;\r | |
292 | }\r | |
293 | for ( ; ; ) {\r | |
294 | i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];\r | |
295 | if (yourtm.tm_mday <= i)\r | |
296 | break;\r | |
297 | yourtm.tm_mday -= i;\r | |
298 | if (++yourtm.tm_mon >= MONSPERYEAR) {\r | |
299 | yourtm.tm_mon = 0;\r | |
300 | if (increment_overflow(&yourtm.tm_year, 1))\r | |
301 | return WRONG;\r | |
302 | }\r | |
303 | }\r | |
304 | if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))\r | |
305 | return WRONG;\r | |
306 | if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)\r | |
307 | saved_seconds = 0;\r | |
308 | else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {\r | |
309 | /*\r | |
310 | ** We can't set tm_sec to 0, because that might push the\r | |
311 | ** time below the minimum representable time.\r | |
312 | ** Set tm_sec to 59 instead.\r | |
313 | ** This assumes that the minimum representable time is\r | |
314 | ** not in the same minute that a leap second was deleted from,\r | |
315 | ** which is a safer assumption than using 58 would be.\r | |
316 | */\r | |
317 | if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))\r | |
318 | return WRONG;\r | |
319 | saved_seconds = yourtm.tm_sec;\r | |
320 | yourtm.tm_sec = SECSPERMIN - 1;\r | |
321 | } else {\r | |
322 | saved_seconds = yourtm.tm_sec;\r | |
323 | yourtm.tm_sec = 0;\r | |
324 | }\r | |
325 | /*\r | |
326 | ** Divide the search space in half\r | |
327 | ** (this works whether time_t is signed or unsigned).\r | |
328 | */\r | |
329 | bits = TYPE_BIT(time_t) - 1;\r | |
330 | /*\r | |
331 | ** Set t to the midpoint of our binary search.\r | |
332 | **\r | |
333 | ** If time_t is signed, then 0 is just above the median,\r | |
334 | ** assuming two's complement arithmetic.\r | |
335 | ** If time_t is unsigned, then (1 << bits) is just above the median.\r | |
336 | */\r | |
337 | t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);\r | |
338 | for ( ; ; ) {\r | |
339 | (*funcp)(&t, offset, &mytm); // Convert t to broken-down time in mytm\r | |
340 | dir = tmcomp(&mytm, &yourtm); // Is mytm larger, equal, or less than yourtm?\r | |
341 | if (dir != 0) { // If mytm != yourtm...\r | |
342 | if (bits-- < 0) // If we have exhausted all the bits..\r | |
343 | return WRONG; // Return that we failed\r | |
344 | if (bits < 0) // If on the last bit...\r | |
345 | --t; /* may be needed if new t is minimal */\r | |
346 | else if (dir > 0) // else if mytm > yourtm...\r | |
347 | t -= ((time_t) 1) << bits; // subtract half the remaining time-space\r | |
348 | else t += ((time_t) 1) << bits; // otherwise add half the remaining time-space\r | |
349 | continue; // Repeat for the next half\r | |
350 | }\r | |
351 | if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)\r | |
352 | break;\r | |
353 | /*\r | |
354 | ** Right time, wrong type.\r | |
355 | ** Hunt for right time, right type.\r | |
356 | ** It's okay to guess wrong since the guess\r | |
357 | ** gets checked.\r | |
358 | */\r | |
359 | /*\r | |
360 | ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r | |
361 | */\r | |
362 | sp = (const struct state *)\r | |
363 | (((void *) funcp == (void *) localsub) ?\r | |
364 | lclptr : gmtptr);\r | |
365 | #ifdef ALL_STATE\r | |
366 | if (sp == NULL)\r | |
367 | return WRONG;\r | |
368 | #endif /* defined ALL_STATE */\r | |
369 | for (i = sp->typecnt - 1; i >= 0; --i) {\r | |
370 | if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)\r | |
371 | continue;\r | |
372 | for (j = sp->typecnt - 1; j >= 0; --j) {\r | |
373 | if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)\r | |
374 | continue;\r | |
375 | newt = t + sp->ttis[j].tt_gmtoff -\r | |
376 | sp->ttis[i].tt_gmtoff;\r | |
377 | (*funcp)(&newt, offset, &mytm);\r | |
378 | if (tmcomp(&mytm, &yourtm) != 0)\r | |
379 | continue;\r | |
380 | if (mytm.tm_isdst != yourtm.tm_isdst)\r | |
381 | continue;\r | |
382 | /*\r | |
383 | ** We have a match.\r | |
384 | */\r | |
385 | t = newt;\r | |
386 | goto label;\r | |
387 | }\r | |
388 | }\r | |
389 | return WRONG;\r | |
390 | }\r | |
391 | label:\r | |
392 | newt = t + saved_seconds;\r | |
393 | if ((newt < t) != (saved_seconds < 0))\r | |
394 | return WRONG;\r | |
395 | t = newt;\r | |
396 | (*funcp)(&t, offset, tmp);\r | |
397 | *okayp = TRUE;\r | |
398 | return t;\r | |
399 | }\r | |
400 | \r | |
d7ce7006 | 401 | time_t\r |
2aa62f2b | 402 | time2(struct tm * const tmp, void (* const funcp)(const time_t*, long, struct tm*),\r |
403 | const long offset, int * const okayp)\r | |
404 | {\r | |
405 | time_t t;\r | |
406 | \r | |
407 | /*\r | |
408 | ** First try without normalization of seconds\r | |
409 | ** (in case tm_sec contains a value associated with a leap second).\r | |
410 | ** If that fails, try with normalization of seconds.\r | |
411 | */\r | |
412 | t = time2sub(tmp, funcp, offset, okayp, FALSE);\r | |
413 | return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);\r | |
414 | }\r | |
415 | \r | |
416 | static time_t\r | |
417 | time1(\r | |
418 | struct tm * const tmp,\r | |
419 | void (* const funcp)(const time_t *, long, struct tm *),\r | |
420 | const long offset\r | |
421 | )\r | |
422 | {\r | |
423 | register time_t t;\r | |
424 | register const struct state * sp;\r | |
425 | register int samei, otheri;\r | |
426 | register int sameind, otherind;\r | |
427 | register int i;\r | |
428 | register int nseen;\r | |
429 | int seen[TZ_MAX_TYPES];\r | |
430 | int types[TZ_MAX_TYPES];\r | |
431 | int okay;\r | |
432 | \r | |
433 | if (tmp->tm_isdst > 1)\r | |
434 | tmp->tm_isdst = 1;\r | |
435 | t = time2(tmp, funcp, offset, &okay);\r | |
436 | #ifdef PCTS\r | |
437 | /*\r | |
438 | ** PCTS code courtesy Grant Sullivan (grant@osf.org).\r | |
439 | */\r | |
440 | if (okay)\r | |
441 | return t;\r | |
442 | if (tmp->tm_isdst < 0)\r | |
443 | tmp->tm_isdst = 0; /* reset to std and try again */\r | |
444 | #endif /* defined PCTS */\r | |
445 | #ifndef PCTS\r | |
446 | if (okay || tmp->tm_isdst < 0)\r | |
447 | return t;\r | |
448 | #endif /* !defined PCTS */\r | |
449 | /*\r | |
450 | ** We're supposed to assume that somebody took a time of one type\r | |
451 | ** and did some math on it that yielded a "struct tm" that's bad.\r | |
452 | ** We try to divine the type they started from and adjust to the\r | |
453 | ** type they need.\r | |
454 | */\r | |
455 | /*\r | |
456 | ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r | |
457 | */\r | |
458 | sp = (const struct state *) (((void *) funcp == (void *) localsub) ?\r | |
459 | lclptr : gmtptr);\r | |
460 | #ifdef ALL_STATE\r | |
461 | if (sp == NULL)\r | |
462 | return WRONG;\r | |
463 | #endif /* defined ALL_STATE */\r | |
464 | for (i = 0; i < sp->typecnt; ++i)\r | |
465 | seen[i] = FALSE;\r | |
466 | nseen = 0;\r | |
467 | for (i = sp->timecnt - 1; i >= 0; --i)\r | |
468 | if (!seen[sp->types[i]]) {\r | |
469 | seen[sp->types[i]] = TRUE;\r | |
470 | types[nseen++] = sp->types[i];\r | |
471 | }\r | |
472 | for (sameind = 0; sameind < nseen; ++sameind) {\r | |
473 | samei = types[sameind];\r | |
474 | if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)\r | |
475 | continue;\r | |
476 | for (otherind = 0; otherind < nseen; ++otherind) {\r | |
477 | otheri = types[otherind];\r | |
478 | if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)\r | |
479 | continue;\r | |
480 | tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -\r | |
481 | sp->ttis[samei].tt_gmtoff);\r | |
482 | tmp->tm_isdst = !tmp->tm_isdst;\r | |
483 | t = time2(tmp, funcp, offset, &okay);\r | |
484 | if (okay)\r | |
485 | return t;\r | |
486 | tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -\r | |
487 | sp->ttis[samei].tt_gmtoff);\r | |
488 | tmp->tm_isdst = !tmp->tm_isdst;\r | |
489 | }\r | |
490 | }\r | |
491 | return WRONG;\r | |
492 | }\r | |
493 | \r | |
494 | /** The mktime function converts the broken-down time, expressed as local time,\r | |
495 | in the structure pointed to by timeptr into a calendar time value with the\r | |
496 | same encoding as that of the values returned by the time function. The\r | |
497 | original values of the tm_wday and tm_yday components of the structure are\r | |
498 | ignored, and the original values of the other components are not restricted\r | |
499 | to the ranges indicated above. Thus, a positive or zero value for tm_isdst\r | |
500 | causes the mktime function to presume initially that Daylight Saving Time,\r | |
501 | respectively, is or is not in effect for the specified time. A negative\r | |
502 | value causes it to attempt to determine whether Daylight Saving Time is in\r | |
503 | effect for the specified time. On successful completion, the values of the\r | |
504 | tm_wday and tm_yday components of the structure are set appropriately, and\r | |
505 | the other components are set to represent the specified calendar time, but\r | |
506 | with their values forced to the ranges indicated above; the final value of\r | |
507 | tm_mday is not set until tm_mon and tm_year are determined.\r | |
508 | \r | |
509 | @return The mktime function returns the specified calendar time encoded\r | |
510 | as a value of type time_t. If the calendar time cannot be\r | |
511 | represented, the function returns the value (time_t)(-1).\r | |
512 | **/\r | |
513 | time_t\r | |
2aa62f2b | 514 | mktime(struct tm *timeptr)\r |
515 | {\r | |
516 | /* From NetBSD */\r | |
517 | time_t result;\r | |
518 | \r | |
519 | rwlock_wrlock(&lcl_lock);\r | |
520 | tzset();\r | |
521 | result = time1(timeptr, &localsub, 0L);\r | |
522 | rwlock_unlock(&lcl_lock);\r | |
523 | return (result);\r | |
524 | }\r | |
525 | \r | |
526 | /** The time function determines the current calendar time. The encoding of\r | |
527 | the value is unspecified.\r | |
528 | \r | |
d7ce7006 | 529 | @return The time function returns the implementation's best approximation\r |
2aa62f2b | 530 | to the current calendar time. The value (time_t)(-1) is returned\r |
531 | if the calendar time is not available. If timer is not a null\r | |
532 | pointer, the return value is also assigned to the object it\r | |
533 | points to.\r | |
534 | **/\r | |
535 | time_t\r | |
2aa62f2b | 536 | time(time_t *timer)\r |
537 | {\r | |
538 | time_t CalTime;\r | |
539 | EFI_STATUS Status;\r | |
540 | EFI_TIME *ET;\r | |
541 | struct tm *BT;\r | |
542 | \r | |
543 | ET = &gMD->TimeBuffer;\r | |
544 | BT = &gMD->BDTime;\r | |
545 | \r | |
546 | // Get EFI Time\r | |
547 | Status = gRT->GetTime( ET, NULL);\r | |
548 | // Status = EfiGetTime( ET, NULL);\r | |
549 | EFIerrno = Status;\r | |
550 | if( Status != RETURN_SUCCESS) {\r | |
551 | return (time_t)-1;\r | |
552 | }\r | |
553 | \r | |
554 | // Convert EFI time to broken-down time.\r | |
555 | Efi2Tm( ET, BT);\r | |
556 | \r | |
557 | // Convert to time_t\r | |
558 | CalTime = mktime(&gMD->BDTime);\r | |
559 | \r | |
560 | if( timer != NULL) {\r | |
561 | *timer = CalTime;\r | |
562 | }\r | |
563 | return CalTime; // Return calendar time in microseconds\r | |
564 | }\r | |
565 | \r | |
8aa163da | 566 | /** The clock function determines the processor time used.\r |
567 | \r | |
568 | @return The clock function returns the implementation's best\r | |
569 | approximation to the processor time used by the program since the\r | |
570 | beginning of an implementation-defined era related only to the\r | |
571 | program invocation. To determine the time in seconds, the value\r | |
572 | returned by the clock function should be divided by the value of\r | |
573 | the macro CLOCKS_PER_SEC. If the processor time used is not\r | |
574 | available or its value cannot be represented, the function\r | |
575 | returns the value (clock_t)(-1).\r | |
576 | **/\r | |
577 | clock_t\r | |
578 | clock(void)\r | |
579 | {\r | |
580 | clock_t retval;\r | |
581 | time_t temp;\r | |
582 | \r | |
583 | temp = time(NULL);\r | |
584 | retval = ((clock_t)((UINT32)temp)) - gMD->AppStartTime;\r | |
585 | return retval;\r | |
586 | }\r | |
587 | \r | |
2aa62f2b | 588 | /* ################# Time Conversion Functions ########################## */\r |
589 | /*\r | |
590 | Except for the strftime function, these functions each return a pointer to\r | |
591 | one of two types of static objects: a broken-down time structure or an\r | |
592 | array of char. Execution of any of the functions that return a pointer to\r | |
593 | one of these object types may overwrite the information in any object of\r | |
594 | the same type pointed to by the value returned from any previous call to\r | |
595 | any of them. The implementation shall behave as if no other library\r | |
596 | functions call these functions.\r | |
597 | */\r | |
598 | \r | |
599 | /** The asctime function converts the broken-down time in the structure pointed\r | |
600 | to by timeptr into a string in the form\r | |
601 | Sun Sep 16 01:03:52 1973\n\0\r | |
602 | using the equivalent of the following algorithm.\r | |
603 | \r | |
604 | char *asctime(const struct tm *timeptr)\r | |
605 | {\r | |
606 | static const char wday_name[7][3] = {\r | |
607 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r | |
608 | };\r | |
609 | static const char mon_name[12][3] = {\r | |
610 | "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r | |
611 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r | |
612 | };\r | |
613 | static char result[26];\r | |
614 | sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",\r | |
615 | wday_name[timeptr->tm_wday],\r | |
616 | mon_name[timeptr->tm_mon],\r | |
617 | timeptr->tm_mday, timeptr->tm_hour,\r | |
618 | timeptr->tm_min, timeptr->tm_sec,\r | |
619 | 1900 + timeptr->tm_year);\r | |
620 | return result;\r | |
621 | }\r | |
622 | @return The asctime function returns a pointer to the string.\r | |
623 | **/\r | |
624 | char *\r | |
2aa62f2b | 625 | asctime(const struct tm *timeptr)\r |
626 | {\r | |
627 | register const char * wn;\r | |
628 | register const char * mn;\r | |
629 | \r | |
630 | if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)\r | |
631 | wn = "???";\r | |
632 | else wn = wday_name[timeptr->tm_wday];\r | |
633 | if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)\r | |
634 | mn = "???";\r | |
635 | else mn = mon_name[timeptr->tm_mon];\r | |
636 | /*\r | |
637 | ** The X3J11-suggested format is\r | |
638 | ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"\r | |
639 | ** Since the .2 in 02.2d is ignored, we drop it.\r | |
640 | */\r | |
641 | (void)snprintf(gMD->ASasctime,\r | |
642 | sizeof (char[ASCTIME_BUFLEN]),\r | |
643 | "%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI\r | |
644 | wn, mn,\r | |
645 | timeptr->tm_mday, timeptr->tm_hour,\r | |
646 | timeptr->tm_min, timeptr->tm_sec,\r | |
647 | TM_YEAR_BASE + timeptr->tm_year);\r | |
648 | return gMD->ASasctime;\r | |
649 | }\r | |
650 | \r | |
651 | /**\r | |
652 | **/\r | |
653 | char *\r | |
2aa62f2b | 654 | ctime(const time_t *timer)\r |
655 | {\r | |
656 | return asctime(localtime(timer));\r | |
657 | }\r | |
658 | \r | |
659 | /*\r | |
660 | ** gmtsub is to gmtime as localsub is to localtime.\r | |
661 | */\r | |
d7ce7006 | 662 | void\r |
2aa62f2b | 663 | gmtsub(\r |
664 | const time_t * const timep,\r | |
665 | const long offset,\r | |
666 | struct tm * const tmp\r | |
667 | )\r | |
668 | {\r | |
669 | #ifdef _REENTRANT\r | |
670 | static mutex_t gmt_mutex = MUTEX_INITIALIZER;\r | |
671 | #endif\r | |
672 | \r | |
673 | mutex_lock(&gmt_mutex);\r | |
674 | if (!gmt_is_set) {\r | |
675 | gmt_is_set = TRUE;\r | |
676 | #ifdef ALL_STATE\r | |
677 | gmtptr = (struct state *) malloc(sizeof *gmtptr);\r | |
678 | if (gmtptr != NULL)\r | |
679 | #endif /* defined ALL_STATE */\r | |
680 | gmtload(gmtptr);\r | |
681 | }\r | |
682 | mutex_unlock(&gmt_mutex);\r | |
683 | timesub(timep, offset, gmtptr, tmp);\r | |
684 | #ifdef TM_ZONE\r | |
685 | /*\r | |
686 | ** Could get fancy here and deliver something such as\r | |
687 | ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,\r | |
688 | ** but this is no time for a treasure hunt.\r | |
689 | */\r | |
690 | if (offset != 0)\r | |
691 | tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);\r | |
692 | else {\r | |
693 | #ifdef ALL_STATE\r | |
694 | if (gmtptr == NULL)\r | |
695 | tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);\r | |
696 | else tmp->TM_ZONE = gmtptr->chars;\r | |
697 | #endif /* defined ALL_STATE */\r | |
698 | #ifndef ALL_STATE\r | |
699 | tmp->TM_ZONE = gmtptr->chars;\r | |
700 | #endif /* State Farm */\r | |
701 | }\r | |
702 | #endif /* defined TM_ZONE */\r | |
703 | }\r | |
704 | \r | |
705 | /**\r | |
706 | **/\r | |
707 | struct tm *\r | |
2aa62f2b | 708 | gmtime(const time_t *timer)\r |
709 | {\r | |
710 | gmtsub(timer, 0L, &gMD->BDTime);\r | |
711 | return &gMD->BDTime;\r | |
712 | }\r | |
713 | \r | |
714 | static void\r | |
715 | localsub(const time_t * const timep, const long offset, struct tm * const tmp)\r | |
716 | {\r | |
717 | register struct state * sp;\r | |
718 | register const struct ttinfo * ttisp;\r | |
719 | register int i;\r | |
720 | const time_t t = *timep;\r | |
721 | \r | |
722 | sp = lclptr;\r | |
723 | #ifdef ALL_STATE\r | |
724 | if (sp == NULL) {\r | |
725 | gmtsub(timep, offset, tmp);\r | |
726 | return;\r | |
727 | }\r | |
728 | #endif /* defined ALL_STATE */\r | |
729 | if (sp->timecnt == 0 || t < sp->ats[0]) {\r | |
730 | i = 0;\r | |
731 | while (sp->ttis[i].tt_isdst)\r | |
732 | if (++i >= sp->typecnt) {\r | |
733 | i = 0;\r | |
734 | break;\r | |
735 | }\r | |
736 | } else {\r | |
737 | for (i = 1; i < sp->timecnt; ++i)\r | |
738 | if (t < sp->ats[i])\r | |
739 | break;\r | |
740 | i = sp->types[i - 1];\r | |
741 | }\r | |
742 | ttisp = &sp->ttis[i];\r | |
743 | /*\r | |
744 | ** To get (wrong) behavior that's compatible with System V Release 2.0\r | |
745 | ** you'd replace the statement below with\r | |
746 | ** t += ttisp->tt_gmtoff;\r | |
747 | ** timesub(&t, 0L, sp, tmp);\r | |
748 | */\r | |
749 | timesub(&t, ttisp->tt_gmtoff, sp, tmp);\r | |
750 | tmp->tm_isdst = ttisp->tt_isdst;\r | |
751 | tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];\r | |
752 | #ifdef TM_ZONE\r | |
753 | tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];\r | |
754 | #endif /* defined TM_ZONE */\r | |
755 | }\r | |
756 | \r | |
757 | /**\r | |
758 | **/\r | |
759 | struct tm *\r | |
2aa62f2b | 760 | localtime(const time_t *timer)\r |
761 | {\r | |
762 | tzset();\r | |
763 | localsub(timer, 0L, &gMD->BDTime);\r | |
764 | return &gMD->BDTime;\r | |
765 | }\r |