1#include <limits.h>2#include <time.h>34#include "../libc.h"56#undef mktime78static int9norm(int *val, int *next, int max)10{11 int v = *val, n = *next, d;1213 if (v < 0) {14 d = -v / max + 1;15 v += d * max;16 if (n > INT_MAX - d)17 return 0;18 n -= d;19 }20 if (v >= max) {21 d = v / max;22 v -= d * max;23 if (n < INT_MIN + d)24 return 0;25 n += d;26 }2728 *val = v;29 *next = n;30 return 1;31}3233static int34normalize(struct tm *tm)35{36 int mon, day, year, yday;3738 /*39 * Normalize sec so that it doesn't over/underflow min40 * Normalize min so that it doesn't over/underflow hour41 * Normalize hour so that it doesn't over/underflow mday42 * Normalize month so that it doesn't over/underflow year43 */44 if (!norm(&tm->tm_sec, &tm->tm_min, 60)45 || !norm(&tm->tm_min, &tm->tm_hour, 60)46 || !norm(&tm->tm_hour, &tm->tm_mday, 24)47 || !norm(&tm->tm_mon, &tm->tm_year, 12))48 return 0;4950 day = tm->tm_mday;51 yday = 0;52 year = BASEYEAR + tm->tm_year;5354 _daysmon[FEB] = FEBDAYS(year);5556 /*57 * Normalize mday so that it doesn't over/underflow month58 * Normalize month so that it doesn't over/underflow year59 */60 for (mon = tm->tm_mon; day < 1; --mon) {61 if (mon == JAN) {62 if (year == INT_MIN)63 return 0;64 year--;65 _daysmon[FEB] = FEBDAYS(year);66 mon = DEC+1;67 }68 day += _daysmon[mon-1];69 }7071 for (; day > _daysmon[mon]; ++mon) {72 day -= _daysmon[mon];73 if (mon == DEC) {74 if (year == INT_MAX)75 return 0;76 year++;77 _daysmon[FEB] = FEBDAYS(year);78 mon = JAN-1;79 }80 }8182 if (year < INT_MIN + BASEYEAR)83 return 0;84 year -= BASEYEAR;8586 if (year > _MAXYEAR || year < _MINYEAR)87 return 0;8889 for (int i = 0; i < mon; ++i)90 yday += _daysmon[i];9192 tm->tm_mon = mon;93 tm->tm_year = year;94 tm->tm_mday = day;95 tm->tm_yday = yday + day - 1;96 tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;9798 return 1;99}100101time_t102mktime(struct tm *ptm)103{104 time_t t;105 long off;106 int i, year;107 struct tm tm;108109 tm = *ptm;110 if (!normalize(&tm))111 return -1;112113 t = 0;114 i = EPOCH;115 year = tm.tm_year + BASEYEAR;116 if (year >= EPOCH) {117 while (i < year)118 t += _daysyear(i++) * SECDAY;119 } else {120 while (i > year)121 t -= _daysyear(--i) * SECDAY;122 }123124 for (i = 0; i < tm.tm_mon; ++i)125 t += _daysmon[i] * SECDAY;126127 t += tm.tm_sec;128 t += tm.tm_min * SECMIN;129 t += tm.tm_hour * SECHOUR;130 t += (tm.tm_mday-1) * SECDAY;131132 _tzset();133 if (tm.tm_isdst == 0 || tm.tm_isdst < 0 && !_isdst(&tm))134 off = _timezone;135 else136 off = _dstzone;137138 if (off > 0 && t > _TIME_MAX - off139 || off < 0 && t < _TIME_MIN - off) {140 return -1;141 }142 t += off;143 *ptm = *localtime(&t);144145 return t;146}