headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / time / localtime_fading_out.c
blob081254a4017308a256cbc688e6fef465cc253fc0
1 /*
2 ** This file is in the public domain, so clarified as of
3 ** 1996-06-05 by Arthur David Olson.
4 */
6 #ifndef lint
7 #ifndef NOID
8 static char elsieid[] = "@(#)localtime.c 8.5";
9 #endif /* !defined NOID */
10 #endif /* !defined lint */
13 ** Leap second handling from Bradley White.
14 ** POSIX-style TZ environment variable handling from Guy Harris.
17 /*LINTLIBRARY*/
19 #include "private.h"
20 #include "tzfile.h"
21 #include "fcntl.h"
22 #include "float.h" /* for FLT_MAX and DBL_MAX */
24 #ifndef TZ_ABBR_MAX_LEN
25 #define TZ_ABBR_MAX_LEN 16
26 #endif /* !defined TZ_ABBR_MAX_LEN */
28 #ifndef TZ_ABBR_CHAR_SET
29 #define TZ_ABBR_CHAR_SET \
30 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
31 #endif /* !defined TZ_ABBR_CHAR_SET */
33 #ifndef TZ_ABBR_ERR_CHAR
34 #define TZ_ABBR_ERR_CHAR '_'
35 #endif /* !defined TZ_ABBR_ERR_CHAR */
38 ** SunOS 4.1.1 headers lack O_BINARY.
41 #ifdef O_BINARY
42 #define OPEN_MODE (O_RDONLY | O_BINARY)
43 #endif /* defined O_BINARY */
44 #ifndef O_BINARY
45 #define OPEN_MODE O_RDONLY
46 #endif /* !defined O_BINARY */
48 #ifndef WILDABBR
50 ** Someone might make incorrect use of a time zone abbreviation:
51 ** 1. They might reference tzname[0] before calling tzset (explicitly
52 ** or implicitly).
53 ** 2. They might reference tzname[1] before calling tzset (explicitly
54 ** or implicitly).
55 ** 3. They might reference tzname[1] after setting to a time zone
56 ** in which Daylight Saving Time is never observed.
57 ** 4. They might reference tzname[0] after setting to a time zone
58 ** in which Standard Time is never observed.
59 ** 5. They might reference tm.TM_ZONE after calling offtime.
60 ** What's best to do in the above cases is open to debate;
61 ** for now, we just set things up so that in any of the five cases
62 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
63 ** string "tzname[0] used before set", and similarly for the other cases.
64 ** And another: initialize tzname[0] to "ERA", with an explanation in the
65 ** manual page of what this "time zone abbreviation" means (doing this so
66 ** that tzname[0] has the "normal" length of three characters).
68 #define WILDABBR " "
69 #endif /* !defined WILDABBR */
71 static char wildabbr[] = WILDABBR;
73 static const char gmt[] = "GMT";
76 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
77 ** We default to US rules as of 1999-08-17.
78 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
79 ** implementation dependent; for historical reasons, US rules are a
80 ** common default.
82 #ifndef TZDEFRULESTRING
83 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
84 #endif /* !defined TZDEFDST */
86 struct ttinfo { /* time type information */
87 long tt_gmtoff; /* UTC offset in seconds */
88 int tt_isdst; /* used to set tm_isdst */
89 int tt_abbrind; /* abbreviation list index */
90 int tt_ttisstd; /* TRUE if transition is std time */
91 int tt_ttisgmt; /* TRUE if transition is UTC */
94 struct lsinfo { /* leap second information */
95 time_t ls_trans; /* transition time */
96 long ls_corr; /* correction to apply */
99 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
101 #ifdef TZNAME_MAX
102 #define MY_TZNAME_MAX TZNAME_MAX
103 #endif /* defined TZNAME_MAX */
104 #ifndef TZNAME_MAX
105 #define MY_TZNAME_MAX 255
106 #endif /* !defined TZNAME_MAX */
108 struct state {
109 int leapcnt;
110 int timecnt;
111 int typecnt;
112 int charcnt;
113 int goback;
114 int goahead;
115 time_t ats[TZ_MAX_TIMES];
116 unsigned char types[TZ_MAX_TIMES];
117 struct ttinfo ttis[TZ_MAX_TYPES];
118 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
119 (2 * (MY_TZNAME_MAX + 1)))];
120 struct lsinfo lsis[TZ_MAX_LEAPS];
123 struct rule {
124 int r_type; /* type of rule--see below */
125 int r_day; /* day number of rule */
126 int r_week; /* week number of rule */
127 int r_mon; /* month number of rule */
128 long r_time; /* transition time of rule */
131 #define JULIAN_DAY 0 /* Jn - Julian day */
132 #define DAY_OF_YEAR 1 /* n - day of year */
133 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
136 ** Prototypes for static functions.
139 static struct tm * gmtsub P((const time_t * timep, long offset,
140 struct tm * tmp));
141 static struct tm * localsub P((const time_t * timep, long offset,
142 struct tm * tmp));
143 static int increment_overflow P((int * number, int delta));
144 static int leaps_thru_end_of P((int y));
145 static int long_increment_overflow P((long * number, int delta));
146 static int long_normalize_overflow P((long * tensptr,
147 int * unitsptr, int base));
148 static int normalize_overflow P((int * tensptr, int * unitsptr,
149 int base));
150 static time_t time1 P((struct tm * tmp,
151 struct tm * (*funcp) P((const time_t *,
152 long, struct tm *)),
153 long offset));
154 static time_t time2 P((struct tm *tmp,
155 struct tm * (*funcp) P((const time_t *,
156 long, struct tm*)),
157 long offset, int * okayp));
158 static time_t time2sub P((struct tm *tmp,
159 struct tm * (*funcp) P((const time_t *,
160 long, struct tm*)),
161 long offset, int * okayp, int do_norm_secs));
162 static struct tm * timesub P((const time_t * timep, long offset,
163 const struct state * sp, struct tm * tmp));
164 static int tmcomp P((const struct tm * atmp,
165 const struct tm * btmp));
168 ** Other prototypes.
170 struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp);
171 time_t __mktime_fallback(struct tm* tmp);
172 time_t timegm(struct tm* const tmp);
174 static struct state lclmem;
175 static struct state gmtmem;
176 #define lclptr (&lclmem)
177 #define gmtptr (&gmtmem)
179 static int gmt_is_set;
181 static const int mon_lengths[2][MONSPERYEAR] = {
182 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
183 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
186 static const int year_lengths[2] = {
187 DAYSPERNYEAR, DAYSPERLYEAR
191 ** The easy way to behave "as if no library function calls" localtime
192 ** is to not call it--so we drop its guts into "localsub", which can be
193 ** freely called. (And no, the PANS doesn't require the above behavior--
194 ** but it *is* desirable.)
196 ** The unused offset argument is for the benefit of mktime variants.
199 /*ARGSUSED*/
200 static struct tm *
201 localsub(timep, offset, tmp)
202 const time_t * const timep;
203 const long offset;
204 struct tm * const tmp;
206 register struct state * sp;
207 register const struct ttinfo * ttisp;
208 register int i;
209 register struct tm * result;
210 const time_t t = *timep;
212 sp = lclptr;
213 if ((sp->goback && t < sp->ats[0]) ||
214 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
215 time_t newt = t;
216 register time_t seconds;
217 register time_t tcycles;
218 register int_fast64_t icycles;
220 if (t < sp->ats[0])
221 seconds = sp->ats[0] - t;
222 else seconds = t - sp->ats[sp->timecnt - 1];
223 --seconds;
224 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
225 ++tcycles;
226 icycles = tcycles;
227 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
228 return NULL;
229 seconds = icycles;
230 seconds *= YEARSPERREPEAT;
231 seconds *= AVGSECSPERYEAR;
232 if (t < sp->ats[0])
233 newt += seconds;
234 else newt -= seconds;
235 if (newt < sp->ats[0] ||
236 newt > sp->ats[sp->timecnt - 1])
237 return NULL; /* "cannot happen" */
238 result = localsub(&newt, offset, tmp);
239 if (result == tmp) {
240 register time_t newy;
242 newy = tmp->tm_year;
243 if (t < sp->ats[0])
244 newy -= icycles * YEARSPERREPEAT;
245 else newy += icycles * YEARSPERREPEAT;
246 tmp->tm_year = newy;
247 if (tmp->tm_year != newy)
248 return NULL;
250 return result;
252 if (sp->timecnt == 0 || t < sp->ats[0]) {
253 i = 0;
254 while (sp->ttis[i].tt_isdst)
255 if (++i >= sp->typecnt) {
256 i = 0;
257 break;
259 } else {
260 register int lo = 1;
261 register int hi = sp->timecnt;
263 while (lo < hi) {
264 register int mid = (lo + hi) >> 1;
266 if (t < sp->ats[mid])
267 hi = mid;
268 else lo = mid + 1;
270 i = (int) sp->types[lo - 1];
272 ttisp = &sp->ttis[i];
274 ** To get (wrong) behavior that's compatible with System V Release 2.0
275 ** you'd replace the statement below with
276 ** t += ttisp->tt_gmtoff;
277 ** timesub(&t, 0L, sp, tmp);
279 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
280 tmp->tm_isdst = ttisp->tt_isdst;
281 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
282 #ifdef TM_ZONE
283 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
284 #endif /* defined TM_ZONE */
285 return result;
290 ** gmtsub is to gmtime as localsub is to localtime.
293 static struct tm *
294 gmtsub(timep, offset, tmp)
295 const time_t * const timep;
296 const long offset;
297 struct tm * const tmp;
299 register struct tm * result;
301 if (!gmt_is_set)
302 gmt_is_set = TRUE;
303 result = timesub(timep, offset, gmtptr, tmp);
304 #ifdef TM_ZONE
306 ** Could get fancy here and deliver something such as
307 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
308 ** but this is no time for a treasure hunt.
310 if (offset != 0)
311 tmp->TM_ZONE = wildabbr;
312 else
313 tmp->TM_ZONE = gmtptr->chars;
314 #endif /* defined TM_ZONE */
315 return result;
320 // used in Haiku as fallback when the locale backend could not be loaded
321 struct tm*
322 __gmtime_r_fallback(const time_t* timep, struct tm* tmp)
324 return gmtsub(timep, 0L, tmp);
328 ** Return the number of leap years through the end of the given year
329 ** where, to make the math easy, the answer for year zero is defined as zero.
332 static int
333 leaps_thru_end_of(y)
334 register const int y;
336 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
337 -(leaps_thru_end_of(-(y + 1)) + 1);
340 static struct tm *
341 timesub(timep, offset, sp, tmp)
342 const time_t * const timep;
343 const long offset;
344 register const struct state * const sp;
345 register struct tm * const tmp;
347 register const struct lsinfo * lp;
348 register time_t tdays;
349 register int idays; /* unsigned would be so 2003 */
350 register long rem;
351 int y;
352 register const int * ip;
353 register long corr;
354 register int hit;
355 register int i;
357 corr = 0;
358 hit = 0;
359 i = sp->leapcnt;
360 while (--i >= 0) {
361 lp = &sp->lsis[i];
362 if (*timep >= lp->ls_trans) {
363 if (*timep == lp->ls_trans) {
364 hit = ((i == 0 && lp->ls_corr > 0) ||
365 lp->ls_corr > sp->lsis[i - 1].ls_corr);
366 if (hit)
367 while (i > 0 &&
368 sp->lsis[i].ls_trans ==
369 sp->lsis[i - 1].ls_trans + 1 &&
370 sp->lsis[i].ls_corr ==
371 sp->lsis[i - 1].ls_corr + 1) {
372 ++hit;
373 --i;
376 corr = lp->ls_corr;
377 break;
380 y = EPOCH_YEAR;
381 tdays = *timep / SECSPERDAY;
382 rem = *timep - tdays * SECSPERDAY;
383 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
384 int newy;
385 register time_t tdelta;
386 register int idelta;
387 register int leapdays;
389 tdelta = tdays / DAYSPERLYEAR;
390 idelta = tdelta;
391 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
392 return NULL;
393 if (idelta == 0)
394 idelta = (tdays < 0) ? -1 : 1;
395 newy = y;
396 if (increment_overflow(&newy, idelta))
397 return NULL;
398 leapdays = leaps_thru_end_of(newy - 1) -
399 leaps_thru_end_of(y - 1);
400 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
401 tdays -= leapdays;
402 y = newy;
405 register long seconds;
407 seconds = tdays * SECSPERDAY + 0.5;
408 tdays = seconds / SECSPERDAY;
409 rem += seconds - tdays * SECSPERDAY;
412 ** Given the range, we can now fearlessly cast...
414 idays = tdays;
415 rem += offset - corr;
416 while (rem < 0) {
417 rem += SECSPERDAY;
418 --idays;
420 while (rem >= SECSPERDAY) {
421 rem -= SECSPERDAY;
422 ++idays;
424 while (idays < 0) {
425 if (increment_overflow(&y, -1))
426 return NULL;
427 idays += year_lengths[isleap(y)];
429 while (idays >= year_lengths[isleap(y)]) {
430 idays -= year_lengths[isleap(y)];
431 if (increment_overflow(&y, 1))
432 return NULL;
434 tmp->tm_year = y;
435 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
436 return NULL;
437 tmp->tm_yday = idays;
439 ** The "extra" mods below avoid overflow problems.
441 tmp->tm_wday = EPOCH_WDAY +
442 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
443 (DAYSPERNYEAR % DAYSPERWEEK) +
444 leaps_thru_end_of(y - 1) -
445 leaps_thru_end_of(EPOCH_YEAR - 1) +
446 idays;
447 tmp->tm_wday %= DAYSPERWEEK;
448 if (tmp->tm_wday < 0)
449 tmp->tm_wday += DAYSPERWEEK;
450 tmp->tm_hour = (int) (rem / SECSPERHOUR);
451 rem %= SECSPERHOUR;
452 tmp->tm_min = (int) (rem / SECSPERMIN);
454 ** A positive leap second requires a special
455 ** representation. This uses "... ??:59:60" et seq.
457 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
458 ip = mon_lengths[isleap(y)];
459 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
460 idays -= ip[tmp->tm_mon];
461 tmp->tm_mday = (int) (idays + 1);
462 tmp->tm_isdst = 0;
463 #ifdef TM_GMTOFF
464 tmp->TM_GMTOFF = offset;
465 #endif /* defined TM_GMTOFF */
466 return tmp;
470 ** Adapted from code provided by Robert Elz, who writes:
471 ** The "best" way to do mktime I think is based on an idea of Bob
472 ** Kridle's (so its said...) from a long time ago.
473 ** It does a binary search of the time_t space. Since time_t's are
474 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
475 ** would still be very reasonable).
478 #ifndef WRONG
479 #define WRONG (-1)
480 #endif /* !defined WRONG */
483 ** Simplified normalize logic courtesy Paul Eggert.
486 static int
487 increment_overflow(number, delta)
488 int * number;
489 int delta;
491 int number0;
493 number0 = *number;
494 *number += delta;
495 return (*number < number0) != (delta < 0);
498 static int
499 long_increment_overflow(number, delta)
500 long * number;
501 int delta;
503 long number0;
505 number0 = *number;
506 *number += delta;
507 return (*number < number0) != (delta < 0);
510 static int
511 normalize_overflow(tensptr, unitsptr, base)
512 int * const tensptr;
513 int * const unitsptr;
514 const int base;
516 register int tensdelta;
518 tensdelta = (*unitsptr >= 0) ?
519 (*unitsptr / base) :
520 (-1 - (-1 - *unitsptr) / base);
521 *unitsptr -= tensdelta * base;
522 return increment_overflow(tensptr, tensdelta);
525 static int
526 long_normalize_overflow(tensptr, unitsptr, base)
527 long * const tensptr;
528 int * const unitsptr;
529 const int base;
531 register int tensdelta;
533 tensdelta = (*unitsptr >= 0) ?
534 (*unitsptr / base) :
535 (-1 - (-1 - *unitsptr) / base);
536 *unitsptr -= tensdelta * base;
537 return long_increment_overflow(tensptr, tensdelta);
540 static int
541 tmcomp(atmp, btmp)
542 register const struct tm * const atmp;
543 register const struct tm * const btmp;
545 register int result;
547 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
548 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
549 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
550 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
551 (result = (atmp->tm_min - btmp->tm_min)) == 0)
552 result = atmp->tm_sec - btmp->tm_sec;
553 return result;
556 static time_t
557 time2sub(tmp, funcp, offset, okayp, do_norm_secs)
558 struct tm * const tmp;
559 struct tm * (* const funcp) P((const time_t*, long, struct tm*));
560 const long offset;
561 int * const okayp;
562 const int do_norm_secs;
564 register const struct state * sp;
565 register int dir;
566 register int i, j;
567 register int saved_seconds;
568 register long li;
569 register time_t lo;
570 register time_t hi;
571 long y;
572 time_t newt;
573 time_t t;
574 struct tm yourtm, mytm;
576 *okayp = FALSE;
577 yourtm = *tmp;
578 if (do_norm_secs) {
579 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
580 SECSPERMIN))
581 return WRONG;
583 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
584 return WRONG;
585 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
586 return WRONG;
587 y = yourtm.tm_year;
588 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
589 return WRONG;
591 ** Turn y into an actual year number for now.
592 ** It is converted back to an offset from TM_YEAR_BASE later.
594 if (long_increment_overflow(&y, TM_YEAR_BASE))
595 return WRONG;
596 while (yourtm.tm_mday <= 0) {
597 if (long_increment_overflow(&y, -1))
598 return WRONG;
599 li = y + (1 < yourtm.tm_mon);
600 yourtm.tm_mday += year_lengths[isleap(li)];
602 while (yourtm.tm_mday > DAYSPERLYEAR) {
603 li = y + (1 < yourtm.tm_mon);
604 yourtm.tm_mday -= year_lengths[isleap(li)];
605 if (long_increment_overflow(&y, 1))
606 return WRONG;
608 for ( ; ; ) {
609 i = mon_lengths[isleap(y)][yourtm.tm_mon];
610 if (yourtm.tm_mday <= i)
611 break;
612 yourtm.tm_mday -= i;
613 if (++yourtm.tm_mon >= MONSPERYEAR) {
614 yourtm.tm_mon = 0;
615 if (long_increment_overflow(&y, 1))
616 return WRONG;
619 if (long_increment_overflow(&y, -TM_YEAR_BASE))
620 return WRONG;
621 yourtm.tm_year = y;
622 if (yourtm.tm_year != y)
623 return WRONG;
624 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
625 saved_seconds = 0;
626 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
628 ** We can't set tm_sec to 0, because that might push the
629 ** time below the minimum representable time.
630 ** Set tm_sec to 59 instead.
631 ** This assumes that the minimum representable time is
632 ** not in the same minute that a leap second was deleted from,
633 ** which is a safer assumption than using 58 would be.
635 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
636 return WRONG;
637 saved_seconds = yourtm.tm_sec;
638 yourtm.tm_sec = SECSPERMIN - 1;
639 } else {
640 saved_seconds = yourtm.tm_sec;
641 yourtm.tm_sec = 0;
644 ** Do a binary search (this works whatever time_t's type is).
646 if (!TYPE_SIGNED(time_t)) {
647 lo = 0;
648 hi = lo - 1;
649 } else if (!TYPE_INTEGRAL(time_t)) {
650 if (sizeof(time_t) > sizeof(float))
651 hi = (time_t) DBL_MAX;
652 else hi = (time_t) FLT_MAX;
653 lo = -hi;
654 } else {
655 lo = 1;
656 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
657 lo *= 2;
658 hi = -(lo + 1);
660 for ( ; ; ) {
661 t = lo / 2 + hi / 2;
662 if (t < lo)
663 t = lo;
664 else if (t > hi)
665 t = hi;
666 if ((*funcp)(&t, offset, &mytm) == NULL) {
668 ** Assume that t is too extreme to be represented in
669 ** a struct tm; arrange things so that it is less
670 ** extreme on the next pass.
672 dir = (t > 0) ? 1 : -1;
673 } else dir = tmcomp(&mytm, &yourtm);
674 if (dir != 0) {
675 if (t == lo) {
676 ++t;
677 if (t <= lo)
678 return WRONG;
679 ++lo;
680 } else if (t == hi) {
681 --t;
682 if (t >= hi)
683 return WRONG;
684 --hi;
686 if (lo > hi)
687 return WRONG;
688 if (dir > 0)
689 hi = t;
690 else lo = t;
691 continue;
693 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
694 break;
696 ** Right time, wrong type.
697 ** Hunt for right time, right type.
698 ** It's okay to guess wrong since the guess
699 ** gets checked.
702 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
704 sp = (const struct state *)
705 (((void *) funcp == (void *) localsub) ?
706 lclptr : gmtptr);
707 for (i = sp->typecnt - 1; i >= 0; --i) {
708 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
709 continue;
710 for (j = sp->typecnt - 1; j >= 0; --j) {
711 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
712 continue;
713 newt = t + sp->ttis[j].tt_gmtoff -
714 sp->ttis[i].tt_gmtoff;
715 if ((*funcp)(&newt, offset, &mytm) == NULL)
716 continue;
717 if (tmcomp(&mytm, &yourtm) != 0)
718 continue;
719 if (mytm.tm_isdst != yourtm.tm_isdst)
720 continue;
722 ** We have a match.
724 t = newt;
725 goto label;
728 return WRONG;
730 label:
731 newt = t + saved_seconds;
732 if ((newt < t) != (saved_seconds < 0))
733 return WRONG;
734 t = newt;
735 if ((*funcp)(&t, offset, tmp))
736 *okayp = TRUE;
737 return t;
740 static time_t
741 time2(tmp, funcp, offset, okayp)
742 struct tm * const tmp;
743 struct tm * (* const funcp) P((const time_t*, long, struct tm*));
744 const long offset;
745 int * const okayp;
747 time_t t;
750 ** First try without normalization of seconds
751 ** (in case tm_sec contains a value associated with a leap second).
752 ** If that fails, try with normalization of seconds.
754 t = time2sub(tmp, funcp, offset, okayp, FALSE);
755 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
758 static time_t
759 time1(tmp, funcp, offset)
760 struct tm * const tmp;
761 struct tm * (* const funcp) P((const time_t *, long, struct tm *));
762 const long offset;
764 register time_t t;
765 register const struct state * sp;
766 register int samei, otheri;
767 register int sameind, otherind;
768 register int i;
769 register int nseen;
770 int seen[TZ_MAX_TYPES];
771 int types[TZ_MAX_TYPES];
772 int okay;
774 if (tmp->tm_isdst > 1)
775 tmp->tm_isdst = 1;
776 t = time2(tmp, funcp, offset, &okay);
778 ** PCTS code courtesy Grant Sullivan.
780 if (okay)
781 return t;
782 if (tmp->tm_isdst < 0)
783 tmp->tm_isdst = 0; /* reset to std and try again */
785 ** We're supposed to assume that somebody took a time of one type
786 ** and did some math on it that yielded a "struct tm" that's bad.
787 ** We try to divine the type they started from and adjust to the
788 ** type they need.
791 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
793 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
794 lclptr : gmtptr);
795 for (i = 0; i < sp->typecnt; ++i)
796 seen[i] = FALSE;
797 nseen = 0;
798 for (i = sp->timecnt - 1; i >= 0; --i)
799 if (!seen[sp->types[i]]) {
800 seen[sp->types[i]] = TRUE;
801 types[nseen++] = sp->types[i];
803 for (sameind = 0; sameind < nseen; ++sameind) {
804 samei = types[sameind];
805 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
806 continue;
807 for (otherind = 0; otherind < nseen; ++otherind) {
808 otheri = types[otherind];
809 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
810 continue;
811 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
812 sp->ttis[samei].tt_gmtoff;
813 tmp->tm_isdst = !tmp->tm_isdst;
814 t = time2(tmp, funcp, offset, &okay);
815 if (okay)
816 return t;
817 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
818 sp->ttis[samei].tt_gmtoff;
819 tmp->tm_isdst = !tmp->tm_isdst;
822 return WRONG;
826 // used in Haiku as fallback when the locale backend could not be loaded
827 time_t
828 __mktime_fallback(struct tm* tmp)
830 return time1(tmp, localsub, 0L);
835 time_t
836 timegm(tmp)
837 struct tm * const tmp;
839 tmp->tm_isdst = 0;
840 return time1(tmp, gmtsub, 0L);