dates.c revision 330449
1139749Simp/*- 2126177Srik * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3126177Srik * 4126177Srik * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>. 5126177Srik * All rights reserved. 6126177Srik * 7126177Srik * Redistribution and use in source and binary forms, with or without 8126177Srik * modification, are permitted provided that the following conditions 9126177Srik * are met: 10126177Srik * 1. Redistributions of source code must retain the above copyright 11126177Srik * notice, this list of conditions and the following disclaimer. 12126177Srik * 2. Redistributions in binary form must reproduce the above copyright 13126177Srik * notice, this list of conditions and the following disclaimer in the 14126177Srik * documentation and/or other materials provided with the distribution. 15126177Srik * 16126177Srik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17126177Srik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18126177Srik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19126177Srik * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20126177Srik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21126177Srik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22126177Srik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23126177Srik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24126177Srik * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25126177Srik * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26126177Srik * SUCH DAMAGE. 27126177Srik * 28126177Srik */ 29126177Srik 30126177Srik#include <sys/cdefs.h> 31126177Srik__FBSDID("$FreeBSD: stable/11/usr.bin/calendar/dates.c 330449 2018-03-05 07:26:05Z eadler $"); 32126177Srik 33126177Srik#include <stdio.h> 34126177Srik#include <stdlib.h> 35126177Srik#include <err.h> 36126177Srik#include <time.h> 37126177Srik 38126177Srik#include "calendar.h" 39126177Srik 40126177Srikstruct cal_year { 41126177Srik int year; /* 19xx, 20xx, 21xx */ 42126177Srik int easter; /* Julian day */ 43126177Srik int paskha; /* Julian day */ 44126177Srik int cny; /* Julian day */ 45126177Srik int firstdayofweek; /* 0 .. 6 */ 46126177Srik struct cal_month *months; 47126177Srik struct cal_year *nextyear; 48126177Srik}; 49126177Srik 50126177Srikstruct cal_month { 51126177Srik int month; /* 01 .. 12 */ 52126177Srik int firstdayjulian; /* 000 .. 366 */ 53126177Srik int firstdayofweek; /* 0 .. 6 */ 54126177Srik struct cal_year *year; /* points back */ 55126177Srik struct cal_day *days; 56126177Srik struct cal_month *nextmonth; 57126177Srik}; 58126177Srik 59126177Srikstruct cal_day { 60126177Srik int dayofmonth; /* 01 .. 31 */ 61126177Srik int julianday; /* 000 .. 366 */ 62126177Srik int dayofweek; /* 0 .. 6 */ 63126177Srik struct cal_day *nextday; 64126177Srik struct cal_month *month; /* points back */ 65126177Srik struct cal_year *year; /* points back */ 66126177Srik struct event *events; 67126177Srik}; 68126177Srik 69126177Srikint debug_remember = 0; 70126177Srikstatic struct cal_year *hyear = NULL; 71126177Srik 72126177Srik/* 1-based month, 0-based days, cumulative */ 73126177Srikint cumdaytab[][14] = { 74126177Srik {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, 75126177Srik {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 76126177Srik}; 77126177Srik/* 1-based month, individual */ 78126177Srikstatic int *monthdays; 79126177Srikint monthdaytab[][14] = { 80126177Srik {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 81126177Srik {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 82126177Srik}; 83126177Srik 84126177Srikstatic struct cal_day * find_day(int yy, int mm, int dd); 85126177Srik 86126177Srikstatic void 87126177Srikcreatedate(int y, int m, int d) 88126177Srik{ 89126177Srik struct cal_year *py, *pyp; 90126177Srik struct cal_month *pm, *pmp; 91126177Srik struct cal_day *pd, *pdp; 92126177Srik int *cumday; 93126177Srik 94126177Srik pyp = NULL; 95126177Srik py = hyear; 96126177Srik while (py != NULL) { 97126177Srik if (py->year == y + 1900) 98126177Srik break; 99126177Srik pyp = py; 100126177Srik py = py->nextyear; 101126177Srik } 102126177Srik 103126177Srik if (py == NULL) { 104126177Srik struct tm td; 105126177Srik time_t t; 106126177Srik py = (struct cal_year *)calloc(1, sizeof(struct cal_year)); 107315221Spfg py->year = y + 1900; 108126177Srik py->easter = easter(y); 109126177Srik py->paskha = paskha(y); 110126177Srik 111126177Srik td = tm0; 112126177Srik td.tm_year = y; 113126177Srik td.tm_mday = 1; 114126177Srik t = mktime(&td); 115126177Srik localtime_r(&t, &td); 116126177Srik py->firstdayofweek = td.tm_wday; 117126177Srik 118126177Srik if (pyp != NULL) 119126177Srik pyp->nextyear = py; 120126177Srik } 121126177Srik if (pyp == NULL) { 122126177Srik /* The very very very first one */ 123126177Srik hyear = py; 124126177Srik } 125126177Srik 126126177Srik pmp = NULL; 127126177Srik pm = py->months; 128126177Srik while (pm != NULL) { 129126177Srik if (pm->month == m) 130126177Srik break; 131126177Srik pmp = pm; 132126177Srik pm = pm->nextmonth; 133126177Srik } 134126177Srik 135126177Srik if (pm == NULL) { 136126177Srik pm = (struct cal_month *)calloc(1, sizeof(struct cal_month)); 137126177Srik pm->year = py; 138126177Srik pm->month = m; 139126177Srik cumday = cumdaytab[isleap(y)]; 140126177Srik pm->firstdayjulian = cumday[m] + 2; 141126177Srik pm->firstdayofweek = 142126177Srik (py->firstdayofweek + pm->firstdayjulian -1) % 7; 143126177Srik if (pmp != NULL) 144126177Srik pmp->nextmonth = pm; 145126177Srik } 146126177Srik if (pmp == NULL) 147126177Srik py->months = pm; 148126177Srik 149126177Srik pdp = NULL; 150126177Srik pd = pm->days; 151126177Srik while (pd != NULL) { 152126177Srik pdp = pd; 153126177Srik pd = pd->nextday; 154126177Srik } 155126177Srik 156126177Srik if (pd == NULL) { /* Always true */ 157126177Srik pd = (struct cal_day *)calloc(1, sizeof(struct cal_day)); 158126177Srik pd->month = pm; 159126177Srik pd->year = py; 160126177Srik pd->dayofmonth = d; 161126177Srik pd->julianday = pm->firstdayjulian + d - 1; 162126177Srik pd->dayofweek = (pm->firstdayofweek + d - 1) % 7; 163126177Srik if (pdp != NULL) 164126177Srik pdp->nextday = pd; 165126177Srik } 166126177Srik if (pdp == NULL) 167126177Srik pm->days = pd; 168126177Srik} 169126177Srik 170126177Srikvoid 171126177Srikgeneratedates(struct tm *tp1, struct tm *tp2) 172126177Srik{ 173126177Srik int y1, m1, d1; 174126177Srik int y2, m2, d2; 175126177Srik int y, m, d; 176126177Srik 177126177Srik y1 = tp1->tm_year; 178126177Srik m1 = tp1->tm_mon + 1; 179126177Srik d1 = tp1->tm_mday; 180126177Srik y2 = tp2->tm_year; 181126177Srik m2 = tp2->tm_mon + 1; 182126177Srik d2 = tp2->tm_mday; 183126177Srik 184126177Srik if (y1 == y2) { 185126177Srik if (m1 == m2) { 186126177Srik /* Same year, same month. Easy! */ 187126177Srik for (d = d1; d <= d2; d++) 188126177Srik createdate(y1, m1, d); 189126177Srik return; 190126177Srik } 191126177Srik /* 192126177Srik * Same year, different month. 193126177Srik * - Take the leftover days from m1 194126177Srik * - Take all days from <m1 .. m2> 195126177Srik * - Take the first days from m2 196126177Srik */ 197126177Srik monthdays = monthdaytab[isleap(y1)]; 198126177Srik for (d = d1; d <= monthdays[m1]; d++) 199126177Srik createdate(y1, m1, d); 200126177Srik for (m = m1 + 1; m < m2; m++) 201126177Srik for (d = 1; d <= monthdays[m]; d++) 202126177Srik createdate(y1, m, d); 203126177Srik for (d = 1; d <= d2; d++) 204126177Srik createdate(y1, m2, d); 205126177Srik return; 206126177Srik } 207126177Srik /* 208126177Srik * Different year, different month. 209126177Srik * - Take the leftover days from y1-m1 210126177Srik * - Take all days from y1-<m1 .. 12] 211126177Srik * - Take all days from <y1 .. y2> 212126177Srik * - Take all days from y2-[1 .. m2> 213126177Srik * - Take the first days of y2-m2 214126177Srik */ 215126177Srik monthdays = monthdaytab[isleap(y1)]; 216126177Srik for (d = d1; d <= monthdays[m1]; d++) 217126177Srik createdate(y1, m1, d); 218126177Srik for (m = m1 + 1; m <= 12; m++) 219126177Srik for (d = 1; d <= monthdays[m]; d++) 220126177Srik createdate(y1, m, d); 221126177Srik for (y = y1 + 1; y < y2; y++) { 222126177Srik monthdays = monthdaytab[isleap(y)]; 223126177Srik for (m = 1; m <= 12; m++) 224126177Srik for (d = 1; d <= monthdays[m]; d++) 225126177Srik createdate(y, m, d); 226126177Srik } 227126177Srik monthdays = monthdaytab[isleap(y2)]; 228126177Srik for (m = 1; m < m2; m++) 229126177Srik for (d = 1; d <= monthdays[m]; d++) 230126177Srik createdate(y2, m, d); 231126177Srik for (d = 1; d <= d2; d++) 232126177Srik createdate(y2, m2, d); 233126177Srik} 234126177Srik 235126177Srikvoid 236126177Srikdumpdates(void) 237126177Srik{ 238126177Srik struct cal_year *y; 239126177Srik struct cal_month *m; 240126177Srik struct cal_day *d; 241126177Srik 242126177Srik y = hyear; 243126177Srik while (y != NULL) { 244126177Srik printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek); 245126177Srik m = y->months; 246126177Srik while (m != NULL) { 247126177Srik printf("-- %-5d (julian:%d, dow:%d)\n", m->month, 248126177Srik m->firstdayjulian, m->firstdayofweek); 249126177Srik d = m->days; 250126177Srik while (d != NULL) { 251126177Srik printf(" -- %-5d (julian:%d, dow:%d)\n", 252126177Srik d->dayofmonth, d->julianday, d->dayofweek); 253126177Srik d = d->nextday; 254126177Srik } 255126177Srik m = m->nextmonth; 256126177Srik } 257126177Srik y = y->nextyear; 258126177Srik } 259126177Srik} 260126177Srik 261126177Srikint 262126177Srikremember_ymd(int yy, int mm, int dd) 263126177Srik{ 264126177Srik struct cal_year *y; 265126177Srik struct cal_month *m; 266126177Srik struct cal_day *d; 267126177Srik 268126177Srik if (debug_remember) 269126177Srik printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 270126177Srik 271126177Srik y = hyear; 272126177Srik while (y != NULL) { 273126177Srik if (y->year != yy) { 274126177Srik y = y->nextyear; 275126177Srik continue; 276126177Srik } 277126177Srik m = y->months; 278126177Srik while (m != NULL) { 279126177Srik if (m->month != mm) { 280126177Srik m = m->nextmonth; 281126177Srik continue; 282126177Srik } 283126177Srik d = m->days; 284126177Srik while (d != NULL) { 285126177Srik if (d->dayofmonth == dd) 286126177Srik return (1); 287126177Srik d = d->nextday; 288126177Srik continue; 289126177Srik } 290126177Srik return (0); 291126177Srik } 292126177Srik return (0); 293126177Srik } 294126177Srik return (0); 295126177Srik} 296126177Srik 297126177Srikint 298126177Srikremember_yd(int yy, int dd, int *rm, int *rd) 299126177Srik{ 300126177Srik struct cal_year *y; 301126177Srik struct cal_month *m; 302126177Srik struct cal_day *d; 303126177Srik 304126177Srik if (debug_remember) 305126177Srik printf("remember_yd: %d - %d\n", yy, dd); 306126177Srik 307126177Srik y = hyear; 308126177Srik while (y != NULL) { 309126177Srik if (y->year != yy) { 310126177Srik y = y->nextyear; 311126177Srik continue; 312126177Srik } 313126177Srik m = y->months; 314126177Srik while (m != NULL) { 315126177Srik d = m->days; 316126177Srik while (d != NULL) { 317126177Srik if (d->julianday == dd) { 318126177Srik *rm = m->month; 319126177Srik *rd = d->dayofmonth; 320126177Srik return (1); 321126177Srik } 322126177Srik d = d->nextday; 323126177Srik } 324126177Srik m = m->nextmonth; 325126177Srik } 326126177Srik return (0); 327126177Srik } 328126177Srik return (0); 329126177Srik} 330126177Srik 331126177Srikint 332126177Srikfirst_dayofweek_of_year(int yy) 333126177Srik{ 334126177Srik struct cal_year *y; 335126177Srik 336126177Srik y = hyear; 337126177Srik while (y != NULL) { 338126177Srik if (y->year == yy) 339126177Srik return (y->firstdayofweek); 340126177Srik y = y->nextyear; 341126177Srik } 342126177Srik 343126177Srik /* Should not happen */ 344126177Srik return (-1); 345126177Srik} 346126177Srik 347126177Srikint 348126177Srikfirst_dayofweek_of_month(int yy, int mm) 349126177Srik{ 350126177Srik struct cal_year *y; 351126177Srik struct cal_month *m; 352126177Srik 353126177Srik y = hyear; 354126177Srik while (y != NULL) { 355126177Srik if (y->year != yy) { 356126177Srik y = y->nextyear; 357126177Srik continue; 358126177Srik } 359126177Srik m = y->months; 360126177Srik while (m != NULL) { 361126177Srik if (m->month == mm) 362126177Srik return (m->firstdayofweek); 363126177Srik m = m->nextmonth; 364126177Srik } 365126177Srik /* No data for this month */ 366126177Srik return (-1); 367126177Srik } 368126177Srik 369126177Srik /* No data for this year. Error? */ 370126177Srik return (-1); 371126177Srik} 372126177Srik 373126177Srikint 374126177Srikwalkthrough_dates(struct event **e) 375126177Srik{ 376126177Srik static struct cal_year *y = NULL; 377126177Srik static struct cal_month *m = NULL; 378126177Srik static struct cal_day *d = NULL; 379126177Srik 380126177Srik if (y == NULL) { 381126177Srik y = hyear; 382126177Srik m = y->months; 383126177Srik d = m->days; 384126177Srik *e = d->events; 385126177Srik return (1); 386126177Srik } 387126177Srik if (d->nextday != NULL) { 388126177Srik d = d->nextday; 389126177Srik *e = d->events; 390126177Srik return (1); 391126177Srik } 392126177Srik if (m->nextmonth != NULL) { 393126177Srik m = m->nextmonth; 394126177Srik d = m->days; 395126177Srik *e = d->events; 396126177Srik return (1); 397126177Srik } 398126177Srik if (y->nextyear != NULL) { 399126177Srik y = y->nextyear; 400126177Srik m = y->months; 401126177Srik d = m->days; 402126177Srik *e = d->events; 403126177Srik return (1); 404126177Srik } 405126177Srik 406126177Srik return (0); 407126177Srik} 408126177Srik 409126177Srikstatic struct cal_day * 410126177Srikfind_day(int yy, int mm, int dd) 411126177Srik{ 412126177Srik struct cal_year *y; 413126177Srik struct cal_month *m; 414126177Srik struct cal_day *d; 415126177Srik 416126177Srik if (debug_remember) 417126177Srik printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 418126177Srik 419126177Srik y = hyear; 420126177Srik while (y != NULL) { 421126177Srik if (y->year != yy) { 422126177Srik y = y->nextyear; 423126177Srik continue; 424126177Srik } 425126177Srik m = y->months; 426126177Srik while (m != NULL) { 427126177Srik if (m->month != mm) { 428126177Srik m = m->nextmonth; 429126177Srik continue; 430126177Srik } 431126177Srik d = m->days; 432126177Srik while (d != NULL) { 433126177Srik if (d->dayofmonth == dd) 434126177Srik return (d); 435126177Srik d = d->nextday; 436126177Srik continue; 437126177Srik } 438126177Srik return (NULL); 439126177Srik } 440126177Srik return (NULL); 441126177Srik } 442126177Srik return (NULL); 443126177Srik} 444126177Srik 445126177Srikvoid 446126177Srikaddtodate(struct event *e, int year, int month, int day) 447126177Srik{ 448126177Srik struct cal_day *d; 449126177Srik 450126177Srik d = find_day(year, month, day); 451126177Srik e->next = d->events; 452126177Srik d->events = e; 453126177Srik} 454126177Srik