1 /* 2 * Copyright (c) 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 35 #include <stdio.h> 36 #include <sys/types.h> 37 #include <time.h> 38 #include <sys/uio.h> 39 #include <string.h> 40 #include <stdlib.h> 41 42 #include "pathnames.h" 43 #include "calendar.h" 44 45 struct tm *tp; 46 int *cumdays, offset, yrdays; 47 char dayname[10]; 48 49 50 /* 1-based month, 0-based days, cumulative */ 51 int daytab[][14] = { 52 { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, 53 { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 54 }; 55 56 static char *days[] = { 57 "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL, 58 }; 59 60 static char *months[] = { 61 "jan", "feb", "mar", "apr", "may", "jun", 62 "jul", "aug", "sep", "oct", "nov", "dec", NULL, 63 }; 64 65 66 67 68 void 69 settime(now) 70 time_t now; 71 { 72 73 tp = localtime(&now); 74 if ( isleap(tp->tm_year + 1900) ) { 75 yrdays = 366; 76 cumdays = daytab[1]; 77 } else { 78 yrdays = 365; 79 cumdays = daytab[0]; 80 } 81 /* Friday displays Monday's events */ 82 offset = tp->tm_wday == 5 ? 3 : 1; 83 header[5].iov_base = dayname; 84 header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp); 85 } 86 87 /* convert Day[/Month][/Year] into unix time (since 1970) 88 * Day: two digits, Month: two digits, Year: digits 89 */ 90 time_t Mktime (date) 91 char *date; 92 { 93 time_t t; 94 int len; 95 struct tm tm; 96 97 (void)time(&t); 98 tp = localtime(&t); 99 100 len = strlen(date); 101 tm.tm_sec = 0; 102 tm.tm_min = 0; 103 tm.tm_hour = 0; 104 tm.tm_mday = tp->tm_mday; 105 tm.tm_mon = tp->tm_mon; 106 tm.tm_year = tp->tm_year; 107 108 109 /* day */ 110 *(date+2) = NULL; 111 tm.tm_mday = atoi(date); 112 113 /* month */ 114 if (len >= 4) { 115 *(date+5) = NULL; 116 tm.tm_mon = atoi(date+3) - 1; 117 } 118 119 /* Year */ 120 if (len >= 7) { 121 tm.tm_year = atoi(date+6); 122 123 /* tm_year up 1900 ... */ 124 if (tm.tm_year > 1900) 125 tm.tm_year -= 1900; 126 } 127 128 #if DEBUG 129 printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len, 130 asctime(&tm)); 131 #endif 132 return(mktime(&tm)); 133 } 134 135 /* 136 * Possible date formats include any combination of: 137 * 3-charmonth (January, Jan, Jan) 138 * 3-charweekday (Friday, Monday, mon.) 139 * numeric month or day (1, 2, 04) 140 * 141 * Any character may separate them, or they may not be separated. Any line, 142 * following a line that is matched, that starts with "whitespace", is shown 143 * along with the matched line. 144 */ 145 int 146 isnow(endp, monthp, dayp, varp) 147 char *endp; 148 int *monthp; 149 int *dayp; 150 int *varp; 151 { 152 int day, flags, month, v1, v2; 153 154 /* 155 * CONVENTION 156 * 157 * Month: 1-12 158 * Monthname: Jan .. Dec 159 * Day: 1-31 160 * Weekday: Mon-Sun 161 * 162 */ 163 164 flags = 0; 165 166 /* read first field */ 167 /* didn't recognize anything, skip it */ 168 if (!(v1 = getfield(endp, &endp, &flags))) 169 return (0); 170 171 /* Easter or Easter depending days */ 172 if (flags & F_EASTER) 173 day = v1 - 1; /* days since January 1 [0-365] */ 174 175 /* 176 * 1. {Weekday,Day} XYZ ... 177 * 178 * where Day is > 12 179 */ 180 else if (flags & F_ISDAY || v1 > 12) { 181 182 /* found a day; day: 1-31 or weekday: 1-7 */ 183 day = v1; 184 185 /* {Day,Weekday} {Month,Monthname} ... */ 186 /* if no recognizable month, assume just a day alone 187 * in other words, find month or use current month */ 188 if (!(month = getfield(endp, &endp, &flags))) 189 month = tp->tm_mon + 1; 190 } 191 192 /* 2. {Monthname} XYZ ... */ 193 else if (flags & F_ISMONTH) { 194 month = v1; 195 196 /* Monthname {day,weekday} */ 197 /* if no recognizable day, assume the first day in month */ 198 if (!(day = getfield(endp, &endp, &flags))) 199 day = 1; 200 } 201 202 /* Hm ... */ 203 else { 204 v2 = getfield(endp, &endp, &flags); 205 206 /* 207 * {Day} {Monthname} ... 208 * where Day <= 12 209 */ 210 if (flags & F_ISMONTH) { 211 day = v1; 212 month = v2; 213 *varp = 0; 214 } 215 216 /* {Month} {Weekday,Day} ... */ 217 else { 218 /* F_ISDAY set, v2 > 12, or no way to tell */ 219 month = v1; 220 /* if no recognizable day, assume the first */ 221 day = v2 ? v2 : 1; 222 *varp = 0; 223 } 224 } 225 226 /* convert Weekday into *next* Day, 227 * e.g.: 'Sunday' -> 22 228 * 'SunayLast' -> ?? 229 */ 230 if (flags & F_ISDAY) { 231 #if DEBUG 232 fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month); 233 #endif 234 235 *varp = 1; 236 /* variable weekday, SundayLast, MondayFirst ... */ 237 if (day < 0 || day >= 10) { 238 239 /* negative offset; last, -4 .. -1 */ 240 if (day < 0) { 241 v1 = day/10 - 1; /* offset -4 ... -1 */ 242 day = 10 + (day % 10); /* day 1 ... 7 */ 243 244 /* day, eg '22th' */ 245 v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); 246 247 /* (month length - day) / 7 + 1 */ 248 if (((int)((cumdays[month+1] - 249 cumdays[month] - v2) / 7) + 1) == -v1) 250 /* bingo ! */ 251 day = v2; 252 253 /* set to yesterday */ 254 else 255 day = tp->tm_mday - 1; 256 } 257 258 /* first, second ... +1 ... +5 */ 259 else { 260 v1 = day/10; /* offset: +1 (first Sunday) ... */ 261 day = day % 10; 262 263 /* day, eg '22th' */ 264 v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); 265 266 /* Hurrah! matched */ 267 if ( ((v2 - 1 + 7) / 7) == v1 ) 268 day = v2; 269 270 /* set to yesterday */ 271 else 272 day = tp->tm_mday - 1; 273 } 274 } 275 276 /* wired */ 277 else { 278 day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); 279 *varp = 1; 280 } 281 } 282 283 #if DEBUG 284 fprintf(stderr, "day2: day %d yday %d\n", day, tp->tm_yday); 285 #endif 286 if (!(flags & F_EASTER)) { 287 *monthp = month; 288 *dayp = day; 289 day = cumdays[month] + day; 290 } 291 else { 292 for (v1 = 0; day > cumdays[v1]; v1++) 293 ; 294 *monthp = v1 - 1; 295 *dayp = day - cumdays[v1 - 1]; 296 *varp = 1; 297 } 298 299 /* if today or today + offset days */ 300 if (day >= tp->tm_yday - f_dayBefore && 301 day <= tp->tm_yday + offset + f_dayAfter) 302 return (1); 303 304 /* if number of days left in this year + days to event in next year */ 305 if (yrdays - tp->tm_yday + day <= offset + f_dayAfter || 306 /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */ 307 tp->tm_yday + day - f_dayBefore < 0 308 ) 309 return (1); 310 return (0); 311 } 312 313 314 int 315 getmonth(s) 316 register char *s; 317 { 318 register char **p; 319 320 for (p = months; *p; ++p) 321 if (!strncasecmp(s, *p, 3)) 322 return ((p - months) + 1); 323 return (0); 324 } 325 326 327 int 328 getday(s) 329 register char *s; 330 { 331 register char **p; 332 333 for (p = days; *p; ++p) 334 if (!strncasecmp(s, *p, 3)) 335 return ((p - days) + 1); 336 return (0); 337 } 338 339 /* return offset for variable weekdays 340 * -1 -> last weekday in month 341 * +1 -> first weekday in month 342 * ... etc ... 343 */ 344 int 345 getdayvar(s) 346 register char *s; 347 { 348 register int offset; 349 350 351 offset = strlen(s); 352 353 354 /* Sun+1 or Wednesday-2 355 * ^ ^ */ 356 357 /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */ 358 switch(*(s + offset - 2)) { 359 case '-': 360 return(-(atoi(s + offset - 1))); 361 break; 362 case '+': 363 return(atoi(s + offset - 1)); 364 break; 365 } 366 367 368 /* 369 * some aliases: last, first, second, third, fourth 370 */ 371 372 /* last */ 373 if (offset > 4 && !strcasecmp(s + offset - 4, "last")) 374 return(-1); 375 else if (offset > 5 && !strcasecmp(s + offset - 5, "first")) 376 return(+1); 377 else if (offset > 6 && !strcasecmp(s + offset - 6, "second")) 378 return(+2); 379 else if (offset > 5 && !strcasecmp(s + offset - 5, "third")) 380 return(+3); 381 else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth")) 382 return(+4); 383 384 385 /* no offset detected */ 386 return(0); 387 } 388