dates.c revision 330449
1139749Simp/*-
2126177Srik * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3126177Srik *
4126177Srik * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
5126177Srik * All rights reserved.
6126177Srik *
7126177Srik * Redistribution and use in source and binary forms, with or without
8126177Srik * modification, are permitted provided that the following conditions
9126177Srik * are met:
10126177Srik * 1. Redistributions of source code must retain the above copyright
11126177Srik *    notice, this list of conditions and the following disclaimer.
12126177Srik * 2. Redistributions in binary form must reproduce the above copyright
13126177Srik *    notice, this list of conditions and the following disclaimer in the
14126177Srik *    documentation and/or other materials provided with the distribution.
15126177Srik *
16126177Srik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17126177Srik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18126177Srik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19126177Srik * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20126177Srik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21126177Srik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22126177Srik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23126177Srik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24126177Srik * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25126177Srik * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26126177Srik * SUCH DAMAGE.
27126177Srik *
28126177Srik */
29126177Srik
30126177Srik#include <sys/cdefs.h>
31126177Srik__FBSDID("$FreeBSD: stable/11/usr.bin/calendar/dates.c 330449 2018-03-05 07:26:05Z eadler $");
32126177Srik
33126177Srik#include <stdio.h>
34126177Srik#include <stdlib.h>
35126177Srik#include <err.h>
36126177Srik#include <time.h>
37126177Srik
38126177Srik#include "calendar.h"
39126177Srik
40126177Srikstruct cal_year {
41126177Srik	int year;	/* 19xx, 20xx, 21xx */
42126177Srik	int easter;	/* Julian day */
43126177Srik	int paskha;	/* Julian day */
44126177Srik	int cny;	/* Julian day */
45126177Srik	int firstdayofweek; /* 0 .. 6 */
46126177Srik	struct cal_month *months;
47126177Srik	struct cal_year	*nextyear;
48126177Srik};
49126177Srik
50126177Srikstruct cal_month {
51126177Srik	int month;			/* 01 .. 12 */
52126177Srik	int firstdayjulian;		/* 000 .. 366 */
53126177Srik	int firstdayofweek;		/* 0 .. 6 */
54126177Srik	struct cal_year *year;		/* points back */
55126177Srik	struct cal_day *days;
56126177Srik	struct cal_month *nextmonth;
57126177Srik};
58126177Srik
59126177Srikstruct cal_day {
60126177Srik	int dayofmonth;			/* 01 .. 31 */
61126177Srik	int julianday;			/* 000 .. 366 */
62126177Srik	int dayofweek;			/* 0 .. 6 */
63126177Srik	struct cal_day *nextday;
64126177Srik	struct cal_month *month;	/* points back */
65126177Srik	struct cal_year	*year;		/* points back */
66126177Srik	struct event *events;
67126177Srik};
68126177Srik
69126177Srikint debug_remember = 0;
70126177Srikstatic struct cal_year *hyear = NULL;
71126177Srik
72126177Srik/* 1-based month, 0-based days, cumulative */
73126177Srikint	cumdaytab[][14] = {
74126177Srik	{0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
75126177Srik	{0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
76126177Srik};
77126177Srik/* 1-based month, individual */
78126177Srikstatic int *monthdays;
79126177Srikint	monthdaytab[][14] = {
80126177Srik	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
81126177Srik	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
82126177Srik};
83126177Srik
84126177Srikstatic struct cal_day *	find_day(int yy, int mm, int dd);
85126177Srik
86126177Srikstatic void
87126177Srikcreatedate(int y, int m, int d)
88126177Srik{
89126177Srik	struct cal_year *py, *pyp;
90126177Srik	struct cal_month *pm, *pmp;
91126177Srik	struct cal_day *pd, *pdp;
92126177Srik	int *cumday;
93126177Srik
94126177Srik	pyp = NULL;
95126177Srik	py = hyear;
96126177Srik	while (py != NULL) {
97126177Srik		if (py->year == y + 1900)
98126177Srik			break;
99126177Srik		pyp = py;
100126177Srik		py = py->nextyear;
101126177Srik	}
102126177Srik
103126177Srik	if (py == NULL) {
104126177Srik		struct tm td;
105126177Srik		time_t t;
106126177Srik		py = (struct cal_year *)calloc(1, sizeof(struct cal_year));
107315221Spfg		py->year = y + 1900;
108126177Srik		py->easter = easter(y);
109126177Srik		py->paskha = paskha(y);
110126177Srik
111126177Srik		td = tm0;
112126177Srik		td.tm_year = y;
113126177Srik		td.tm_mday = 1;
114126177Srik		t = mktime(&td);
115126177Srik		localtime_r(&t, &td);
116126177Srik		py->firstdayofweek = td.tm_wday;
117126177Srik
118126177Srik		if (pyp != NULL)
119126177Srik			pyp->nextyear = py;
120126177Srik	}
121126177Srik	if (pyp == NULL) {
122126177Srik		/* The very very very first one */
123126177Srik		hyear = py;
124126177Srik	}
125126177Srik
126126177Srik	pmp = NULL;
127126177Srik	pm = py->months;
128126177Srik	while (pm != NULL) {
129126177Srik		if (pm->month == m)
130126177Srik			break;
131126177Srik		pmp = pm;
132126177Srik		pm = pm->nextmonth;
133126177Srik	}
134126177Srik
135126177Srik	if (pm == NULL) {
136126177Srik		pm = (struct cal_month *)calloc(1, sizeof(struct cal_month));
137126177Srik		pm->year = py;
138126177Srik		pm->month = m;
139126177Srik		cumday = cumdaytab[isleap(y)];
140126177Srik		pm->firstdayjulian = cumday[m] + 2;
141126177Srik		pm->firstdayofweek =
142126177Srik		    (py->firstdayofweek + pm->firstdayjulian -1) % 7;
143126177Srik		if (pmp != NULL)
144126177Srik			pmp->nextmonth = pm;
145126177Srik	}
146126177Srik	if (pmp == NULL)
147126177Srik		py->months = pm;
148126177Srik
149126177Srik	pdp = NULL;
150126177Srik	pd = pm->days;
151126177Srik	while (pd != NULL) {
152126177Srik		pdp = pd;
153126177Srik		pd = pd->nextday;
154126177Srik	}
155126177Srik
156126177Srik	if (pd == NULL) {	/* Always true */
157126177Srik		pd = (struct cal_day *)calloc(1, sizeof(struct cal_day));
158126177Srik		pd->month = pm;
159126177Srik		pd->year = py;
160126177Srik		pd->dayofmonth = d;
161126177Srik		pd->julianday = pm->firstdayjulian + d - 1;
162126177Srik		pd->dayofweek = (pm->firstdayofweek + d - 1) % 7;
163126177Srik		if (pdp != NULL)
164126177Srik			pdp->nextday = pd;
165126177Srik	}
166126177Srik	if (pdp == NULL)
167126177Srik		pm->days = pd;
168126177Srik}
169126177Srik
170126177Srikvoid
171126177Srikgeneratedates(struct tm *tp1, struct tm *tp2)
172126177Srik{
173126177Srik	int y1, m1, d1;
174126177Srik	int y2, m2, d2;
175126177Srik	int y, m, d;
176126177Srik
177126177Srik	y1 = tp1->tm_year;
178126177Srik	m1 = tp1->tm_mon + 1;
179126177Srik	d1 = tp1->tm_mday;
180126177Srik	y2 = tp2->tm_year;
181126177Srik	m2 = tp2->tm_mon + 1;
182126177Srik	d2 = tp2->tm_mday;
183126177Srik
184126177Srik	if (y1 == y2) {
185126177Srik		if (m1 == m2) {
186126177Srik			/* Same year, same month. Easy! */
187126177Srik			for (d = d1; d <= d2; d++)
188126177Srik				createdate(y1, m1, d);
189126177Srik			return;
190126177Srik		}
191126177Srik		/*
192126177Srik		 * Same year, different month.
193126177Srik		 * - Take the leftover days from m1
194126177Srik		 * - Take all days from <m1 .. m2>
195126177Srik		 * - Take the first days from m2
196126177Srik		 */
197126177Srik		monthdays = monthdaytab[isleap(y1)];
198126177Srik		for (d = d1; d <= monthdays[m1]; d++)
199126177Srik			createdate(y1, m1, d);
200126177Srik		for (m = m1 + 1; m < m2; m++)
201126177Srik			for (d = 1; d <= monthdays[m]; d++)
202126177Srik				createdate(y1, m, d);
203126177Srik		for (d = 1; d <= d2; d++)
204126177Srik			createdate(y1, m2, d);
205126177Srik		return;
206126177Srik	}
207126177Srik	/*
208126177Srik	 * Different year, different month.
209126177Srik	 * - Take the leftover days from y1-m1
210126177Srik	 * - Take all days from y1-<m1 .. 12]
211126177Srik	 * - Take all days from <y1 .. y2>
212126177Srik	 * - Take all days from y2-[1 .. m2>
213126177Srik	 * - Take the first days of y2-m2
214126177Srik	 */
215126177Srik	monthdays = monthdaytab[isleap(y1)];
216126177Srik	for (d = d1; d <= monthdays[m1]; d++)
217126177Srik		createdate(y1, m1, d);
218126177Srik	for (m = m1 + 1; m <= 12; m++)
219126177Srik		for (d = 1; d <= monthdays[m]; d++)
220126177Srik			createdate(y1, m, d);
221126177Srik	for (y = y1 + 1; y < y2; y++) {
222126177Srik		monthdays = monthdaytab[isleap(y)];
223126177Srik		for (m = 1; m <= 12; m++)
224126177Srik			for (d = 1; d <= monthdays[m]; d++)
225126177Srik				createdate(y, m, d);
226126177Srik	}
227126177Srik	monthdays = monthdaytab[isleap(y2)];
228126177Srik	for (m = 1; m < m2; m++)
229126177Srik		for (d = 1; d <= monthdays[m]; d++)
230126177Srik			createdate(y2, m, d);
231126177Srik	for (d = 1; d <= d2; d++)
232126177Srik		createdate(y2, m2, d);
233126177Srik}
234126177Srik
235126177Srikvoid
236126177Srikdumpdates(void)
237126177Srik{
238126177Srik	struct cal_year *y;
239126177Srik	struct cal_month *m;
240126177Srik	struct cal_day *d;
241126177Srik
242126177Srik	y = hyear;
243126177Srik	while (y != NULL) {
244126177Srik		printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek);
245126177Srik		m = y->months;
246126177Srik		while (m != NULL) {
247126177Srik			printf("-- %-5d (julian:%d, dow:%d)\n", m->month,
248126177Srik			    m->firstdayjulian, m->firstdayofweek);
249126177Srik			d = m->days;
250126177Srik			while (d != NULL) {
251126177Srik				printf("  -- %-5d (julian:%d, dow:%d)\n",
252126177Srik				    d->dayofmonth, d->julianday, d->dayofweek);
253126177Srik				d = d->nextday;
254126177Srik			}
255126177Srik			m = m->nextmonth;
256126177Srik		}
257126177Srik		y = y->nextyear;
258126177Srik	}
259126177Srik}
260126177Srik
261126177Srikint
262126177Srikremember_ymd(int yy, int mm, int dd)
263126177Srik{
264126177Srik	struct cal_year *y;
265126177Srik	struct cal_month *m;
266126177Srik	struct cal_day *d;
267126177Srik
268126177Srik	if (debug_remember)
269126177Srik		printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
270126177Srik
271126177Srik	y = hyear;
272126177Srik	while (y != NULL) {
273126177Srik		if (y->year != yy) {
274126177Srik			y = y->nextyear;
275126177Srik			continue;
276126177Srik		}
277126177Srik		m = y->months;
278126177Srik		while (m != NULL) {
279126177Srik			if (m->month != mm) {
280126177Srik				m = m->nextmonth;
281126177Srik				continue;
282126177Srik			}
283126177Srik			d = m->days;
284126177Srik			while (d != NULL) {
285126177Srik				if (d->dayofmonth == dd)
286126177Srik					return (1);
287126177Srik				d = d->nextday;
288126177Srik				continue;
289126177Srik			}
290126177Srik			return (0);
291126177Srik		}
292126177Srik		return (0);
293126177Srik	}
294126177Srik	return (0);
295126177Srik}
296126177Srik
297126177Srikint
298126177Srikremember_yd(int yy, int dd, int *rm, int *rd)
299126177Srik{
300126177Srik	struct cal_year *y;
301126177Srik	struct cal_month *m;
302126177Srik	struct cal_day *d;
303126177Srik
304126177Srik	if (debug_remember)
305126177Srik		printf("remember_yd: %d - %d\n", yy, dd);
306126177Srik
307126177Srik	y = hyear;
308126177Srik	while (y != NULL) {
309126177Srik		if (y->year != yy) {
310126177Srik			y = y->nextyear;
311126177Srik			continue;
312126177Srik		}
313126177Srik		m = y->months;
314126177Srik		while (m != NULL) {
315126177Srik			d = m->days;
316126177Srik			while (d != NULL) {
317126177Srik				if (d->julianday == dd) {
318126177Srik					*rm = m->month;
319126177Srik					*rd = d->dayofmonth;
320126177Srik					return (1);
321126177Srik				}
322126177Srik				d = d->nextday;
323126177Srik			}
324126177Srik			m = m->nextmonth;
325126177Srik		}
326126177Srik		return (0);
327126177Srik	}
328126177Srik	return (0);
329126177Srik}
330126177Srik
331126177Srikint
332126177Srikfirst_dayofweek_of_year(int yy)
333126177Srik{
334126177Srik	struct cal_year *y;
335126177Srik
336126177Srik	y = hyear;
337126177Srik	while (y != NULL) {
338126177Srik		if (y->year == yy)
339126177Srik			return (y->firstdayofweek);
340126177Srik		y = y->nextyear;
341126177Srik	}
342126177Srik
343126177Srik	/* Should not happen */
344126177Srik	return (-1);
345126177Srik}
346126177Srik
347126177Srikint
348126177Srikfirst_dayofweek_of_month(int yy, int mm)
349126177Srik{
350126177Srik	struct cal_year *y;
351126177Srik	struct cal_month *m;
352126177Srik
353126177Srik	y = hyear;
354126177Srik	while (y != NULL) {
355126177Srik		if (y->year != yy) {
356126177Srik			y = y->nextyear;
357126177Srik			continue;
358126177Srik		}
359126177Srik		m = y->months;
360126177Srik		while (m != NULL) {
361126177Srik			if (m->month == mm)
362126177Srik				return (m->firstdayofweek);
363126177Srik			m = m->nextmonth;
364126177Srik		}
365126177Srik		/* No data for this month */
366126177Srik		return (-1);
367126177Srik	}
368126177Srik
369126177Srik	/* No data for this year.  Error? */
370126177Srik        return (-1);
371126177Srik}
372126177Srik
373126177Srikint
374126177Srikwalkthrough_dates(struct event **e)
375126177Srik{
376126177Srik	static struct cal_year *y = NULL;
377126177Srik	static struct cal_month *m = NULL;
378126177Srik	static struct cal_day *d = NULL;
379126177Srik
380126177Srik	if (y == NULL) {
381126177Srik		y = hyear;
382126177Srik		m = y->months;
383126177Srik		d = m->days;
384126177Srik		*e = d->events;
385126177Srik		return (1);
386126177Srik	}
387126177Srik	if (d->nextday != NULL) {
388126177Srik		d = d->nextday;
389126177Srik		*e = d->events;
390126177Srik		return (1);
391126177Srik	}
392126177Srik	if (m->nextmonth != NULL) {
393126177Srik		m = m->nextmonth;
394126177Srik		d = m->days;
395126177Srik		*e = d->events;
396126177Srik		return (1);
397126177Srik	}
398126177Srik	if (y->nextyear != NULL) {
399126177Srik		y = y->nextyear;
400126177Srik		m = y->months;
401126177Srik		d = m->days;
402126177Srik		*e = d->events;
403126177Srik		return (1);
404126177Srik	}
405126177Srik
406126177Srik	return (0);
407126177Srik}
408126177Srik
409126177Srikstatic struct cal_day *
410126177Srikfind_day(int yy, int mm, int dd)
411126177Srik{
412126177Srik	struct cal_year *y;
413126177Srik	struct cal_month *m;
414126177Srik	struct cal_day *d;
415126177Srik
416126177Srik	if (debug_remember)
417126177Srik		printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
418126177Srik
419126177Srik	y = hyear;
420126177Srik	while (y != NULL) {
421126177Srik		if (y->year != yy) {
422126177Srik			y = y->nextyear;
423126177Srik			continue;
424126177Srik		}
425126177Srik		m = y->months;
426126177Srik		while (m != NULL) {
427126177Srik			if (m->month != mm) {
428126177Srik				m = m->nextmonth;
429126177Srik				continue;
430126177Srik			}
431126177Srik			d = m->days;
432126177Srik			while (d != NULL) {
433126177Srik				if (d->dayofmonth == dd)
434126177Srik					return (d);
435126177Srik				d = d->nextday;
436126177Srik				continue;
437126177Srik			}
438126177Srik			return (NULL);
439126177Srik		}
440126177Srik		return (NULL);
441126177Srik	}
442126177Srik	return (NULL);
443126177Srik}
444126177Srik
445126177Srikvoid
446126177Srikaddtodate(struct event *e, int year, int month, int day)
447126177Srik{
448126177Srik	struct cal_day *d;
449126177Srik
450126177Srik	d = find_day(year, month, day);
451126177Srik	e->next = d->events;
452126177Srik	d->events = e;
453126177Srik}
454126177Srik