]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Time/Time.c
StdLib: GCC 6 build fixes
[mirror_edk2.git] / StdLib / LibC / Time / Time.c
CommitLineData
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
47static 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
58const 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
63const int year_lengths[2] = {\r
64 DAYSPERNYEAR, DAYSPERLYEAR\r
65};\r
66\r
67\r
68static const char *wday_name[7] = {\r
69 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
70};\r
71\r
72static 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
77static int gmt_is_set;\r
78\r
79/* ############### Implementation Functions ############################ */\r
80// Forward reference\r
81static void\r
82localsub(const time_t * const timep, const long offset, struct tm * const tmp);\r
83\r
84clock_t\r
2aa62f2b 85__getCPS(void)\r
86{\r
87 return gMD->ClocksPerSecond;\r
88}\r
89\r
90static void\r
91timesub(\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
185double\r
2aa62f2b 186difftime(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
209static int\r
210increment_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
219static int\r
220normalize_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
230static int\r
231tmcomp(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
244static time_t\r
245time2sub(\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 401time_t\r
2aa62f2b 402time2(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
416static time_t\r
417time1(\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
65ed9d7f
LL
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
2aa62f2b 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
513time_t\r
2aa62f2b 514mktime(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
535time_t\r
2aa62f2b 536time(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
577clock_t\r
578clock(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
624char *\r
2aa62f2b 625asctime(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
653char *\r
2aa62f2b 654ctime(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 662void\r
2aa62f2b 663gmtsub(\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
707struct tm *\r
2aa62f2b 708gmtime(const time_t *timer)\r
709{\r
710 gmtsub(timer, 0L, &gMD->BDTime);\r
711 return &gMD->BDTime;\r
712}\r
713\r
714static void\r
715localsub(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
759struct tm *\r
2aa62f2b 760localtime(const time_t *timer)\r
761{\r
762 tzset();\r
763 localsub(timer, 0L, &gMD->BDTime);\r
764 return &gMD->BDTime;\r
765}\r