scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <limits.h>
  2#include <time.h>
  3
  4#include "../libc.h"
  5
  6#undef mktime
  7
  8static int
  9norm(int *val, int *next, int max)
 10{
 11	int v = *val, n = *next, d;
 12
 13	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	}
 27
 28	*val = v;
 29	*next = n;
 30	return 1;
 31}
 32
 33static int
 34normalize(struct tm *tm)
 35{
 36	int mon, day, year, yday;
 37
 38	/*
 39	 * Normalize sec so that it doesn't over/underflow min
 40	 * Normalize min so that it doesn't over/underflow hour
 41	 * Normalize hour so that it doesn't over/underflow mday
 42	 * Normalize month so that it doesn't over/underflow year
 43	 */
 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;
 49
 50	day = tm->tm_mday;
 51	yday = 0;
 52	year = BASEYEAR + tm->tm_year;
 53
 54	_daysmon[FEB] = FEBDAYS(year);
 55
 56	/*
 57	 * Normalize mday so that it doesn't over/underflow month
 58	 * Normalize month so that it doesn't over/underflow year
 59	 */
 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	}
 70
 71	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	}
 81
 82	if (year < INT_MIN + BASEYEAR)
 83		return 0;
 84	year -= BASEYEAR;
 85
 86	if (year > _MAXYEAR || year < _MINYEAR)
 87		return 0;
 88
 89	for (int i = 0; i < mon; ++i)
 90		yday += _daysmon[i];
 91
 92	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;
 97
 98	return 1;
 99}
100
101time_t
102mktime(struct tm *ptm)
103{
104	time_t t;
105	long off;
106	int i, year;
107	struct tm tm;
108
109	tm = *ptm;
110	if (!normalize(&tm))
111		return -1;
112
113	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	}
123
124	for (i = 0; i < tm.tm_mon; ++i)
125		t += _daysmon[i] * SECDAY;
126
127	t += tm.tm_sec;
128	t += tm.tm_min * SECMIN;
129	t += tm.tm_hour * SECHOUR;
130	t += (tm.tm_mday-1) * SECDAY;
131
132	_tzset();
133	if (tm.tm_isdst == 0 || tm.tm_isdst < 0 && !_isdst(&tm))
134		off = _timezone;
135	else
136		off = _dstzone;
137
138	if (off > 0 && t > _TIME_MAX - off
139	||  off < 0 && t < _TIME_MIN - off) {
140		return -1;
141	}
142	t += off;
143	*ptm = *localtime(&t);
144
145	return t;
146}