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