changeset 394:92ef50262ec7

Implment cal.
author Rob Landley <rob@landley.net>
date Sun, 11 Dec 2011 02:36:01 -0600
parents bfc208c5ac79
children 32c7b6af5b29
files toys/cal.c
diffstat 1 files changed, 134 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/cal.c	Sun Dec 11 02:36:01 2011 -0600
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4:
+ *
+ * cal.c - show calendar.
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html
+
+USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CAL
+	bool "cal"
+	default y
+	help
+	  usage: cal [[month] year]
+	  Print a calendar.
+
+	  With one argument, prints all months of the specified year.
+	  With two arguments, prints calendar for month and year.
+*/
+
+#include "toys.h"
+
+// Write calendar into buffer: each line is 20 chars wide, end indicated
+// by empty string.
+
+static char *calstrings(char *buf, struct tm *tm)
+{
+	char temp[21];
+	int wday, mday, start, len, line;
+
+	// header
+	len = strftime(temp, 21, "%B %Y", tm);
+	len += (20-len)/2;
+	buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, "");
+	buf++;
+	buf += sprintf(buf, "Su Mo Tu We Th Fr Sa ");
+	buf++;
+
+	// What day of the week does this month start on?
+	if (tm->tm_mday>1)
+		start = (36+tm->tm_wday-tm->tm_mday)%7;
+	else start = tm->tm_wday;
+
+	// What day does this month end on?  Alas, libc doesn't tell us...
+	len = 31;
+	if (tm->tm_mon == 1) {
+		int year = tm->tm_year;
+		len = 28;
+		if (!(year & 3) && !((year&100) && !(year&400))) len++;
+	} else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30;
+
+	for (mday=line=0;line<6;line++) {
+		for (wday=0; wday<7; wday++) {
+			char *pat = "   ";
+			if (!mday ? wday==start : mday<len) {
+				pat = "%2d ";
+				mday++;
+			}
+			buf += sprintf(buf, pat, mday);
+		}
+		buf++;
+	}
+
+	return buf;
+}
+
+void xcheckrange(long val, long low, long high)
+{
+	char *err = "%ld %s than %ld";
+
+	if (val < low) error_exit(err, val, "less", low);
+	if (val > high) error_exit(err, val, "greater", high);
+}
+
+// Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line
+// plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer.
+
+void cal_main(void)
+{
+	struct tm *tm;
+	char *buf = toybuf;
+
+	if (toys.optc) {
+		// Conveniently starts zeroed
+		tm = (struct tm *)toybuf;
+		buf += sizeof(struct tm);
+
+		// Last argument is year, one before that (if any) is month.
+		xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999);
+		tm->tm_year -= 1900;
+		tm->tm_mday = 1;
+		tm->tm_hour = 12;  // noon to avoid timezone weirdness
+		if (toys.optc) {
+			xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12);
+			tm->tm_mon--;
+
+		// Print 12 months of the year
+
+		} else {
+			char *bufs[12];
+			int i, j, k;
+
+			for (i=0; i<12; i++) {
+				tm->tm_mon=i;
+				mktime(tm);
+				buf = calstrings(bufs[i]=buf, tm);
+			}
+
+			// 4 rows, 6 lines each, 3 columns
+			for (i=0; i<4; i++) {
+				for (j=0; j<8; j++) {
+					for(k=0; k<3; k++) {
+						char **b = bufs+(k+i*3);
+						*b += printf("%s ", *b);
+					}
+					puts("");
+				}
+			}
+			return;
+		}
+
+		// What day of the week does that start on?
+		mktime(tm);
+
+	} else {
+		time_t now;
+		time(&now);
+		tm = localtime(&now);
+	}
+
+	calstrings(buf, tm);
+	while (*buf) buf += printf("%s\n", buf);
+}