Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Dec 2009 11:41:04 +0000 (UTC)
From:      Edwin Groothuis <edwin@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r200984 - user/edwin/calendar
Message-ID:  <200912251141.nBPBf4Tw060225@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: edwin
Date: Fri Dec 25 11:41:04 2009
New Revision: 200984
URL: http://svn.freebsd.org/changeset/base/200984

Log:
  Intermittent commit:
  
  - Fix the handling of the years (leapyear / nonleapyear, span over
    multiple years) in Paskha and Easter handling.
  - Add code to properly handle absurd long intervals.

Added:
  user/edwin/calendar/dates.c
Modified:
  user/edwin/calendar/Makefile
  user/edwin/calendar/calendar.c
  user/edwin/calendar/calendar.h
  user/edwin/calendar/day.c
  user/edwin/calendar/events.c
  user/edwin/calendar/ostern.c
  user/edwin/calendar/paskha.c

Modified: user/edwin/calendar/Makefile
==============================================================================
--- user/edwin/calendar/Makefile	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/Makefile	Fri Dec 25 11:41:04 2009	(r200984)
@@ -4,7 +4,8 @@
 CFLAGS=	 -pipe  -g -std=gnu99 -fstack-protector   -Wall
 
 PROG=	calendar
-SRCS=   calendar.c locale.c events.c parsedata.c io.c day.c ostern.c paskha.c
+SRCS=   calendar.c locale.c events.c dates.c parsedata.c io.c day.c \
+	ostern.c paskha.c
 INTER=          de_AT.ISO_8859-15 de_DE.ISO8859-1 fr_FR.ISO8859-1 \
 		hr_HR.ISO8859-2 hu_HU.ISO8859-2 ru_RU.KOI8-R uk_UA.KOI8-U
 DE_LINKS=       de_DE.ISO8859-15

Modified: user/edwin/calendar/calendar.c
==============================================================================
--- user/edwin/calendar/calendar.c	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/calendar.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -129,7 +129,9 @@ main(int argc, char *argv[])
 	if (f_time <= 0)
 		(void)time(&f_time);
 
-	settimes(f_time, f_dayBefore, f_dayAfter);
+	settimes(f_time, f_dayBefore, f_dayAfter, &tp1, &tp2);
+	generatedates(&tp1, &tp2);
+	dumpdates();
 
 	if (doall)
 		while ((pw = getpwent()) != NULL) {

Modified: user/edwin/calendar/calendar.h
==============================================================================
--- user/edwin/calendar/calendar.h	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/calendar.h	Fri Dec 25 11:41:04 2009	(r200984)
@@ -46,7 +46,6 @@ extern struct iovec header[];
 extern struct tm tp1, tp2;
 extern time_t t1, t2;
 extern const char *calendarFile;
-extern int *cumdays;
 extern int yrdays;
 extern struct fixs neaster, npaskha, ncny;
 
@@ -114,7 +113,8 @@ extern const char *fdays[];
 void	setnnames(void);
 
 /* day.c */
-void	settimes(time_t,int, int);
+extern const struct tm tm0;
+void	settimes(time_t,int, int, struct tm *tp1, struct tm *tp2);
 time_t	Mktime(char *);
 
 /* parsedata.c */
@@ -126,7 +126,10 @@ void	closecal(FILE *);
 FILE	*opencal(void);
 
 /* ostern.c / pashka.c */
-int	geteaster(char *, int);
-int	getpaskha(char *, int);
+int	paskha(int);
 int	easter(int);
 
+/* dates.c */
+extern int cumdaytab[][14];
+void	generatedates(struct tm *tp1, struct tm *tp2);
+void	dumpdates(void);

Added: user/edwin/calendar/dates.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/edwin/calendar/dates.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <time.h>
+
+#include "calendar.h"
+
+struct cal_year {
+	int year;	/* 19xx, 20xx, 21xx */
+	int easter;	/* Julian day */
+	int paskha;	/* Julian day */
+	int cny;	/* Julian day */
+	int firstdayofweek; /* 0 .. 6 */
+	struct cal_month *months;
+	struct cal_year	*nextyear;
+} cal_year;
+
+struct cal_month {
+	int month;			/* 01 .. 12 */
+	int firstdayjulian;		/* 000 .. 366 */
+	int firstdayofweek;		/* 0 .. 6 */
+	struct cal_year *year;		/* points back */
+	struct cal_day *days;
+	struct cal_month *nextmonth;
+} cal_month;
+
+struct cal_day {
+	int dayofmonth;			/* 01 .. 31 */
+	int julianday;			/* 000 .. 366 */
+	int dayofweek;			/* 0 .. 6 */
+	struct cal_day *nextday;
+	struct cal_month *month;
+	struct cal_year	*year;
+	struct event *events;
+} cal_day;
+
+struct cal_year	*hyear = NULL;
+
+/* 1-based month, 0-based days, cumulative */
+int *cumdays;
+int	cumdaytab[][14] = {
+	{0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
+	{0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+};
+/* 1-based month, individual */
+int *mondays;
+int	mondaytab[][14] = {
+	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
+	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
+};
+
+static void
+createdate(int y, int m, int d)
+{
+	struct cal_year *py, *pyp;
+	struct cal_month *pm, *pmp;
+	struct cal_day *pd, *pdp;
+	int *cumday;
+
+	pyp = NULL;
+	py = hyear;
+	while (py != NULL) {
+		if (py->year == y + 1900)
+			break;
+		pyp = py;
+		py = py->nextyear;
+	}
+
+	if (py == NULL) {
+		struct tm td;
+		time_t t;
+		py = (struct cal_year *)calloc(1, sizeof(struct cal_year));
+		py->year = y + 1900;
+		py->easter = easter(y);
+		py->paskha = paskha(y);
+
+		td = tm0;
+		td.tm_year = y;
+		td.tm_mday = 1;
+		t = mktime(&td);
+		localtime_r(&t, &td);
+		py->firstdayofweek = td.tm_wday;
+
+		if (pyp != NULL)
+			pyp->nextyear = py;
+	}
+	if (pyp == NULL) {
+		/* The very very very first one */
+		hyear = py;
+	}
+
+	pmp = NULL;
+	pm = py->months;
+	while (pm != NULL) {
+		if (pm->month == m)
+			break;
+		pmp = pm;
+		pm = pm->nextmonth;
+	}
+
+	if (pm == NULL) {
+		pm = (struct cal_month *)calloc(1, sizeof(struct cal_month));
+		pm->year = py;
+		pm->month = m;
+		cumday = cumdaytab[isleap(y)];
+		pm->firstdayjulian = cumday[m] + 2;
+		pm->firstdayofweek =
+		    (py->firstdayofweek + pm->firstdayjulian -1) % 7;
+		if (pmp != NULL)
+			pmp->nextmonth = pm;
+	}
+	if (pmp == NULL)
+		py->months = pm;
+
+	pdp = NULL;
+	pd = pm->days;
+	while (pd != NULL) {
+		pdp = pd;
+		pd = pd->nextday;
+	}
+
+	if (pd == NULL) {	/* Always true */
+		pd = (struct cal_day *)calloc(1, sizeof(struct cal_day));
+		pd->month = pm;
+		pd->year = py;
+		pd->dayofmonth = d;
+		pd->julianday = pm->firstdayjulian + d - 1;
+		pd->dayofweek = (pm->firstdayofweek + d - 1) % 7;
+		if (pdp != NULL)
+			pdp->nextday = pd;
+	}
+	if (pdp == NULL)
+		pm->days = pd;
+}
+
+void
+generatedates(struct tm *tp1, struct tm *tp2)
+{
+	int y1, m1, d1;
+	int y2, m2, d2;
+	int y, m, d;
+	int *mondays;
+
+	y1 = tp1->tm_year;
+	m1 = tp1->tm_mon + 1;
+	d1 = tp1->tm_mday;
+	y2 = tp2->tm_year;
+	m2 = tp2->tm_mon + 1;
+	d2 = tp2->tm_mday;
+
+	if (y1 == y2) {
+		if (m1 == m2) {
+			/* Same year, same month. Easy! */
+			for (d = d1; d <= d2; d++)
+				createdate(y1, m1, d);
+			return;
+		}
+		/*
+		 * Same year, different month.
+		 * - Take the leftover days from m1
+		 * - Take all days from <m1 .. m2>
+		 * - Take the first days from m2
+		 */
+		mondays = mondaytab[isleap(y1)];
+		for (d = d1; d <= mondays[m1]; d++)
+			createdate(y1, m1, d);
+		for (m = m1 + 1; m < m2; m++)
+			for (d = 1; d <= mondays[m]; d++)
+				createdate(y1, m, d);
+		for (d = 1; d <= d2; d++)
+			createdate(y1, m2, d);
+		return;
+	}
+	/*
+	 * Different year, different month.
+	 * - Take the leftover days from y1-m1
+	 * - Take all days from y1-<m1 .. 12]
+	 * - Take all days from <y1 .. y2>
+	 * - Take all days from y2-[1 .. m2>
+	 * - Take the first days of y2-m2
+	 */
+	mondays = mondaytab[isleap(y1)];
+	for (d = d1; d <= mondays[m1]; d++)
+		createdate(y1, m1, d);
+	for (m = m1 + 1; m <= 12; m++)
+		for (d = 1; d <= mondays[m]; d++)
+			createdate(y1, m, d);
+	for (y = y1 + 1; y < y2; y++) {
+		mondays = mondaytab[isleap(y)];
+		for (m = 1; m <= 12; m++)
+			for (d = 1; d <= mondays[m]; d++)
+				createdate(y, m, d);
+	}
+	mondays = mondaytab[isleap(y2)];
+	for (m = 1; m < m2; m++)
+		for (d = 1; d <= mondays[m]; d++)
+			createdate(y2, m, d);
+	for (d = 1; d <= d2; d++)
+		createdate(y2, m2, d);
+}
+
+void
+dumpdates(void)
+{
+	struct cal_year *y;
+	struct cal_month *m;
+	struct cal_day *d;
+
+	y = hyear;
+	while (y != NULL) {
+		printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek);
+		m = y->months;
+		while (m != NULL) {
+			printf("-- %-5d (julian:%d, dow:%d)\n", m->month,
+			    m->firstdayjulian, m->firstdayofweek);
+			d = m->days;
+			while (d != NULL) {
+				printf("  -- %-5d (julian:%d, dow:%d)\n",
+				    d->dayofmonth, d->julianday, d->dayofweek);
+				d = d->nextday;
+			}
+			m = m->nextmonth;
+		}
+		y = y->nextyear;
+	}
+}

Modified: user/edwin/calendar/day.c
==============================================================================
--- user/edwin/calendar/day.c	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/day.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -45,40 +45,26 @@ __FBSDID("$FreeBSD$");
 
 struct tm		tp1, tp2;
 time_t			time1, time2;
-static const struct tm	tm0;
-int			*cumdays, yrdays;
+const struct tm		tm0;
 char			dayname[10];
 
 
-/* 1-based month, 0-based days, cumulative */
-int	daytab[][14] = {
-	{0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
-	{0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
-};
-
-
 void
-settimes(time_t now, int before, int after)
+settimes(time_t now, int before, int after, struct tm *tp1, struct tm *tp2)
 {
 	char *oldl, *lbufp;
 	struct tm tp;
 
 	localtime_r(&now, &tp);
-	if (isleap(tp.tm_year + 1900)) {
-		yrdays = 366;
-		cumdays = daytab[1];
-	} else {
-		yrdays = 365;
-		cumdays = daytab[0];
-	}
+
 	/* Friday displays Monday's events */
 	if (f_dayAfter == 0 && f_dayBefore == 0 && Friday != -1)
 		f_dayAfter = tp.tm_wday == Friday ? 3 : 1;
 
 	time1 = now - SECSPERDAY * f_dayBefore;
-	localtime_r(&time1, &tp1);
+	localtime_r(&time1, tp1);
 	time2 = now + SECSPERDAY * f_dayAfter;
-	localtime_r(&time2, &tp2);
+	localtime_r(&time2, tp2);
 
 	header[5].iov_base = dayname;
 

Modified: user/edwin/calendar/events.c
==============================================================================
--- user/edwin/calendar/events.c	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/events.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -120,23 +120,23 @@ event_print_all(FILE *fp, struct event *
 	for (daycounter = 0; daycounter <= f_dayAfter + f_dayBefore;
 	    daycounter++) {
 		day = tp1.tm_yday - f_dayBefore + daycounter;
-		if (day < 0)
-			day += yrdays;
-		if (day >= yrdays)
-			day -= yrdays;
+//		if (day < 0)
+//			day += yrdays;
+//		if (day >= yrdays)
+//			day -= yrdays;
 
 		/*
 		 * When we know the day of the year, we can determine the day
 		 * of the month and the month.
 		 */
-		month = 1;
-		while (month <= 12) {
-			if (day <= cumdays[month])
-				break;
-			month++;
-		}
-		month--;
-		day -= cumdays[month];
+//		month = 1;
+//		while (month <= 12) {
+//			if (day <= cumdays[month])
+//				break;
+//			month++;
+//		}
+//		month--;
+//		day -= cumdays[month];
 
 #ifdef DEBUG
 		fprintf(stderr, "event_print_allmonth: %d, day: %d\n",

Modified: user/edwin/calendar/ostern.c
==============================================================================
--- user/edwin/calendar/ostern.c	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/ostern.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -60,7 +60,7 @@ easter(int year) /* 0 ... abcd, NOT sinc
 
 	L = I - J;
 
-	if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
+	if (isleap(year))
 		return 31 + 29 + 21 + L + 7;
 	else
 		return 31 + 28 + 21 + L + 7;

Modified: user/edwin/calendar/paskha.c
==============================================================================
--- user/edwin/calendar/paskha.c	Fri Dec 25 11:12:05 2009	(r200983)
+++ user/edwin/calendar/paskha.c	Fri Dec 25 11:41:04 2009	(r200984)
@@ -36,24 +36,24 @@ __FBSDID("$FreeBSD$");
 #define	PASKHA		"paskha"
 #define	PASKHALEN	(sizeof(PASKHA) - 1)
 
-static int paskha(int);
-
 /* return year day for Orthodox Easter using Gauss formula */
 /* (old style result) */
 
-static int
+int
 paskha(int R) /*year*/
 {
 	int a, b, c, d, e;
 	static int x = 15;
 	static int y = 6;
+	int *cumday;
 
 	a = R % 19;
 	b = R % 4;
 	c = R % 7;
 	d = (19 * a + x) % 30;
 	e = (2 * b + 4 * c + 6 * d + y) % 7;
-	return (((cumdays[3] + 1) + 22) + (d + e));
+	cumday = cumdaytab[isleap(R)];
+	return (((cumday[3] + 1) + 22) + (d + e));
 }
 
 /* return year day for Orthodox Easter depending days */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912251141.nBPBf4Tw060225>