• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
__getCPS(void)85 __getCPS(void)
86 {
87   return gMD->ClocksPerSecond;
88 }
89 
90 static void
timesub(const time_t * const timep,const long offset,const struct state * const sp,struct tm * const tmp)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
difftime(time_t time1,time_t time0)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
increment_overflow(int * number,int delta)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
normalize_overflow(int * const tensptr,int * const unitsptr,const int base)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
tmcomp(const struct tm * const atmp,const struct tm * const btmp)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
time2sub(struct tm * const tmp,void (* const funcp)(const time_t *,long,struct tm *),const long offset,int * const okayp,const int do_norm_secs)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
time2(struct tm * const tmp,void (* const funcp)(const time_t *,long,struct tm *),const long offset,int * const okayp)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
time1(struct tm * const tmp,void (* const funcp)(const time_t *,long,struct tm *),const long offset)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
mktime(struct tm * timeptr)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
time(time_t * timer)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
clock(void)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 *
asctime(const struct tm * timeptr)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 *
ctime(const time_t * timer)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
gmtsub(const time_t * const timep,const long offset,struct tm * const tmp)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 *
gmtime(const time_t * timer)708 gmtime(const time_t *timer)
709 {
710   gmtsub(timer, 0L, &gMD->BDTime);
711   return &gMD->BDTime;
712 }
713 
714 static void
localsub(const time_t * const timep,const long offset,struct tm * const tmp)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 *
localtime(const time_t * timer)760 localtime(const time_t *timer)
761 {
762   tzset();
763   localsub(timer, 0L, &gMD->BDTime);
764   return &gMD->BDTime;
765 }
766