]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/calendar/dates.c
trim(8): Fix a few issues reported by mandoc
[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         struct event *lastevent;
68 };
69
70 int debug_remember = 0;
71 static struct cal_year *hyear = NULL;
72
73 /* 1-based month, 0-based days, cumulative */
74 int     cumdaytab[][14] = {
75         {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
76         {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
77 };
78 /* 1-based month, individual */
79 static int *monthdays;
80 int     monthdaytab[][14] = {
81         {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
82         {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30},
83 };
84
85 static struct cal_day * find_day(int yy, int mm, int dd);
86
87 static void
88 createdate(int y, int m, int d)
89 {
90         struct cal_year *py, *pyp;
91         struct cal_month *pm, *pmp;
92         struct cal_day *pd, *pdp;
93         int *cumday;
94
95         pyp = NULL;
96         py = hyear;
97         while (py != NULL) {
98                 if (py->year == y + 1900)
99                         break;
100                 pyp = py;
101                 py = py->nextyear;
102         }
103
104         if (py == NULL) {
105                 struct tm td;
106                 time_t t;
107                 py = (struct cal_year *)calloc(1, sizeof(struct cal_year));
108                 py->year = y + 1900;
109                 py->easter = easter(y);
110                 py->paskha = paskha(y);
111
112                 td = tm0;
113                 td.tm_year = y;
114                 td.tm_mday = 1;
115                 t = mktime(&td);
116                 localtime_r(&t, &td);
117                 py->firstdayofweek = td.tm_wday;
118
119                 if (pyp != NULL)
120                         pyp->nextyear = py;
121         }
122         if (pyp == NULL) {
123                 /* The very very very first one */
124                 hyear = py;
125         }
126
127         pmp = NULL;
128         pm = py->months;
129         while (pm != NULL) {
130                 if (pm->month == m)
131                         break;
132                 pmp = pm;
133                 pm = pm->nextmonth;
134         }
135
136         if (pm == NULL) {
137                 pm = (struct cal_month *)calloc(1, sizeof(struct cal_month));
138                 pm->year = py;
139                 pm->month = m;
140                 cumday = cumdaytab[isleap(y)];
141                 pm->firstdayjulian = cumday[m] + 2;
142                 pm->firstdayofweek =
143                     (py->firstdayofweek + pm->firstdayjulian -1) % 7;
144                 if (pmp != NULL)
145                         pmp->nextmonth = pm;
146         }
147         if (pmp == NULL)
148                 py->months = pm;
149
150         pdp = NULL;
151         pd = pm->days;
152         while (pd != NULL) {
153                 pdp = pd;
154                 pd = pd->nextday;
155         }
156
157         if (pd == NULL) {       /* Always true */
158                 pd = (struct cal_day *)calloc(1, sizeof(struct cal_day));
159                 pd->month = pm;
160                 pd->year = py;
161                 pd->dayofmonth = d;
162                 pd->julianday = pm->firstdayjulian + d - 1;
163                 pd->dayofweek = (pm->firstdayofweek + d - 1) % 7;
164                 if (pdp != NULL)
165                         pdp->nextday = pd;
166         }
167         if (pdp == NULL)
168                 pm->days = pd;
169 }
170
171 void
172 generatedates(struct tm *tp1, struct tm *tp2)
173 {
174         int y1, m1, d1;
175         int y2, m2, d2;
176         int y, m, d;
177
178         y1 = tp1->tm_year;
179         m1 = tp1->tm_mon + 1;
180         d1 = tp1->tm_mday;
181         y2 = tp2->tm_year;
182         m2 = tp2->tm_mon + 1;
183         d2 = tp2->tm_mday;
184
185         if (y1 == y2) {
186                 if (m1 == m2) {
187                         /* Same year, same month. Easy! */
188                         for (d = d1; d <= d2; d++)
189                                 createdate(y1, m1, d);
190                         return;
191                 }
192                 /*
193                  * Same year, different month.
194                  * - Take the leftover days from m1
195                  * - Take all days from <m1 .. m2>
196                  * - Take the first days from m2
197                  */
198                 monthdays = monthdaytab[isleap(y1)];
199                 for (d = d1; d <= monthdays[m1]; d++)
200                         createdate(y1, m1, d);
201                 for (m = m1 + 1; m < m2; m++)
202                         for (d = 1; d <= monthdays[m]; d++)
203                                 createdate(y1, m, d);
204                 for (d = 1; d <= d2; d++)
205                         createdate(y1, m2, d);
206                 return;
207         }
208         /*
209          * Different year, different month.
210          * - Take the leftover days from y1-m1
211          * - Take all days from y1-<m1 .. 12]
212          * - Take all days from <y1 .. y2>
213          * - Take all days from y2-[1 .. m2>
214          * - Take the first days of y2-m2
215          */
216         monthdays = monthdaytab[isleap(y1)];
217         for (d = d1; d <= monthdays[m1]; d++)
218                 createdate(y1, m1, d);
219         for (m = m1 + 1; m <= 12; m++)
220                 for (d = 1; d <= monthdays[m]; d++)
221                         createdate(y1, m, d);
222         for (y = y1 + 1; y < y2; y++) {
223                 monthdays = monthdaytab[isleap(y)];
224                 for (m = 1; m <= 12; m++)
225                         for (d = 1; d <= monthdays[m]; d++)
226                                 createdate(y, m, d);
227         }
228         monthdays = monthdaytab[isleap(y2)];
229         for (m = 1; m < m2; m++)
230                 for (d = 1; d <= monthdays[m]; d++)
231                         createdate(y2, m, d);
232         for (d = 1; d <= d2; d++)
233                 createdate(y2, m2, d);
234 }
235
236 void
237 dumpdates(void)
238 {
239         struct cal_year *y;
240         struct cal_month *m;
241         struct cal_day *d;
242
243         y = hyear;
244         while (y != NULL) {
245                 printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek);
246                 m = y->months;
247                 while (m != NULL) {
248                         printf("-- %-5d (julian:%d, dow:%d)\n", m->month,
249                             m->firstdayjulian, m->firstdayofweek);
250                         d = m->days;
251                         while (d != NULL) {
252                                 printf("  -- %-5d (julian:%d, dow:%d)\n",
253                                     d->dayofmonth, d->julianday, d->dayofweek);
254                                 d = d->nextday;
255                         }
256                         m = m->nextmonth;
257                 }
258                 y = y->nextyear;
259         }
260 }
261
262 int
263 remember_ymd(int yy, int mm, int dd)
264 {
265         struct cal_year *y;
266         struct cal_month *m;
267         struct cal_day *d;
268
269         if (debug_remember)
270                 printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
271
272         y = hyear;
273         while (y != NULL) {
274                 if (y->year != yy) {
275                         y = y->nextyear;
276                         continue;
277                 }
278                 m = y->months;
279                 while (m != NULL) {
280                         if (m->month != mm) {
281                                 m = m->nextmonth;
282                                 continue;
283                         }
284                         d = m->days;
285                         while (d != NULL) {
286                                 if (d->dayofmonth == dd)
287                                         return (1);
288                                 d = d->nextday;
289                                 continue;
290                         }
291                         return (0);
292                 }
293                 return (0);
294         }
295         return (0);
296 }
297
298 int
299 remember_yd(int yy, int dd, int *rm, int *rd)
300 {
301         struct cal_year *y;
302         struct cal_month *m;
303         struct cal_day *d;
304
305         if (debug_remember)
306                 printf("remember_yd: %d - %d\n", yy, dd);
307
308         y = hyear;
309         while (y != NULL) {
310                 if (y->year != yy) {
311                         y = y->nextyear;
312                         continue;
313                 }
314                 m = y->months;
315                 while (m != NULL) {
316                         d = m->days;
317                         while (d != NULL) {
318                                 if (d->julianday == dd) {
319                                         *rm = m->month;
320                                         *rd = d->dayofmonth;
321                                         return (1);
322                                 }
323                                 d = d->nextday;
324                         }
325                         m = m->nextmonth;
326                 }
327                 return (0);
328         }
329         return (0);
330 }
331
332 int
333 first_dayofweek_of_year(int yy)
334 {
335         struct cal_year *y;
336
337         y = hyear;
338         while (y != NULL) {
339                 if (y->year == yy)
340                         return (y->firstdayofweek);
341                 y = y->nextyear;
342         }
343
344         /* Should not happen */
345         return (-1);
346 }
347
348 int
349 first_dayofweek_of_month(int yy, int mm)
350 {
351         struct cal_year *y;
352         struct cal_month *m;
353
354         y = hyear;
355         while (y != NULL) {
356                 if (y->year != yy) {
357                         y = y->nextyear;
358                         continue;
359                 }
360                 m = y->months;
361                 while (m != NULL) {
362                         if (m->month == mm)
363                                 return (m->firstdayofweek);
364                         m = m->nextmonth;
365                 }
366                 /* No data for this month */
367                 return (-1);
368         }
369
370         /* No data for this year.  Error? */
371         return (-1);
372 }
373
374 int
375 walkthrough_dates(struct event **e)
376 {
377         static struct cal_year *y = NULL;
378         static struct cal_month *m = NULL;
379         static struct cal_day *d = NULL;
380
381         if (y == NULL) {
382                 y = hyear;
383                 m = y->months;
384                 d = m->days;
385                 *e = d->events;
386                 return (1);
387         }
388         if (d->nextday != NULL) {
389                 d = d->nextday;
390                 *e = d->events;
391                 return (1);
392         }
393         if (m->nextmonth != NULL) {
394                 m = m->nextmonth;
395                 d = m->days;
396                 *e = d->events;
397                 return (1);
398         }
399         if (y->nextyear != NULL) {
400                 y = y->nextyear;
401                 m = y->months;
402                 d = m->days;
403                 *e = d->events;
404                 return (1);
405         }
406
407         return (0);
408 }
409
410 static struct cal_day *
411 find_day(int yy, int mm, int dd)
412 {
413         struct cal_year *y;
414         struct cal_month *m;
415         struct cal_day *d;
416
417         if (debug_remember)
418                 printf("remember_ymd: %d - %d - %d\n", yy, mm, dd);
419
420         y = hyear;
421         while (y != NULL) {
422                 if (y->year != yy) {
423                         y = y->nextyear;
424                         continue;
425                 }
426                 m = y->months;
427                 while (m != NULL) {
428                         if (m->month != mm) {
429                                 m = m->nextmonth;
430                                 continue;
431                         }
432                         d = m->days;
433                         while (d != NULL) {
434                                 if (d->dayofmonth == dd)
435                                         return (d);
436                                 d = d->nextday;
437                                 continue;
438                         }
439                         return (NULL);
440                 }
441                 return (NULL);
442         }
443         return (NULL);
444 }
445
446 void
447 addtodate(struct event *e)
448 {
449         struct cal_day *d;
450         struct event *ee;
451
452         d = find_day(e->year, e->month, e->day);
453         ee = d->lastevent;
454         if (ee != NULL)
455                 ee->next = e;
456         else
457                 d->events = e;
458         d->lastevent = e;
459 }