scc

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

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

  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4#include <time.h>
  5
  6/*
  7output:
  8testing
  950592 dates compared, all OK
 10done
 11end:
 12*/
 13
 14
 15#ifndef __unix__
 16#define putenv(x) (x)
 17/*
 18 * Ok, this is by definition undefined behaviour because
 19 * we are using the name of a library function. The reallity
 20 * is that if you use a static linker then this would
 21 * overload the libc getenv and it will work as expected,
 22 * but if you use a dynamic linker then the internal
 23 * references will be tied to the internal getenv function
 24 * and this would not work. For our main use case that is
 25 * testing scc libc this is good enough, and with the
 26 * fallback to putenv and unsetenv this will work in
 27 * the systems we are interested on
 28 */
 29char *
 30getenv(const char *name)
 31{
 32	if (strcmp(name, "TZ") != 0)
 33		return NULL;
 34	return "UTC";
 35}
 36#endif
 37
 38static long long
 39datetounix(long long year, int mon, int day, int hour, int min, int sec)
 40{
 41	/* seconds in a month in a regular (non-leap) year */
 42	static const long secs_through_month[] = {
 43		0, 31 * 86400, 59 * 86400, 90 * 86400,
 44		120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400,
 45		243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400 };
 46	int is_leap = 0, cycles, centuries = 0, leaps = 0, rem;
 47	long long t;
 48
 49	/* optimization: handle common range year 1902 up to and including 2038 */
 50	if (year - 2ULL < 136) {
 51		/* amount of leap days relative to 1970: every 4 years */
 52		leaps = (year - 68) >> 2;
 53		if (!((year - 68) & 3)) {
 54			leaps--;
 55			is_leap = 1;
 56		} else {
 57			is_leap = 0;
 58		}
 59		t = 31536000 * (year - 70) + (86400 * leaps); /* 365 * 86400 = 31536000 */
 60	} else {
 61		/* general leap year calculation:
 62		   leap years occur mostly every 4 years but every 100 years
 63		   a leap year is skipped unless the year is divisible by 400 */
 64		cycles = (year - 100) / 400;
 65		rem = (year - 100) % 400;
 66		if (rem < 0) {
 67			cycles--;
 68			rem += 400;
 69		}
 70		if (!rem) {
 71			is_leap = 1;
 72		} else {
 73			if (rem >= 300) {
 74				centuries = 3;
 75				rem -= 300;
 76			} else if (rem >= 200) {
 77				centuries = 2;
 78				rem -= 200;
 79			} else if (rem >= 100) {
 80				centuries = 1;
 81				rem -= 100;
 82			}
 83			if (rem) {
 84				leaps = rem / 4U;
 85				rem %= 4U;
 86				is_leap = !rem;
 87			}
 88		}
 89		leaps += (97 * cycles) + (24 * centuries) - is_leap;
 90
 91		/* adjust 8 leap days from 1970 up to and including 2000:
 92		   ((30 * 365) + 8) * 86400 = 946771200 */
 93		t = ((year - 100) * 31536000LL) + (leaps * 86400LL) + 946771200LL;
 94	}
 95	t += secs_through_month[mon];
 96	if (is_leap && mon >= 2)
 97		t += 86400;
 98	t += 86400LL * (day - 1);
 99	t += 3600LL * hour;
100	t += 60LL * min;
101	t += sec;
102
103	return t;
104}
105
106void
107testtm(struct tm *tm)
108{
109	time_t t1, t2; /* assume time_t is signed 64-bit */
110	long long ll;
111
112	t1 = mktime(tm);
113	if (t1 == (time_t)-1) {
114		printf("timegm failed for %d, %d, %d, %d, %d, %d\n",
115			tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
116	}
117
118	ll = datetounix(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
119	t2 = (time_t)ll;
120
121	if (t1 != t2) {
122		printf("result: %lld != %lld\n", (long long)t1, (long long)t2);
123		printf("for: %d, %d, %d, %d, %d, %d\n",
124			tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
125		exit(1);
126	}
127}
128
129int
130main(void)
131{
132	struct tm tm;
133	int y, mon, d;
134	unsigned counter = 0;
135
136	puts("testing");
137	putenv("TZ=UTC");
138
139	for (y = 1902; y < 2038; y++) {
140		for (mon = 0; mon < 12; mon++) {
141			for (d = 1; d <= 31; d++) {
142
143				memset(&tm, 0, sizeof(tm));
144				tm.tm_year = y - 1900;
145				tm.tm_mon = mon - 1;
146				tm.tm_mday = d;
147				tm.tm_hour = 0;
148				tm.tm_min = 0;
149				tm.tm_sec = 0;
150				tm.tm_isdst = -1;
151
152				testtm(&tm);
153				counter++;
154			}
155		}
156	}
157	printf("%u dates compared, all OK\n", counter);
158	puts("done");
159
160	return 0;
161}