blob: 0296a5dc93910871cd3d10e2382fbed2168016e7 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/**
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
47static 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
58const 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
63const int year_lengths[2] = {
64 DAYSPERNYEAR, DAYSPERLYEAR
65};
66
67
68static const char *wday_name[7] = {
69 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
70};
71
72static const char *mon_name[12] = {
73 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
74 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
75};
76
77static int gmt_is_set;
78
79/* ############### Implementation Functions ############################ */
80// Forward reference
81static void
82localsub(const time_t * const timep, const long offset, struct tm * const tmp);
83
84clock_t
85__getCPS(void)
86{
87 return gMD->ClocksPerSecond;
88}
89
90static void
91timesub(
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**/
185double
186difftime(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
209static int
210increment_overflow(int * number, int delta)
211{
212 int number0;
213
214 number0 = *number;
215 *number += delta;
216 return (*number < number0) != (delta < 0);
217}
218
219static int
220normalize_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
230static int
231tmcomp(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
244static time_t
245time2sub(
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
401time_t
402time2(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
416static time_t
417time1(
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**/
513time_t
514mktime(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**/
535time_t
536time(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**/
577clock_t
578clock(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**/
624char *
625asctime(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**/
653char *
654ctime(const time_t *timer)
655{
656 return asctime(localtime(timer));
657}
658
659/*
660** gmtsub is to gmtime as localsub is to localtime.
661*/
662void
663gmtsub(
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**/
707struct tm *
708gmtime(const time_t *timer)
709{
710 gmtsub(timer, 0L, &gMD->BDTime);
711 return &gMD->BDTime;
712}
713
714static void
715localsub(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**/
759struct tm *
760localtime(const time_t *timer)
761{
762 tzset();
763 localsub(timer, 0L, &gMD->BDTime);
764 return &gMD->BDTime;
765}