1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <err.h> 36 #include <time.h> 37 38 #include "calendar.h" 39 40 struct cal_year { 41 int year; /* 19xx, 20xx, 21xx */ 42 int easter; /* Julian day */ 43 int paskha; /* Julian day */ 44 int cny; /* Julian day */ 45 int firstdayofweek; /* 0 .. 6 */ 46 struct cal_month *months; 47 struct cal_year *nextyear; 48 }; 49 50 struct cal_month { 51 int month; /* 01 .. 12 */ 52 int firstdayjulian; /* 000 .. 366 */ 53 int firstdayofweek; /* 0 .. 6 */ 54 struct cal_year *year; /* points back */ 55 struct cal_day *days; 56 struct cal_month *nextmonth; 57 }; 58 59 struct cal_day { 60 int dayofmonth; /* 01 .. 31 */ 61 int julianday; /* 000 .. 366 */ 62 int dayofweek; /* 0 .. 6 */ 63 struct cal_day *nextday; 64 struct cal_month *month; /* points back */ 65 struct cal_year *year; /* points back */ 66 struct event *events; 67 }; 68 69 int debug_remember = 0; 70 static struct cal_year *hyear = NULL; 71 72 /* 1-based month, 0-based days, cumulative */ 73 int cumdaytab[][14] = { 74 {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, 75 {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 76 }; 77 /* 1-based month, individual */ 78 static int *monthdays; 79 int monthdaytab[][14] = { 80 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 81 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, 82 }; 83 84 static struct cal_day * find_day(int yy, int mm, int dd); 85 86 static void 87 createdate(int y, int m, int d) 88 { 89 struct cal_year *py, *pyp; 90 struct cal_month *pm, *pmp; 91 struct cal_day *pd, *pdp; 92 int *cumday; 93 94 pyp = NULL; 95 py = hyear; 96 while (py != NULL) { 97 if (py->year == y + 1900) 98 break; 99 pyp = py; 100 py = py->nextyear; 101 } 102 103 if (py == NULL) { 104 struct tm td; 105 time_t t; 106 py = (struct cal_year *)calloc(1, sizeof(struct cal_year)); 107 py->year = y + 1900; 108 py->easter = easter(y); 109 py->paskha = paskha(y); 110 111 td = tm0; 112 td.tm_year = y; 113 td.tm_mday = 1; 114 t = mktime(&td); 115 localtime_r(&t, &td); 116 py->firstdayofweek = td.tm_wday; 117 118 if (pyp != NULL) 119 pyp->nextyear = py; 120 } 121 if (pyp == NULL) { 122 /* The very very very first one */ 123 hyear = py; 124 } 125 126 pmp = NULL; 127 pm = py->months; 128 while (pm != NULL) { 129 if (pm->month == m) 130 break; 131 pmp = pm; 132 pm = pm->nextmonth; 133 } 134 135 if (pm == NULL) { 136 pm = (struct cal_month *)calloc(1, sizeof(struct cal_month)); 137 pm->year = py; 138 pm->month = m; 139 cumday = cumdaytab[isleap(y)]; 140 pm->firstdayjulian = cumday[m] + 2; 141 pm->firstdayofweek = 142 (py->firstdayofweek + pm->firstdayjulian -1) % 7; 143 if (pmp != NULL) 144 pmp->nextmonth = pm; 145 } 146 if (pmp == NULL) 147 py->months = pm; 148 149 pdp = NULL; 150 pd = pm->days; 151 while (pd != NULL) { 152 pdp = pd; 153 pd = pd->nextday; 154 } 155 156 if (pd == NULL) { /* Always true */ 157 pd = (struct cal_day *)calloc(1, sizeof(struct cal_day)); 158 pd->month = pm; 159 pd->year = py; 160 pd->dayofmonth = d; 161 pd->julianday = pm->firstdayjulian + d - 1; 162 pd->dayofweek = (pm->firstdayofweek + d - 1) % 7; 163 if (pdp != NULL) 164 pdp->nextday = pd; 165 } 166 if (pdp == NULL) 167 pm->days = pd; 168 } 169 170 void 171 generatedates(struct tm *tp1, struct tm *tp2) 172 { 173 int y1, m1, d1; 174 int y2, m2, d2; 175 int y, m, d; 176 177 y1 = tp1->tm_year; 178 m1 = tp1->tm_mon + 1; 179 d1 = tp1->tm_mday; 180 y2 = tp2->tm_year; 181 m2 = tp2->tm_mon + 1; 182 d2 = tp2->tm_mday; 183 184 if (y1 == y2) { 185 if (m1 == m2) { 186 /* Same year, same month. Easy! */ 187 for (d = d1; d <= d2; d++) 188 createdate(y1, m1, d); 189 return; 190 } 191 /* 192 * Same year, different month. 193 * - Take the leftover days from m1 194 * - Take all days from <m1 .. m2> 195 * - Take the first days from m2 196 */ 197 monthdays = monthdaytab[isleap(y1)]; 198 for (d = d1; d <= monthdays[m1]; d++) 199 createdate(y1, m1, d); 200 for (m = m1 + 1; m < m2; m++) 201 for (d = 1; d <= monthdays[m]; d++) 202 createdate(y1, m, d); 203 for (d = 1; d <= d2; d++) 204 createdate(y1, m2, d); 205 return; 206 } 207 /* 208 * Different year, different month. 209 * - Take the leftover days from y1-m1 210 * - Take all days from y1-<m1 .. 12] 211 * - Take all days from <y1 .. y2> 212 * - Take all days from y2-[1 .. m2> 213 * - Take the first days of y2-m2 214 */ 215 monthdays = monthdaytab[isleap(y1)]; 216 for (d = d1; d <= monthdays[m1]; d++) 217 createdate(y1, m1, d); 218 for (m = m1 + 1; m <= 12; m++) 219 for (d = 1; d <= monthdays[m]; d++) 220 createdate(y1, m, d); 221 for (y = y1 + 1; y < y2; y++) { 222 monthdays = monthdaytab[isleap(y)]; 223 for (m = 1; m <= 12; m++) 224 for (d = 1; d <= monthdays[m]; d++) 225 createdate(y, m, d); 226 } 227 monthdays = monthdaytab[isleap(y2)]; 228 for (m = 1; m < m2; m++) 229 for (d = 1; d <= monthdays[m]; d++) 230 createdate(y2, m, d); 231 for (d = 1; d <= d2; d++) 232 createdate(y2, m2, d); 233 } 234 235 void 236 dumpdates(void) 237 { 238 struct cal_year *y; 239 struct cal_month *m; 240 struct cal_day *d; 241 242 y = hyear; 243 while (y != NULL) { 244 printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek); 245 m = y->months; 246 while (m != NULL) { 247 printf("-- %-5d (julian:%d, dow:%d)\n", m->month, 248 m->firstdayjulian, m->firstdayofweek); 249 d = m->days; 250 while (d != NULL) { 251 printf(" -- %-5d (julian:%d, dow:%d)\n", 252 d->dayofmonth, d->julianday, d->dayofweek); 253 d = d->nextday; 254 } 255 m = m->nextmonth; 256 } 257 y = y->nextyear; 258 } 259 } 260 261 int 262 remember_ymd(int yy, int mm, int dd) 263 { 264 struct cal_year *y; 265 struct cal_month *m; 266 struct cal_day *d; 267 268 if (debug_remember) 269 printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 270 271 y = hyear; 272 while (y != NULL) { 273 if (y->year != yy) { 274 y = y->nextyear; 275 continue; 276 } 277 m = y->months; 278 while (m != NULL) { 279 if (m->month != mm) { 280 m = m->nextmonth; 281 continue; 282 } 283 d = m->days; 284 while (d != NULL) { 285 if (d->dayofmonth == dd) 286 return (1); 287 d = d->nextday; 288 continue; 289 } 290 return (0); 291 } 292 return (0); 293 } 294 return (0); 295 } 296 297 int 298 remember_yd(int yy, int dd, int *rm, int *rd) 299 { 300 struct cal_year *y; 301 struct cal_month *m; 302 struct cal_day *d; 303 304 if (debug_remember) 305 printf("remember_yd: %d - %d\n", yy, dd); 306 307 y = hyear; 308 while (y != NULL) { 309 if (y->year != yy) { 310 y = y->nextyear; 311 continue; 312 } 313 m = y->months; 314 while (m != NULL) { 315 d = m->days; 316 while (d != NULL) { 317 if (d->julianday == dd) { 318 *rm = m->month; 319 *rd = d->dayofmonth; 320 return (1); 321 } 322 d = d->nextday; 323 } 324 m = m->nextmonth; 325 } 326 return (0); 327 } 328 return (0); 329 } 330 331 int 332 first_dayofweek_of_year(int yy) 333 { 334 struct cal_year *y; 335 336 y = hyear; 337 while (y != NULL) { 338 if (y->year == yy) 339 return (y->firstdayofweek); 340 y = y->nextyear; 341 } 342 343 /* Should not happen */ 344 return (-1); 345 } 346 347 int 348 first_dayofweek_of_month(int yy, int mm) 349 { 350 struct cal_year *y; 351 struct cal_month *m; 352 353 y = hyear; 354 while (y != NULL) { 355 if (y->year != yy) { 356 y = y->nextyear; 357 continue; 358 } 359 m = y->months; 360 while (m != NULL) { 361 if (m->month == mm) 362 return (m->firstdayofweek); 363 m = m->nextmonth; 364 } 365 /* No data for this month */ 366 return (-1); 367 } 368 369 /* No data for this year. Error? */ 370 return (-1); 371 } 372 373 int 374 walkthrough_dates(struct event **e) 375 { 376 static struct cal_year *y = NULL; 377 static struct cal_month *m = NULL; 378 static struct cal_day *d = NULL; 379 380 if (y == NULL) { 381 y = hyear; 382 m = y->months; 383 d = m->days; 384 *e = d->events; 385 return (1); 386 } 387 if (d->nextday != NULL) { 388 d = d->nextday; 389 *e = d->events; 390 return (1); 391 } 392 if (m->nextmonth != NULL) { 393 m = m->nextmonth; 394 d = m->days; 395 *e = d->events; 396 return (1); 397 } 398 if (y->nextyear != NULL) { 399 y = y->nextyear; 400 m = y->months; 401 d = m->days; 402 *e = d->events; 403 return (1); 404 } 405 406 return (0); 407 } 408 409 static struct cal_day * 410 find_day(int yy, int mm, int dd) 411 { 412 struct cal_year *y; 413 struct cal_month *m; 414 struct cal_day *d; 415 416 if (debug_remember) 417 printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); 418 419 y = hyear; 420 while (y != NULL) { 421 if (y->year != yy) { 422 y = y->nextyear; 423 continue; 424 } 425 m = y->months; 426 while (m != NULL) { 427 if (m->month != mm) { 428 m = m->nextmonth; 429 continue; 430 } 431 d = m->days; 432 while (d != NULL) { 433 if (d->dayofmonth == dd) 434 return (d); 435 d = d->nextday; 436 continue; 437 } 438 return (NULL); 439 } 440 return (NULL); 441 } 442 return (NULL); 443 } 444 445 void 446 addtodate(struct event *e, int year, int month, int day) 447 { 448 struct cal_day *d; 449 450 d = find_day(year, month, day); 451 e->next = d->events; 452 d->events = e; 453 } 454