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