commit c6f1e8aa20bc6f49b8d47b85c687d910c5b5ec2f
parent 6faeb36e1484bf4f674861414485f6e69b4cb464
Author: Greg Reagle <greg.reagle@umbc.edu>
Date: Fri, 2 Jan 2015 13:12:59 +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
Diffstat:
M | LICENSE | | | 1 | + |
M | cal.c | | | 152 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
2 files changed, 78 insertions(+), 75 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -54,3 +54,4 @@ Authors/contributors include:
© 2014 Ari Malinen <ari.malinen@gmail.com>
© 2014 Brandon Mulcahy <brandon@jangler.info>
© 2014 Adria Garriga <rhaps0dy@installgentoo.com>
+© 2014 Greg Reagle <greg.reagle@umbc.edu>
diff --git 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;
}