1 #define INSIDE_GIGABASE
2 
3 #include <winbase.h>
4 #include "wince_time.h"
5 
6 /* non-zero if daylight savings time is used */
7 _CRTIMP int _daylight;
8 
9 /* offset for Daylight Saving Time */
10 _CRTIMP long _dstbias;
11 
12 /* difference in seconds between GMT and local time */
13 _CRTIMP long _timezone;
14 
15 /* standard/daylight savings time zone names */
16 _CRTIMP char * _tzname[2];
17 
18 
19 struct __lc_time_data {
20         char *wday_abbr[7];
21         char *wday[7];
22         char *month_abbr[12];
23         char *month[12];
24         char *ampm[2];
25         char *ww_sdatefmt;
26         char *ww_ldatefmt;
27         char *ww_timefmt;
28 };
29 
30 
31 static int _lpdays[] = {
32         -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
33 };
34 
35 static int _days[] = {
36         -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
37 };
38 
39 /*
40  * Flag indicating that time zone information came from GetTimeZoneInformation
41  * API call.
42  */
43 static int tzapiused;
44 
45 static TIME_ZONE_INFORMATION tzinfo;
46 
47 /* Prototypes for local routines */
48 static void __cdecl _expandtime (char specifier, const struct tm *tmptr,
49         char **out, size_t *count, struct __lc_time_data *lc_time);
50 static void __cdecl _store_str (char *in, char **out, size_t *count);
51 static void __cdecl _store_num (int num, int digits, char **out, size_t *count);
52 static void __cdecl _store_number (int num, char **out, size_t *count);
53 static void __cdecl _store_winword (const char *format, const struct tm *tmptr, char **out, size_t *count, struct __lc_time_data *lc_time);
54 
55 time_t __cdecl __loctotime_t (
56                 int yr,         /* 0 based */
57         int mo,         /* 1 based */
58         int dy,         /* 1 based */
59         int hr,
60         int mn,
61         int sc,
62         int dstflag );
63 int __cdecl _isindst(struct tm *);
64 void __cdecl __tzset(void);
65 
66 /*
67  * DST start and end structs.
68  */
69 static transitiondate dststart = { -1, 0, 0L };
70 static transitiondate dstend   = { -1, 0, 0L };
71 
72 /*
73  *  Code page.
74  */
75 UINT __lc_codepage = _CLOCALECP;                /* CP_ACP */
76 
77 
78 /*
79 time_t __cdecl time(time_t *pTime)
80 {
81         // what a mess for getting a simple time!
82         SYSTEMTIME lTime;
83         FILETIME lFileTime;
84 
85         ::GetLocalTime(&lTime);
86         SystemTimeToFileTime(&lTime, &lFileTime);
87         ULARGE_INTEGER lNTime = *(ULARGE_INTEGER*)&lFileTime;
88         if (0l != pTime)
89                 *pTime = *(time_t*)&lNTime;
90         return *(time_t*)&lNTime;
91 }
92 */
93 
94 /* LC_TIME data for local "C" */
95 
96 __declspec(selectany) struct __lc_time_data __lc_time_c = {
97 
98         {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
99 
100         {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
101                 "Friday", "Saturday", },
102 
103         {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
104                 "Sep", "Oct", "Nov", "Dec"},
105 
106         {"January", "February", "March", "April", "May", "June",
107                 "July", "August", "September", "October",
108                 "November", "December"},
109 
110         {"AM", "PM"}
111 
112         , { "M/d/yy" }
113         , { "dddd, MMMM dd, yyyy" }
114         , { "H:mm:ss" }
115         };
116 
117 /* Pointer to the current LC_TIME data structure. */
118 
119 struct __lc_time_data *__lc_time_curr = &__lc_time_c;
120 
121 
122 /* Flags */
123 static unsigned __alternate_form;
124 static unsigned __no_lead_zeros;
125 
126 
mktime(struct tm * lTms)127 time_t __cdecl mktime(struct tm * lTms)
128 {
129         SYSTEMTIME lSTime;
130         lSTime.wYear = lTms->tm_year + 1900;
131         lSTime.wMonth = lTms->tm_mon + 1;
132         lSTime.wDay = lTms->tm_mday;
133         lSTime.wDayOfWeek = lTms->tm_wday;
134         lSTime.wHour = lTms->tm_hour;
135         lSTime.wMinute = lTms->tm_min;
136         lSTime.wSecond = lTms->tm_sec;
137         lSTime.wMilliseconds = 0;
138 
139         FILETIME lFileTime;
140 
141         SystemTimeToFileTime(&lSTime, &lFileTime);
142         ULARGE_INTEGER lNTime = *(ULARGE_INTEGER*)&lFileTime;
143 
144         //TODO: update the values of wDay and yDay in the
145         //      original structure.
146         return *(time_t*)&lNTime;
147 }
148 
149 /*
150 struct tm * __cdecl localtime(const time_t* pTime)
151 {
152         FILETIME lFileTime = *(FILETIME *)&pTime;
153         FILETIME lLocalFileTime;
154 
155         ::FileTimeToLocalFileTime(&lFileTime, &lLocalFileTime);
156 
157         SYSTEMTIME lSTime;
158         if (::FileTimeToSystemTime(&lLocalFimeTime, &lSTime) != 0)
159         {
160                 struct tm* lTms = new struct tm;
161 
162                 lTms->tm_year   =       lSTime.wYear - 1900;
163                 lTms->tm_mon    =       lSTime.wMonth - 1;
164                 lTms->tm_mday   =       lSTime.wDay;
165                 lTms->tm_wday   =       lSTime.wDayOfWeek;
166                 lTms->tm_hour   =       lSTime.wHour;
167                 lTms->tm_min    =       lSTime.wMinute;
168                 lTms->tm_sec    =       lSTime.wSecond;
169 
170                 return lTms;
171         }
172         return 0l;
173 }
174 
175 size_t __cdecl wcsftime(wchar_t *pDest, size_t maxsize, const wchar_t *pFormat,
176         const struct tm *pTime)
177 {
178 
179 }
180 */
181 
182 /***
183 *size_t _Strftime(string, maxsize, format,
184 *       timeptr, lc_time) - Format a time string for a given locale
185 *
186 *Purpose:
187 *       Place characters into the user's output buffer expanding time
188 *       format directives as described in the user's control string.
189 *       Use the supplied 'tm' structure for time data when expanding
190 *       the format directives. use the locale information at lc_time.
191 *       [ANSI]
192 *
193 *Entry:
194 *       char *string = pointer to output string
195 *       size_t maxsize = max length of string
196 *       const char *format = format control string
197 *       const struct tm *timeptr = pointer to tb data structure
198 *               struct __lc_time_data *lc_time = pointer to locale-specific info
199 *                       (passed as void * to avoid type mismatch with C++)
200 *
201 *Exit:
202 *       !0 = If the total number of resulting characters including the
203 *       terminating null is not more than 'maxsize', then return the
204 *       number of chars placed in the 'string' array (not including the
205 *       null terminator).
206 *
207 *       0 = Otherwise, return 0 and the contents of the string are
208 *       indeterminate.
209 *
210 *Exceptions:
211 *
212 *******************************************************************************/
213 
_Strftime(char * string,size_t maxsize,const char * format,const struct tm * timeptr,void * lc_time_arg)214 size_t __cdecl _Strftime (
215         char *string,
216         size_t maxsize,
217         const char *format,
218         const struct tm *timeptr,
219                 void *lc_time_arg
220         )
221 {
222         struct __lc_time_data *lc_time;
223 
224         size_t left;                    /* space left in output string */
225 
226         /* Copy maxsize into temp. */
227         left = maxsize;
228 
229         /* Defer initialization until the crtitical section has been entered */
230         lc_time = lc_time_arg == 0 ? __lc_time_curr : (struct __lc_time_data *)lc_time_arg;
231 
232         /* Copy the input string to the output string expanding the format
233         designations appropriately.  Stop copying when one of the following
234         is true: (1) we hit a null char in the input stream, or (2) there's
235         no room left in the output stream. */
236 
237         while (left > 0)
238         {
239                 switch(*format)
240                 {
241 
242                 case('\0'):
243 
244                         /* end of format input string */
245                         goto done;
246 
247                 case('%'):
248 
249                         /* Format directive.  Take appropriate action based
250                         on format control character. */
251 
252                         format++;                       /* skip over % char */
253 
254                         /* process flags */
255                         __alternate_form = 0;
256                         if (*format == '#')
257                         {
258                                 __alternate_form = 1;
259                                 format++;
260                         }
261                         _expandtime(*format, timeptr, &string, &left,
262                                                         lc_time);
263                         format++;                       /* skip format char */
264                         break;
265 
266 
267                 default:
268 
269                         /* store character, bump pointers, dec the char count */
270                         if (isleadbyte((int)(*format)) && left > 1)
271                         {
272                                 *string++ = *format++;
273                                 left--;
274                         }
275                         *string++ = *format++;
276                         left--;
277                         break;
278                 }
279         }
280 
281 
282         /* All done.  See if we terminated because we hit a null char or because
283         we ran out of space */
284 
285         done:
286 
287         if (left > 0) {
288 
289                 /* Store a terminating null char and return the number of chars
290                 we stored in the output string. */
291 
292                 *string = '\0';
293                 return(maxsize-left);
294         }
295 
296         else
297                 return(0);
298 
299 }
300 
301 
302 /***
303 *_expandtime() - Expand the conversion specifier
304 *
305 *Purpose:
306 *       Expand the given strftime conversion specifier using the time struct
307 *       and store it in the supplied buffer.
308 *
309 *       The expansion is locale-dependent.
310 *
311 *       *** For internal use with strftime() only ***
312 *
313 *Entry:
314 *       char specifier = strftime conversion specifier to expand
315 *       const struct tm *tmptr = pointer to time/date structure
316 *       char **string = address of pointer to output string
317 *       size_t *count = address of char count (space in output area)
318 *       struct __lc_time_data *lc_time = pointer to locale-specific info
319 *
320 *Exit:
321 *       none
322 *
323 *Exceptions:
324 *
325 *******************************************************************************/
326 
_expandtime(char specifier,const struct tm * timeptr,char ** string,size_t * left,struct __lc_time_data * lc_time)327 static void __cdecl _expandtime (
328         char specifier,
329         const struct tm *timeptr,
330         char **string,
331         size_t *left,
332         struct __lc_time_data *lc_time
333         )
334 {
335         unsigned temp;                  /* temps */
336         int wdaytemp;
337 
338         /* Use a copy of the appropriate __lc_time_data pointer.  This
339         should prevent the necessity of locking/unlocking in mthread
340         code (if we can guarantee that the various __lc_time data
341         structures are always in the same segment). contents of time
342         strings structure can now change, so thus we do use locking */
343 
344         switch(specifier) {             /* switch on specifier */
345 
346                 case('a'):              /* abbreviated weekday name */
347                         _store_str((char *)(lc_time->wday_abbr[timeptr->tm_wday]),
348                                  string, left);
349                         break;
350 
351                 case('A'):              /* full weekday name */
352                         _store_str((char *)(lc_time->wday[timeptr->tm_wday]),
353                                  string, left);
354                         break;
355 
356                 case('b'):              /* abbreviated month name */
357                         _store_str((char *)(lc_time->month_abbr[timeptr->tm_mon]),
358                                  string, left);
359                         break;
360 
361                 case('B'):              /* full month name */
362                         _store_str((char *)(lc_time->month[timeptr->tm_mon]),
363                                  string, left);
364                         break;
365 
366                 case('c'):              /* date and time display */
367                         if (__alternate_form)
368                         {
369                                 __alternate_form = FALSE;
370                                 _store_winword(lc_time->ww_ldatefmt, timeptr, string, left, lc_time);
371                                 if (*left == 0)
372                                         return;
373                                 *(*string)++=' ';
374                                 (*left)--;
375                                 _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
376                         }
377                         else {
378                                 _store_winword(lc_time->ww_sdatefmt, timeptr, string, left, lc_time);
379                                 if (*left == 0)
380                                         return;
381                                 *(*string)++=' ';
382                                 (*left)--;
383                                 _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
384                         }
385                         break;
386 
387                 case('d'):              /* mday in decimal (01-31) */
388                         __no_lead_zeros = __alternate_form;
389                         _store_num(timeptr->tm_mday, 2, string, left);
390                         break;
391 
392                 case('H'):              /* 24-hour decimal (00-23) */
393                         __no_lead_zeros = __alternate_form;
394                         _store_num(timeptr->tm_hour, 2, string, left);
395                         break;
396 
397                 case('I'):              /* 12-hour decimal (01-12) */
398                         __no_lead_zeros = __alternate_form;
399                         if (!(temp = timeptr->tm_hour%12))
400                                 temp=12;
401                         _store_num(temp, 2, string, left);
402                         break;
403 
404                 case('j'):              /* yday in decimal (001-366) */
405                         __no_lead_zeros = __alternate_form;
406                         _store_num(timeptr->tm_yday+1, 3, string, left);
407                         break;
408 
409                 case('m'):              /* month in decimal (01-12) */
410                         __no_lead_zeros = __alternate_form;
411                         _store_num(timeptr->tm_mon+1, 2, string, left);
412                         break;
413 
414                 case('M'):              /* minute in decimal (00-59) */
415                         __no_lead_zeros = __alternate_form;
416                         _store_num(timeptr->tm_min, 2, string, left);
417                         break;
418 
419                 case('p'):              /* AM/PM designation */
420                         if (timeptr->tm_hour <= 11)
421                             _store_str((char *)(lc_time->ampm[0]), string, left);
422                         else
423                             _store_str((char *)(lc_time->ampm[1]), string, left);
424                         break;
425 
426                 case('S'):              /* secs in decimal (00-59) */
427                         __no_lead_zeros = __alternate_form;
428                         _store_num(timeptr->tm_sec, 2, string, left);
429                         break;
430 
431                 case('U'):              /* sunday week number (00-53) */
432                         __no_lead_zeros = __alternate_form;
433                         wdaytemp = timeptr->tm_wday;
434                         goto weeknum;   /* join common code */
435 
436                 case('w'):              /* week day in decimal (0-6) */
437                         __no_lead_zeros = __alternate_form;
438                         _store_num(timeptr->tm_wday, 1, string, left);
439                         break;
440 
441                 case('W'):              /* monday week number (00-53) */
442                         __no_lead_zeros = __alternate_form;
443                         if (timeptr->tm_wday == 0)  /* monday based */
444                                 wdaytemp = 6;
445                         else
446                                 wdaytemp = timeptr->tm_wday-1;
447                 weeknum:
448                         if (timeptr->tm_yday < wdaytemp)
449                                 temp=0;
450                         else {
451                                 temp = timeptr->tm_yday/7;
452                                 if ((timeptr->tm_yday%7) >= wdaytemp)
453                                         temp++;
454                                 }
455                         _store_num(temp, 2, string, left);
456                         break;
457 
458                 case('x'):              /* date display */
459                         if (__alternate_form)
460                         {
461                                 __alternate_form = FALSE;
462                                 _store_winword(lc_time->ww_ldatefmt, timeptr, string, left, lc_time);
463                         }
464                         else
465                         {
466                                 _store_winword(lc_time->ww_sdatefmt, timeptr, string, left, lc_time);
467                         }
468                         break;
469 
470                 case('X'):              /* time display */
471                         __alternate_form = FALSE;
472                         _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
473                         break;
474 
475                 case('y'):              /* year w/o century (00-99) */
476                         __no_lead_zeros = __alternate_form;
477                         temp = timeptr->tm_year%100;
478                         _store_num(temp, 2, string, left);
479                         break;
480 
481                 case('Y'):              /* year w/ century */
482                         __no_lead_zeros = __alternate_form;
483                         temp = (((timeptr->tm_year/100)+19)*100) +
484                                (timeptr->tm_year%100);
485                         _store_num(temp, 4, string, left);
486                         break;
487 
488                 case('Z'):              /* time zone name, if any */
489                 case('z'):              /* time zone name, if any */
490                         __tzset();      /* Set time zone info */
491                         _store_str(_tzname[((timeptr->tm_isdst)?1:0)],
492                                  string, left);
493                         break;
494 
495                 case('%'):              /* percent sign */
496                         *(*string)++ = '%';
497                         (*left)--;
498                         break;
499 
500                 default:                /* unknown format directive */
501                         /* ignore the directive and continue */
502                         /* [ANSI: Behavior is undefined.]    */
503                         break;
504 
505         }       /* end % switch */
506 }
507 
508 
509 /*
510  * Cache holding the last time (GMT) for which the Daylight time status was
511  * determined by an API call.
512  */
513 static SYSTEMTIME gmt_cache;
514 
515 /*
516  * Three values of dstflag_cache and dstflag (local variable in code
517  * below)
518  */
519 #define DAYLIGHT_TIME   1
520 #define STANDARD_TIME   0
521 #define UNKNOWN_TIME    -1
522 
523 static int dstflag_cache;
524 
525 /***
526 *time_t time(timeptr) - Get current system time and convert to time_t value.
527 *
528 *Purpose:
529 *       Gets the current date and time and stores it in internal (time_t)
530 *       format. The time is returned and stored via the pointer passed in
531 *       timeptr. If timeptr == NULL, the time is only returned, not stored in
532 *       *timeptr. The internal (time_t) format is the number of seconds since
533 *       00:00:00, Jan 1 1970 (UTC).
534 *
535 *       Note: We cannot use GetSystemTime since its return is ambiguous. In
536 *       Windows NT, in return UTC. In Win32S, probably also Win32C, it
537 *       returns local time.
538 *
539 *Entry:
540 *       time_t *timeptr - pointer to long to store time in.
541 *
542 *Exit:
543 *       returns the current time.
544 *
545 *Exceptions:
546 *
547 *******************************************************************************/
548 
time(time_t * timeptr)549 time_t __cdecl time (
550         time_t *timeptr
551         )
552 {
553         time_t tim;
554 
555         SYSTEMTIME loct, gmt;
556         TIME_ZONE_INFORMATION tzinfo;
557         DWORD tzstate;
558         int dstflag;
559 
560         /*
561          * Get local time from Win32
562          */
563         GetLocalTime( &loct );
564 
565         /*
566          * Determine whether or not the local time is a Daylight Saving
567          * Time. On Windows NT, the GetTimeZoneInformation API is *VERY*
568          * expensive. The scheme below is intended to avoid this API call in
569          * many important case by caching the GMT value and dstflag.In a
570          * subsequent call to time(), the cached value of dstflag is used
571          * unless the new GMT differs from the cached value at least in the
572          * minutes place.
573          */
574         GetSystemTime( &gmt );
575 
576         if ( (gmt.wMinute == gmt_cache.wMinute) &&
577              (gmt.wHour == gmt_cache.wHour) &&
578              (gmt.wDay == gmt_cache.wDay) &&
579              (gmt.wMonth == gmt_cache.wMonth) &&
580              (gmt.wYear == gmt_cache.wYear) )
581         {
582             dstflag = dstflag_cache;
583         }
584         else
585         {
586             if ( (tzstate = GetTimeZoneInformation( &tzinfo )) != 0xFFFFFFFF )
587             {
588                 /*
589                  * Must be very careful in determining whether or not DST is
590                  * really in effect.
591                  */
592                 if ( (tzstate == TIME_ZONE_ID_DAYLIGHT) &&
593                      (tzinfo.DaylightDate.wMonth != 0) &&
594                      (tzinfo.DaylightBias != 0) )
595                     dstflag = DAYLIGHT_TIME;
596                 else
597                     /*
598                      * When in doubt, assume standard time
599                      */
600                     dstflag = STANDARD_TIME;
601             }
602             else
603                 dstflag = UNKNOWN_TIME;
604 
605             dstflag_cache = dstflag;
606             gmt_cache = gmt;
607         }
608 
609         /* convert using our private routine */
610 
611         tim = __loctotime_t( (int)loct.wYear,
612                              (int)loct.wMonth,
613                              (int)loct.wDay,
614                              (int)loct.wHour,
615                              (int)loct.wMinute,
616                              (int)loct.wSecond,
617                              dstflag );
618 
619         if (timeptr)
620                 *timeptr = tim;         /* store time if requested */
621 
622         return tim;
623 }
624 
625 
626 /***
627 *time_t __loctotime_t(yr, mo, dy, hr, mn, sc, dstflag) - converts OS local
628 *       time to internal time format (i.e., a time_t value)
629 *
630 *Purpose:
631 *       Converts a local time value, obtained in a broken down format from
632 *       the host OS, to time_t format (i.e., the number elapsed seconds since
633 *       01-01-70, 00:00:00, UTC).
634 *
635 *Entry:
636 *       int yr, mo, dy -    date
637 *       int hr, mn, sc -    time
638 *       int dstflag    -    1 if Daylight Time, 0 if Standard Time, -1 if
639 *                           not specified.
640 *
641 *Exit:
642 *       Returns calendar time value.
643 *
644 *Exceptions:
645 *
646 *******************************************************************************/
647 
__loctotime_t(int yr,int mo,int dy,int hr,int mn,int sc,int dstflag)648 time_t __cdecl __loctotime_t (
649         int yr,         /* 0 based */
650         int mo,         /* 1 based */
651         int dy,         /* 1 based */
652         int hr,
653         int mn,
654         int sc,
655         int dstflag )
656 {
657         int tmpdays;
658         long tmptim;
659         struct tm tb;
660 
661         /*
662          * Do a quick range check on the year and convert it to a delta
663          * off of 1900.
664          */
665         if ( ((long)(yr -= 1900) < _BASE_YEAR) || ((long)yr > _MAX_YEAR) )
666                 return (time_t)(-1);
667 
668         /*
669          * Compute the number of elapsed days in the current year. Note the
670          * test for a leap year would fail in the year 2100, if this was in
671          * range (which it isn't).
672          */
673         tmpdays = dy + _days[mo - 1];
674         if ( !(yr & 3) && (mo > 2) )
675                 tmpdays++;
676 
677         /*
678          * Compute the number of elapsed seconds since the Epoch. Note the
679          * computation of elapsed leap years would break down after 2100
680          * if such values were in range (fortunately, they aren't).
681          */
682         tmptim = /* 365 days for each year */
683                  (((long)yr - _BASE_YEAR) * 365L
684 
685                  /* one day for each elapsed leap year */
686                  + (long)((yr - 1) >> 2) - _LEAP_YEAR_ADJUST
687 
688                  /* number of elapsed days in yr */
689                  + tmpdays)
690 
691                  /* convert to hours and add in hr */
692                  * 24L + hr;
693 
694         tmptim = /* convert to minutes and add in mn */
695                  (tmptim * 60L + mn)
696 
697                  /* convert to seconds and add in sec */
698                  * 60L + sc;
699         /*
700          * Account for time zone.
701          */
702         __tzset();
703         tmptim += _timezone;
704 
705         /*
706          * Fill in enough fields of tb for _isindst(), then call it to
707          * determine DST.
708          */
709         tb.tm_yday = tmpdays;
710         tb.tm_year = yr;
711         tb.tm_mon  = mo - 1;
712         tb.tm_hour = hr;
713         if ( (dstflag == 1) || ((dstflag == -1) && _daylight &&
714                                 _isindst(&tb)) )
715                 tmptim += _dstbias;
716         return(tmptim);
717 }
718 
719 /***
720 *static void cvtdate( trantype, datetype, year, month, week, dayofweek,
721 *                     date, hour, min, second, millisec ) - convert
722 *       transition date format
723 *
724 *Purpose:
725 *       Convert the format of a transition date specification to a value of
726 *       a transitiondate structure.
727 *
728 *Entry:
729 *       int trantype    - 1, if it is the start of DST
730 *                         0, if is the end of DST (in which case the date is
731 *                            is a DST date)
732 *       int datetype    - 1, if a day-in-month format is specified.
733 *                         0, if an absolute date is specified.
734 *       int year        - year for which the date is being converted (70 ==
735 *                         1970)
736 *       int month       - month (0 == January)
737 *       int week        - week of month, if datetype == 1 (note that 5== last
738 *                         week of month),
739 *                         0, otherwise.
740 *       int dayofweek   - day of week (0 == Sunday), if datetype == 1.
741 *                         0, otherwise.
742 *       int date        - date of month (1 - 31)
743 *       int hour        - hours (0 - 23)
744 *       int min         - minutes (0 - 59)
745 *       int sec         - seconds (0 - 59)
746 *       int msec        - milliseconds (0 - 999)
747 *
748 *Exit:
749 *       dststart or dstend is filled in with the converted date.
750 *
751 *******************************************************************************/
752 
cvtdate(int trantype,int datetype,int year,int month,int week,int dayofweek,int date,int hour,int min,int sec,int msec)753 static void __cdecl cvtdate (
754         int trantype,
755         int datetype,
756         int year,
757         int month,
758         int week,
759         int dayofweek,
760         int date,
761         int hour,
762         int min,
763         int sec,
764         int msec
765         )
766 {
767         int yearday;
768         int monthdow;
769 
770         if ( datetype == 1 ) {
771 
772             /*
773              * Transition day specified in day-in-month format.
774              */
775 
776             /*
777              * Figure the year-day of the start of the month.
778              */
779             yearday = 1 + (IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
780                       _days[month - 1]);
781 
782             /*
783              * Figure the day of the week of the start of the month.
784              */
785             monthdow = (yearday + ((year - 70) * 365) + ((year - 1) >> 2) -
786                         _LEAP_YEAR_ADJUST + _BASE_DOW) % 7;
787 
788             /*
789              * Figure the year-day of the transition date
790              */
791             if ( monthdow <= dayofweek )
792                 yearday += (dayofweek - monthdow) + (week - 1) * 7;
793             else
794                 yearday += (dayofweek - monthdow) + week * 7;
795 
796             /*
797              * May have to adjust the calculation above if week == 5 (meaning
798              * the last instance of the day in the month). Check if year falls
799              * beyond after month and adjust accordingly.
800              */
801             if ( (week == 5) &&
802                  (yearday > (IS_LEAP_YEAR(year) ? _lpdays[month] :
803                              _days[month])) )
804             {
805                 yearday -= 7;
806             }
807         }
808         else {
809             /*
810              * Transition day specified as an absolute day
811              */
812             yearday = IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
813                       _days[month - 1];
814 
815             yearday += date;
816         }
817 
818         if ( trantype == 1 ) {
819             /*
820              * Converted date was for the start of DST
821              */
822             dststart.yd = yearday;
823             dststart.ms = (long)msec +
824                           (1000L * (sec + 60L * (min + 60L * hour)));
825             /*
826              * Set year field of dststart so that unnecessary calls to
827              * cvtdate() may be avoided.
828              */
829             dststart.yr = year;
830         }
831         else {
832             /*
833              * Converted date was for the end of DST
834              */
835             dstend.yd = yearday;
836             dstend.ms = (long)msec +
837                               (1000L * (sec + 60L * (min + 60L * hour)));
838             /*
839              * The converted date is still a DST date. Must convert to a
840              * standard (local) date while being careful the millisecond field
841              * does not overflow or underflow.
842              */
843             if ( (dstend.ms += (_dstbias * 1000L)) < 0 ) {
844                 dstend.ms += DAY_MILLISEC;
845                 dstend.yd--;
846             }
847             else if ( dstend.ms >= DAY_MILLISEC ) {
848                 dstend.ms -= DAY_MILLISEC;
849                 dstend.yd++;
850             }
851 
852             /*
853              * Set year field of dstend so that unnecessary calls to cvtdate()
854              * may be avoided.
855              */
856             dstend.yr = year;
857         }
858 
859         return;
860 }
861 
862 /***
863 *int _isindst(tb) - determine if broken-down time falls in DST
864 *
865 *Purpose:
866 *       Determine if the given broken-down time falls within daylight saving
867 *       time (DST). The DST rules are either obtained from Win32 (tzapiused !=
868 *       TRUE) or assumed to be USA rules, post 1986.
869 *
870 *       If the DST rules are obtained from Win32's GetTimeZoneInformation API,
871 *       the transition dates to/from DST can be specified in either of two
872 *       formats. First, a day-in-month format, similar to the way USA rules
873 *       are specified, can be used. The transition date is given as the n-th
874 *       occurence of a specified day of the week in a specified month. Second,
875 *       an absolute date can be specified. The two cases are distinguished by
876 *       the value of wYear field in the SYSTEMTIME structure (0 denotes a
877 *       day-in-month format).
878 *
879 *       USA rules for DST are that a time is in DST iff it is on or after
880 *       02:00 on the first Sunday in April, and before 01:00 on the last
881 *       Sunday in October.
882 *
883 *Entry:
884 *       struct tm *tb - structure holding broken-down time value
885 *
886 *Exit:
887 *       1, if time represented is in DST
888 *       0, otherwise
889 *
890 *******************************************************************************/
891 
_isindst(struct tm * tb)892 int __cdecl _isindst (
893         struct tm *tb
894         )
895 {
896         long ms;
897 
898         if ( _daylight == 0 )
899             return 0;
900 
901         /*
902          * Compute (recompute) the transition dates for daylight saving time
903          * if necessary.The yr (year) fields of dststart and dstend is
904          * compared to the year of interest to determine necessity.
905          */
906         if ( (tb->tm_year != dststart.yr) || (tb->tm_year != dstend.yr) ) {
907             if ( tzapiused ) {
908                 /*
909                  * Convert the start of daylight saving time to dststart.
910                  */
911                 if ( tzinfo.DaylightDate.wYear == 0 )
912                     cvtdate( 1,
913                              1,             /* day-in-month format */
914                              tb->tm_year,
915                              tzinfo.DaylightDate.wMonth,
916                              tzinfo.DaylightDate.wDay,
917                              tzinfo.DaylightDate.wDayOfWeek,
918                              0,
919                              tzinfo.DaylightDate.wHour,
920                              tzinfo.DaylightDate.wMinute,
921                              tzinfo.DaylightDate.wSecond,
922                              tzinfo.DaylightDate.wMilliseconds );
923                 else
924                     cvtdate( 1,
925                              0,             /* absolute date */
926                              tb->tm_year,
927                              tzinfo.DaylightDate.wMonth,
928                              0,
929                              0,
930                              tzinfo.DaylightDate.wDay,
931                              tzinfo.DaylightDate.wHour,
932                              tzinfo.DaylightDate.wMinute,
933                              tzinfo.DaylightDate.wSecond,
934                              tzinfo.DaylightDate.wMilliseconds );
935                 /*
936                  * Convert start of standard time to dstend.
937                  */
938                 if ( tzinfo.StandardDate.wYear == 0 )
939                     cvtdate( 0,
940                              1,             /* day-in-month format */
941                              tb->tm_year,
942                              tzinfo.StandardDate.wMonth,
943                              tzinfo.StandardDate.wDay,
944                              tzinfo.StandardDate.wDayOfWeek,
945                              0,
946                              tzinfo.StandardDate.wHour,
947                              tzinfo.StandardDate.wMinute,
948                              tzinfo.StandardDate.wSecond,
949                              tzinfo.StandardDate.wMilliseconds );
950                 else
951                     cvtdate( 0,
952                              0,             /* absolute date */
953                              tb->tm_year,
954                              tzinfo.StandardDate.wMonth,
955                              0,
956                              0,
957                              tzinfo.StandardDate.wDay,
958                              tzinfo.StandardDate.wHour,
959                              tzinfo.StandardDate.wMinute,
960                              tzinfo.StandardDate.wSecond,
961                              tzinfo.StandardDate.wMilliseconds );
962 
963             }
964             else {
965                 /*
966                  * GetTimeZoneInformation API was NOT used, or failed. USA
967                  * daylight saving time rules are assumed.
968                  */
969                 cvtdate( 1,
970                          1,
971                          tb->tm_year,
972                          4,                 /* April */
973                          1,                 /* first... */
974                          0,                 /* ...Sunday */
975                          0,
976                          2,                 /* 02:00 (2 AM) */
977                          0,
978                          0,
979                          0 );
980 
981                 cvtdate( 0,
982                          1,
983                          tb->tm_year,
984                          10,                /* October */
985                          5,                 /* last... */
986                          0,                 /* ...Sunday */
987                          0,
988                          2,                 /* 02:00 (2 AM) */
989                          0,
990                          0,
991                          0 );
992             }
993         }
994 
995         /*
996          * Handle simple cases first.
997          */
998         if ( dststart.yd < dstend.yd ) {
999             /*
1000              * Northern hemisphere ordering
1001              */
1002             if ( (tb->tm_yday < dststart.yd) || (tb->tm_yday > dstend.yd) )
1003                 return 0;
1004             if ( (tb->tm_yday > dststart.yd) && (tb->tm_yday < dstend.yd) )
1005                 return 1;
1006         }
1007         else {
1008             /*
1009              * Southern hemisphere ordering
1010              */
1011             if ( (tb->tm_yday < dstend.yd) || (tb->tm_yday > dststart.yd) )
1012                 return 1;
1013             if ( (tb->tm_yday > dstend.yd) && (tb->tm_yday < dststart.yd) )
1014                 return 0;
1015         }
1016 
1017         ms = 1000L * (tb->tm_sec + 60L * tb->tm_min + 3600L * tb->tm_hour);
1018 
1019         if ( tb->tm_yday == dststart.yd ) {
1020             if ( ms >= dststart.ms )
1021                 return 1;
1022             else
1023                 return 0;
1024         }
1025         else {
1026             /*
1027              * tb->tm_yday == dstend.yd
1028              */
1029             if ( ms < dstend.ms )
1030                 return 1;
1031             else
1032                 return 0;
1033         }
1034 
1035 }
1036 
1037 /***
1038 *_store_num() - Convert a number to ascii and copy it
1039 *
1040 *Purpose:
1041 *       Convert the supplied number to decimal and store
1042 *       in the output buffer.  Update both the count and
1043 *       buffer pointers.
1044 *
1045 *       *** For internal use with strftime() only ***
1046 *
1047 *Entry:
1048 *       int num = pointer to integer value
1049 *       int digits = # of ascii digits to put into string
1050 *       char **out = address of pointer to output string
1051 *       size_t *count = address of char count (space in output area)
1052 *
1053 *Exit:
1054 *       none
1055 *Exceptions:
1056 *
1057 *******************************************************************************/
1058 
_store_num(int num,int digits,char ** out,size_t * count)1059 static void __cdecl _store_num (
1060         int num,
1061         int digits,
1062         char **out,
1063         size_t *count
1064         )
1065 {
1066 int temp=0;
1067 
1068         if (__no_lead_zeros) {
1069                 _store_number (num, out, count);
1070                 return;
1071         }
1072 
1073         if ((size_t)digits < *count)  {
1074                 for (digits--; (digits+1); digits--) {
1075                         (*out)[digits] = (char)('0' + num % 10);
1076                         num /= 10;
1077                         temp++;
1078                 }
1079                 *out += temp;
1080                 *count -= temp;
1081         }
1082 else
1083         *count = 0;
1084 }
1085 
1086 /***
1087 *_store_str() - Copy a time string
1088 *
1089 *Purpose:
1090 *       Copy the supplied time string into the output string until
1091 *       (1) we hit a null in the time string, or (2) the given count
1092 *       goes to 0.
1093 *
1094 *       *** For internal use with strftime() only ***
1095 *
1096 *Entry:
1097 *       char *in = pointer to null terminated time string
1098 *       char **out = address of pointer to output string
1099 *       size_t *count = address of char count (space in output area)
1100 *
1101 *Exit:
1102 *       none
1103 *Exceptions:
1104 *
1105 *******************************************************************************/
1106 
_store_str(char * in,char ** out,size_t * count)1107 static void __cdecl _store_str (
1108         char *in,
1109         char **out,
1110         size_t *count
1111         )
1112 {
1113 
1114         while ((*count != 0) && (*in != '\0')) {
1115                 *(*out)++ = *in++;
1116                 (*count)--;
1117         }
1118 }
1119 
1120 /***
1121 *_store_winword() - Store date/time in WinWord format
1122 *
1123 *Purpose:
1124 *       Format the date/time in the supplied WinWord format
1125 *       and store it in the supplied buffer.
1126 *
1127 *       *** For internal use with strftime() only ***
1128 *
1129 *       The WinWord format is converted token by token to
1130 *       strftime conversion specifiers.  _expandtime is then called to
1131 *       do the work.  The WinWord format is expected to be a
1132 *       character string (not wide-chars).
1133 *
1134 *Entry:
1135 *       const char **format = address of pointer to WinWord format
1136 *       const struct tm *tmptr = pointer to time/date structure
1137 *       char **out = address of pointer to output string
1138 *       size_t *count = address of char count (space in output area)
1139 *       struct __lc_time_data *lc_time = pointer to locale-specific info
1140 *
1141 *Exit:
1142 *       none
1143 *
1144 *Exceptions:
1145 *
1146 *******************************************************************************/
1147 
_store_winword(const char * format,const struct tm * tmptr,char ** out,size_t * count,struct __lc_time_data * lc_time)1148 static void __cdecl _store_winword (
1149         const char *format,
1150         const struct tm *tmptr,
1151         char **out,
1152         size_t *count,
1153         struct __lc_time_data *lc_time
1154         )
1155 {
1156         char specifier;
1157         const char *p;
1158         int repeat;
1159         char *ampmstr;
1160 
1161         while (*format && *count != 0)
1162         {
1163                 specifier = 0;          /* indicate no match */
1164                 __no_lead_zeros = 0;    /* default is print leading zeros */
1165 
1166                 /* count the number of repetitions of this character */
1167                 for (repeat=0, p=format; *p++ == *format; repeat++);
1168                 /* leave p pointing to the beginning of the next token */
1169                 p--;
1170 
1171                 /* switch on ascii format character and determine specifier */
1172                 switch (*format)
1173                 {
1174                         case 'M':
1175                                 switch (repeat)
1176                                 {
1177                                         case 1: __no_lead_zeros = 1; /* fall thru */
1178                                         case 2: specifier = 'm'; break;
1179                                         case 3: specifier = 'b'; break;
1180                                         case 4: specifier = 'B'; break;
1181                                 } break;
1182                         case 'd':
1183                                 switch (repeat)
1184                                 {
1185                                         case 1: __no_lead_zeros = 1; /* fall thru */
1186                                         case 2: specifier = 'd'; break;
1187                                         case 3: specifier = 'a'; break;
1188                                         case 4: specifier = 'A'; break;
1189                                 } break;
1190                         case 'y':
1191                                 switch (repeat)
1192                                 {
1193                                         case 2: specifier = 'y'; break;
1194                                         case 4: specifier = 'Y'; break;
1195                                 } break;
1196                         case 'h':
1197                                 switch (repeat)
1198                                 {
1199                                         case 1: __no_lead_zeros = 1; /* fall thru */
1200                                         case 2: specifier = 'I'; break;
1201                                 } break;
1202                         case 'H':
1203                                 switch (repeat)
1204                                 {
1205                                         case 1: __no_lead_zeros = 1; /* fall thru */
1206                                         case 2: specifier = 'H'; break;
1207                                 } break;
1208                         case 'm':
1209                                 switch (repeat)
1210                                 {
1211                                         case 1: __no_lead_zeros = 1; /* fall thru */
1212                                         case 2: specifier = 'M'; break;
1213                                 } break;
1214                         case 's': /* for compatibility; not strictly WinWord */
1215                                 switch (repeat)
1216                                 {
1217                                         case 1: __no_lead_zeros = 1; /* fall thru */
1218                                         case 2: specifier = 'S'; break;
1219                                 } break;
1220                         case 'A':
1221                         case 'a':
1222                                 if (!_stricmp(format, "am/pm"))
1223                                         p = format + 5;
1224                                 else if (!_stricmp(format, "a/p"))
1225                                         p = format + 3;
1226                                 specifier = 'p';
1227                                 break;
1228                         case 't': /* t or tt time marker suffix */
1229                                 if ( tmptr->tm_hour <= 11 )
1230                                         ampmstr = lc_time->ampm[0];
1231                                 else
1232                                         ampmstr = lc_time->ampm[1];
1233 
1234                                 while ( (repeat > 0) && (*count > 0) )
1235                                 {
1236                                         if ( isleadbyte((int)*ampmstr) &&
1237                                              (*count > 1) )
1238                                         {
1239                                                 *(*out)++ = *ampmstr++;
1240                                                 (*count)--;
1241                                         }
1242                                         *(*out)++ = *ampmstr++;
1243                                         (*count)--;
1244                                         repeat--;
1245                                 }
1246                                 format = p;
1247                                 continue;
1248 
1249                         case '\'': /* literal string */
1250                                 if (repeat & 1) /* odd number */
1251                                 {
1252                                         format += repeat;
1253                                         while (*format && *count != 0)
1254                                         {
1255                                                 if (*format == '\'')
1256                                                 {
1257                                                         format++;
1258                                                         break;
1259                                                 }
1260                                                 if ( isleadbyte((int)*format) &&
1261                                                      (*count > 1) )
1262                                                 {
1263                                                         *(*out)++ = *format++;
1264                                                         (*count)--;
1265                                                 }
1266                                                 *(*out)++ = *format++;
1267                                                 (*count)--;
1268                                         }
1269                                 }
1270                                 else { /* even number */
1271                                         format += repeat;
1272                                 }
1273                                 continue;
1274 
1275                         default: /* non-control char, print it */
1276                                 break;
1277                 } /* switch */
1278 
1279                 /* expand specifier, or copy literal if specifier not found */
1280                 if (specifier)
1281                 {
1282                         _expandtime(specifier, tmptr, out, count, lc_time);
1283                         format = p; /* bump format up to the next token */
1284                 } else {
1285                         if (isleadbyte((int)*format))
1286                         {
1287                                 *(*out)++ = *format++;
1288                                 (*count)--;
1289                         }
1290                         *(*out)++ = *format++;
1291                         (*count)--;
1292                 }
1293         } /* while */
1294 }
1295 
1296 /***
1297 *_store_number() - Convert positive integer to string
1298 *
1299 *Purpose:
1300 *       Convert positive integer to a string and store it in the output
1301 *       buffer with no null terminator.  Update both the count and
1302 *       buffer pointers.
1303 *
1304 *       Differs from _store_num in that the precision is not specified,
1305 *       and no leading zeros are added.
1306 *
1307 *       *** For internal use with strftime() only ***
1308 *
1309 *       Created from xtoi.c
1310 *
1311 *Entry:
1312 *       int num = pointer to integer value
1313 *       char **out = address of pointer to output string
1314 *       size_t *count = address of char count (space in output area)
1315 *
1316 *Exit:
1317 *       none
1318 *
1319 *Exceptions:
1320 *       The buffer is filled until it is out of space.  There is no
1321 *       way to tell beforehand (as in _store_num) if the buffer will
1322 *       run out of space.
1323 *
1324 *******************************************************************************/
1325 
_store_number(int num,char ** out,size_t * count)1326 static void __cdecl _store_number (
1327         int num,
1328         char **out,
1329         size_t *count
1330         )
1331 {
1332         char *p;                /* pointer to traverse string */
1333         char *firstdig;         /* pointer to first digit */
1334         char temp;              /* temp char */
1335 
1336         p = *out;
1337 
1338         /* put the digits in the buffer in reverse order */
1339         if (*count > 1)
1340         {
1341                 do {
1342                         *p++ = (char) (num % 10 + '0');
1343                         (*count)--;
1344                 } while ((num/=10) > 0 && *count > 1);
1345         }
1346 
1347         firstdig = *out;                /* firstdig points to first digit */
1348         *out = p;                       /* return pointer to next space */
1349         p--;                            /* p points to last digit */
1350 
1351         /* reverse the buffer */
1352         do {
1353                 temp = *p;
1354                 *p-- = *firstdig;
1355                 *firstdig++ = temp;     /* swap *p and *firstdig */
1356         } while (firstdig < p);         /* repeat until halfway */
1357 }
1358 
1359 /***
1360 *void tzset() - sets timezone information and calc if in daylight time
1361 *
1362 *Purpose:
1363 *       Sets the timezone information from the TZ environment variable
1364 *       and then sets _timezone, _daylight, and _tzname. If we're in daylight
1365 *       time is automatically calculated.
1366 *
1367 *Entry:
1368 *       None, reads TZ environment variable.
1369 *
1370 *Exit:
1371 *       sets _daylight, _timezone, and _tzname global vars, no return value
1372 *
1373 *Exceptions:
1374 *
1375 *******************************************************************************/
1376 
1377 
__tzset(void)1378 void __cdecl __tzset(void)
1379 {
1380         int defused;
1381         int negdiff = 0;
1382 
1383         /*
1384          * Clear the flag indicated whether GetTimeZoneInformation was used.
1385          */
1386         tzapiused = 0;
1387 
1388         /*
1389          * Set year fields of dststart and dstend structures to -1 to ensure
1390          * they are recomputed as after this
1391          */
1392         dststart.yr = dstend.yr = -1;
1393 
1394         /*
1395          * Fetch the value of the TZ environment variable.
1396          */
1397         if ( 1 /*(TZ = _getenv_lk("TZ")) == NULL */) {
1398 
1399             /*
1400              * There is no TZ environment variable, try to use the time zone
1401              * information from the system.
1402              */
1403 
1404             if ( GetTimeZoneInformation( &tzinfo ) != 0xFFFFFFFF ) {
1405                 /*
1406                  * Note that the API was used.
1407                  */
1408                 tzapiused = 1;
1409 
1410                 /*
1411                  * Derive _timezone value from Bias and StandardBias fields.
1412                  */
1413                 _timezone = tzinfo.Bias * 60L;
1414 
1415                 if ( tzinfo.StandardDate.wMonth != 0 )
1416                     _timezone += (tzinfo.StandardBias * 60L);
1417 
1418                 /*
1419                  * Check to see if there is a daylight time bias. Since the
1420                  * StandardBias has been added into _timezone, it must be
1421                  * compensated for in the value computed for _dstbias.
1422                  */
1423                 if ( (tzinfo.DaylightDate.wMonth != 0) &&
1424                      (tzinfo.DaylightBias != 0) )
1425                 {
1426                     _daylight = 1;
1427                     _dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) *
1428                                60L;
1429                 }
1430                 else {
1431                         _daylight = 0;
1432 
1433                     /*
1434                      * Set daylight bias to 0 because GetTimeZoneInformation
1435                      * may return TIME_ZONE_ID_DAYLIGHT even though there is
1436                      * no DST (in NT 3.51, just turn off the automatic DST
1437                      * adjust in the control panel)!
1438                      */
1439                     _dstbias = 0;
1440                 }
1441 
1442                 /*
1443                  * Try to grab the name strings for both the time zone and the
1444                  * daylight zone. Note the wide character strings in tzinfo
1445                  * must be converted to multibyte characters strings. The
1446                  * locale codepage, __lc_codepage, is used for this. Note that
1447                  * if setlocale() with LC_ALL or LC_CTYPE has not been called,
1448                  * then __lc_codepage will be 0 (_CLOCALECP), which is CP_ACP
1449                  * (which means use the host's default ANSI codepage).
1450                  */
1451                 if ( (WideCharToMultiByte( __lc_codepage,
1452                                            WC_COMPOSITECHECK |
1453                                             WC_SEPCHARS,
1454                                            tzinfo.StandardName,
1455                                            -1,
1456                                            _tzname[0],
1457                                            63,
1458                                            NULL,
1459                                            &defused ) != 0) &&
1460                      (!defused) )
1461                     _tzname[0][63] = '\0';
1462                 else
1463                     _tzname[0][0] = '\0';
1464 
1465                 if ( (WideCharToMultiByte( __lc_codepage,
1466                                            WC_COMPOSITECHECK |
1467                                             WC_SEPCHARS,
1468                                            tzinfo.DaylightName,
1469                                            -1,
1470                                            _tzname[1],
1471                                            63,
1472                                            NULL,
1473                                            &defused ) != 0) &&
1474                      (!defused) )
1475                     _tzname[1][63] = '\0';
1476                 else
1477                     _tzname[1][0] = '\0';
1478 
1479             }
1480 
1481             /*
1482              * Time zone information is unavailable, just return.
1483              */
1484             return;
1485         }
1486 }
1487 
1488 /***
1489 *struct tm *localtime(ptime) - convert time_t value to tm structure
1490 *
1491 *Purpose:
1492 *       Convert a value in internal (time_t) format to a tm struct
1493 *       containing the corresponding local time.
1494 *
1495 * NOTES:
1496 *       (1) gmtime must be called before _isindst to ensure that the tb time
1497 *           structure is initialized.
1498 *       (2) gmtime and localtime use a single statically allocated buffer.
1499 *           Each call to one of these routines destroys the contents of the
1500 *           previous call.
1501 *       (3) It is assumed that time_t is a 32-bit long integer representing
1502 *           the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the
1503 *           Posix/Unix Epoch. Only non-negative values are supported.
1504 *       (4) It is assumed that the maximum adjustment for local time is
1505 *           less than three days (include Daylight Savings Time adjustment).
1506 *           This only a concern in Posix where the specification of the TZ
1507 *           environment restricts the combined offset for time zone and
1508 *           Daylight Savings Time to 2 * (24:59:59), just under 50 hours.
1509 *
1510 *Entry:
1511 *       time_t *ptime - pointer to a long time value
1512 *
1513 *Exit:
1514 *       If *ptime is non-negative, returns a pointer to the tm structure.
1515 *       Otherwise, returns NULL.
1516 *
1517 *Exceptions:
1518 *       See items (3) and (4) in the NOTES above. If these assumptions are
1519 *       violated, behavior is undefined.
1520 *
1521 *******************************************************************************/
localtime(const time_t * ptime)1522 struct tm * __cdecl localtime (
1523         const time_t *ptime
1524         )
1525 {
1526         struct tm *ptm;
1527         long ltime;
1528 
1529         /*
1530          * Check for illegal time_t value
1531          */
1532         if ( (long)*ptime < 0L )
1533                 return( NULL );
1534 
1535 #ifdef _WIN32
1536         __tzset();
1537 #else  /* _WIN32 */
1538 #if defined (_M_MPPC) || defined (_M_M68K)
1539         _tzset();
1540 #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
1541 #endif  /* _WIN32 */
1542 
1543         if ( (*ptime > 3 * _DAY_SEC) && (*ptime < LONG_MAX - 3 * _DAY_SEC) ) {
1544                 /*
1545                  * The date does not fall within the first three, or last
1546                  * three, representable days of the Epoch. Therefore, there
1547                  * is no possibility of overflowing or underflowing the
1548                  * time_t representation as we compensate for timezone and
1549                  * Daylight Savings Time.
1550                  */
1551 
1552                 ltime = (long)*ptime - _timezone;
1553                 ptm = gmtime( (time_t *)&ltime );
1554 
1555                 /*
1556                  * Check and adjust for Daylight Saving Time.
1557                  */
1558                 if ( _daylight && _isindst( ptm ) ) {
1559                         ltime -= _dstbias;
1560                         ptm = gmtime( (time_t *)&ltime );
1561                         ptm->tm_isdst = 1;
1562                 }
1563         }
1564         else {
1565                 ptm = gmtime( ptime );
1566 
1567                 /*
1568                  * The date falls with the first three, or last three days
1569                  * of the Epoch. It is possible the time_t representation
1570                  * would overflow or underflow while compensating for
1571                  * timezone and Daylight Savings Time. Therefore, make the
1572                  * timezone and Daylight Savings Time adjustments directly
1573                  * in the tm structure. The beginning of the Epoch is
1574                  * 00:00:00, 01-01-70 (UTC) and the last representable second
1575                  * in the Epoch is 03:14:07, 01-19-2038 (UTC). This will be
1576                  * used in the calculations below.
1577                  *
1578                  * First, adjust for the timezone.
1579                  */
1580                 if ( _isindst(ptm) )
1581                         ltime = (long)ptm->tm_sec - (_timezone + _dstbias);
1582                 else
1583                         ltime = (long)ptm->tm_sec - _timezone;
1584                 ptm->tm_sec = (int)(ltime % 60);
1585                 if ( ptm->tm_sec < 0 ) {
1586                         ptm->tm_sec += 60;
1587                         ltime -= 60;
1588                 }
1589 
1590                 ltime = (long)ptm->tm_min + ltime/60;
1591                 ptm->tm_min = (int)(ltime % 60);
1592                 if ( ptm->tm_min < 0 ) {
1593                         ptm->tm_min += 60;
1594                         ltime -= 60;
1595                 }
1596 
1597                 ltime = (long)ptm->tm_hour + ltime/60;
1598                 ptm->tm_hour = (int)(ltime % 24);
1599                 if ( ptm->tm_hour < 0 ) {
1600                         ptm->tm_hour += 24;
1601                         ltime -=24;
1602                 }
1603 
1604                 ltime /= 24;
1605 
1606                 if ( ltime > 0L ) {
1607                         /*
1608                          * There is no possibility of overflowing the tm_mday
1609                          * and tm_yday fields since the date can be no later
1610                          * than January 19.
1611                          */
1612                         ptm->tm_wday = (ptm->tm_wday + ltime) % 7;
1613                         ptm->tm_mday += ltime;
1614                         ptm->tm_yday += ltime;
1615                 }
1616                 else if ( ltime < 0L ) {
1617                         /*
1618                          * It is possible to underflow the tm_mday and tm_yday
1619                          * fields. If this happens, then adjusted date must
1620                          * lie in December 1969.
1621                          */
1622                         ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7;
1623                         if ( (ptm->tm_mday += ltime) <= 0 ) {
1624                                 ptm->tm_mday += 31;
1625                                 ptm->tm_yday = 364;
1626                                 ptm->tm_mon = 11;
1627                                 ptm->tm_year--;
1628                         }
1629                         else {
1630                                 ptm->tm_yday += ltime;
1631                         }
1632                 }
1633 
1634 
1635         }
1636 
1637 
1638         return(ptm);
1639 }
1640 
1641 static struct tm tb = { 0 };    /* time block */
1642 
1643 /***
1644 *struct tm *gmtime(timp) - convert *timp to a structure (UTC)
1645 *
1646 *Purpose:
1647 *       Converts the calendar time value, in internal format (time_t), to
1648 *       broken-down time (tm structure) with the corresponding UTC time.
1649 *
1650 *Entry:
1651 *       const time_t *timp - pointer to time_t value to convert
1652 *
1653 *Exit:
1654 *       returns pointer to filled-in tm structure.
1655 *       returns NULL if *timp < 0L
1656 *
1657 *Exceptions:
1658 *
1659 *******************************************************************************/
1660 
gmtime(const time_t * timp)1661 struct tm * __cdecl gmtime (
1662         const time_t *timp
1663         )
1664 {
1665 
1666         long caltim = *timp;            /* calendar time to convert */
1667         int islpyr = 0;                 /* is-current-year-a-leap-year flag */
1668         int tmptim;
1669         int *mdays;                /* pointer to days or lpdays */
1670 
1671         struct tm *ptb = &tb;
1672 
1673         if ( caltim < 0L )
1674                 return(NULL);
1675 
1676         /*
1677          * Determine years since 1970. First, identify the four-year interval
1678          * since this makes handling leap-years easy (note that 2000 IS a
1679          * leap year and 2100 is out-of-range).
1680          */
1681         tmptim = (int)(caltim / _FOUR_YEAR_SEC);
1682         caltim -= ((long)tmptim * _FOUR_YEAR_SEC);
1683 
1684         /*
1685          * Determine which year of the interval
1686          */
1687         tmptim = (tmptim * 4) + 70;         /* 1970, 1974, 1978,...,etc. */
1688 
1689         if ( caltim >= _YEAR_SEC ) {
1690 
1691             tmptim++;                       /* 1971, 1975, 1979,...,etc. */
1692             caltim -= _YEAR_SEC;
1693 
1694             if ( caltim >= _YEAR_SEC ) {
1695 
1696                 tmptim++;                   /* 1972, 1976, 1980,...,etc. */
1697                 caltim -= _YEAR_SEC;
1698 
1699                 /*
1700                  * Note, it takes 366 days-worth of seconds to get past a leap
1701                  * year.
1702                  */
1703                 if ( caltim >= (_YEAR_SEC + _DAY_SEC) ) {
1704 
1705                         tmptim++;           /* 1973, 1977, 1981,...,etc. */
1706                         caltim -= (_YEAR_SEC + _DAY_SEC);
1707                 }
1708                 else {
1709                         /*
1710                          * In a leap year after all, set the flag.
1711                          */
1712                         islpyr++;
1713                 }
1714             }
1715         }
1716 
1717         /*
1718          * tmptim now holds the value for tm_year. caltim now holds the
1719          * number of elapsed seconds since the beginning of that year.
1720          */
1721         ptb->tm_year = tmptim;
1722 
1723         /*
1724          * Determine days since January 1 (0 - 365). This is the tm_yday value.
1725          * Leave caltim with number of elapsed seconds in that day.
1726          */
1727         ptb->tm_yday = (int)(caltim / _DAY_SEC);
1728         caltim -= (long)(ptb->tm_yday) * _DAY_SEC;
1729 
1730         /*
1731          * Determine months since January (0 - 11) and day of month (1 - 31)
1732          */
1733         if ( islpyr )
1734             mdays = _lpdays;
1735         else
1736             mdays = _days;
1737 
1738 
1739         for ( tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++ ) ;
1740 
1741         ptb->tm_mon = --tmptim;
1742 
1743         ptb->tm_mday = ptb->tm_yday - mdays[tmptim];
1744 
1745         /*
1746          * Determine days since Sunday (0 - 6)
1747          */
1748         ptb->tm_wday = ((int)(*timp / _DAY_SEC) + _BASE_DOW) % 7;
1749 
1750         /*
1751          *  Determine hours since midnight (0 - 23), minutes after the hour
1752          *  (0 - 59), and seconds after the minute (0 - 59).
1753          */
1754         ptb->tm_hour = (int)(caltim / 3600);
1755         caltim -= (long)ptb->tm_hour * 3600L;
1756 
1757         ptb->tm_min = (int)(caltim / 60);
1758         ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60);
1759 
1760         ptb->tm_isdst = 0;
1761         return( (struct tm *)ptb );
1762 
1763 }
1764 
abort()1765 int abort() { return 0; }
1766