#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <time.h>
#include "calendar.h"
struct cal_year {
int year;
int easter;
int paskha;
int cny;
int firstdayofweek;
struct cal_month *months;
struct cal_year *nextyear;
};
struct cal_month {
int month;
int firstdayjulian;
int firstdayofweek;
struct cal_year *year;
struct cal_day *days;
struct cal_month *nextmonth;
};
struct cal_day {
int dayofmonth;
int julianday;
int dayofweek;
struct cal_day *nextday;
struct cal_month *month;
struct cal_year *year;
struct event *events;
struct event *lastevent;
};
int debug_remember = 0;
static struct cal_year *hyear = NULL;
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},
};
static int *monthdays;
int monthdaytab[][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 struct cal_day * find_day(int yy, int mm, int dd);
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) {
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) {
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;
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) {
for (d = d1; d <= d2; d++)
createdate(y1, m1, d);
return;
}
monthdays = monthdaytab[isleap(y1)];
for (d = d1; d <= monthdays[m1]; d++)
createdate(y1, m1, d);
for (m = m1 + 1; m < m2; m++)
for (d = 1; d <= monthdays[m]; d++)
createdate(y1, m, d);
for (d = 1; d <= d2; d++)
createdate(y1, m2, d);
return;
}
monthdays = monthdaytab[isleap(y1)];
for (d = d1; d <= monthdays[m1]; d++)
createdate(y1, m1, d);
for (m = m1 + 1; m <= 12; m++)
for (d = 1; d <= monthdays[m]; d++)
createdate(y1, m, d);
for (y = y1 + 1; y < y2; y++) {
monthdays = monthdaytab[isleap(y)];
for (m = 1; m <= 12; m++)
for (d = 1; d <= monthdays[m]; d++)
createdate(y, m, d);
}
monthdays = monthdaytab[isleap(y2)];
for (m = 1; m < m2; m++)
for (d = 1; d <= monthdays[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;
}
}
int
remember_ymd(int yy, int mm, int dd)
{
struct cal_year *y;
struct cal_month *m;
struct cal_day *d;
if (debug_remember)
printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
y = hyear;
while (y != NULL) {
if (y->year != yy) {
y = y->nextyear;
continue;
}
m = y->months;
while (m != NULL) {
if (m->month != mm) {
m = m->nextmonth;
continue;
}
d = m->days;
while (d != NULL) {
if (d->dayofmonth == dd)
return (1);
d = d->nextday;
continue;
}
return (0);
}
return (0);
}
return (0);
}
int
remember_yd(int yy, int dd, int *rm, int *rd)
{
struct cal_year *y;
struct cal_month *m;
struct cal_day *d;
if (debug_remember)
printf("remember_yd: %d - %d\n", yy, dd);
y = hyear;
while (y != NULL) {
if (y->year != yy) {
y = y->nextyear;
continue;
}
m = y->months;
while (m != NULL) {
d = m->days;
while (d != NULL) {
if (d->julianday == dd) {
*rm = m->month;
*rd = d->dayofmonth;
return (1);
}
d = d->nextday;
}
m = m->nextmonth;
}
return (0);
}
return (0);
}
int
first_dayofweek_of_year(int yy)
{
struct cal_year *y;
y = hyear;
while (y != NULL) {
if (y->year == yy)
return (y->firstdayofweek);
y = y->nextyear;
}
return (-1);
}
int
first_dayofweek_of_month(int yy, int mm)
{
struct cal_year *y;
struct cal_month *m;
y = hyear;
while (y != NULL) {
if (y->year != yy) {
y = y->nextyear;
continue;
}
m = y->months;
while (m != NULL) {
if (m->month == mm)
return (m->firstdayofweek);
m = m->nextmonth;
}
return (-1);
}
return (-1);
}
int
walkthrough_dates(struct event **e)
{
static struct cal_year *y = NULL;
static struct cal_month *m = NULL;
static struct cal_day *d = NULL;
if (y == NULL) {
y = hyear;
m = y->months;
d = m->days;
*e = d->events;
return (1);
}
if (d->nextday != NULL) {
d = d->nextday;
*e = d->events;
return (1);
}
if (m->nextmonth != NULL) {
m = m->nextmonth;
d = m->days;
*e = d->events;
return (1);
}
if (y->nextyear != NULL) {
y = y->nextyear;
m = y->months;
d = m->days;
*e = d->events;
return (1);
}
return (0);
}
static struct cal_day *
find_day(int yy, int mm, int dd)
{
struct cal_year *y;
struct cal_month *m;
struct cal_day *d;
if (debug_remember)
printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
y = hyear;
while (y != NULL) {
if (y->year != yy) {
y = y->nextyear;
continue;
}
m = y->months;
while (m != NULL) {
if (m->month != mm) {
m = m->nextmonth;
continue;
}
d = m->days;
while (d != NULL) {
if (d->dayofmonth == dd)
return (d);
d = d->nextday;
continue;
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
void
addtodate(struct event *e)
{
struct cal_day *d;
struct event *ee;
d = find_day(e->year, e->month, e->day);
ee = d->lastevent;
if (ee != NULL)
ee->next = e;
else
d->events = e;
d->lastevent = e;
}