dates.c revision 205872
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. 13205821Sedwin * 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. 25205821Sedwin * 26205821Sedwin */ 27205821Sedwin 28205821Sedwin#include <sys/cdefs.h> 29205821Sedwin__FBSDID("$FreeBSD: head/usr.bin/calendar/dates.c 205872 2010-03-30 06:42:01Z edwin $"); 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; 46205821Sedwin} cal_year; 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; 55205821Sedwin} cal_month; 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; 65205821Sedwin} cal_day; 66205821Sedwin 67205821Sedwinint debug_remember = 0; 68205821Sedwinstruct cal_year *hyear = NULL; 69205821Sedwin 70205821Sedwin/* 1-based month, 0-based days, cumulative */ 71205821Sedwinint *cumdays; 72205821Sedwinint cumdaytab[][14] = { 73205821Sedwin {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, 74205821Sedwin {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 75205821Sedwin}; 76205821Sedwin/* 1-based month, individual */ 77205821Sedwinint *mondays; 78205821Sedwinint mondaytab[][14] = { 79205821Sedwin {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 80205821Sedwin {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 81205821Sedwin}; 82205821Sedwin 83205821Sedwinstatic struct cal_day * find_day(int yy, int mm, int dd); 84205821Sedwin 85205821Sedwinstatic void 86205821Sedwincreatedate(int y, int m, int d) 87205821Sedwin{ 88205821Sedwin struct cal_year *py, *pyp; 89205821Sedwin struct cal_month *pm, *pmp; 90205821Sedwin struct cal_day *pd, *pdp; 91205821Sedwin int *cumday; 92205821Sedwin 93205821Sedwin pyp = NULL; 94205821Sedwin py = hyear; 95205821Sedwin while (py != NULL) { 96205821Sedwin if (py->year == y + 1900) 97205821Sedwin break; 98205821Sedwin pyp = py; 99205821Sedwin py = py->nextyear; 100205821Sedwin } 101205821Sedwin 102205821Sedwin if (py == NULL) { 103205821Sedwin struct tm td; 104205821Sedwin time_t t; 105205821Sedwin py = (struct cal_year *)calloc(1, sizeof(struct cal_year)); 106205821Sedwin py->year = y + 1900; 107205821Sedwin py->easter = easter(y); 108205821Sedwin py->paskha = paskha(y); 109205821Sedwin 110205821Sedwin td = tm0; 111205821Sedwin td.tm_year = y; 112205821Sedwin td.tm_mday = 1; 113205821Sedwin t = mktime(&td); 114205821Sedwin localtime_r(&t, &td); 115205821Sedwin py->firstdayofweek = td.tm_wday; 116205821Sedwin 117205821Sedwin if (pyp != NULL) 118205821Sedwin pyp->nextyear = py; 119205821Sedwin } 120205821Sedwin if (pyp == NULL) { 121205821Sedwin /* The very very very first one */ 122205821Sedwin hyear = py; 123205821Sedwin } 124205821Sedwin 125205821Sedwin pmp = NULL; 126205821Sedwin pm = py->months; 127205821Sedwin while (pm != NULL) { 128205821Sedwin if (pm->month == m) 129205821Sedwin break; 130205821Sedwin pmp = pm; 131205821Sedwin pm = pm->nextmonth; 132205821Sedwin } 133205821Sedwin 134205821Sedwin if (pm == NULL) { 135205821Sedwin pm = (struct cal_month *)calloc(1, sizeof(struct cal_month)); 136205821Sedwin pm->year = py; 137205821Sedwin pm->month = m; 138205821Sedwin cumday = cumdaytab[isleap(y)]; 139205821Sedwin pm->firstdayjulian = cumday[m] + 2; 140205821Sedwin pm->firstdayofweek = 141205821Sedwin (py->firstdayofweek + pm->firstdayjulian -1) % 7; 142205821Sedwin if (pmp != NULL) 143205821Sedwin pmp->nextmonth = pm; 144205821Sedwin } 145205821Sedwin if (pmp == NULL) 146205821Sedwin py->months = pm; 147205821Sedwin 148205821Sedwin pdp = NULL; 149205821Sedwin pd = pm->days; 150205821Sedwin while (pd != NULL) { 151205821Sedwin pdp = pd; 152205821Sedwin pd = pd->nextday; 153205821Sedwin } 154205821Sedwin 155205821Sedwin if (pd == NULL) { /* Always true */ 156205821Sedwin pd = (struct cal_day *)calloc(1, sizeof(struct cal_day)); 157205821Sedwin pd->month = pm; 158205821Sedwin pd->year = py; 159205821Sedwin pd->dayofmonth = d; 160205821Sedwin pd->julianday = pm->firstdayjulian + d - 1; 161205821Sedwin pd->dayofweek = (pm->firstdayofweek + d - 1) % 7; 162205821Sedwin if (pdp != NULL) 163205821Sedwin pdp->nextday = pd; 164205821Sedwin } 165205821Sedwin if (pdp == NULL) 166205821Sedwin pm->days = pd; 167205821Sedwin} 168205821Sedwin 169205821Sedwinvoid 170205821Sedwingeneratedates(struct tm *tp1, struct tm *tp2) 171205821Sedwin{ 172205821Sedwin int y1, m1, d1; 173205821Sedwin int y2, m2, d2; 174205821Sedwin int y, m, d; 175205821Sedwin 176205821Sedwin y1 = tp1->tm_year; 177205821Sedwin m1 = tp1->tm_mon + 1; 178205821Sedwin d1 = tp1->tm_mday; 179205821Sedwin y2 = tp2->tm_year; 180205821Sedwin m2 = tp2->tm_mon + 1; 181205821Sedwin d2 = tp2->tm_mday; 182205821Sedwin 183205821Sedwin if (y1 == y2) { 184205821Sedwin if (m1 == m2) { 185205821Sedwin /* Same year, same month. Easy! */ 186205821Sedwin for (d = d1; d <= d2; d++) 187205821Sedwin createdate(y1, m1, d); 188205821Sedwin return; 189205821Sedwin } 190205821Sedwin /* 191205821Sedwin * Same year, different month. 192205821Sedwin * - Take the leftover days from m1 193205821Sedwin * - Take all days from <m1 .. m2> 194205821Sedwin * - Take the first days from m2 195205821Sedwin */ 196205821Sedwin mondays = mondaytab[isleap(y1)]; 197205821Sedwin for (d = d1; d <= mondays[m1]; d++) 198205821Sedwin createdate(y1, m1, d); 199205821Sedwin for (m = m1 + 1; m < m2; m++) 200205821Sedwin for (d = 1; d <= mondays[m]; d++) 201205821Sedwin createdate(y1, m, d); 202205821Sedwin for (d = 1; d <= d2; d++) 203205821Sedwin createdate(y1, m2, d); 204205821Sedwin return; 205205821Sedwin } 206205821Sedwin /* 207205821Sedwin * Different year, different month. 208205821Sedwin * - Take the leftover days from y1-m1 209205821Sedwin * - Take all days from y1-<m1 .. 12] 210205821Sedwin * - Take all days from <y1 .. y2> 211205821Sedwin * - Take all days from y2-[1 .. m2> 212205821Sedwin * - Take the first days of y2-m2 213205821Sedwin */ 214205821Sedwin mondays = mondaytab[isleap(y1)]; 215205821Sedwin for (d = d1; d <= mondays[m1]; d++) 216205821Sedwin createdate(y1, m1, d); 217205821Sedwin for (m = m1 + 1; m <= 12; m++) 218205821Sedwin for (d = 1; d <= mondays[m]; d++) 219205821Sedwin createdate(y1, m, d); 220205821Sedwin for (y = y1 + 1; y < y2; y++) { 221205821Sedwin mondays = mondaytab[isleap(y)]; 222205821Sedwin for (m = 1; m <= 12; m++) 223205821Sedwin for (d = 1; d <= mondays[m]; d++) 224205821Sedwin createdate(y, m, d); 225205821Sedwin } 226205821Sedwin mondays = mondaytab[isleap(y2)]; 227205821Sedwin for (m = 1; m < m2; m++) 228205821Sedwin for (d = 1; d <= mondays[m]; d++) 229205821Sedwin createdate(y2, m, d); 230205821Sedwin for (d = 1; d <= d2; d++) 231205821Sedwin createdate(y2, m2, d); 232205821Sedwin} 233205821Sedwin 234205821Sedwinvoid 235205821Sedwindumpdates(void) 236205821Sedwin{ 237205821Sedwin struct cal_year *y; 238205821Sedwin struct cal_month *m; 239205821Sedwin struct cal_day *d; 240205821Sedwin 241205821Sedwin y = hyear; 242205821Sedwin while (y != NULL) { 243205821Sedwin printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek); 244205821Sedwin m = y->months; 245205821Sedwin while (m != NULL) { 246205821Sedwin printf("-- %-5d (julian:%d, dow:%d)\n", m->month, 247205821Sedwin m->firstdayjulian, m->firstdayofweek); 248205821Sedwin d = m->days; 249205821Sedwin while (d != NULL) { 250205821Sedwin printf(" -- %-5d (julian:%d, dow:%d)\n", 251205821Sedwin d->dayofmonth, d->julianday, d->dayofweek); 252205821Sedwin d = d->nextday; 253205821Sedwin } 254205821Sedwin m = m->nextmonth; 255205821Sedwin } 256205821Sedwin y = y->nextyear; 257205821Sedwin } 258205821Sedwin} 259205821Sedwin 260205821Sedwinint 261205821Sedwinremember_ymd(int yy, int mm, int dd) 262205821Sedwin{ 263205821Sedwin struct cal_year *y; 264205821Sedwin struct cal_month *m; 265205821Sedwin struct cal_day *d; 266205821Sedwin 267205821Sedwin if (debug_remember) 268205821Sedwin printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 269205821Sedwin 270205821Sedwin y = hyear; 271205821Sedwin while (y != NULL) { 272205821Sedwin if (y->year != yy) { 273205821Sedwin y = y->nextyear; 274205821Sedwin continue; 275205821Sedwin } 276205821Sedwin m = y->months; 277205821Sedwin while (m != NULL) { 278205821Sedwin if (m->month != mm) { 279205821Sedwin m = m->nextmonth; 280205821Sedwin continue; 281205821Sedwin } 282205821Sedwin d = m->days; 283205821Sedwin while (d != NULL) { 284205821Sedwin if (d->dayofmonth == dd) 285205821Sedwin return (1); 286205821Sedwin d = d->nextday; 287205821Sedwin continue; 288205821Sedwin } 289205821Sedwin return (0); 290205821Sedwin } 291205821Sedwin return (0); 292205821Sedwin } 293205821Sedwin return (0); 294205821Sedwin} 295205821Sedwin 296205821Sedwinint 297205821Sedwinremember_yd(int yy, int dd, int *rm, int *rd) 298205821Sedwin{ 299205821Sedwin struct cal_year *y; 300205821Sedwin struct cal_month *m; 301205821Sedwin struct cal_day *d; 302205821Sedwin 303205821Sedwin if (debug_remember) 304205821Sedwin printf("remember_yd: %d - %d\n", yy, dd); 305205821Sedwin 306205821Sedwin y = hyear; 307205821Sedwin while (y != NULL) { 308205821Sedwin if (y->year != yy) { 309205821Sedwin y = y->nextyear; 310205821Sedwin continue; 311205821Sedwin } 312205821Sedwin m = y->months; 313205821Sedwin while (m != NULL) { 314205821Sedwin d = m->days; 315205821Sedwin while (d != NULL) { 316205821Sedwin if (d->julianday == dd) { 317205821Sedwin *rm = m->month; 318205821Sedwin *rd = d->dayofmonth; 319205821Sedwin return (1); 320205821Sedwin } 321205821Sedwin d = d->nextday; 322205821Sedwin } 323205821Sedwin m = m->nextmonth; 324205821Sedwin } 325205821Sedwin return (0); 326205821Sedwin } 327205821Sedwin return (0); 328205821Sedwin} 329205821Sedwin 330205821Sedwinint 331205821Sedwinfirst_dayofweek_of_year(int yy) 332205821Sedwin{ 333205821Sedwin struct cal_year *y; 334205821Sedwin 335205821Sedwin y = hyear; 336205821Sedwin while (y != NULL) { 337205821Sedwin if (y->year == yy) 338205821Sedwin return (y->firstdayofweek); 339205821Sedwin y = y->nextyear; 340205821Sedwin } 341205821Sedwin 342205821Sedwin /* Should not happen */ 343205821Sedwin return (-1); 344205821Sedwin} 345205821Sedwin 346205821Sedwinint 347205821Sedwinfirst_dayofweek_of_month(int yy, int mm) 348205821Sedwin{ 349205821Sedwin struct cal_year *y; 350205821Sedwin struct cal_month *m; 351205821Sedwin 352205821Sedwin y = hyear; 353205821Sedwin while (y != NULL) { 354205821Sedwin if (y->year != yy) { 355205821Sedwin y = y->nextyear; 356205821Sedwin continue; 357205821Sedwin } 358205821Sedwin m = y->months; 359205821Sedwin while (m != NULL) { 360205821Sedwin if (m->month == mm) 361205821Sedwin return (m->firstdayofweek); 362205821Sedwin m = m->nextmonth; 363205821Sedwin } 364205821Sedwin /* Should not happen */ 365205821Sedwin return (-1); 366205821Sedwin } 367205821Sedwin 368205821Sedwin /* Should not happen */ 369205821Sedwin return (-1); 370205821Sedwin} 371205821Sedwin 372205821Sedwinint 373205821Sedwinwalkthrough_dates(struct event **e) 374205821Sedwin{ 375205821Sedwin static struct cal_year *y = NULL; 376205821Sedwin static struct cal_month *m = NULL; 377205821Sedwin static struct cal_day *d = NULL; 378205821Sedwin 379205821Sedwin if (y == NULL) { 380205821Sedwin y = hyear; 381205821Sedwin m = y->months; 382205821Sedwin d = m->days; 383205821Sedwin *e = d->events; 384205821Sedwin return (1); 385205821Sedwin }; 386205821Sedwin if (d->nextday != NULL) { 387205821Sedwin d = d->nextday; 388205821Sedwin *e = d->events; 389205821Sedwin return (1); 390205821Sedwin } 391205821Sedwin if (m->nextmonth != NULL) { 392205821Sedwin m = m->nextmonth; 393205821Sedwin d = m->days; 394205821Sedwin *e = d->events; 395205821Sedwin return (1); 396205821Sedwin } 397205821Sedwin if (y->nextyear != NULL) { 398205821Sedwin y = y->nextyear; 399205821Sedwin m = y->months; 400205821Sedwin d = m->days; 401205821Sedwin *e = d->events; 402205821Sedwin return (1); 403205821Sedwin } 404205821Sedwin 405205821Sedwin return (0); 406205821Sedwin} 407205821Sedwin 408205821Sedwinstatic struct cal_day * 409205821Sedwinfind_day(int yy, int mm, int dd) 410205821Sedwin{ 411205821Sedwin struct cal_year *y; 412205821Sedwin struct cal_month *m; 413205821Sedwin struct cal_day *d; 414205821Sedwin 415205821Sedwin if (debug_remember) 416205821Sedwin printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 417205821Sedwin 418205821Sedwin y = hyear; 419205821Sedwin while (y != NULL) { 420205821Sedwin if (y->year != yy) { 421205821Sedwin y = y->nextyear; 422205821Sedwin continue; 423205821Sedwin } 424205821Sedwin m = y->months; 425205821Sedwin while (m != NULL) { 426205821Sedwin if (m->month != mm) { 427205821Sedwin m = m->nextmonth; 428205821Sedwin continue; 429205821Sedwin } 430205821Sedwin d = m->days; 431205821Sedwin while (d != NULL) { 432205821Sedwin if (d->dayofmonth == dd) 433205821Sedwin return (d); 434205821Sedwin d = d->nextday; 435205821Sedwin continue; 436205821Sedwin } 437205821Sedwin return (NULL); 438205821Sedwin } 439205821Sedwin return (NULL); 440205821Sedwin } 441205821Sedwin return (NULL); 442205821Sedwin} 443205821Sedwin 444205821Sedwinvoid 445205821Sedwinaddtodate(struct event *e, int year, int month, int day) 446205821Sedwin{ 447205821Sedwin struct cal_day *d; 448205821Sedwin 449205821Sedwin d = find_day(year, month, day); 450205821Sedwin e->next = d->events; 451205821Sedwin d->events = e; 452205821Sedwin} 453