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