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