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 } 236