]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/calendar/dates.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / usr.bin / calendar / dates.c
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 }