dates.c revision 251647
1193326Sed/*- 2193326Sed * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>. 3193326Sed * All rights reserved. 4193326Sed * 5193326Sed * Redistribution and use in source and binary forms, with or without 6193326Sed * modification, are permitted provided that the following conditions 7193326Sed * are met: 8193326Sed * 1. Redistributions of source code must retain the above copyright 9193326Sed * notice, this list of conditions and the following disclaimer. 10193326Sed * 2. Redistributions in binary form must reproduce the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer in the 12193326Sed * documentation and/or other materials provided with the distribution. 13193326Sed * 14193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17249423Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19249423Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20263508Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193326Sed * SUCH DAMAGE. 25249423Sdim * 26218893Sdim */ 27263508Sdim 28193326Sed#include <sys/cdefs.h> 29249423Sdim__FBSDID("$FreeBSD: head/usr.bin/calendar/dates.c 251647 2013-06-12 07:52:49Z grog $"); 30224145Sdim 31193326Sed#include <stdio.h> 32193326Sed#include <stdlib.h> 33249423Sdim#include <err.h> 34193326Sed#include <time.h> 35193326Sed 36193326Sed#include "calendar.h" 37193326Sed 38198092Srdivackystruct cal_year { 39207619Srdivacky int year; /* 19xx, 20xx, 21xx */ 40193326Sed int easter; /* Julian day */ 41193326Sed int paskha; /* Julian day */ 42198398Srdivacky int cny; /* Julian day */ 43193326Sed int firstdayofweek; /* 0 .. 6 */ 44210299Sed struct cal_month *months; 45193326Sed struct cal_year *nextyear; 46193326Sed}; 47193326Sed 48193326Sedstruct cal_month { 49234353Sdim int month; /* 01 .. 12 */ 50193326Sed int firstdayjulian; /* 000 .. 366 */ 51221345Sdim int firstdayofweek; /* 0 .. 6 */ 52198092Srdivacky struct cal_year *year; /* points back */ 53193326Sed struct cal_day *days; 54218893Sdim struct cal_month *nextmonth; 55193326Sed}; 56193326Sed 57193326Sedstruct cal_day { 58193326Sed int dayofmonth; /* 01 .. 31 */ 59193326Sed int julianday; /* 000 .. 366 */ 60193326Sed int dayofweek; /* 0 .. 6 */ 61193326Sed struct cal_day *nextday; 62193326Sed struct cal_month *month; /* points back */ 63193326Sed struct cal_year *year; /* points back */ 64193326Sed struct event *events; 65193326Sed}; 66204643Srdivacky 67193326Sedint debug_remember = 0; 68193326Sedstatic struct cal_year *hyear = NULL; 69193326Sed 70193326Sed/* 1-based month, 0-based days, cumulative */ 71193326Sedint cumdaytab[][14] = { 72224145Sdim {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, 73193326Sed {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 74193326Sed}; 75193326Sed/* 1-based month, individual */ 76193326Sedstatic int *monthdays; 77193326Sedint monthdaytab[][14] = { 78208600Srdivacky {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 79212904Sdim {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 80218893Sdim}; 81218893Sdim 82193326Sedstatic struct cal_day * find_day(int yy, int mm, int dd); 83249423Sdim 84249423Sdimstatic void 85249423Sdimcreatedate(int y, int m, int d) 86249423Sdim{ 87249423Sdim struct cal_year *py, *pyp; 88249423Sdim struct cal_month *pm, *pmp; 89249423Sdim struct cal_day *pd, *pdp; 90249423Sdim int *cumday; 91249423Sdim 92249423Sdim pyp = NULL; 93249423Sdim py = hyear; 94193326Sed while (py != NULL) { 95193326Sed if (py->year == y + 1900) 96218893Sdim break; 97243830Sdim pyp = py; 98243830Sdim py = py->nextyear; 99212904Sdim } 100212904Sdim 101193326Sed if (py == NULL) { 102212904Sdim struct tm td; 103212904Sdim time_t t; 104210299Sed py = (struct cal_year *)calloc(1, sizeof(struct cal_year)); 105212904Sdim py->year = y + 1900; 106212904Sdim py->easter = easter(y); 107212904Sdim py->paskha = paskha(y); 108212904Sdim 109212904Sdim td = tm0; 110212904Sdim td.tm_year = y; 111212904Sdim td.tm_mday = 1; 112212904Sdim t = mktime(&td); 113212904Sdim localtime_r(&t, &td); 114212904Sdim py->firstdayofweek = td.tm_wday; 115218893Sdim 116249423Sdim if (pyp != NULL) 117249423Sdim pyp->nextyear = py; 118249423Sdim } 119249423Sdim if (pyp == NULL) { 120249423Sdim /* The very very very first one */ 121212904Sdim hyear = py; 122210299Sed } 123210299Sed 124212904Sdim pmp = NULL; 125210299Sed pm = py->months; 126210299Sed while (pm != NULL) { 127193326Sed if (pm->month == m) 128199482Srdivacky break; 129193326Sed pmp = pm; 130193326Sed pm = pm->nextmonth; 131193326Sed } 132193326Sed 133251662Sdim if (pm == NULL) { 134251662Sdim pm = (struct cal_month *)calloc(1, sizeof(struct cal_month)); 135193326Sed pm->year = py; 136193326Sed pm->month = m; 137193326Sed cumday = cumdaytab[isleap(y)]; 138193326Sed pm->firstdayjulian = cumday[m] + 2; 139193326Sed pm->firstdayofweek = 140193326Sed (py->firstdayofweek + pm->firstdayjulian -1) % 7; 141193326Sed if (pmp != NULL) 142200583Srdivacky pmp->nextmonth = pm; 143200583Srdivacky } 144200583Srdivacky if (pmp == NULL) 145224145Sdim py->months = pm; 146224145Sdim 147224145Sdim pdp = NULL; 148224145Sdim pd = pm->days; 149193326Sed while (pd != NULL) { 150210299Sed pdp = pd; 151210299Sed pd = pd->nextday; 152193326Sed } 153193326Sed 154200583Srdivacky if (pd == NULL) { /* Always true */ 155193326Sed pd = (struct cal_day *)calloc(1, sizeof(struct cal_day)); 156193326Sed pd->month = pm; 157193326Sed pd->year = py; 158193326Sed pd->dayofmonth = d; 159193326Sed pd->julianday = pm->firstdayjulian + d - 1; 160263508Sdim pd->dayofweek = (pm->firstdayofweek + d - 1) % 7; 161263508Sdim if (pdp != NULL) 162263508Sdim pdp->nextday = pd; 163263508Sdim } 164263508Sdim if (pdp == NULL) 165263508Sdim pm->days = pd; 166263508Sdim} 167263508Sdim 168263508Sdimvoid 169263508Sdimgeneratedates(struct tm *tp1, struct tm *tp2) 170263508Sdim{ 171263508Sdim int y1, m1, d1; 172263508Sdim int y2, m2, d2; 173263508Sdim int y, m, d; 174263508Sdim 175263508Sdim y1 = tp1->tm_year; 176263508Sdim m1 = tp1->tm_mon + 1; 177263508Sdim d1 = tp1->tm_mday; 178263508Sdim y2 = tp2->tm_year; 179263508Sdim m2 = tp2->tm_mon + 1; 180263508Sdim d2 = tp2->tm_mday; 181263508Sdim 182263508Sdim if (y1 == y2) { 183263508Sdim if (m1 == m2) { 184263508Sdim /* Same year, same month. Easy! */ 185263508Sdim for (d = d1; d <= d2; d++) 186263508Sdim createdate(y1, m1, d); 187263508Sdim return; 188263508Sdim } 189263508Sdim /* 190263508Sdim * Same year, different month. 191263508Sdim * - Take the leftover days from m1 192263508Sdim * - Take all days from <m1 .. m2> 193263508Sdim * - Take the first days from m2 194263508Sdim */ 195263508Sdim monthdays = monthdaytab[isleap(y1)]; 196263508Sdim for (d = d1; d <= monthdays[m1]; d++) 197263508Sdim createdate(y1, m1, d); 198263508Sdim for (m = m1 + 1; m < m2; m++) 199263508Sdim for (d = 1; d <= monthdays[m]; d++) 200263508Sdim createdate(y1, m, d); 201263508Sdim for (d = 1; d <= d2; d++) 202263508Sdim createdate(y1, m2, d); 203263508Sdim return; 204263508Sdim } 205263508Sdim /* 206263508Sdim * Different year, different month. 207263508Sdim * - Take the leftover days from y1-m1 208263508Sdim * - Take all days from y1-<m1 .. 12] 209263508Sdim * - Take all days from <y1 .. y2> 210263508Sdim * - Take all days from y2-[1 .. m2> 211263508Sdim * - Take the first days of y2-m2 212263508Sdim */ 213263508Sdim monthdays = monthdaytab[isleap(y1)]; 214263508Sdim for (d = d1; d <= monthdays[m1]; d++) 215263508Sdim createdate(y1, m1, d); 216263508Sdim for (m = m1 + 1; m <= 12; m++) 217263508Sdim for (d = 1; d <= monthdays[m]; d++) 218263508Sdim createdate(y1, m, d); 219239462Sdim for (y = y1 + 1; y < y2; y++) { 220239462Sdim monthdays = monthdaytab[isleap(y)]; 221239462Sdim for (m = 1; m <= 12; m++) 222239462Sdim for (d = 1; d <= monthdays[m]; d++) 223243830Sdim createdate(y, m, d); 224243830Sdim } 225243830Sdim monthdays = monthdaytab[isleap(y2)]; 226193326Sed for (m = 1; m < m2; m++) 227249423Sdim for (d = 1; d <= monthdays[m]; d++) 228249423Sdim createdate(y2, m, d); 229249423Sdim for (d = 1; d <= d2; d++) 230224145Sdim createdate(y2, m2, d); 231224145Sdim} 232224145Sdim 233218893Sdimvoid 234218893Sdimdumpdates(void) 235218893Sdim{ 236234353Sdim struct cal_year *y; 237234353Sdim struct cal_month *m; 238234353Sdim struct cal_day *d; 239208600Srdivacky 240208600Srdivacky y = hyear; 241208600Srdivacky while (y != NULL) { 242193326Sed printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek); 243210299Sed m = y->months; 244263508Sdim while (m != NULL) { 245193326Sed printf("-- %-5d (julian:%d, dow:%d)\n", m->month, 246263508Sdim m->firstdayjulian, m->firstdayofweek); 247263508Sdim d = m->days; 248263508Sdim while (d != NULL) { 249263508Sdim printf(" -- %-5d (julian:%d, dow:%d)\n", 250263508Sdim d->dayofmonth, d->julianday, d->dayofweek); 251263508Sdim d = d->nextday; 252263508Sdim } 253263508Sdim m = m->nextmonth; 254263508Sdim } 255263508Sdim y = y->nextyear; 256263508Sdim } 257212904Sdim} 258212904Sdim 259212904Sdimint 260212904Sdimremember_ymd(int yy, int mm, int dd) 261212904Sdim{ 262234353Sdim struct cal_year *y; 263234353Sdim struct cal_month *m; 264234353Sdim struct cal_day *d; 265226633Sdim 266226633Sdim if (debug_remember) 267226633Sdim printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 268226633Sdim 269226633Sdim y = hyear; 270210299Sed while (y != NULL) { 271193326Sed if (y->year != yy) { 272226633Sdim y = y->nextyear; 273226633Sdim continue; 274223017Sdim } 275223017Sdim m = y->months; 276210299Sed while (m != NULL) { 277210299Sed if (m->month != mm) { 278193326Sed m = m->nextmonth; 279210299Sed continue; 280193326Sed } 281218893Sdim d = m->days; 282218893Sdim while (d != NULL) { 283218893Sdim if (d->dayofmonth == dd) 284218893Sdim return (1); 285218893Sdim d = d->nextday; 286210299Sed continue; 287210299Sed } 288210299Sed return (0); 289226633Sdim } 290200583Srdivacky return (0); 291224145Sdim } 292224145Sdim return (0); 293224145Sdim} 294224145Sdim 295224145Sdimint 296224145Sdimremember_yd(int yy, int dd, int *rm, int *rd) 297224145Sdim{ 298224145Sdim struct cal_year *y; 299224145Sdim struct cal_month *m; 300224145Sdim struct cal_day *d; 301224145Sdim 302224145Sdim if (debug_remember) 303224145Sdim printf("remember_yd: %d - %d\n", yy, dd); 304224145Sdim 305224145Sdim y = hyear; 306224145Sdim while (y != NULL) { 307224145Sdim if (y->year != yy) { 308224145Sdim y = y->nextyear; 309224145Sdim continue; 310224145Sdim } 311224145Sdim m = y->months; 312193326Sed while (m != NULL) { 313193326Sed d = m->days; 314218893Sdim while (d != NULL) { 315218893Sdim if (d->julianday == dd) { 316218893Sdim *rm = m->month; 317218893Sdim *rd = d->dayofmonth; 318218893Sdim return (1); 319218893Sdim } 320218893Sdim d = d->nextday; 321224145Sdim } 322224145Sdim m = m->nextmonth; 323218893Sdim } 324218893Sdim return (0); 325218893Sdim } 326218893Sdim return (0); 327218893Sdim} 328218893Sdim 329218893Sdimint 330218893Sdimfirst_dayofweek_of_year(int yy) 331218893Sdim{ 332218893Sdim struct cal_year *y; 333218893Sdim 334218893Sdim y = hyear; 335218893Sdim while (y != NULL) { 336218893Sdim if (y->year == yy) 337218893Sdim return (y->firstdayofweek); 338224145Sdim y = y->nextyear; 339224145Sdim } 340218893Sdim 341218893Sdim /* Should not happen */ 342218893Sdim return (-1); 343218893Sdim} 344218893Sdim 345218893Sdimint 346218893Sdimfirst_dayofweek_of_month(int yy, int mm) 347218893Sdim{ 348218893Sdim struct cal_year *y; 349224145Sdim struct cal_month *m; 350224145Sdim 351224145Sdim y = hyear; 352224145Sdim while (y != NULL) { 353224145Sdim if (y->year != yy) { 354224145Sdim y = y->nextyear; 355224145Sdim continue; 356224145Sdim } 357224145Sdim m = y->months; 358224145Sdim while (m != NULL) { 359224145Sdim if (m->month == mm) 360224145Sdim return (m->firstdayofweek); 361224145Sdim m = m->nextmonth; 362224145Sdim } 363224145Sdim /* No data for this month */ 364224145Sdim return (-1); 365224145Sdim } 366224145Sdim 367224145Sdim /* No data for this year. Error? */ 368224145Sdim return (-1); 369224145Sdim} 370224145Sdim 371224145Sdimint 372224145Sdimwalkthrough_dates(struct event **e) 373224145Sdim{ 374224145Sdim static struct cal_year *y = NULL; 375224145Sdim static struct cal_month *m = NULL; 376224145Sdim static struct cal_day *d = NULL; 377224145Sdim 378224145Sdim if (y == NULL) { 379224145Sdim y = hyear; 380224145Sdim m = y->months; 381224145Sdim d = m->days; 382224145Sdim *e = d->events; 383224145Sdim return (1); 384224145Sdim }; 385224145Sdim if (d->nextday != NULL) { 386224145Sdim d = d->nextday; 387224145Sdim *e = d->events; 388224145Sdim return (1); 389224145Sdim } 390224145Sdim if (m->nextmonth != NULL) { 391263508Sdim m = m->nextmonth; 392263508Sdim d = m->days; 393263508Sdim *e = d->events; 394263508Sdim return (1); 395263508Sdim } 396263508Sdim if (y->nextyear != NULL) { 397263508Sdim y = y->nextyear; 398263508Sdim m = y->months; 399263508Sdim d = m->days; 400263508Sdim *e = d->events; 401263508Sdim return (1); 402263508Sdim } 403263508Sdim 404263508Sdim return (0); 405263508Sdim} 406263508Sdim 407263508Sdimstatic struct cal_day * 408234353Sdimfind_day(int yy, int mm, int dd) 409234353Sdim{ 410234353Sdim struct cal_year *y; 411234353Sdim struct cal_month *m; 412210299Sed struct cal_day *d; 413210299Sed 414210299Sed if (debug_remember) 415210299Sed printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 416210299Sed 417193326Sed y = hyear; 418212904Sdim while (y != NULL) { 419212904Sdim if (y->year != yy) { 420212904Sdim y = y->nextyear; 421212904Sdim continue; 422212904Sdim } 423212904Sdim m = y->months; 424210299Sed while (m != NULL) { 425210299Sed if (m->month != mm) { 426263508Sdim m = m->nextmonth; 427210299Sed continue; 428218893Sdim } 429218893Sdim d = m->days; 430218893Sdim while (d != NULL) { 431234353Sdim if (d->dayofmonth == dd) 432234353Sdim return (d); 433234353Sdim d = d->nextday; 434234353Sdim continue; 435234353Sdim } 436234353Sdim return (NULL); 437234353Sdim } 438193326Sed return (NULL); 439218893Sdim } 440218893Sdim return (NULL); 441234353Sdim} 442234353Sdim 443234353Sdimvoid 444234353Sdimaddtodate(struct event *e, int year, int month, int day) 445234353Sdim{ 446234353Sdim struct cal_day *d; 447234353Sdim 448218893Sdim d = find_day(year, month, day); 449210299Sed e->next = d->events; 450210299Sed d->events = e; 451210299Sed} 452210299Sed