Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.bin/calendar/dates.c
34677 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 1992-2009 Edwin Groothuis <[email protected]>.
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
#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
struct event *lastevent;
66
};
67
68
int debug_remember = 0;
69
static struct cal_year *hyear = NULL;
70
71
/* 1-based month, 0-based days, cumulative */
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
static int *monthdays;
78
int monthdaytab[][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
monthdays = monthdaytab[isleap(y1)];
197
for (d = d1; d <= monthdays[m1]; d++)
198
createdate(y1, m1, d);
199
for (m = m1 + 1; m < m2; m++)
200
for (d = 1; d <= monthdays[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
monthdays = monthdaytab[isleap(y1)];
215
for (d = d1; d <= monthdays[m1]; d++)
216
createdate(y1, m1, d);
217
for (m = m1 + 1; m <= 12; m++)
218
for (d = 1; d <= monthdays[m]; d++)
219
createdate(y1, m, d);
220
for (y = y1 + 1; y < y2; y++) {
221
monthdays = monthdaytab[isleap(y)];
222
for (m = 1; m <= 12; m++)
223
for (d = 1; d <= monthdays[m]; d++)
224
createdate(y, m, d);
225
}
226
monthdays = monthdaytab[isleap(y2)];
227
for (m = 1; m < m2; m++)
228
for (d = 1; d <= monthdays[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
/* No data for this month */
365
return (-1);
366
}
367
368
/* No data for this year. Error? */
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)
446
{
447
struct cal_day *d;
448
struct event *ee;
449
450
d = find_day(e->year, e->month, e->day);
451
ee = d->lastevent;
452
if (ee != NULL)
453
ee->next = e;
454
else
455
d->events = e;
456
d->lastevent = e;
457
}
458
459