--- /dev/null
+/**\r
+ Definitions and Implementation for <time.h>.\r
+\r
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available under\r
+ the terms and conditions of the BSD License that accompanies this distribution.\r
+ The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ Portions derived from the NIH time zone package file, localtime.c,\r
+ which contains the following notice:\r
+\r
+ This file is in the public domain, so clarified as of\r
+ 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
+\r
+ NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp\r
+**/\r
+#include <Uefi.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+//#include <Library/UefiRuntimeLib.h>\r
+\r
+#include <LibConfig.h>\r
+\r
+#include <errno.h>\r
+#include <limits.h>\r
+#include <time.h>\r
+#include <reentrant.h>\r
+#include "tzfile.h"\r
+#include "TimeVals.h"\r
+#include <MainData.h>\r
+#include <extern.h> // Library/include/extern.h: Private to implementation\r
+\r
+#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */\r
+// Keep compiler quiet about casting from function to data pointers\r
+#pragma warning ( disable : 4054 )\r
+#endif /* defined(_MSC_VER) */\r
+\r
+/* ####################### Private Data ################################# */\r
+\r
+#if 0\r
+static EFI_TIME TimeBuffer;\r
+\r
+ static UINT16 MonthOffs[12] = {\r
+ 00,\r
+ 31, 59, 90, 120,\r
+ 151, 181, 212, 243,\r
+ 273, 304, 334\r
+ };\r
+ static clock_t y2kOffs = 730485;\r
+#endif\r
+\r
+const int mon_lengths[2][MONSPERYEAR] = {\r
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },\r
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }\r
+};\r
+\r
+const int year_lengths[2] = {\r
+ DAYSPERNYEAR, DAYSPERLYEAR\r
+};\r
+\r
+\r
+static const char *wday_name[7] = {\r
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
+};\r
+\r
+static const char *mon_name[12] = {\r
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+};\r
+\r
+static int gmt_is_set;\r
+\r
+/* ############### Implementation Functions ############################ */\r
+// Forward reference\r
+static void\r
+localsub(const time_t * const timep, const long offset, struct tm * const tmp);\r
+\r
+clock_t\r
+EFIAPI\r
+__getCPS(void)\r
+{\r
+ return gMD->ClocksPerSecond;\r
+}\r
+\r
+static void\r
+timesub(\r
+ const time_t * const timep,\r
+ const long offset,\r
+ const struct state * const sp,\r
+ struct tm * const tmp\r
+ )\r
+{\r
+ const struct lsinfo * lp;\r
+ time_t /*INTN*/ days;\r
+ time_t /*INTN*/ rem;\r
+ time_t /*INTN*/ y;\r
+ int yleap;\r
+ const int * ip;\r
+ time_t /*INTN*/ corr;\r
+ int hit;\r
+ int i;\r
+\r
+ corr = 0;\r
+ hit = 0;\r
+#ifdef ALL_STATE\r
+ i = (sp == NULL) ? 0 : sp->leapcnt;\r
+#endif /* defined ALL_STATE */\r
+#ifndef ALL_STATE\r
+ i = sp->leapcnt;\r
+#endif /* State Farm */\r
+ while (--i >= 0) {\r
+ lp = &sp->lsis[i];\r
+ if (*timep >= lp->ls_trans) {\r
+ if (*timep == lp->ls_trans) {\r
+ hit = ((i == 0 && lp->ls_corr > 0) ||\r
+ lp->ls_corr > sp->lsis[i - 1].ls_corr);\r
+ if (hit)\r
+ while (i > 0 &&\r
+ sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&\r
+ sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1 )\r
+ {\r
+ ++hit;\r
+ --i;\r
+ }\r
+ }\r
+ corr = lp->ls_corr;\r
+ break;\r
+ }\r
+ }\r
+ days = *timep / SECSPERDAY;\r
+ rem = *timep % SECSPERDAY;\r
+ rem += (offset - corr);\r
+ while (rem < 0) {\r
+ rem += SECSPERDAY;\r
+ --days;\r
+ }\r
+ while (rem >= SECSPERDAY) {\r
+ rem -= SECSPERDAY;\r
+ ++days;\r
+ }\r
+ tmp->tm_hour = (int) (rem / SECSPERHOUR);\r
+ rem = rem % SECSPERHOUR;\r
+ tmp->tm_min = (int) (rem / SECSPERMIN);\r
+ /*\r
+ ** A positive leap second requires a special\r
+ ** representation. This uses "... ??:59:60" et seq.\r
+ */\r
+ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;\r
+ tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);\r
+ if (tmp->tm_wday < 0)\r
+ tmp->tm_wday += DAYSPERWEEK;\r
+ y = EPOCH_YEAR;\r
+ while (days < 0 || days >= (LONG32) year_lengths[yleap = isleap(y)]) {\r
+ time_t /*INTN*/ newy;\r
+\r
+ newy = (y + days / DAYSPERNYEAR);\r
+ if (days < 0)\r
+ --newy;\r
+ days -= (newy - y) * DAYSPERNYEAR +\r
+ LEAPS_THRU_END_OF(newy - 1) -\r
+ LEAPS_THRU_END_OF(y - 1);\r
+ y = newy;\r
+ }\r
+ tmp->tm_year = (int)(y - TM_YEAR_BASE);\r
+ tmp->tm_yday = (int) days;\r
+ ip = mon_lengths[yleap];\r
+ for (tmp->tm_mon = 0; days >= (LONG32) ip[tmp->tm_mon]; ++(tmp->tm_mon))\r
+ days = days - (LONG32) ip[tmp->tm_mon];\r
+ tmp->tm_mday = (int) (days + 1);\r
+ tmp->tm_isdst = 0;\r
+#ifdef TM_GMTOFF\r
+ tmp->TM_GMTOFF = offset;\r
+#endif /* defined TM_GMTOFF */\r
+}\r
+\r
+/* ############### Time Manipulation Functions ########################## */\r
+\r
+/** The clock function determines the processor time used.\r
+\r
+ @return The clock function returns the implementation\92s best\r
+ approximation to the processor time used by the program since the\r
+ beginning of an implementation-defined era related only to the\r
+ program invocation. To determine the time in seconds, the value\r
+ returned by the clock function should be divided by the value of\r
+ the macro CLOCKS_PER_SEC. If the processor time used is not\r
+ available or its value cannot be represented, the function\r
+ returns the value (clock_t)(-1).\r
+\r
+ On IA32 or X64 platforms, the value returned is the number of\r
+ CPU TimeStamp Counter ticks since the appliation started.\r
+**/\r
+clock_t\r
+EFIAPI\r
+clock(void)\r
+{\r
+ clock_t temp;\r
+\r
+#ifdef NT32dvm\r
+ temp = 0;\r
+#else\r
+ temp = (clock_t)GetPerformanceCounter();\r
+#endif /* NT32dvm */\r
+\r
+ return temp - gMD->AppStartTime;\r
+}\r
+\r
+/**\r
+**/\r
+double\r
+EFIAPI\r
+difftime(time_t time1, time_t time0)\r
+{\r
+ return (double)(time1 - time0);\r
+}\r
+\r
+/*\r
+** Adapted from code provided by Robert Elz, who writes:\r
+** The "best" way to do mktime I think is based on an idea of Bob\r
+** Kridle's (so its said...) from a long time ago.\r
+** [kridle@xinet.com as of 1996-01-16.]\r
+** It does a binary search of the time_t space. Since time_t's are\r
+** just 32 bits, its a max of 32 iterations (even at 64 bits it\r
+** would still be very reasonable).\r
+*/\r
+\r
+#ifndef WRONG\r
+#define WRONG (-1)\r
+#endif /* !defined WRONG */\r
+\r
+/*\r
+** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).\r
+*/\r
+\r
+static int\r
+increment_overflow(int * number, int delta)\r
+{\r
+ int number0;\r
+\r
+ number0 = *number;\r
+ *number += delta;\r
+ return (*number < number0) != (delta < 0);\r
+}\r
+\r
+static int\r
+normalize_overflow(int * const tensptr, int * const unitsptr, const int base)\r
+{\r
+ register int tensdelta;\r
+\r
+ tensdelta = (*unitsptr >= 0) ?\r
+ (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);\r
+ *unitsptr -= tensdelta * base;\r
+ return increment_overflow(tensptr, tensdelta);\r
+}\r
+\r
+static int\r
+tmcomp(const struct tm * const atmp, const struct tm * const btmp)\r
+{\r
+ register int result;\r
+\r
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&\r
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&\r
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&\r
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&\r
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)\r
+ result = atmp->tm_sec - btmp->tm_sec;\r
+ return result;\r
+}\r
+\r
+static time_t\r
+time2sub(\r
+ struct tm * const tmp,\r
+ void (* const funcp)(const time_t*, long, struct tm*),\r
+ const long offset,\r
+ int * const okayp,\r
+ const int do_norm_secs\r
+ )\r
+{\r
+ register const struct state * sp;\r
+ register int dir;\r
+ register int bits;\r
+ register int i, j ;\r
+ register int saved_seconds;\r
+ time_t newt;\r
+ time_t t;\r
+ struct tm yourtm, mytm;\r
+\r
+ *okayp = FALSE;\r
+ yourtm = *tmp; // Create a copy of tmp\r
+ if (do_norm_secs) {\r
+ if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,\r
+ SECSPERMIN))\r
+ return WRONG;\r
+ }\r
+ if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))\r
+ return WRONG;\r
+ if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))\r
+ return WRONG;\r
+ if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))\r
+ return WRONG;\r
+ /*\r
+ ** Turn yourtm.tm_year into an actual year number for now.\r
+ ** It is converted back to an offset from TM_YEAR_BASE later.\r
+ */\r
+ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))\r
+ return WRONG;\r
+ while (yourtm.tm_mday <= 0) {\r
+ if (increment_overflow(&yourtm.tm_year, -1))\r
+ return WRONG;\r
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
+ yourtm.tm_mday += year_lengths[isleap(i)];\r
+ }\r
+ while (yourtm.tm_mday > DAYSPERLYEAR) {\r
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
+ yourtm.tm_mday -= year_lengths[isleap(i)];\r
+ if (increment_overflow(&yourtm.tm_year, 1))\r
+ return WRONG;\r
+ }\r
+ for ( ; ; ) {\r
+ i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];\r
+ if (yourtm.tm_mday <= i)\r
+ break;\r
+ yourtm.tm_mday -= i;\r
+ if (++yourtm.tm_mon >= MONSPERYEAR) {\r
+ yourtm.tm_mon = 0;\r
+ if (increment_overflow(&yourtm.tm_year, 1))\r
+ return WRONG;\r
+ }\r
+ }\r
+ if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))\r
+ return WRONG;\r
+ if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)\r
+ saved_seconds = 0;\r
+ else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {\r
+ /*\r
+ ** We can't set tm_sec to 0, because that might push the\r
+ ** time below the minimum representable time.\r
+ ** Set tm_sec to 59 instead.\r
+ ** This assumes that the minimum representable time is\r
+ ** not in the same minute that a leap second was deleted from,\r
+ ** which is a safer assumption than using 58 would be.\r
+ */\r
+ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))\r
+ return WRONG;\r
+ saved_seconds = yourtm.tm_sec;\r
+ yourtm.tm_sec = SECSPERMIN - 1;\r
+ } else {\r
+ saved_seconds = yourtm.tm_sec;\r
+ yourtm.tm_sec = 0;\r
+ }\r
+ /*\r
+ ** Divide the search space in half\r
+ ** (this works whether time_t is signed or unsigned).\r
+ */\r
+ bits = TYPE_BIT(time_t) - 1;\r
+ /*\r
+ ** Set t to the midpoint of our binary search.\r
+ **\r
+ ** If time_t is signed, then 0 is just above the median,\r
+ ** assuming two's complement arithmetic.\r
+ ** If time_t is unsigned, then (1 << bits) is just above the median.\r
+ */\r
+ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);\r
+ for ( ; ; ) {\r
+ (*funcp)(&t, offset, &mytm); // Convert t to broken-down time in mytm\r
+ dir = tmcomp(&mytm, &yourtm); // Is mytm larger, equal, or less than yourtm?\r
+ if (dir != 0) { // If mytm != yourtm...\r
+ if (bits-- < 0) // If we have exhausted all the bits..\r
+ return WRONG; // Return that we failed\r
+ if (bits < 0) // If on the last bit...\r
+ --t; /* may be needed if new t is minimal */\r
+ else if (dir > 0) // else if mytm > yourtm...\r
+ t -= ((time_t) 1) << bits; // subtract half the remaining time-space\r
+ else t += ((time_t) 1) << bits; // otherwise add half the remaining time-space\r
+ continue; // Repeat for the next half\r
+ }\r
+ if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)\r
+ break;\r
+ /*\r
+ ** Right time, wrong type.\r
+ ** Hunt for right time, right type.\r
+ ** It's okay to guess wrong since the guess\r
+ ** gets checked.\r
+ */\r
+ /*\r
+ ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
+ */\r
+ sp = (const struct state *)\r
+ (((void *) funcp == (void *) localsub) ?\r
+ lclptr : gmtptr);\r
+#ifdef ALL_STATE\r
+ if (sp == NULL)\r
+ return WRONG;\r
+#endif /* defined ALL_STATE */\r
+ for (i = sp->typecnt - 1; i >= 0; --i) {\r
+ if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)\r
+ continue;\r
+ for (j = sp->typecnt - 1; j >= 0; --j) {\r
+ if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)\r
+ continue;\r
+ newt = t + sp->ttis[j].tt_gmtoff -\r
+ sp->ttis[i].tt_gmtoff;\r
+ (*funcp)(&newt, offset, &mytm);\r
+ if (tmcomp(&mytm, &yourtm) != 0)\r
+ continue;\r
+ if (mytm.tm_isdst != yourtm.tm_isdst)\r
+ continue;\r
+ /*\r
+ ** We have a match.\r
+ */\r
+ t = newt;\r
+ goto label;\r
+ }\r
+ }\r
+ return WRONG;\r
+ }\r
+ label:\r
+ newt = t + saved_seconds;\r
+ if ((newt < t) != (saved_seconds < 0))\r
+ return WRONG;\r
+ t = newt;\r
+ (*funcp)(&t, offset, tmp);\r
+ *okayp = TRUE;\r
+ return t;\r
+}\r
+\r
+static time_t\r
+time2(struct tm * const tmp, void (* const funcp)(const time_t*, long, struct tm*),\r
+ const long offset, int * const okayp)\r
+{\r
+ time_t t;\r
+\r
+ /*\r
+ ** First try without normalization of seconds\r
+ ** (in case tm_sec contains a value associated with a leap second).\r
+ ** If that fails, try with normalization of seconds.\r
+ */\r
+ t = time2sub(tmp, funcp, offset, okayp, FALSE);\r
+ return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);\r
+}\r
+\r
+static time_t\r
+time1(\r
+ struct tm * const tmp,\r
+ void (* const funcp)(const time_t *, long, struct tm *),\r
+ const long offset\r
+ )\r
+{\r
+ register time_t t;\r
+ register const struct state * sp;\r
+ register int samei, otheri;\r
+ register int sameind, otherind;\r
+ register int i;\r
+ register int nseen;\r
+ int seen[TZ_MAX_TYPES];\r
+ int types[TZ_MAX_TYPES];\r
+ int okay;\r
+\r
+ if (tmp->tm_isdst > 1)\r
+ tmp->tm_isdst = 1;\r
+ t = time2(tmp, funcp, offset, &okay);\r
+#ifdef PCTS\r
+ /*\r
+ ** PCTS code courtesy Grant Sullivan (grant@osf.org).\r
+ */\r
+ if (okay)\r
+ return t;\r
+ if (tmp->tm_isdst < 0)\r
+ tmp->tm_isdst = 0; /* reset to std and try again */\r
+#endif /* defined PCTS */\r
+#ifndef PCTS\r
+ if (okay || tmp->tm_isdst < 0)\r
+ return t;\r
+#endif /* !defined PCTS */\r
+ /*\r
+ ** We're supposed to assume that somebody took a time of one type\r
+ ** and did some math on it that yielded a "struct tm" that's bad.\r
+ ** We try to divine the type they started from and adjust to the\r
+ ** type they need.\r
+ */\r
+ /*\r
+ ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
+ */\r
+ sp = (const struct state *) (((void *) funcp == (void *) localsub) ?\r
+ lclptr : gmtptr);\r
+#ifdef ALL_STATE\r
+ if (sp == NULL)\r
+ return WRONG;\r
+#endif /* defined ALL_STATE */\r
+ for (i = 0; i < sp->typecnt; ++i)\r
+ seen[i] = FALSE;\r
+ nseen = 0;\r
+ for (i = sp->timecnt - 1; i >= 0; --i)\r
+ if (!seen[sp->types[i]]) {\r
+ seen[sp->types[i]] = TRUE;\r
+ types[nseen++] = sp->types[i];\r
+ }\r
+ for (sameind = 0; sameind < nseen; ++sameind) {\r
+ samei = types[sameind];\r
+ if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)\r
+ continue;\r
+ for (otherind = 0; otherind < nseen; ++otherind) {\r
+ otheri = types[otherind];\r
+ if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)\r
+ continue;\r
+ tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -\r
+ sp->ttis[samei].tt_gmtoff);\r
+ tmp->tm_isdst = !tmp->tm_isdst;\r
+ t = time2(tmp, funcp, offset, &okay);\r
+ if (okay)\r
+ return t;\r
+ tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -\r
+ sp->ttis[samei].tt_gmtoff);\r
+ tmp->tm_isdst = !tmp->tm_isdst;\r
+ }\r
+ }\r
+ return WRONG;\r
+}\r
+\r
+/** The mktime function converts the broken-down time, expressed as local time,\r
+ in the structure pointed to by timeptr into a calendar time value with the\r
+ same encoding as that of the values returned by the time function. The\r
+ original values of the tm_wday and tm_yday components of the structure are\r
+ ignored, and the original values of the other components are not restricted\r
+ to the ranges indicated above. Thus, a positive or zero value for tm_isdst\r
+ causes the mktime function to presume initially that Daylight Saving Time,\r
+ respectively, is or is not in effect for the specified time. A negative\r
+ value causes it to attempt to determine whether Daylight Saving Time is in\r
+ effect for the specified time. On successful completion, the values of the\r
+ tm_wday and tm_yday components of the structure are set appropriately, and\r
+ the other components are set to represent the specified calendar time, but\r
+ with their values forced to the ranges indicated above; the final value of\r
+ tm_mday is not set until tm_mon and tm_year are determined.\r
+\r
+ @return The mktime function returns the specified calendar time encoded\r
+ as a value of type time_t. If the calendar time cannot be\r
+ represented, the function returns the value (time_t)(-1).\r
+**/\r
+time_t\r
+EFIAPI\r
+mktime(struct tm *timeptr)\r
+{\r
+ /* From NetBSD */\r
+ time_t result;\r
+\r
+ rwlock_wrlock(&lcl_lock);\r
+ tzset();\r
+ result = time1(timeptr, &localsub, 0L);\r
+ rwlock_unlock(&lcl_lock);\r
+ return (result);\r
+}\r
+\r
+/** The time function determines the current calendar time. The encoding of\r
+ the value is unspecified.\r
+\r
+ @return The time function returns the implementation\92s best approximation\r
+ to the current calendar time. The value (time_t)(-1) is returned\r
+ if the calendar time is not available. If timer is not a null\r
+ pointer, the return value is also assigned to the object it\r
+ points to.\r
+**/\r
+time_t\r
+EFIAPI\r
+time(time_t *timer)\r
+{\r
+ time_t CalTime;\r
+ EFI_STATUS Status;\r
+ EFI_TIME *ET;\r
+ struct tm *BT;\r
+\r
+ ET = &gMD->TimeBuffer;\r
+ BT = &gMD->BDTime;\r
+\r
+ // Get EFI Time\r
+ Status = gRT->GetTime( ET, NULL);\r
+// Status = EfiGetTime( ET, NULL);\r
+ EFIerrno = Status;\r
+ if( Status != RETURN_SUCCESS) {\r
+ return (time_t)-1;\r
+ }\r
+\r
+ // Convert EFI time to broken-down time.\r
+ Efi2Tm( ET, BT);\r
+\r
+ // Convert to time_t\r
+ CalTime = mktime(&gMD->BDTime);\r
+\r
+ if( timer != NULL) {\r
+ *timer = CalTime;\r
+ }\r
+ return CalTime; // Return calendar time in microseconds\r
+}\r
+\r
+/* ################# Time Conversion Functions ########################## */\r
+/*\r
+ Except for the strftime function, these functions each return a pointer to\r
+ one of two types of static objects: a broken-down time structure or an\r
+ array of char. Execution of any of the functions that return a pointer to\r
+ one of these object types may overwrite the information in any object of\r
+ the same type pointed to by the value returned from any previous call to\r
+ any of them. The implementation shall behave as if no other library\r
+ functions call these functions.\r
+*/\r
+\r
+/** The asctime function converts the broken-down time in the structure pointed\r
+ to by timeptr into a string in the form\r
+ Sun Sep 16 01:03:52 1973\n\0\r
+ using the equivalent of the following algorithm.\r
+\r
+ char *asctime(const struct tm *timeptr)\r
+ {\r
+ static const char wday_name[7][3] = {\r
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
+ };\r
+ static const char mon_name[12][3] = {\r
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+ };\r
+ static char result[26];\r
+ sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",\r
+ wday_name[timeptr->tm_wday],\r
+ mon_name[timeptr->tm_mon],\r
+ timeptr->tm_mday, timeptr->tm_hour,\r
+ timeptr->tm_min, timeptr->tm_sec,\r
+ 1900 + timeptr->tm_year);\r
+ return result;\r
+ }\r
+ @return The asctime function returns a pointer to the string.\r
+**/\r
+char *\r
+EFIAPI\r
+asctime(const struct tm *timeptr)\r
+{\r
+ register const char * wn;\r
+ register const char * mn;\r
+\r
+ if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)\r
+ wn = "???";\r
+ else wn = wday_name[timeptr->tm_wday];\r
+ if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)\r
+ mn = "???";\r
+ else mn = mon_name[timeptr->tm_mon];\r
+ /*\r
+ ** The X3J11-suggested format is\r
+ ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"\r
+ ** Since the .2 in 02.2d is ignored, we drop it.\r
+ */\r
+ (void)snprintf(gMD->ASasctime,\r
+ sizeof (char[ASCTIME_BUFLEN]),\r
+ "%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI\r
+ wn, mn,\r
+ timeptr->tm_mday, timeptr->tm_hour,\r
+ timeptr->tm_min, timeptr->tm_sec,\r
+ TM_YEAR_BASE + timeptr->tm_year);\r
+ return gMD->ASasctime;\r
+}\r
+\r
+/**\r
+**/\r
+char *\r
+EFIAPI\r
+ctime(const time_t *timer)\r
+{\r
+ return asctime(localtime(timer));\r
+}\r
+\r
+/*\r
+** gmtsub is to gmtime as localsub is to localtime.\r
+*/\r
+static void\r
+gmtsub(\r
+ const time_t * const timep,\r
+ const long offset,\r
+ struct tm * const tmp\r
+ )\r
+{\r
+#ifdef _REENTRANT\r
+ static mutex_t gmt_mutex = MUTEX_INITIALIZER;\r
+#endif\r
+\r
+ mutex_lock(&gmt_mutex);\r
+ if (!gmt_is_set) {\r
+ gmt_is_set = TRUE;\r
+#ifdef ALL_STATE\r
+ gmtptr = (struct state *) malloc(sizeof *gmtptr);\r
+ if (gmtptr != NULL)\r
+#endif /* defined ALL_STATE */\r
+ gmtload(gmtptr);\r
+ }\r
+ mutex_unlock(&gmt_mutex);\r
+ timesub(timep, offset, gmtptr, tmp);\r
+#ifdef TM_ZONE\r
+ /*\r
+ ** Could get fancy here and deliver something such as\r
+ ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,\r
+ ** but this is no time for a treasure hunt.\r
+ */\r
+ if (offset != 0)\r
+ tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);\r
+ else {\r
+#ifdef ALL_STATE\r
+ if (gmtptr == NULL)\r
+ tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);\r
+ else tmp->TM_ZONE = gmtptr->chars;\r
+#endif /* defined ALL_STATE */\r
+#ifndef ALL_STATE\r
+ tmp->TM_ZONE = gmtptr->chars;\r
+#endif /* State Farm */\r
+ }\r
+#endif /* defined TM_ZONE */\r
+}\r
+\r
+/**\r
+**/\r
+struct tm *\r
+EFIAPI\r
+gmtime(const time_t *timer)\r
+{\r
+ gmtsub(timer, 0L, &gMD->BDTime);\r
+ return &gMD->BDTime;\r
+}\r
+\r
+static void\r
+localsub(const time_t * const timep, const long offset, struct tm * const tmp)\r
+{\r
+ register struct state * sp;\r
+ register const struct ttinfo * ttisp;\r
+ register int i;\r
+ const time_t t = *timep;\r
+\r
+ sp = lclptr;\r
+#ifdef ALL_STATE\r
+ if (sp == NULL) {\r
+ gmtsub(timep, offset, tmp);\r
+ return;\r
+ }\r
+#endif /* defined ALL_STATE */\r
+ if (sp->timecnt == 0 || t < sp->ats[0]) {\r
+ i = 0;\r
+ while (sp->ttis[i].tt_isdst)\r
+ if (++i >= sp->typecnt) {\r
+ i = 0;\r
+ break;\r
+ }\r
+ } else {\r
+ for (i = 1; i < sp->timecnt; ++i)\r
+ if (t < sp->ats[i])\r
+ break;\r
+ i = sp->types[i - 1];\r
+ }\r
+ ttisp = &sp->ttis[i];\r
+ /*\r
+ ** To get (wrong) behavior that's compatible with System V Release 2.0\r
+ ** you'd replace the statement below with\r
+ ** t += ttisp->tt_gmtoff;\r
+ ** timesub(&t, 0L, sp, tmp);\r
+ */\r
+ timesub(&t, ttisp->tt_gmtoff, sp, tmp);\r
+ tmp->tm_isdst = ttisp->tt_isdst;\r
+ tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];\r
+#ifdef TM_ZONE\r
+ tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];\r
+#endif /* defined TM_ZONE */\r
+}\r
+\r
+/**\r
+**/\r
+struct tm *\r
+EFIAPI\r
+localtime(const time_t *timer)\r
+{\r
+ tzset();\r
+ localsub(timer, 0L, &gMD->BDTime);\r
+ return &gMD->BDTime;\r
+}\r