]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Time/Time.c
Add Socket Libraries.
[mirror_edk2.git] / StdLib / LibC / Time / Time.c
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 /** The clock function determines the processor time used.
184
185 @return The clock function returns the implementation's best
186 approximation to the processor time used by the program since the
187 beginning of an implementation-defined era related only to the
188 program invocation. To determine the time in seconds, the value
189 returned by the clock function should be divided by the value of
190 the macro CLOCKS_PER_SEC. If the processor time used is not
191 available or its value cannot be represented, the function
192 returns the value (clock_t)(-1).
193
194 On IA32 or X64 platforms, the value returned is the number of
195 CPU TimeStamp Counter ticks since the appliation started.
196 **/
197 clock_t
198 clock(void)
199 {
200 #ifndef NT32dvm
201 clock_t temp;
202
203 temp = (clock_t)GetPerformanceCounter();
204
205 return temp - gMD->AppStartTime;
206 #else
207 return (clock_t)-1;
208 #endif /* NT32dvm */
209 }
210
211 /**
212 **/
213 double
214 difftime(time_t time1, time_t time0)
215 {
216 return (double)(time1 - time0);
217 }
218
219 /*
220 ** Adapted from code provided by Robert Elz, who writes:
221 ** The "best" way to do mktime I think is based on an idea of Bob
222 ** Kridle's (so its said...) from a long time ago.
223 ** [kridle@xinet.com as of 1996-01-16.]
224 ** It does a binary search of the time_t space. Since time_t's are
225 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
226 ** would still be very reasonable).
227 */
228
229 #ifndef WRONG
230 #define WRONG (-1)
231 #endif /* !defined WRONG */
232
233 /*
234 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
235 */
236
237 static int
238 increment_overflow(int * number, int delta)
239 {
240 int number0;
241
242 number0 = *number;
243 *number += delta;
244 return (*number < number0) != (delta < 0);
245 }
246
247 static int
248 normalize_overflow(int * const tensptr, int * const unitsptr, const int base)
249 {
250 register int tensdelta;
251
252 tensdelta = (*unitsptr >= 0) ?
253 (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
254 *unitsptr -= tensdelta * base;
255 return increment_overflow(tensptr, tensdelta);
256 }
257
258 static int
259 tmcomp(const struct tm * const atmp, const struct tm * const btmp)
260 {
261 register int result;
262
263 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
264 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
265 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
266 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
267 (result = (atmp->tm_min - btmp->tm_min)) == 0)
268 result = atmp->tm_sec - btmp->tm_sec;
269 return result;
270 }
271
272 static time_t
273 time2sub(
274 struct tm * const tmp,
275 void (* const funcp)(const time_t*, long, struct tm*),
276 const long offset,
277 int * const okayp,
278 const int do_norm_secs
279 )
280 {
281 register const struct state * sp;
282 register int dir;
283 register int bits;
284 register int i, j ;
285 register int saved_seconds;
286 time_t newt;
287 time_t t;
288 struct tm yourtm, mytm;
289
290 *okayp = FALSE;
291 yourtm = *tmp; // Create a copy of tmp
292 if (do_norm_secs) {
293 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
294 SECSPERMIN))
295 return WRONG;
296 }
297 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
298 return WRONG;
299 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
300 return WRONG;
301 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
302 return WRONG;
303 /*
304 ** Turn yourtm.tm_year into an actual year number for now.
305 ** It is converted back to an offset from TM_YEAR_BASE later.
306 */
307 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
308 return WRONG;
309 while (yourtm.tm_mday <= 0) {
310 if (increment_overflow(&yourtm.tm_year, -1))
311 return WRONG;
312 i = yourtm.tm_year + (1 < yourtm.tm_mon);
313 yourtm.tm_mday += year_lengths[isleap(i)];
314 }
315 while (yourtm.tm_mday > DAYSPERLYEAR) {
316 i = yourtm.tm_year + (1 < yourtm.tm_mon);
317 yourtm.tm_mday -= year_lengths[isleap(i)];
318 if (increment_overflow(&yourtm.tm_year, 1))
319 return WRONG;
320 }
321 for ( ; ; ) {
322 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
323 if (yourtm.tm_mday <= i)
324 break;
325 yourtm.tm_mday -= i;
326 if (++yourtm.tm_mon >= MONSPERYEAR) {
327 yourtm.tm_mon = 0;
328 if (increment_overflow(&yourtm.tm_year, 1))
329 return WRONG;
330 }
331 }
332 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
333 return WRONG;
334 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
335 saved_seconds = 0;
336 else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
337 /*
338 ** We can't set tm_sec to 0, because that might push the
339 ** time below the minimum representable time.
340 ** Set tm_sec to 59 instead.
341 ** This assumes that the minimum representable time is
342 ** not in the same minute that a leap second was deleted from,
343 ** which is a safer assumption than using 58 would be.
344 */
345 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
346 return WRONG;
347 saved_seconds = yourtm.tm_sec;
348 yourtm.tm_sec = SECSPERMIN - 1;
349 } else {
350 saved_seconds = yourtm.tm_sec;
351 yourtm.tm_sec = 0;
352 }
353 /*
354 ** Divide the search space in half
355 ** (this works whether time_t is signed or unsigned).
356 */
357 bits = TYPE_BIT(time_t) - 1;
358 /*
359 ** Set t to the midpoint of our binary search.
360 **
361 ** If time_t is signed, then 0 is just above the median,
362 ** assuming two's complement arithmetic.
363 ** If time_t is unsigned, then (1 << bits) is just above the median.
364 */
365 t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
366 for ( ; ; ) {
367 (*funcp)(&t, offset, &mytm); // Convert t to broken-down time in mytm
368 dir = tmcomp(&mytm, &yourtm); // Is mytm larger, equal, or less than yourtm?
369 if (dir != 0) { // If mytm != yourtm...
370 if (bits-- < 0) // If we have exhausted all the bits..
371 return WRONG; // Return that we failed
372 if (bits < 0) // If on the last bit...
373 --t; /* may be needed if new t is minimal */
374 else if (dir > 0) // else if mytm > yourtm...
375 t -= ((time_t) 1) << bits; // subtract half the remaining time-space
376 else t += ((time_t) 1) << bits; // otherwise add half the remaining time-space
377 continue; // Repeat for the next half
378 }
379 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
380 break;
381 /*
382 ** Right time, wrong type.
383 ** Hunt for right time, right type.
384 ** It's okay to guess wrong since the guess
385 ** gets checked.
386 */
387 /*
388 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
389 */
390 sp = (const struct state *)
391 (((void *) funcp == (void *) localsub) ?
392 lclptr : gmtptr);
393 #ifdef ALL_STATE
394 if (sp == NULL)
395 return WRONG;
396 #endif /* defined ALL_STATE */
397 for (i = sp->typecnt - 1; i >= 0; --i) {
398 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
399 continue;
400 for (j = sp->typecnt - 1; j >= 0; --j) {
401 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
402 continue;
403 newt = t + sp->ttis[j].tt_gmtoff -
404 sp->ttis[i].tt_gmtoff;
405 (*funcp)(&newt, offset, &mytm);
406 if (tmcomp(&mytm, &yourtm) != 0)
407 continue;
408 if (mytm.tm_isdst != yourtm.tm_isdst)
409 continue;
410 /*
411 ** We have a match.
412 */
413 t = newt;
414 goto label;
415 }
416 }
417 return WRONG;
418 }
419 label:
420 newt = t + saved_seconds;
421 if ((newt < t) != (saved_seconds < 0))
422 return WRONG;
423 t = newt;
424 (*funcp)(&t, offset, tmp);
425 *okayp = TRUE;
426 return t;
427 }
428
429 time_t
430 time2(struct tm * const tmp, void (* const funcp)(const time_t*, long, struct tm*),
431 const long offset, int * const okayp)
432 {
433 time_t t;
434
435 /*
436 ** First try without normalization of seconds
437 ** (in case tm_sec contains a value associated with a leap second).
438 ** If that fails, try with normalization of seconds.
439 */
440 t = time2sub(tmp, funcp, offset, okayp, FALSE);
441 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
442 }
443
444 static time_t
445 time1(
446 struct tm * const tmp,
447 void (* const funcp)(const time_t *, long, struct tm *),
448 const long offset
449 )
450 {
451 register time_t t;
452 register const struct state * sp;
453 register int samei, otheri;
454 register int sameind, otherind;
455 register int i;
456 register int nseen;
457 int seen[TZ_MAX_TYPES];
458 int types[TZ_MAX_TYPES];
459 int okay;
460
461 if (tmp->tm_isdst > 1)
462 tmp->tm_isdst = 1;
463 t = time2(tmp, funcp, offset, &okay);
464 #ifdef PCTS
465 /*
466 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
467 */
468 if (okay)
469 return t;
470 if (tmp->tm_isdst < 0)
471 tmp->tm_isdst = 0; /* reset to std and try again */
472 #endif /* defined PCTS */
473 #ifndef PCTS
474 if (okay || tmp->tm_isdst < 0)
475 return t;
476 #endif /* !defined PCTS */
477 /*
478 ** We're supposed to assume that somebody took a time of one type
479 ** and did some math on it that yielded a "struct tm" that's bad.
480 ** We try to divine the type they started from and adjust to the
481 ** type they need.
482 */
483 /*
484 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
485 */
486 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
487 lclptr : gmtptr);
488 #ifdef ALL_STATE
489 if (sp == NULL)
490 return WRONG;
491 #endif /* defined ALL_STATE */
492 for (i = 0; i < sp->typecnt; ++i)
493 seen[i] = FALSE;
494 nseen = 0;
495 for (i = sp->timecnt - 1; i >= 0; --i)
496 if (!seen[sp->types[i]]) {
497 seen[sp->types[i]] = TRUE;
498 types[nseen++] = sp->types[i];
499 }
500 for (sameind = 0; sameind < nseen; ++sameind) {
501 samei = types[sameind];
502 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
503 continue;
504 for (otherind = 0; otherind < nseen; ++otherind) {
505 otheri = types[otherind];
506 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
507 continue;
508 tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -
509 sp->ttis[samei].tt_gmtoff);
510 tmp->tm_isdst = !tmp->tm_isdst;
511 t = time2(tmp, funcp, offset, &okay);
512 if (okay)
513 return t;
514 tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -
515 sp->ttis[samei].tt_gmtoff);
516 tmp->tm_isdst = !tmp->tm_isdst;
517 }
518 }
519 return WRONG;
520 }
521
522 /** The mktime function converts the broken-down time, expressed as local time,
523 in the structure pointed to by timeptr into a calendar time value with the
524 same encoding as that of the values returned by the time function. The
525 original values of the tm_wday and tm_yday components of the structure are
526 ignored, and the original values of the other components are not restricted
527 to the ranges indicated above. Thus, a positive or zero value for tm_isdst
528 causes the mktime function to presume initially that Daylight Saving Time,
529 respectively, is or is not in effect for the specified time. A negative
530 value causes it to attempt to determine whether Daylight Saving Time is in
531 effect for the specified time. On successful completion, the values of the
532 tm_wday and tm_yday components of the structure are set appropriately, and
533 the other components are set to represent the specified calendar time, but
534 with their values forced to the ranges indicated above; the final value of
535 tm_mday is not set until tm_mon and tm_year are determined.
536
537 @return The mktime function returns the specified calendar time encoded
538 as a value of type time_t. If the calendar time cannot be
539 represented, the function returns the value (time_t)(-1).
540 **/
541 time_t
542 mktime(struct tm *timeptr)
543 {
544 /* From NetBSD */
545 time_t result;
546
547 rwlock_wrlock(&lcl_lock);
548 tzset();
549 result = time1(timeptr, &localsub, 0L);
550 rwlock_unlock(&lcl_lock);
551 return (result);
552 }
553
554 /** The time function determines the current calendar time. The encoding of
555 the value is unspecified.
556
557 @return The time function returns the implementation's best approximation
558 to the current calendar time. The value (time_t)(-1) is returned
559 if the calendar time is not available. If timer is not a null
560 pointer, the return value is also assigned to the object it
561 points to.
562 **/
563 time_t
564 time(time_t *timer)
565 {
566 time_t CalTime;
567 EFI_STATUS Status;
568 EFI_TIME *ET;
569 struct tm *BT;
570
571 ET = &gMD->TimeBuffer;
572 BT = &gMD->BDTime;
573
574 // Get EFI Time
575 Status = gRT->GetTime( ET, NULL);
576 // Status = EfiGetTime( ET, NULL);
577 EFIerrno = Status;
578 if( Status != RETURN_SUCCESS) {
579 return (time_t)-1;
580 }
581
582 // Convert EFI time to broken-down time.
583 Efi2Tm( ET, BT);
584
585 // Convert to time_t
586 CalTime = mktime(&gMD->BDTime);
587
588 if( timer != NULL) {
589 *timer = CalTime;
590 }
591 return CalTime; // Return calendar time in microseconds
592 }
593
594 /* ################# Time Conversion Functions ########################## */
595 /*
596 Except for the strftime function, these functions each return a pointer to
597 one of two types of static objects: a broken-down time structure or an
598 array of char. Execution of any of the functions that return a pointer to
599 one of these object types may overwrite the information in any object of
600 the same type pointed to by the value returned from any previous call to
601 any of them. The implementation shall behave as if no other library
602 functions call these functions.
603 */
604
605 /** The asctime function converts the broken-down time in the structure pointed
606 to by timeptr into a string in the form
607 Sun Sep 16 01:03:52 1973\n\0
608 using the equivalent of the following algorithm.
609
610 char *asctime(const struct tm *timeptr)
611 {
612 static const char wday_name[7][3] = {
613 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
614 };
615 static const char mon_name[12][3] = {
616 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
617 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
618 };
619 static char result[26];
620 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
621 wday_name[timeptr->tm_wday],
622 mon_name[timeptr->tm_mon],
623 timeptr->tm_mday, timeptr->tm_hour,
624 timeptr->tm_min, timeptr->tm_sec,
625 1900 + timeptr->tm_year);
626 return result;
627 }
628 @return The asctime function returns a pointer to the string.
629 **/
630 char *
631 asctime(const struct tm *timeptr)
632 {
633 register const char * wn;
634 register const char * mn;
635
636 if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
637 wn = "???";
638 else wn = wday_name[timeptr->tm_wday];
639 if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
640 mn = "???";
641 else mn = mon_name[timeptr->tm_mon];
642 /*
643 ** The X3J11-suggested format is
644 ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
645 ** Since the .2 in 02.2d is ignored, we drop it.
646 */
647 (void)snprintf(gMD->ASasctime,
648 sizeof (char[ASCTIME_BUFLEN]),
649 "%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI
650 wn, mn,
651 timeptr->tm_mday, timeptr->tm_hour,
652 timeptr->tm_min, timeptr->tm_sec,
653 TM_YEAR_BASE + timeptr->tm_year);
654 return gMD->ASasctime;
655 }
656
657 /**
658 **/
659 char *
660 ctime(const time_t *timer)
661 {
662 return asctime(localtime(timer));
663 }
664
665 /*
666 ** gmtsub is to gmtime as localsub is to localtime.
667 */
668 void
669 gmtsub(
670 const time_t * const timep,
671 const long offset,
672 struct tm * const tmp
673 )
674 {
675 #ifdef _REENTRANT
676 static mutex_t gmt_mutex = MUTEX_INITIALIZER;
677 #endif
678
679 mutex_lock(&gmt_mutex);
680 if (!gmt_is_set) {
681 gmt_is_set = TRUE;
682 #ifdef ALL_STATE
683 gmtptr = (struct state *) malloc(sizeof *gmtptr);
684 if (gmtptr != NULL)
685 #endif /* defined ALL_STATE */
686 gmtload(gmtptr);
687 }
688 mutex_unlock(&gmt_mutex);
689 timesub(timep, offset, gmtptr, tmp);
690 #ifdef TM_ZONE
691 /*
692 ** Could get fancy here and deliver something such as
693 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
694 ** but this is no time for a treasure hunt.
695 */
696 if (offset != 0)
697 tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);
698 else {
699 #ifdef ALL_STATE
700 if (gmtptr == NULL)
701 tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);
702 else tmp->TM_ZONE = gmtptr->chars;
703 #endif /* defined ALL_STATE */
704 #ifndef ALL_STATE
705 tmp->TM_ZONE = gmtptr->chars;
706 #endif /* State Farm */
707 }
708 #endif /* defined TM_ZONE */
709 }
710
711 /**
712 **/
713 struct tm *
714 gmtime(const time_t *timer)
715 {
716 gmtsub(timer, 0L, &gMD->BDTime);
717 return &gMD->BDTime;
718 }
719
720 static void
721 localsub(const time_t * const timep, const long offset, struct tm * const tmp)
722 {
723 register struct state * sp;
724 register const struct ttinfo * ttisp;
725 register int i;
726 const time_t t = *timep;
727
728 sp = lclptr;
729 #ifdef ALL_STATE
730 if (sp == NULL) {
731 gmtsub(timep, offset, tmp);
732 return;
733 }
734 #endif /* defined ALL_STATE */
735 if (sp->timecnt == 0 || t < sp->ats[0]) {
736 i = 0;
737 while (sp->ttis[i].tt_isdst)
738 if (++i >= sp->typecnt) {
739 i = 0;
740 break;
741 }
742 } else {
743 for (i = 1; i < sp->timecnt; ++i)
744 if (t < sp->ats[i])
745 break;
746 i = sp->types[i - 1];
747 }
748 ttisp = &sp->ttis[i];
749 /*
750 ** To get (wrong) behavior that's compatible with System V Release 2.0
751 ** you'd replace the statement below with
752 ** t += ttisp->tt_gmtoff;
753 ** timesub(&t, 0L, sp, tmp);
754 */
755 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
756 tmp->tm_isdst = ttisp->tt_isdst;
757 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
758 #ifdef TM_ZONE
759 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
760 #endif /* defined TM_ZONE */
761 }
762
763 /**
764 **/
765 struct tm *
766 localtime(const time_t *timer)
767 {
768 tzset();
769 localsub(timer, 0L, &gMD->BDTime);
770 return &gMD->BDTime;
771 }