commit c6f1e8aa20bc6f49b8d47b85c687d910c5b5ec2f
Author: Greg Reagle <[email protected]>
Date: Fri Jan 2 13:12:59 2015 +0000
Various cal(1) improvements
1) No limit on number of months (removed MONTHMAX)
2) Strings printed to stdout rather than copied to an internal buffer
3) Rewritten date calculation algorithms
diff --git a/LICENSE b/LICENSE
index bb81bfd..e9d33fc 100644
--- a/LICENSE
+++ b/LICENSE
@@ -54,3 +54,4 @@ Authors/contributors include:
© 2014 Ari Malinen <[email protected]>
© 2014 Brandon Mulcahy <[email protected]>
© 2014 Adria Garriga <[email protected]>
+© 2014 Greg Reagle <[email protected]>
diff --git a/cal.c b/cal.c
index dca2313..28e58fe 100644
--- a/cal.c
+++ b/cal.c
@@ -5,97 +5,100 @@
#include "util.h"
-#define MONTHMAX 100
+static int
+isleap(int year)
+{
+ if (year % 400 == 0)
+ return 1;
+ if (year % 100 == 0)
+ return 0;
+ return (year % 4 == 0);
+}
-static void drawcal(int, int, int, int, int, int);
-static int dayofweek(int, int, int, int);
-static int isleap(int);
-static void usage(void);
+static int
+monthlength(int year, int month)
+{
+ int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ return (month==1 && isleap(year)) ? 29 : mdays[month];
+}
+
+/* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
+static int
+dayofweek(int year, int month, int dom)
+{
+ int m, y, a;
+ month += 1; /* in this formula, 1 <= month <= 12 */
+ a = (14 - month) / 12;
+ y = year - a;
+ m = month + 12*a - 2;
+ return (dom + y + y/4 - y/100 + y/400 +((31*m)/12)) % 7;
+}
+
+static void
+printgrid(int year, int month, int fday, int line)
+{
+ int dom, offset, d=0;
+
+ offset = dayofweek(year, month, 1) - fday;
+ if (offset < 0)
+ offset += 7;
+ if (line==1) {
+ for ( ; d < offset; ++d)
+ printf(" ");
+ dom = 1;
+ } else {
+ dom = 8-offset + (line-2)*7;
+ }
+ for ( ; d < 7 && dom <= monthlength(year, month); ++d, ++dom)
+ printf("%2d ", dom);
+ for ( ; d < 7; ++d)
+ printf(" ");
+}
static void
drawcal(int year, int month, int day, int ncols, int nmons, int fday)
{
- char str[21];
- int count[MONTHMAX];
- int d, i, r, j;
- int moff, yoff, cur, last, ndays, day1;
- char *smon[] = {
- " January", " February", " March",
- " April", " May", " June",
- " July", " August", " September",
- " October", " November", " December" };
- int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- int row = 0;
+ char *smon[] = {" January", " February", " March", " April",
+ " May", " June", " July", " August",
+ "September", " October", " November", " December" };
char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
-
- if (!ncols)
- ncols = nmons;
- while (nmons > 0) {
- last = MIN(nmons, ncols);
- for (i = 0; i < last; i++) {
- moff = month + ncols * row + i - 1;
- cur = moff % 12;
- yoff = year + moff / 12;
-
- snprintf(str, sizeof(str), "%s %d", smon[cur], yoff);
- printf("%-20s ", str);
- count[i] = 1;
+ int m, n, col, cur_year, cur_month, line, dow;
+
+ for (m = 0; m < nmons; ) {
+ n = m;
+ for (col = 0; m < nmons && col < ncols; ++col, ++m) {
+ cur_year = year + m/12;
+ cur_month = month + m%12;
+ if (cur_month > 11) {
+ cur_month -= 12;
+ cur_year += 1;
+ }
+ printf(" %s %d ", smon[cur_month], cur_year);
+ printf(" ");
}
printf("\n");
-
- for (i = 0; i < last; i++) {
- for (j = fday; j < LEN(days); j++)
- printf("%s ", days[j]);
- for (j = 0; j < fday; j++)
- printf("%s ", days[j]);
+ for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
+ for (dow = fday; dow < (fday+7); ++dow)
+ printf("%s ", days[dow%7]);
printf(" ");
}
printf("\n");
-
- for (r = 0; r < 6; r++) {
- for (i = 0; i < last; i++) {
- moff = month + ncols * row + i - 1;
- cur = moff % 12;
- yoff = year + moff / 12;
-
- ndays = mdays[cur] + ((cur == 1) &&
isleap(yoff));
- day1 = dayofweek(yoff, cur, 1, fday);
-
- for (d = 0; d < 7; d++) {
- if ((r || d >= day1) && count[i] <=
ndays)
- printf("%2d ", count[i]++);
- else
- printf(" ");
+ for (line=1; line<=6; ++line) {
+ for (col=0, m=n; m<nmons && col<ncols; ++col, ++m) {
+ cur_year = year + m/12;
+ cur_month = month + m%12;
+ if (cur_month > 11) {
+ cur_month -= 12;
+ cur_year += 1;
}
+ printgrid(cur_year, cur_month, fday, line);
printf(" ");
}
printf("\n");
}
- nmons -= ncols;
- row++;
}
}
-static int
-dayofweek(int year, int month, int day, int fday)
-{
- static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
-
- day += 7 - fday;
- year -= month < 2;
- return (year + year / 4 - year / 100 + year / 400 + t[month] + day) % 7;
-}
-
-static int
-isleap(int year)
-{
- if (year % 400 == 0)
- return 1;
- if (year % 100 == 0)
- return 0;
- return (year % 4 == 0);
-}
-
static void
usage(void)
{
@@ -172,12 +175,11 @@ main(int argc, char *argv[])
usage();
}
- if (ncols < 0 || month < 1 || month > 12 || nmons < 1 \
- || nmons > MONTHMAX || fday < 0 || fday > 6) {
+ if (ncols < 0 || month < 1 || month > 12 || nmons < 1 || fday < 0 ||
fday > 6) {
usage();
}
- drawcal(year, month, day, ncols, nmons, fday);
+ drawcal(year, month-1, day, ncols, nmons, fday);
return 0;
}