nrelease - fix/improve livecd
[dragonfly.git] / usr.bin / calendar / dates.c
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
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
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 *
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 *
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 *
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
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 }