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