1205821Sedwin/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4205872Sedwin * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
5205872Sedwin * All rights reserved.
6205821Sedwin *
7205821Sedwin * Redistribution and use in source and binary forms, with or without
8205821Sedwin * modification, are permitted provided that the following conditions
9205821Sedwin * are met:
10205821Sedwin * 1. Redistributions of source code must retain the above copyright
11205821Sedwin *    notice, this list of conditions and the following disclaimer.
12205821Sedwin * 2. Redistributions in binary form must reproduce the above copyright
13205821Sedwin *    notice, this list of conditions and the following disclaimer in the
14205821Sedwin *    documentation and/or other materials provided with the distribution.
15251647Sgrog *
16205821Sedwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17205821Sedwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18205821Sedwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19205821Sedwin * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20205821Sedwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21205821Sedwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22205821Sedwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23205821Sedwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24205821Sedwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25205821Sedwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26205821Sedwin * SUCH DAMAGE.
27251647Sgrog *
28205821Sedwin */
29205821Sedwin
30205821Sedwin#include <sys/cdefs.h>
31205821Sedwin__FBSDID("$FreeBSD: stable/11/usr.bin/calendar/dates.c 330449 2018-03-05 07:26:05Z eadler $");
32205821Sedwin
33205821Sedwin#include <stdio.h>
34205821Sedwin#include <stdlib.h>
35205821Sedwin#include <err.h>
36205821Sedwin#include <time.h>
37205821Sedwin
38205821Sedwin#include "calendar.h"
39205821Sedwin
40205821Sedwinstruct cal_year {
41205821Sedwin	int year;	/* 19xx, 20xx, 21xx */
42205821Sedwin	int easter;	/* Julian day */
43205821Sedwin	int paskha;	/* Julian day */
44205821Sedwin	int cny;	/* Julian day */
45205821Sedwin	int firstdayofweek; /* 0 .. 6 */
46205821Sedwin	struct cal_month *months;
47205821Sedwin	struct cal_year	*nextyear;
48241737Sed};
49205821Sedwin
50205821Sedwinstruct cal_month {
51205821Sedwin	int month;			/* 01 .. 12 */
52205821Sedwin	int firstdayjulian;		/* 000 .. 366 */
53205821Sedwin	int firstdayofweek;		/* 0 .. 6 */
54205821Sedwin	struct cal_year *year;		/* points back */
55205821Sedwin	struct cal_day *days;
56205821Sedwin	struct cal_month *nextmonth;
57241737Sed};
58205821Sedwin
59205821Sedwinstruct cal_day {
60205821Sedwin	int dayofmonth;			/* 01 .. 31 */
61205821Sedwin	int julianday;			/* 000 .. 366 */
62205821Sedwin	int dayofweek;			/* 0 .. 6 */
63205821Sedwin	struct cal_day *nextday;
64205821Sedwin	struct cal_month *month;	/* points back */
65205821Sedwin	struct cal_year	*year;		/* points back */
66205821Sedwin	struct event *events;
67241737Sed};
68205821Sedwin
69205821Sedwinint debug_remember = 0;
70241737Sedstatic struct cal_year *hyear = NULL;
71205821Sedwin
72205821Sedwin/* 1-based month, 0-based days, cumulative */
73205821Sedwinint	cumdaytab[][14] = {
74205821Sedwin	{0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
75205821Sedwin	{0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
76205821Sedwin};
77205821Sedwin/* 1-based month, individual */
78251647Sgrogstatic int *monthdays;
79251647Sgrogint	monthdaytab[][14] = {
80205821Sedwin	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
81205821Sedwin	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
82205821Sedwin};
83205821Sedwin
84205821Sedwinstatic struct cal_day *	find_day(int yy, int mm, int dd);
85205821Sedwin
86205821Sedwinstatic void
87205821Sedwincreatedate(int y, int m, int d)
88205821Sedwin{
89205821Sedwin	struct cal_year *py, *pyp;
90205821Sedwin	struct cal_month *pm, *pmp;
91205821Sedwin	struct cal_day *pd, *pdp;
92205821Sedwin	int *cumday;
93205821Sedwin
94205821Sedwin	pyp = NULL;
95205821Sedwin	py = hyear;
96205821Sedwin	while (py != NULL) {
97205821Sedwin		if (py->year == y + 1900)
98205821Sedwin			break;
99205821Sedwin		pyp = py;
100205821Sedwin		py = py->nextyear;
101205821Sedwin	}
102205821Sedwin
103205821Sedwin	if (py == NULL) {
104205821Sedwin		struct tm td;
105205821Sedwin		time_t t;
106205821Sedwin		py = (struct cal_year *)calloc(1, sizeof(struct cal_year));
107205821Sedwin		py->year = y + 1900;
108205821Sedwin		py->easter = easter(y);
109205821Sedwin		py->paskha = paskha(y);
110205821Sedwin
111205821Sedwin		td = tm0;
112205821Sedwin		td.tm_year = y;
113205821Sedwin		td.tm_mday = 1;
114205821Sedwin		t = mktime(&td);
115205821Sedwin		localtime_r(&t, &td);
116205821Sedwin		py->firstdayofweek = td.tm_wday;
117205821Sedwin
118205821Sedwin		if (pyp != NULL)
119205821Sedwin			pyp->nextyear = py;
120205821Sedwin	}
121205821Sedwin	if (pyp == NULL) {
122205821Sedwin		/* The very very very first one */
123205821Sedwin		hyear = py;
124205821Sedwin	}
125205821Sedwin
126205821Sedwin	pmp = NULL;
127205821Sedwin	pm = py->months;
128205821Sedwin	while (pm != NULL) {
129205821Sedwin		if (pm->month == m)
130205821Sedwin			break;
131205821Sedwin		pmp = pm;
132205821Sedwin		pm = pm->nextmonth;
133205821Sedwin	}
134205821Sedwin
135205821Sedwin	if (pm == NULL) {
136205821Sedwin		pm = (struct cal_month *)calloc(1, sizeof(struct cal_month));
137205821Sedwin		pm->year = py;
138205821Sedwin		pm->month = m;
139205821Sedwin		cumday = cumdaytab[isleap(y)];
140205821Sedwin		pm->firstdayjulian = cumday[m] + 2;
141205821Sedwin		pm->firstdayofweek =
142205821Sedwin		    (py->firstdayofweek + pm->firstdayjulian -1) % 7;
143205821Sedwin		if (pmp != NULL)
144205821Sedwin			pmp->nextmonth = pm;
145205821Sedwin	}
146205821Sedwin	if (pmp == NULL)
147205821Sedwin		py->months = pm;
148205821Sedwin
149205821Sedwin	pdp = NULL;
150205821Sedwin	pd = pm->days;
151205821Sedwin	while (pd != NULL) {
152205821Sedwin		pdp = pd;
153205821Sedwin		pd = pd->nextday;
154205821Sedwin	}
155205821Sedwin
156205821Sedwin	if (pd == NULL) {	/* Always true */
157205821Sedwin		pd = (struct cal_day *)calloc(1, sizeof(struct cal_day));
158205821Sedwin		pd->month = pm;
159205821Sedwin		pd->year = py;
160205821Sedwin		pd->dayofmonth = d;
161205821Sedwin		pd->julianday = pm->firstdayjulian + d - 1;
162205821Sedwin		pd->dayofweek = (pm->firstdayofweek + d - 1) % 7;
163205821Sedwin		if (pdp != NULL)
164205821Sedwin			pdp->nextday = pd;
165205821Sedwin	}
166205821Sedwin	if (pdp == NULL)
167205821Sedwin		pm->days = pd;
168205821Sedwin}
169205821Sedwin
170205821Sedwinvoid
171205821Sedwingeneratedates(struct tm *tp1, struct tm *tp2)
172205821Sedwin{
173205821Sedwin	int y1, m1, d1;
174205821Sedwin	int y2, m2, d2;
175205821Sedwin	int y, m, d;
176205821Sedwin
177205821Sedwin	y1 = tp1->tm_year;
178205821Sedwin	m1 = tp1->tm_mon + 1;
179205821Sedwin	d1 = tp1->tm_mday;
180205821Sedwin	y2 = tp2->tm_year;
181205821Sedwin	m2 = tp2->tm_mon + 1;
182205821Sedwin	d2 = tp2->tm_mday;
183205821Sedwin
184205821Sedwin	if (y1 == y2) {
185205821Sedwin		if (m1 == m2) {
186205821Sedwin			/* Same year, same month. Easy! */
187205821Sedwin			for (d = d1; d <= d2; d++)
188205821Sedwin				createdate(y1, m1, d);
189205821Sedwin			return;
190205821Sedwin		}
191205821Sedwin		/*
192205821Sedwin		 * Same year, different month.
193205821Sedwin		 * - Take the leftover days from m1
194205821Sedwin		 * - Take all days from <m1 .. m2>
195205821Sedwin		 * - Take the first days from m2
196205821Sedwin		 */
197251647Sgrog		monthdays = monthdaytab[isleap(y1)];
198251647Sgrog		for (d = d1; d <= monthdays[m1]; d++)
199205821Sedwin			createdate(y1, m1, d);
200205821Sedwin		for (m = m1 + 1; m < m2; m++)
201251647Sgrog			for (d = 1; d <= monthdays[m]; d++)
202205821Sedwin				createdate(y1, m, d);
203205821Sedwin		for (d = 1; d <= d2; d++)
204205821Sedwin			createdate(y1, m2, d);
205205821Sedwin		return;
206205821Sedwin	}
207205821Sedwin	/*
208205821Sedwin	 * Different year, different month.
209205821Sedwin	 * - Take the leftover days from y1-m1
210205821Sedwin	 * - Take all days from y1-<m1 .. 12]
211205821Sedwin	 * - Take all days from <y1 .. y2>
212205821Sedwin	 * - Take all days from y2-[1 .. m2>
213205821Sedwin	 * - Take the first days of y2-m2
214205821Sedwin	 */
215251647Sgrog	monthdays = monthdaytab[isleap(y1)];
216251647Sgrog	for (d = d1; d <= monthdays[m1]; d++)
217205821Sedwin		createdate(y1, m1, d);
218205821Sedwin	for (m = m1 + 1; m <= 12; m++)
219251647Sgrog		for (d = 1; d <= monthdays[m]; d++)
220205821Sedwin			createdate(y1, m, d);
221205821Sedwin	for (y = y1 + 1; y < y2; y++) {
222251647Sgrog		monthdays = monthdaytab[isleap(y)];
223205821Sedwin		for (m = 1; m <= 12; m++)
224251647Sgrog			for (d = 1; d <= monthdays[m]; d++)
225205821Sedwin				createdate(y, m, d);
226205821Sedwin	}
227251647Sgrog	monthdays = monthdaytab[isleap(y2)];
228205821Sedwin	for (m = 1; m < m2; m++)
229251647Sgrog		for (d = 1; d <= monthdays[m]; d++)
230205821Sedwin			createdate(y2, m, d);
231205821Sedwin	for (d = 1; d <= d2; d++)
232205821Sedwin		createdate(y2, m2, d);
233205821Sedwin}
234205821Sedwin
235205821Sedwinvoid
236205821Sedwindumpdates(void)
237205821Sedwin{
238205821Sedwin	struct cal_year *y;
239205821Sedwin	struct cal_month *m;
240205821Sedwin	struct cal_day *d;
241205821Sedwin
242205821Sedwin	y = hyear;
243205821Sedwin	while (y != NULL) {
244205821Sedwin		printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek);
245205821Sedwin		m = y->months;
246205821Sedwin		while (m != NULL) {
247205821Sedwin			printf("-- %-5d (julian:%d, dow:%d)\n", m->month,
248205821Sedwin			    m->firstdayjulian, m->firstdayofweek);
249205821Sedwin			d = m->days;
250205821Sedwin			while (d != NULL) {
251205821Sedwin				printf("  -- %-5d (julian:%d, dow:%d)\n",
252205821Sedwin				    d->dayofmonth, d->julianday, d->dayofweek);
253205821Sedwin				d = d->nextday;
254205821Sedwin			}
255205821Sedwin			m = m->nextmonth;
256205821Sedwin		}
257205821Sedwin		y = y->nextyear;
258205821Sedwin	}
259205821Sedwin}
260205821Sedwin
261205821Sedwinint
262205821Sedwinremember_ymd(int yy, int mm, int dd)
263205821Sedwin{
264205821Sedwin	struct cal_year *y;
265205821Sedwin	struct cal_month *m;
266205821Sedwin	struct cal_day *d;
267205821Sedwin
268205821Sedwin	if (debug_remember)
269205821Sedwin		printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
270205821Sedwin
271205821Sedwin	y = hyear;
272205821Sedwin	while (y != NULL) {
273205821Sedwin		if (y->year != yy) {
274205821Sedwin			y = y->nextyear;
275205821Sedwin			continue;
276205821Sedwin		}
277205821Sedwin		m = y->months;
278205821Sedwin		while (m != NULL) {
279205821Sedwin			if (m->month != mm) {
280205821Sedwin				m = m->nextmonth;
281205821Sedwin				continue;
282205821Sedwin			}
283205821Sedwin			d = m->days;
284205821Sedwin			while (d != NULL) {
285205821Sedwin				if (d->dayofmonth == dd)
286205821Sedwin					return (1);
287205821Sedwin				d = d->nextday;
288205821Sedwin				continue;
289205821Sedwin			}
290205821Sedwin			return (0);
291205821Sedwin		}
292205821Sedwin		return (0);
293205821Sedwin	}
294205821Sedwin	return (0);
295205821Sedwin}
296205821Sedwin
297205821Sedwinint
298205821Sedwinremember_yd(int yy, int dd, int *rm, int *rd)
299205821Sedwin{
300205821Sedwin	struct cal_year *y;
301205821Sedwin	struct cal_month *m;
302205821Sedwin	struct cal_day *d;
303205821Sedwin
304205821Sedwin	if (debug_remember)
305205821Sedwin		printf("remember_yd: %d - %d\n", yy, dd);
306205821Sedwin
307205821Sedwin	y = hyear;
308205821Sedwin	while (y != NULL) {
309205821Sedwin		if (y->year != yy) {
310205821Sedwin			y = y->nextyear;
311205821Sedwin			continue;
312205821Sedwin		}
313205821Sedwin		m = y->months;
314205821Sedwin		while (m != NULL) {
315205821Sedwin			d = m->days;
316205821Sedwin			while (d != NULL) {
317205821Sedwin				if (d->julianday == dd) {
318205821Sedwin					*rm = m->month;
319205821Sedwin					*rd = d->dayofmonth;
320205821Sedwin					return (1);
321205821Sedwin				}
322205821Sedwin				d = d->nextday;
323205821Sedwin			}
324205821Sedwin			m = m->nextmonth;
325205821Sedwin		}
326205821Sedwin		return (0);
327205821Sedwin	}
328205821Sedwin	return (0);
329205821Sedwin}
330205821Sedwin
331205821Sedwinint
332205821Sedwinfirst_dayofweek_of_year(int yy)
333205821Sedwin{
334205821Sedwin	struct cal_year *y;
335205821Sedwin
336205821Sedwin	y = hyear;
337205821Sedwin	while (y != NULL) {
338205821Sedwin		if (y->year == yy)
339205821Sedwin			return (y->firstdayofweek);
340205821Sedwin		y = y->nextyear;
341205821Sedwin	}
342205821Sedwin
343205821Sedwin	/* Should not happen */
344205821Sedwin	return (-1);
345205821Sedwin}
346205821Sedwin
347205821Sedwinint
348205821Sedwinfirst_dayofweek_of_month(int yy, int mm)
349205821Sedwin{
350205821Sedwin	struct cal_year *y;
351205821Sedwin	struct cal_month *m;
352205821Sedwin
353205821Sedwin	y = hyear;
354205821Sedwin	while (y != NULL) {
355205821Sedwin		if (y->year != yy) {
356205821Sedwin			y = y->nextyear;
357205821Sedwin			continue;
358205821Sedwin		}
359205821Sedwin		m = y->months;
360205821Sedwin		while (m != NULL) {
361205821Sedwin			if (m->month == mm)
362205821Sedwin				return (m->firstdayofweek);
363205821Sedwin			m = m->nextmonth;
364205821Sedwin		}
365251647Sgrog		/* No data for this month */
366205821Sedwin		return (-1);
367205821Sedwin	}
368205821Sedwin
369251647Sgrog	/* No data for this year.  Error? */
370251647Sgrog        return (-1);
371205821Sedwin}
372205821Sedwin
373205821Sedwinint
374205821Sedwinwalkthrough_dates(struct event **e)
375205821Sedwin{
376205821Sedwin	static struct cal_year *y = NULL;
377205821Sedwin	static struct cal_month *m = NULL;
378205821Sedwin	static struct cal_day *d = NULL;
379205821Sedwin
380205821Sedwin	if (y == NULL) {
381205821Sedwin		y = hyear;
382205821Sedwin		m = y->months;
383205821Sedwin		d = m->days;
384205821Sedwin		*e = d->events;
385205821Sedwin		return (1);
386298089Spfg	}
387205821Sedwin	if (d->nextday != NULL) {
388205821Sedwin		d = d->nextday;
389205821Sedwin		*e = d->events;
390205821Sedwin		return (1);
391205821Sedwin	}
392205821Sedwin	if (m->nextmonth != NULL) {
393205821Sedwin		m = m->nextmonth;
394205821Sedwin		d = m->days;
395205821Sedwin		*e = d->events;
396205821Sedwin		return (1);
397205821Sedwin	}
398205821Sedwin	if (y->nextyear != NULL) {
399205821Sedwin		y = y->nextyear;
400205821Sedwin		m = y->months;
401205821Sedwin		d = m->days;
402205821Sedwin		*e = d->events;
403205821Sedwin		return (1);
404205821Sedwin	}
405205821Sedwin
406205821Sedwin	return (0);
407205821Sedwin}
408205821Sedwin
409205821Sedwinstatic struct cal_day *
410205821Sedwinfind_day(int yy, int mm, int dd)
411205821Sedwin{
412205821Sedwin	struct cal_year *y;
413205821Sedwin	struct cal_month *m;
414205821Sedwin	struct cal_day *d;
415205821Sedwin
416205821Sedwin	if (debug_remember)
417205821Sedwin		printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
418205821Sedwin
419205821Sedwin	y = hyear;
420205821Sedwin	while (y != NULL) {
421205821Sedwin		if (y->year != yy) {
422205821Sedwin			y = y->nextyear;
423205821Sedwin			continue;
424205821Sedwin		}
425205821Sedwin		m = y->months;
426205821Sedwin		while (m != NULL) {
427205821Sedwin			if (m->month != mm) {
428205821Sedwin				m = m->nextmonth;
429205821Sedwin				continue;
430205821Sedwin			}
431205821Sedwin			d = m->days;
432205821Sedwin			while (d != NULL) {
433205821Sedwin				if (d->dayofmonth == dd)
434205821Sedwin					return (d);
435205821Sedwin				d = d->nextday;
436205821Sedwin				continue;
437205821Sedwin			}
438205821Sedwin			return (NULL);
439205821Sedwin		}
440205821Sedwin		return (NULL);
441205821Sedwin	}
442205821Sedwin	return (NULL);
443205821Sedwin}
444205821Sedwin
445205821Sedwinvoid
446205821Sedwinaddtodate(struct event *e, int year, int month, int day)
447205821Sedwin{
448205821Sedwin	struct cal_day *d;
449205821Sedwin
450205821Sedwin	d = find_day(year, month, day);
451205821Sedwin	e->next = d->events;
452205821Sedwin	d->events = e;
453205821Sedwin}
454