day.c revision 87235
113840Swosch/*
213840Swosch * Copyright (c) 1989, 1993, 1994
313840Swosch *	The Regents of the University of California.  All rights reserved.
413840Swosch *
513840Swosch * Redistribution and use in source and binary forms, with or without
613840Swosch * modification, are permitted provided that the following conditions
713840Swosch * are met:
813840Swosch * 1. Redistributions of source code must retain the above copyright
913840Swosch *    notice, this list of conditions and the following disclaimer.
1013840Swosch * 2. Redistributions in binary form must reproduce the above copyright
1113840Swosch *    notice, this list of conditions and the following disclaimer in the
1213840Swosch *    documentation and/or other materials provided with the distribution.
1313840Swosch * 3. All advertising materials mentioning features or use of this software
1413840Swosch *    must display the following acknowledgement:
1513840Swosch *	This product includes software developed by the University of
1613840Swosch *	California, Berkeley and its contributors.
1713840Swosch * 4. Neither the name of the University nor the names of its contributors
1813840Swosch *    may be used to endorse or promote products derived from this software
1913840Swosch *    without specific prior written permission.
2013840Swosch *
2113840Swosch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213840Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313840Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413840Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513840Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613840Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713840Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813840Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913840Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013840Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113840Swosch * SUCH DAMAGE.
3213840Swosch */
3313840Swosch
3487235Smarkm#include <sys/cdefs.h>
3513840Swosch
3687235Smarkm__FBSDID("$FreeBSD: head/usr.bin/calendar/day.c 87235 2001-12-02 22:44:14Z markm $");
3787235Smarkm
3887235Smarkm#include <sys/types.h>
3987235Smarkm#include <sys/uio.h>
4015714Sache#include <ctype.h>
4187235Smarkm#include <err.h>
4215714Sache#include <locale.h>
4313840Swosch#include <stdio.h>
4487235Smarkm#include <stdlib.h>
4515714Sache#include <string.h>
4687235Smarkm#include <string.h>
4713840Swosch#include <time.h>
4813840Swosch
4913840Swosch#include "pathnames.h"
5013840Swosch#include "calendar.h"
5113840Swosch
5213840Swoschstruct tm *tp;
5313840Swoschint *cumdays, offset, yrdays;
5413840Swoschchar dayname[10];
5513840Swosch
5613840Swosch
5713840Swosch/* 1-based month, 0-based days, cumulative */
5813840Swoschint daytab[][14] = {
5949053Sn_hibma	{ 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
6013840Swosch	{ 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
6113840Swosch};
6213840Swosch
6387235Smarkmstatic char const *days[] = {
6413840Swosch	"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
6513840Swosch};
6613840Swosch
6787235Smarkmstatic const char *months[] = {
6813840Swosch	"jan", "feb", "mar", "apr", "may", "jun",
6913840Swosch	"jul", "aug", "sep", "oct", "nov", "dec", NULL,
7013840Swosch};
7113840Swosch
7215720Sachestatic struct fixs fndays[8];         /* full national days names */
7315720Sachestatic struct fixs ndays[8];          /* short national days names */
7413840Swosch
7515720Sachestatic struct fixs fnmonths[13];      /* full national months names */
7615720Sachestatic struct fixs nmonths[13];       /* short national month names */
7713840Swosch
7815720Sache
7915714Sachevoid setnnames(void)
8015714Sache{
8115714Sache	char buf[80];
8215714Sache	int i, l;
8315714Sache	struct tm tm;
8413840Swosch
8515714Sache	for (i = 0; i < 7; i++) {
8615714Sache		tm.tm_wday = i;
8715714Sache		strftime(buf, sizeof(buf), "%a", &tm);
8815714Sache		for (l = strlen(buf);
8915714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
9015714Sache		     l--)
9115714Sache			;
9215714Sache		buf[l] = '\0';
9315720Sache		if (ndays[i].name != NULL)
9415720Sache			free(ndays[i].name);
9526839Scharnier		if ((ndays[i].name = strdup(buf)) == NULL)
9626839Scharnier			errx(1, "cannot allocate memory");
9715720Sache		ndays[i].len = strlen(buf);
9815714Sache
9915714Sache		strftime(buf, sizeof(buf), "%A", &tm);
10015714Sache		for (l = strlen(buf);
10115714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
10215714Sache		     l--)
10315714Sache			;
10415714Sache		buf[l] = '\0';
10515720Sache		if (fndays[i].name != NULL)
10615720Sache			free(fndays[i].name);
10726839Scharnier		if ((fndays[i].name = strdup(buf)) == NULL)
10826839Scharnier			errx(1, "cannot allocate memory");
10915720Sache		fndays[i].len = strlen(buf);
11015714Sache	}
11115714Sache
11215714Sache	for (i = 0; i < 12; i++) {
11315714Sache		tm.tm_mon = i;
11415714Sache		strftime(buf, sizeof(buf), "%b", &tm);
11515714Sache		for (l = strlen(buf);
11615714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
11715714Sache		     l--)
11815714Sache			;
11915714Sache		buf[l] = '\0';
12015720Sache		if (nmonths[i].name != NULL)
12115720Sache			free(nmonths[i].name);
12226839Scharnier		if ((nmonths[i].name = strdup(buf)) == NULL)
12326839Scharnier			errx(1, "cannot allocate memory");
12415720Sache		nmonths[i].len = strlen(buf);
12515714Sache
12615714Sache		strftime(buf, sizeof(buf), "%B", &tm);
12715714Sache		for (l = strlen(buf);
12815714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
12915714Sache		     l--)
13015714Sache			;
13115714Sache		buf[l] = '\0';
13215720Sache		if (fnmonths[i].name != NULL)
13315720Sache			free(fnmonths[i].name);
13426839Scharnier		if ((fnmonths[i].name = strdup(buf)) == NULL)
13526839Scharnier			errx(1, "cannot allocate memory");
13615720Sache		fnmonths[i].len = strlen(buf);
13715714Sache	}
13815714Sache}
13915714Sache
14013840Swoschvoid
14113840Swoschsettime(now)
14213840Swosch    	time_t now;
14313840Swosch{
14474582Sache	char *oldl;
14574582Sache
14613840Swosch	tp = localtime(&now);
14713840Swosch	if ( isleap(tp->tm_year + 1900) ) {
14813840Swosch		yrdays = 366;
14913840Swosch		cumdays = daytab[1];
15013840Swosch	} else {
15113840Swosch		yrdays = 365;
15213840Swosch		cumdays = daytab[0];
15313840Swosch	}
15413840Swosch	/* Friday displays Monday's events */
15513840Swosch	offset = tp->tm_wday == 5 ? 3 : 1;
15613840Swosch	header[5].iov_base = dayname;
15715714Sache
15874582Sache	oldl = setlocale(LC_TIME, NULL);
15915714Sache	(void) setlocale(LC_TIME, "C");
16013840Swosch	header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
16174582Sache	(void) setlocale(LC_TIME, oldl);
16215714Sache
16315714Sache	setnnames();
16413840Swosch}
16513840Swosch
16613840Swosch/* convert Day[/Month][/Year] into unix time (since 1970)
16715066Smpp * Day: two digits, Month: two digits, Year: digits
16813840Swosch */
16921615Smpptime_t Mktime (dp)
17021615Smpp    char *dp;
17121615Smpp{
17213840Swosch    time_t t;
17370598Sdwmalone    int d, m, y;
17413840Swosch    struct tm tm;
17513840Swosch
17613840Swosch    (void)time(&t);
17713840Swosch    tp = localtime(&t);
17849053Sn_hibma
17913840Swosch    tm.tm_sec = 0;
18013840Swosch    tm.tm_min = 0;
18113840Swosch    tm.tm_hour = 0;
18215723Sache    tm.tm_wday = 0;
18313840Swosch    tm.tm_mday = tp->tm_mday;
18413840Swosch    tm.tm_mon = tp->tm_mon;
18513840Swosch    tm.tm_year = tp->tm_year;
18613840Swosch
18770598Sdwmalone    switch (sscanf(dp, "%d.%d.%d", &d, &m, &y)) {
18870598Sdwmalone    case 3:
18970598Sdwmalone	if (y > 1900)
19070598Sdwmalone	    y -= 1900;
19170598Sdwmalone	tm.tm_year = y;
19270598Sdwmalone	/* FALLTHROUGH */
19370598Sdwmalone    case 2:
19470598Sdwmalone	tm.tm_mon = m - 1;
19570598Sdwmalone	/* FALLTHROUGH */
19670598Sdwmalone    case 1:
19770598Sdwmalone	tm.tm_mday = d;
19813840Swosch    }
19913840Swosch
20049053Sn_hibma#ifdef DEBUG
20186051Sdd    fprintf(stderr, "Mktime: %d %d %s\n", (int)mktime(&tm), (int)t,
20213840Swosch	   asctime(&tm));
20313840Swosch#endif
20413840Swosch    return(mktime(&tm));
20513840Swosch}
20613840Swosch
20713840Swosch/*
20813840Swosch * Possible date formats include any combination of:
20913840Swosch *	3-charmonth			(January, Jan, Jan)
21013840Swosch *	3-charweekday			(Friday, Monday, mon.)
21113840Swosch *	numeric month or day		(1, 2, 04)
21213840Swosch *
21313840Swosch * Any character may separate them, or they may not be separated.  Any line,
21413840Swosch * following a line that is matched, that starts with "whitespace", is shown
21513840Swosch * along with the matched line.
21613840Swosch */
21713840Swoschint
21815066Smppisnow(endp, monthp, dayp, varp)
21913840Swosch	char *endp;
22015066Smpp	int	*monthp;
22115066Smpp	int	*dayp;
22215066Smpp	int	*varp;
22313840Swosch{
22415714Sache	int day, flags, month = 0, v1, v2;
22513840Swosch
22649053Sn_hibma	/*
22713840Swosch	 * CONVENTION
22813840Swosch	 *
22913840Swosch	 * Month:     1-12
23013840Swosch	 * Monthname: Jan .. Dec
23113840Swosch	 * Day:       1-31
23213840Swosch	 * Weekday:   Mon-Sun
23313840Swosch	 *
23413840Swosch	 */
23513840Swosch
23613840Swosch	flags = 0;
23749053Sn_hibma
23813840Swosch	/* read first field */
23913840Swosch	/* didn't recognize anything, skip it */
24013840Swosch	if (!(v1 = getfield(endp, &endp, &flags)))
24113840Swosch		return (0);
24213840Swosch
24313840Swosch	/* Easter or Easter depending days */
24449053Sn_hibma	if (flags & F_EASTER)
24515160Swosch	    day = v1 - 1; /* days since January 1 [0-365] */
24613840Swosch
24749053Sn_hibma	 /*
24849053Sn_hibma	  * 1. {Weekday,Day} XYZ ...
24913840Swosch	  *
25049053Sn_hibma	  *    where Day is > 12
25149053Sn_hibma	  */
25213840Swosch	else if (flags & F_ISDAY || v1 > 12) {
25313840Swosch
25413840Swosch		/* found a day; day: 1-31 or weekday: 1-7 */
25513840Swosch		day = v1;
25613840Swosch
25713840Swosch		/* {Day,Weekday} {Month,Monthname} ... */
25849053Sn_hibma		/* if no recognizable month, assume just a day alone
25913840Swosch		 * in other words, find month or use current month */
26013840Swosch		if (!(month = getfield(endp, &endp, &flags)))
26113840Swosch			month = tp->tm_mon + 1;
26249053Sn_hibma	}
26313840Swosch
26413840Swosch	/* 2. {Monthname} XYZ ... */
26513840Swosch	else if (flags & F_ISMONTH) {
26613840Swosch		month = v1;
26713840Swosch
26813840Swosch		/* Monthname {day,weekday} */
26913840Swosch		/* if no recognizable day, assume the first day in month */
27013840Swosch		if (!(day = getfield(endp, &endp, &flags)))
27113840Swosch			day = 1;
27249053Sn_hibma	}
27313840Swosch
27413840Swosch	/* Hm ... */
27513840Swosch	else {
27613840Swosch		v2 = getfield(endp, &endp, &flags);
27713840Swosch
27813840Swosch		/*
27913840Swosch		 * {Day} {Monthname} ...
28013840Swosch		 * where Day <= 12
28113840Swosch		 */
28213840Swosch		if (flags & F_ISMONTH) {
28313840Swosch			day = v1;
28413840Swosch			month = v2;
28515066Smpp			*varp = 0;
28649053Sn_hibma		}
28713840Swosch
28813840Swosch		/* {Month} {Weekday,Day} ...  */
28913840Swosch		else {
29013840Swosch			/* F_ISDAY set, v2 > 12, or no way to tell */
29113840Swosch			month = v1;
29213840Swosch			/* if no recognizable day, assume the first */
29313840Swosch			day = v2 ? v2 : 1;
29415066Smpp			*varp = 0;
29513840Swosch		}
29613840Swosch	}
29713840Swosch
29849053Sn_hibma	/* convert Weekday into *next*  Day,
29949053Sn_hibma	 * e.g.: 'Sunday' -> 22
30030735Swosch	 *       'SundayLast' -> ??
30113840Swosch	 */
30213840Swosch	if (flags & F_ISDAY) {
30349053Sn_hibma#ifdef DEBUG
30413840Swosch	    fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
30513840Swosch#endif
30613840Swosch
30715066Smpp	    *varp = 1;
30813840Swosch	    /* variable weekday, SundayLast, MondayFirst ... */
30913840Swosch	    if (day < 0 || day >= 10) {
31013840Swosch
31113840Swosch		/* negative offset; last, -4 .. -1 */
31213840Swosch		if (day < 0) {
31313840Swosch		    v1 = day/10 - 1;          /* offset -4 ... -1 */
31413840Swosch	            day = 10 + (day % 10);    /* day 1 ... 7 */
31513840Swosch
31649053Sn_hibma		    /* day, eg '22nd' */
31713840Swosch		    v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
31813840Swosch
31913840Swosch		    /* (month length - day) / 7 + 1 */
32049053Sn_hibma		    if (cumdays[month+1] - cumdays[month] >= v2
32149053Sn_hibma			&& ((int)((cumdays[month+1] -
32213840Swosch		               cumdays[month] - v2) / 7) + 1) == -v1)
32313840Swosch			/* bingo ! */
32413840Swosch			day = v2;
32549053Sn_hibma
32613840Swosch		    /* set to yesterday */
32722198Smpp		    else {
32813840Swosch			day = tp->tm_mday - 1;
32922198Smpp			if (day == 0)
33022198Smpp			    return (0);
33122198Smpp		    }
33249053Sn_hibma		}
33313840Swosch
33413840Swosch		/* first, second ... +1 ... +5 */
33513840Swosch		else {
33613840Swosch		    v1 = day/10;        /* offset: +1 (first Sunday) ... */
33713840Swosch		    day = day % 10;
33813840Swosch
33913840Swosch		    /* day, eg '22th' */
34013840Swosch		    v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
34113840Swosch
34213840Swosch		    /* Hurrah! matched */
34313840Swosch		    if ( ((v2 - 1 + 7) / 7) == v1 )
34413840Swosch			day = v2;
34513840Swosch
34613840Swosch		    /* set to yesterday */
34722198Smpp		    else {
34813840Swosch			day = tp->tm_mday - 1;
34922198Smpp			if (day == 0)
35022198Smpp			    return (0);
35122198Smpp		    }
35213840Swosch		}
35313840Swosch	    }
35413840Swosch
35513840Swosch	    /* wired */
35613840Swosch	    else {
35713840Swosch		day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
35815066Smpp		*varp = 1;
35913840Swosch	    }
36013840Swosch	}
36149053Sn_hibma
36215066Smpp	if (!(flags & F_EASTER)) {
36315066Smpp	    *monthp = month;
36415066Smpp	    *dayp = day;
36513840Swosch	    day = cumdays[month] + day;
36615066Smpp	}
36715066Smpp	else {
36815066Smpp	    for (v1 = 0; day > cumdays[v1]; v1++)
36915066Smpp		;
37015066Smpp	    *monthp = v1 - 1;
37115160Swosch	    *dayp = day - cumdays[v1 - 1];
37215066Smpp	    *varp = 1;
37315066Smpp	}
37413840Swosch
37549053Sn_hibma#ifdef DEBUG
37649053Sn_hibma	fprintf(stderr, "day2: day %d(%d-%d) yday %d\n", *dayp, day, cumdays[month], tp->tm_yday);
37715723Sache#endif
37813840Swosch	/* if today or today + offset days */
37949053Sn_hibma	if (day >= tp->tm_yday - f_dayBefore &&
38013840Swosch	    day <= tp->tm_yday + offset + f_dayAfter)
38113840Swosch		return (1);
38213840Swosch
38313840Swosch	/* if number of days left in this year + days to event in next year */
38413840Swosch	if (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||
38513840Swosch	    /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */
38649053Sn_hibma	    tp->tm_yday + day - f_dayBefore < 0
38713840Swosch	    )
38813840Swosch		return (1);
38913840Swosch	return (0);
39013840Swosch}
39113840Swosch
39213840Swosch
39313840Swoschint
39413840Swoschgetmonth(s)
39587235Smarkm	char *s;
39613840Swosch{
39787235Smarkm	const char **p;
39815720Sache	struct fixs *n;
39913840Swosch
40015720Sache	for (n = fnmonths; n->name; ++n)
40115720Sache		if (!strncasecmp(s, n->name, n->len))
40215720Sache			return ((n - fnmonths) + 1);
40315720Sache	for (n = nmonths; n->name; ++n)
40415720Sache		if (!strncasecmp(s, n->name, n->len))
40515720Sache			return ((n - nmonths) + 1);
40613840Swosch	for (p = months; *p; ++p)
40713840Swosch		if (!strncasecmp(s, *p, 3))
40813840Swosch			return ((p - months) + 1);
40913840Swosch	return (0);
41013840Swosch}
41113840Swosch
41213840Swosch
41313840Swoschint
41413840Swoschgetday(s)
41587235Smarkm	char *s;
41613840Swosch{
41787235Smarkm	const char **p;
41815720Sache	struct fixs *n;
41913840Swosch
42015720Sache	for (n = fndays; n->name; ++n)
42115720Sache		if (!strncasecmp(s, n->name, n->len))
42215720Sache			return ((n - fndays) + 1);
42315720Sache	for (n = ndays; n->name; ++n)
42415720Sache		if (!strncasecmp(s, n->name, n->len))
42515720Sache			return ((n - ndays) + 1);
42613840Swosch	for (p = days; *p; ++p)
42713840Swosch		if (!strncasecmp(s, *p, 3))
42813840Swosch			return ((p - days) + 1);
42913840Swosch	return (0);
43013840Swosch}
43113840Swosch
43213840Swosch/* return offset for variable weekdays
43313840Swosch * -1 -> last weekday in month
43449053Sn_hibma * +1 -> first weekday in month
43513840Swosch * ... etc ...
43613840Swosch */
43713840Swoschint
43813840Swoschgetdayvar(s)
43987235Smarkm	char *s;
44013840Swosch{
44187235Smarkm	int offs;
44213840Swosch
44313840Swosch
44487235Smarkm	offs = strlen(s);
44513840Swosch
44613840Swosch
44713840Swosch	/* Sun+1 or Wednesday-2
44813840Swosch	 *    ^              ^   */
44913840Swosch
45087235Smarkm	/* fprintf(stderr, "x: %s %s %d\n", s, s + offs - 2, offs); */
45187235Smarkm	switch(*(s + offs - 2)) {
45213840Swosch	case '-':
45387235Smarkm	    return(-(atoi(s + offs - 1)));
45413840Swosch	    break;
45513840Swosch	case '+':
45687235Smarkm	    return(atoi(s + offs - 1));
45713840Swosch	    break;
45813840Swosch	}
45913840Swosch
46049053Sn_hibma
46149053Sn_hibma	/*
46213840Swosch	 * some aliases: last, first, second, third, fourth
46313840Swosch	 */
46449053Sn_hibma
46513840Swosch	/* last */
46687235Smarkm	if      (offs > 4 && !strcasecmp(s + offs - 4, "last"))
46713840Swosch	    return(-1);
46887235Smarkm	else if (offs > 5 && !strcasecmp(s + offs - 5, "first"))
46913840Swosch	    return(+1);
47087235Smarkm	else if (offs > 6 && !strcasecmp(s + offs - 6, "second"))
47113840Swosch	    return(+2);
47287235Smarkm	else if (offs > 5 && !strcasecmp(s + offs - 5, "third"))
47313840Swosch	    return(+3);
47487235Smarkm	else if (offs > 6 && !strcasecmp(s + offs - 6, "fourth"))
47513840Swosch	    return(+4);
47613840Swosch
47713840Swosch
47813840Swosch	/* no offset detected */
47913840Swosch	return(0);
48013840Swosch}
481