--- calendar.c.orig	Mon Oct 12 20:12:25 2009
+++ calendar.c	Mon Nov 16 09:52:28 2009
@@ -62,6 +62,11 @@ static const char rcsid[] = "$OpenBSD: calendar.c,v 1.
 #include "pathnames.h"
 #include "calendar.h"
 
+struct wday_t{
+	char *s;
+	int c;
+};
+
 char *calendarFile = "calendar";  /* default calendar file */
 char *calendarHome = ".calendar"; /* HOME */
 char *calendarNoMail = "nomail";  /* don't sent mail if this file exists */
@@ -78,16 +83,19 @@ int f_SetdayAfter = 0; /* calendar invoked with -A */
 struct specialev spev[NUMEV];
 
 void childsig(int);
+time_t weekday(char*);
+unsigned int mdays(unsigned int, unsigned int);
 
 int
 main(int argc, char *argv[])
 {
 	int ch;
 	char *caldir;
+	int t=0,w=0;
 
 	(void)setlocale(LC_ALL, "");
 
-	while ((ch = getopt(argc, argv, "abf:t:A:B:-")) != -1)
+	while ((ch = getopt(argc, argv, "abw:f:t:A:B:-")) != -1)
 		switch (ch) {
 		case '-':		/* backward contemptible */
 		case 'a':
@@ -107,6 +115,7 @@ main(int argc, char *argv[])
 		case 't': /* other date, undocumented, for tests */
 			if ((f_time = Mktime(optarg)) <= 0)
 				errx(1, "specified date is outside allowed range");
+			t = 1;
 			break;
 
 		case 'A': /* days after current date */
@@ -117,6 +126,10 @@ main(int argc, char *argv[])
 		case 'B': /* days before current date */
 			f_dayBefore = atoi(optarg);
 			break;
+		case 'w':
+			f_time = weekday(optarg);
+			w = 1;
+			break;
 
 		default:
 			usage();
@@ -126,6 +139,8 @@ main(int argc, char *argv[])
 
 	if (argc)
 		usage();
+	if (t && w)
+		errx(1, "you cannot use -t and -w");
 
 	/* use current time */
 	if (f_time <= 0)
@@ -260,7 +275,7 @@ usage(void)
 {
 	(void)fprintf(stderr,
 	    "usage: calendar [-ab] [-A num] [-B num] [-f calendarfile] "
-	    "[-t [[[cc]yy][mm]]dd]\n");
+	    "[-t [[[cc]yy][mm]]dd | -w weekday]\n");
 	exit(1);
 }
 
@@ -269,3 +284,66 @@ void
 childsig(int signo)
 {
 }
+
+time_t
+weekday(char *in)
+{
+ 	struct wday_t	wday[7] = {"sun", 0,
+				"mon", 1,
+				"tue", 2,
+				"wed", 3,
+				"thu", 4,
+				"fri", 5,
+				"sat", 6};
+
+	time_t now;
+	struct tm *conv;
+	int dest = -1;
+	int i;
+
+	time(&now);
+	conv = localtime(&now);
+
+	for (i=0;i < 7 && dest == -1; ++i)
+		if (!strncasecmp(wday[i].s, in, 3))
+			dest = wday[i].c;
+
+	if (dest == -1)
+		errx(1, "invalid day to -w");
+	if (conv->tm_wday < dest)
+		conv->tm_mday += (dest - conv->tm_wday);
+	else if (conv->tm_wday == dest)
+		conv->tm_mday += 7;
+	else
+		conv->tm_mday += (7 - conv->tm_wday) + dest;
+
+	/* Handle month roll-overs */
+	if (conv->tm_mday > mdays(conv->tm_mon, conv->tm_year)) {
+		conv->tm_mday -= mdays(conv->tm_mon, conv->tm_year);
+		++conv->tm_mon;
+		if (conv->tm_mon > 11) {
+			conv->tm_mon -= 11;
+			++conv->tm_year;
+		}
+	}
+
+	now = mktime(conv);
+	return now;
+}
+
+unsigned int
+mdays(unsigned int month, unsigned int year){
+	if (month == 3 || month == 5 || month == 8 || month == 10)
+		return 30;
+	else if (month == 1) {
+		/* Stupid February! */
+		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
+			return 29;
+		else
+			return 28;
+	} else
+		return 31;
+}
+

