• 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