1148ae050SAaron LI /*-
2148ae050SAaron LI * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3148ae050SAaron LI *
4*d19ef5a2SAaron LI * Copyright (c) 2020 The DragonFly Project. All rights reserved.
5148ae050SAaron LI * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
6148ae050SAaron LI * All rights reserved.
7148ae050SAaron LI *
8*d19ef5a2SAaron LI * This code is derived from software contributed to The DragonFly Project
9*d19ef5a2SAaron LI * by Aaron LI <aly@aaronly.me>
10*d19ef5a2SAaron LI *
11148ae050SAaron LI * Redistribution and use in source and binary forms, with or without
12148ae050SAaron LI * modification, are permitted provided that the following conditions
13148ae050SAaron LI * are met:
14148ae050SAaron LI * 1. Redistributions of source code must retain the above copyright
15148ae050SAaron LI * notice, this list of conditions and the following disclaimer.
16148ae050SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
17148ae050SAaron LI * notice, this list of conditions and the following disclaimer in the
18148ae050SAaron LI * documentation and/or other materials provided with the distribution.
19148ae050SAaron LI *
20148ae050SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21148ae050SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22148ae050SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23148ae050SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24148ae050SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25148ae050SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26148ae050SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27148ae050SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28148ae050SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29148ae050SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30148ae050SAaron LI * SUCH DAMAGE.
31148ae050SAaron LI *
32cd0cff33SAaron LI * $FreeBSD: head/usr.bin/calendar/dates.c 326276 2017-11-27 15:37:16Z pfg $
33148ae050SAaron LI */
34148ae050SAaron LI
35*d19ef5a2SAaron LI #include <assert.h>
36cd0cff33SAaron LI #include <stdbool.h>
37148ae050SAaron LI #include <stdio.h>
38148ae050SAaron LI #include <stdlib.h>
39148ae050SAaron LI #include <time.h>
40148ae050SAaron LI
41148ae050SAaron LI #include "calendar.h"
42*d19ef5a2SAaron LI #include "basics.h"
43*d19ef5a2SAaron LI #include "dates.h"
44*d19ef5a2SAaron LI #include "gregorian.h"
45*d19ef5a2SAaron LI #include "io.h"
46*d19ef5a2SAaron LI #include "utils.h"
47148ae050SAaron LI
48*d19ef5a2SAaron LI
49*d19ef5a2SAaron LI struct event {
50*d19ef5a2SAaron LI bool variable; /* Whether a variable event ? */
51*d19ef5a2SAaron LI char date[32]; /* Date in Gregorian calendar */
52*d19ef5a2SAaron LI char date_user[64]; /* Date in user-chosen calendar */
53*d19ef5a2SAaron LI struct cal_desc *description; /* Event description */
54*d19ef5a2SAaron LI char *extra; /* Extra data of the event */
55*d19ef5a2SAaron LI struct event *next;
56148ae050SAaron LI };
57148ae050SAaron LI
58*d19ef5a2SAaron LI static struct cal_day *cal_days = NULL;
59148ae050SAaron LI
60148ae050SAaron LI
61*d19ef5a2SAaron LI void
generate_dates(void)62*d19ef5a2SAaron LI generate_dates(void)
63148ae050SAaron LI {
64*d19ef5a2SAaron LI struct cal_day *dp;
65*d19ef5a2SAaron LI struct date date;
66*d19ef5a2SAaron LI int daycount, dow, year, month, day;
67*d19ef5a2SAaron LI int rd_month1, rd_nextmonth, rd_nextyear;
68148ae050SAaron LI
69*d19ef5a2SAaron LI daycount = Options.day_end - Options.day_begin + 1;
70*d19ef5a2SAaron LI cal_days = xcalloc((size_t)daycount, sizeof(struct cal_day));
71*d19ef5a2SAaron LI
72*d19ef5a2SAaron LI dow = dayofweek_from_fixed(Options.day_begin);
73*d19ef5a2SAaron LI gregorian_from_fixed(Options.day_begin, &date);
74*d19ef5a2SAaron LI year = date.year;
75*d19ef5a2SAaron LI month = date.month;
76*d19ef5a2SAaron LI day = date.day;
77*d19ef5a2SAaron LI
78*d19ef5a2SAaron LI date.day = 1;
79*d19ef5a2SAaron LI rd_month1 = fixed_from_gregorian(&date);
80*d19ef5a2SAaron LI if (date.month == 12) {
81*d19ef5a2SAaron LI date_set(&date, date.year+1, 1, 1);
82*d19ef5a2SAaron LI rd_nextmonth = fixed_from_gregorian(&date);
83*d19ef5a2SAaron LI rd_nextyear = rd_nextmonth;
84*d19ef5a2SAaron LI } else {
85*d19ef5a2SAaron LI date.month++;
86*d19ef5a2SAaron LI rd_nextmonth = fixed_from_gregorian(&date);
87*d19ef5a2SAaron LI date_set(&date, date.year+1, 1, 1);
88*d19ef5a2SAaron LI rd_nextyear = fixed_from_gregorian(&date);
89148ae050SAaron LI }
90148ae050SAaron LI
91*d19ef5a2SAaron LI for (int i = 0; i < daycount; i++) {
92*d19ef5a2SAaron LI dp = &cal_days[i];
93*d19ef5a2SAaron LI dp->rd = Options.day_begin + i;
94148ae050SAaron LI
95*d19ef5a2SAaron LI if (dp->rd == rd_nextmonth) {
96*d19ef5a2SAaron LI month++;
97*d19ef5a2SAaron LI day = 1;
98*d19ef5a2SAaron LI rd_month1 = rd_nextmonth;
99*d19ef5a2SAaron LI if (dp->rd == rd_nextyear) {
100*d19ef5a2SAaron LI year++;
101*d19ef5a2SAaron LI month = 1;
102148ae050SAaron LI }
103148ae050SAaron LI
104*d19ef5a2SAaron LI date_set(&date, year, month, day);
105*d19ef5a2SAaron LI if (date.month == 12) {
106*d19ef5a2SAaron LI date_set(&date, date.year+1, 1, 1);
107*d19ef5a2SAaron LI rd_nextmonth = fixed_from_gregorian(&date);
108*d19ef5a2SAaron LI rd_nextyear = rd_nextmonth;
109*d19ef5a2SAaron LI } else {
110*d19ef5a2SAaron LI date.month++;
111*d19ef5a2SAaron LI rd_nextmonth = fixed_from_gregorian(&date);
112*d19ef5a2SAaron LI date_set(&date, date.year+1, 1, 1);
113*d19ef5a2SAaron LI rd_nextyear = fixed_from_gregorian(&date);
114148ae050SAaron LI }
115148ae050SAaron LI }
116148ae050SAaron LI
117*d19ef5a2SAaron LI dp->year = year;
118*d19ef5a2SAaron LI dp->month = month;
119*d19ef5a2SAaron LI dp->day = dp->rd - rd_month1 + 1;
120*d19ef5a2SAaron LI dp->dow[0] = (dow + i) % 7;
121*d19ef5a2SAaron LI dp->dow[1] = (dp->rd - rd_month1) / 7 + 1;
122*d19ef5a2SAaron LI dp->dow[2] = -((rd_nextmonth - dp->rd - 1) / 7 + 1);
123*d19ef5a2SAaron LI dp->last_dom = (dp->rd == rd_nextmonth - 1);
124*d19ef5a2SAaron LI
125*d19ef5a2SAaron LI DPRINTF("%s: [%d] rd:%d, date:%d-%02d-%02d, dow:[%d,%d,%d]\n",
126*d19ef5a2SAaron LI __func__, i, dp->rd, dp->year, dp->month,
127*d19ef5a2SAaron LI dp->day, dp->dow[0], dp->dow[1], dp->dow[2]);
128148ae050SAaron LI }
129148ae050SAaron LI }
130148ae050SAaron LI
131148ae050SAaron LI void
free_dates(void)132*d19ef5a2SAaron LI free_dates(void)
133148ae050SAaron LI {
134*d19ef5a2SAaron LI struct event *e;
135*d19ef5a2SAaron LI struct cal_day *dp = NULL;
136148ae050SAaron LI
137*d19ef5a2SAaron LI while ((dp = loop_dates(dp)) != NULL) {
138*d19ef5a2SAaron LI while ((e = dp->events) != NULL) {
139*d19ef5a2SAaron LI dp->events = e->next;
140*d19ef5a2SAaron LI free(e->extra);
141*d19ef5a2SAaron LI free(e);
142*d19ef5a2SAaron LI }
143*d19ef5a2SAaron LI }
144*d19ef5a2SAaron LI free(cal_days);
145*d19ef5a2SAaron LI }
146148ae050SAaron LI
147*d19ef5a2SAaron LI struct cal_day *
loop_dates(struct cal_day * dp)148*d19ef5a2SAaron LI loop_dates(struct cal_day *dp)
149*d19ef5a2SAaron LI {
150*d19ef5a2SAaron LI int daycount = Options.day_end - Options.day_begin + 1;
151*d19ef5a2SAaron LI
152*d19ef5a2SAaron LI if (dp == NULL)
153*d19ef5a2SAaron LI dp = &cal_days[0];
154*d19ef5a2SAaron LI else
155*d19ef5a2SAaron LI dp++;
156*d19ef5a2SAaron LI
157*d19ef5a2SAaron LI if (dp < &cal_days[0] || dp > &cal_days[daycount-1])
158*d19ef5a2SAaron LI return NULL;
159*d19ef5a2SAaron LI else
160*d19ef5a2SAaron LI return dp;
161148ae050SAaron LI }
162*d19ef5a2SAaron LI
163*d19ef5a2SAaron LI
164*d19ef5a2SAaron LI struct cal_day *
find_rd(int rd,int offset)165*d19ef5a2SAaron LI find_rd(int rd, int offset)
166*d19ef5a2SAaron LI {
167*d19ef5a2SAaron LI rd += offset;
168*d19ef5a2SAaron LI if (rd < Options.day_begin || rd > Options.day_end)
169*d19ef5a2SAaron LI return NULL;
170*d19ef5a2SAaron LI
171*d19ef5a2SAaron LI return &cal_days[rd - Options.day_begin];
172148ae050SAaron LI }
173*d19ef5a2SAaron LI
174*d19ef5a2SAaron LI
175*d19ef5a2SAaron LI struct event *
event_add(struct cal_day * dp,bool day_first,bool variable,struct cal_desc * desc,char * extra)176*d19ef5a2SAaron LI event_add(struct cal_day *dp, bool day_first, bool variable,
177*d19ef5a2SAaron LI struct cal_desc *desc, char *extra)
178*d19ef5a2SAaron LI {
179*d19ef5a2SAaron LI struct event *e;
180*d19ef5a2SAaron LI struct date gdate;
181*d19ef5a2SAaron LI struct tm tm = { 0 };
182*d19ef5a2SAaron LI
183*d19ef5a2SAaron LI e = xcalloc(1, sizeof(*e));
184*d19ef5a2SAaron LI
185*d19ef5a2SAaron LI gregorian_from_fixed(dp->rd, &gdate);
186*d19ef5a2SAaron LI tm.tm_year = gdate.year - 1900;
187*d19ef5a2SAaron LI tm.tm_mon = gdate.month - 1;
188*d19ef5a2SAaron LI tm.tm_mday = gdate.day;
189*d19ef5a2SAaron LI strftime(e->date, sizeof(e->date),
190*d19ef5a2SAaron LI (day_first ? "%e %b" : "%b %e"), &tm);
191*d19ef5a2SAaron LI if (Calendar->format_date != NULL) {
192*d19ef5a2SAaron LI (Calendar->format_date)(e->date_user, sizeof(e->date_user),
193*d19ef5a2SAaron LI dp->rd);
194148ae050SAaron LI }
195*d19ef5a2SAaron LI
196*d19ef5a2SAaron LI e->variable = variable;
197*d19ef5a2SAaron LI e->description = desc;
198*d19ef5a2SAaron LI if (extra != NULL && extra[0] != '\0')
199*d19ef5a2SAaron LI e->extra = extra;
200*d19ef5a2SAaron LI
201*d19ef5a2SAaron LI e->next = dp->events;
202*d19ef5a2SAaron LI dp->events = e;
203*d19ef5a2SAaron LI
204*d19ef5a2SAaron LI return (e);
205148ae050SAaron LI }
206148ae050SAaron LI
207148ae050SAaron LI void
event_print_all(FILE * fp)208*d19ef5a2SAaron LI event_print_all(FILE *fp)
209148ae050SAaron LI {
210*d19ef5a2SAaron LI struct event *e;
211*d19ef5a2SAaron LI struct cal_day *dp = NULL;
212*d19ef5a2SAaron LI struct cal_desc *desc;
213*d19ef5a2SAaron LI struct cal_line *line;
214148ae050SAaron LI
215*d19ef5a2SAaron LI while ((dp = loop_dates(dp)) != NULL) {
216*d19ef5a2SAaron LI for (e = dp->events; e != NULL; e = e->next) {
217*d19ef5a2SAaron LI fprintf(fp, "%s%c\t", e->date, e->variable ? '*' : ' ');
218*d19ef5a2SAaron LI if (e->date_user[0] != '\0')
219*d19ef5a2SAaron LI fprintf(fp, "[%s] ", e->date_user);
220148ae050SAaron LI
221*d19ef5a2SAaron LI desc = e->description;
222*d19ef5a2SAaron LI for (line = desc->firstline; line; line = line->next) {
223*d19ef5a2SAaron LI fprintf(fp, "%s%s%s",
224*d19ef5a2SAaron LI (line == desc->firstline) ? "" : "\t\t",
225*d19ef5a2SAaron LI line->str,
226*d19ef5a2SAaron LI (line == desc->lastline) ? "" : "\n");
227*d19ef5a2SAaron LI }
228*d19ef5a2SAaron LI if (e->extra)
229*d19ef5a2SAaron LI fprintf(fp, " (%s)", e->extra);
230148ae050SAaron LI
231*d19ef5a2SAaron LI fputc('\n', fp);
232*d19ef5a2SAaron LI fflush(fp);
233148ae050SAaron LI }
234148ae050SAaron LI }
235148ae050SAaron LI }
236