1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2020 The DragonFly Project. All rights reserved.
5 * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The DragonFly Project
9 * by Aaron LI <aly@aaronly.me>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/usr.bin/calendar/dates.c 326276 2017-11-27 15:37:16Z pfg $
33 */
34
35 #include <assert.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <time.h>
40
41 #include "calendar.h"
42 #include "basics.h"
43 #include "dates.h"
44 #include "gregorian.h"
45 #include "io.h"
46 #include "utils.h"
47
48
49 struct event {
50 bool variable; /* Whether a variable event ? */
51 char date[32]; /* Date in Gregorian calendar */
52 char date_user[64]; /* Date in user-chosen calendar */
53 struct cal_desc *description; /* Event description */
54 char *extra; /* Extra data of the event */
55 struct event *next;
56 };
57
58 static struct cal_day *cal_days = NULL;
59
60
61 void
generate_dates(void)62 generate_dates(void)
63 {
64 struct cal_day *dp;
65 struct date date;
66 int daycount, dow, year, month, day;
67 int rd_month1, rd_nextmonth, rd_nextyear;
68
69 daycount = Options.day_end - Options.day_begin + 1;
70 cal_days = xcalloc((size_t)daycount, sizeof(struct cal_day));
71
72 dow = dayofweek_from_fixed(Options.day_begin);
73 gregorian_from_fixed(Options.day_begin, &date);
74 year = date.year;
75 month = date.month;
76 day = date.day;
77
78 date.day = 1;
79 rd_month1 = fixed_from_gregorian(&date);
80 if (date.month == 12) {
81 date_set(&date, date.year+1, 1, 1);
82 rd_nextmonth = fixed_from_gregorian(&date);
83 rd_nextyear = rd_nextmonth;
84 } else {
85 date.month++;
86 rd_nextmonth = fixed_from_gregorian(&date);
87 date_set(&date, date.year+1, 1, 1);
88 rd_nextyear = fixed_from_gregorian(&date);
89 }
90
91 for (int i = 0; i < daycount; i++) {
92 dp = &cal_days[i];
93 dp->rd = Options.day_begin + i;
94
95 if (dp->rd == rd_nextmonth) {
96 month++;
97 day = 1;
98 rd_month1 = rd_nextmonth;
99 if (dp->rd == rd_nextyear) {
100 year++;
101 month = 1;
102 }
103
104 date_set(&date, year, month, day);
105 if (date.month == 12) {
106 date_set(&date, date.year+1, 1, 1);
107 rd_nextmonth = fixed_from_gregorian(&date);
108 rd_nextyear = rd_nextmonth;
109 } else {
110 date.month++;
111 rd_nextmonth = fixed_from_gregorian(&date);
112 date_set(&date, date.year+1, 1, 1);
113 rd_nextyear = fixed_from_gregorian(&date);
114 }
115 }
116
117 dp->year = year;
118 dp->month = month;
119 dp->day = dp->rd - rd_month1 + 1;
120 dp->dow[0] = (dow + i) % 7;
121 dp->dow[1] = (dp->rd - rd_month1) / 7 + 1;
122 dp->dow[2] = -((rd_nextmonth - dp->rd - 1) / 7 + 1);
123 dp->last_dom = (dp->rd == rd_nextmonth - 1);
124
125 DPRINTF("%s: [%d] rd:%d, date:%d-%02d-%02d, dow:[%d,%d,%d]\n",
126 __func__, i, dp->rd, dp->year, dp->month,
127 dp->day, dp->dow[0], dp->dow[1], dp->dow[2]);
128 }
129 }
130
131 void
free_dates(void)132 free_dates(void)
133 {
134 struct event *e;
135 struct cal_day *dp = NULL;
136
137 while ((dp = loop_dates(dp)) != NULL) {
138 while ((e = dp->events) != NULL) {
139 dp->events = e->next;
140 free(e->extra);
141 free(e);
142 }
143 }
144 free(cal_days);
145 }
146
147 struct cal_day *
loop_dates(struct cal_day * dp)148 loop_dates(struct cal_day *dp)
149 {
150 int daycount = Options.day_end - Options.day_begin + 1;
151
152 if (dp == NULL)
153 dp = &cal_days[0];
154 else
155 dp++;
156
157 if (dp < &cal_days[0] || dp > &cal_days[daycount-1])
158 return NULL;
159 else
160 return dp;
161 }
162
163
164 struct cal_day *
find_rd(int rd,int offset)165 find_rd(int rd, int offset)
166 {
167 rd += offset;
168 if (rd < Options.day_begin || rd > Options.day_end)
169 return NULL;
170
171 return &cal_days[rd - Options.day_begin];
172 }
173
174
175 struct event *
event_add(struct cal_day * dp,bool day_first,bool variable,struct cal_desc * desc,char * extra)176 event_add(struct cal_day *dp, bool day_first, bool variable,
177 struct cal_desc *desc, char *extra)
178 {
179 struct event *e;
180 struct date gdate;
181 struct tm tm = { 0 };
182
183 e = xcalloc(1, sizeof(*e));
184
185 gregorian_from_fixed(dp->rd, &gdate);
186 tm.tm_year = gdate.year - 1900;
187 tm.tm_mon = gdate.month - 1;
188 tm.tm_mday = gdate.day;
189 strftime(e->date, sizeof(e->date),
190 (day_first ? "%e %b" : "%b %e"), &tm);
191 if (Calendar->format_date != NULL) {
192 (Calendar->format_date)(e->date_user, sizeof(e->date_user),
193 dp->rd);
194 }
195
196 e->variable = variable;
197 e->description = desc;
198 if (extra != NULL && extra[0] != '\0')
199 e->extra = extra;
200
201 e->next = dp->events;
202 dp->events = e;
203
204 return (e);
205 }
206
207 void
event_print_all(FILE * fp)208 event_print_all(FILE *fp)
209 {
210 struct event *e;
211 struct cal_day *dp = NULL;
212 struct cal_desc *desc;
213 struct cal_line *line;
214
215 while ((dp = loop_dates(dp)) != NULL) {
216 for (e = dp->events; e != NULL; e = e->next) {
217 fprintf(fp, "%s%c\t", e->date, e->variable ? '*' : ' ');
218 if (e->date_user[0] != '\0')
219 fprintf(fp, "[%s] ", e->date_user);
220
221 desc = e->description;
222 for (line = desc->firstline; line; line = line->next) {
223 fprintf(fp, "%s%s%s",
224 (line == desc->firstline) ? "" : "\t\t",
225 line->str,
226 (line == desc->lastline) ? "" : "\n");
227 }
228 if (e->extra)
229 fprintf(fp, " (%s)", e->extra);
230
231 fputc('\n', fp);
232 fflush(fp);
233 }
234 }
235 }
236