I have a patch to output the current date in red (by default; configurable
via environment variable) for both ncal and cal.
The patch is not the cleanest, and it does things other than just colour
(like implements -3 for ncal (rotated version), and slightly changes the
layout of ncal).
If there is sufficient interest, I may try to split the patch into more
logical units, but this could be difficult, and if there is no interest, I
won't bother :)
Has been tested for a few months now; seems to work well for all
combinations of supported options.
TODO: Some of the code was stolen via grep's colour handling. We should
also check whether we are outputting to a tty or not just as grep does,
but I want to implement the command line style of grep's colour settings,
and this requires getlongopt() -- something which ncal doesn't yet use,
and I don't want to break any compatibility until I get feedback (and I
don't yet know how to use getlongopt :)
TOCHECK:
Man page has been updated, but since I don't know troff very well, the
text highlighting of NCAL_COLOR is probably wrong.
Default is not to print in colour. If printing to a tty, should the
default *be* colour?
--
TimC
If the plural of moose is meese the singular of sheep must be shoop.
--Hetta on RHODIndex: ncal.1
===================================================================
RCS file: /home/ssi/tconnors/cvsroot/bin/ncal.src/ncal.1,v
retrieving revision 1.1
retrieving revision 1.3
diff -u -b -r1.1 -r1.3
--- ncal.1 21 Aug 2005 11:15:16 -0000 1.1
+++ ncal.1 9 Sep 2005 05:02:04 -0000 1.3
@@ -33,20 +33,20 @@
.Nd displays a calendar and the date of easter
.Sh SYNOPSIS
.Nm
-.Op Fl 3jmy
+.Op Fl 3jmyc
.Oo
.Op Ar month
.Ar year
.Oc
.Nm ncal
-.Op Fl jJpwy
+.Op Fl 3jJpwyc
.Op Fl s Ar country_code
.Oo
.Op Ar month
.Ar year
.Oc
.Nm ncal
-.Op Fl Jeo
+.Op Fl Jeoc
.Op Ar year
.Sh DESCRIPTION
The
@@ -63,15 +63,16 @@
.Bl -tag -width indent
.It Fl 3
Print the previous month, the current month, and the next month all on one row.
-This flag will only work if you are not displaying Julian days (see
-.Fl J
-below).
.It Fl J
Display Julian Calendar, if combined with the
.Fl e
option, display date of easter according to the Julian Calendar.
.It Fl e
Display date of easter (for western churches).
+.It Fl c
+Highlight current date if in current view, using
+.Nm NCAL_COLOR
+environment variable, if defined (defaults to "01;31" for bright red).
.It Fl m
Print a calendar where Monday is the first day of the week, as opposed to
Sunday.
Index: ncal.c
===================================================================
RCS file: /home/ssi/tconnors/cvsroot/bin/ncal.src/ncal.c,v
retrieving revision 1.1
diff -u -b -r1.1 ncal.c
--- ncal.c 21 Aug 2005 11:12:15 -0000 1.1
+++ ncal.c 18 Sep 2005 10:48:11 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*-
* Copyright (c) 1997 Wolfgang Helbig
* All rights reserved.
@@ -50,7 +51,7 @@
#define MONTH_WIDTH_J 24
#define MONTH_WIDTH 18
-#define MAX_WIDTH 28
+#define MAX_WIDTH 28+13 /* The extra 13 is so we can print ANSI escape
sequences if necessary */
typedef struct date date;
@@ -115,7 +116,7 @@
char daystr[] = " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
" 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
" 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
- " 48 49 50 51 52 53";
+ " 48 49 50 51 52 53 ";
/* Table used to print day of year and week numbers */
char jdaystr[] = " 1 2 3 4 5 6 7 8 9"
@@ -154,7 +155,7 @@
" 330 331 332 333 334 335 336 337 338 339"
" 340 341 342 343 344 345 346 347 348 349"
" 350 351 352 353 354 355 356 357 358 359"
- " 360 361 362 363 364 365 366";
+ " 360 361 362 363 364 365 366 ";
int flag_weeks; /* user wants number of week */
int nswitch; /* user defined switch date */
@@ -162,6 +163,18 @@
int weekstart; /* day the week starts on (Sun [0] - Sat [6]) */
+/* Settings for printing out current day as colour */
+int color_option; /* If nonzero, use ncal_color marker. */
+char *ncal_color = "01;31"; /* The color string used. The user
+ can overwrite it using the
+ environment variable NCAL_COLOR.
+ The default is to print red. */
+
+int cm = 0; /* current month */
+int cy = 0; /* current year */
+int cd = 0; /* current day of month */
+int cdoy = 0; /* current day of year (for julian output) */
+
char *align(char *s, char *t, int w, int l);
#define center(s, t, w) align((s), (t), (w), 0)
void mkmonth(int year, int month, int jd_flag, struct monthlines * monthl);
@@ -172,7 +185,8 @@
void printeaster(int year, int julian, int orthodox);
void printmonth(int year, int month, int jd_flag);
void printmonthb(int year, int month, int jd_flag);
-void printmonthl(int year, int month);
+void printmonthl(int year, int month, int jd_flag);
+void printmonthlb(int year, int month, int jd_flag);
void printyear(int year, int jd_flag);
void printyearb(int year, int jd_flag);
int firstday(int y, int m);
@@ -186,6 +200,8 @@
int
main(int argc, char *argv[])
{
+ time_t t; /* For obtaining current day */
+ struct tm *tm; /* " " */
struct djswitch *p, *q; /* to search user defined switch date */
date never = {5875706, 1, 1};/* outside valid range of dates */
date ukswitch = {1752, 9, 2};/* switch date for Great Britain */
@@ -194,7 +210,7 @@
int y = 0; /* year */
int flag_three = 0; /* show previous, current, and next
month */
int flag_backward = 0; /* user called cal--backward compat. */
- int flag_hole_year = 0; /* user wants the whole year */
+ int flag_whole_year = 0; /* user wants the whole year */
int flag_julian_cal = 0; /* user wants Julian Calendar */
int flag_julian_day = 0; /* user wants the Julian day
* numbers */
@@ -244,11 +260,9 @@
if (flag_backward)
nswitchb = ndaysj(&ukswitch);
- while ((ch = getopt(argc, argv, "3Jejmops:wy")) != -1)
+ while ((ch = getopt(argc, argv, "3Jejmops:wyc")) != -1)
switch (ch) {
case '3':
- if (!flag_backward)
- usage();
flag_three = 1;
break;
case 'J':
@@ -301,7 +315,35 @@
flag_weeks = 1;
break;
case 'y':
- flag_hole_year = 1;
+ flag_whole_year = 1;
+ break;
+ case 'c':
+ color_option = 1;
+ /*Stollen from grep: Ideally, we would want to
+ * parse --colour=blah, but we are not using
+ * getopt_long, and this is a BSD program, so
+ * I don't think we can */
+/* if(optarg) {
+ if(!strcasecmp(optarg, "always") ||
!strcasecmp(optarg, "yes") ||
+ !strcasecmp(optarg, "force"))
+ color_option = 1;
+ else if(!strcasecmp(optarg, "never") ||
!strcasecmp(optarg, "no") ||
+ !strcasecmp(optarg, "none"))
+ color_option = 0;
+ else if(!strcasecmp(optarg, "auto") ||
!strcasecmp(optarg, "tty") ||
+ !strcasecmp(optarg, "if-tty"))
+ color_option = 2;
+ else
+ show_help = 1;
+ } else
+ color_option = 2;
+ if(color_option == 2) {
+ if(isatty(STDOUT_FILENO) && getenv("TERM") &&
+ strcmp(getenv("TERM"), "dumb"))
+ color_option = 1;
+ else
+ color_option = 0;
+ }*/
break;
default:
usage();
@@ -310,12 +352,22 @@
argc -= optind;
argv += optind;
- if (argc == 0) {
- time_t t;
- struct tm *tm;
+ if (color_option)
+ {
+ char *userval = getenv ("NCAL_COLOR");
+ if (userval != NULL && *userval != '\0') {
+ ncal_color = userval;
+ ncal_color[5]='\0'; /* Truncate any user value to the
5 ANSI chars that make sense */
+ }
+ }
t = time(NULL);
tm = localtime(&t);
+ cd = tm->tm_mday; /* Need to obtain the current day
for highlighting anyway */
+ cy = tm->tm_year + 1900;
+ cm = tm->tm_mon + 1;
+ cdoy = tm->tm_yday + 1;
+ if (argc == 0) {
y = tm->tm_year + 1900;
m = tm->tm_mon + 1;
}
@@ -343,13 +395,16 @@
if (flag_easter)
printeaster(y, flag_julian_cal, flag_orthodox);
- else if (argc == 1 || flag_hole_year)
+ else if (argc == 1 || flag_whole_year)
if (flag_backward)
printyearb(y, flag_julian_day);
else
printyear(y, flag_julian_day);
else if (flag_three)
- printmonthl(y, m);
+ if (flag_backward)
+ printmonthlb(y, m, flag_julian_day);
+ else
+ printmonthl(y, m, flag_julian_day);
else
if (flag_backward)
printmonthb(y, m, flag_julian_day);
@@ -364,9 +419,9 @@
{
fprintf(stderr, "%s\n%s\n%s\n",
- "usage: cal [-3jmy] [[month] year]",
- " ncal [-Jjpwy] [-s country_code] [[month] year]",
- " ncal [-Jeo] [year]");
+ "usage: cal [-3jmyc] [[month] year]",
+ " ncal [-3Jjpwyc] [-s country_code] [[month] year]",
+ " ncal [-Jeoc] [year]");
exit(EX_USAGE);
}
@@ -398,6 +453,8 @@
date dt;
struct tm tm;
char buf[80];
+ char colstr1[9]; /* opening ansi color escape codes */
+ char colstr2[6]; /* closing ansi color escape codes */
#ifndef D_MD_ORDER
static int d_first = 1; /* XXX */
#else
@@ -419,11 +476,19 @@
easterg(y, &dt);
memset(&tm, 0, sizeof(tm));
+
tm.tm_year = dt.y - 1900;
tm.tm_mon = dt.m - 1;
tm.tm_mday = dt.d;
strftime(buf, sizeof(buf), d_first ? "%e %B %Y" : "%B %e %Y", &tm);
- printf("%s\n", buf);
+
+ strcpy(colstr1, "");
+ strcpy(colstr2, "");
+ if (color_option && dt.d == cd && dt.m == cm && dt.y == cy) {
+ snprintf(colstr1, 9, "\33[%sm", ncal_color);
+ snprintf(colstr2, 6, "\33[00m");
+ }
+ printf("%s%s%s\n", colstr1,buf,colstr2);
}
void
@@ -431,17 +496,18 @@
{
struct monthlines month;
struct weekdays wds;
- int i;
+ int i, daywidth;
+ daywidth = jd_flag ? 4 : 3;
mkmonth(y, m - 1, jd_flag, &month);
mkweekdays(&wds);
printf(" %s %d\n", month.name, y);
for (i = 0; i != 7; i++)
- printf("%s%s\n", wds.names[i], month.lines[i]);
+ printf("%-*s%s\n", daywidth, wds.names[i], month.lines[i]);
for (i = 0; i != 7; i++)
free(wds.names[i]);
if (flag_weeks)
- printf(" %s\n", month.weeks);
+ printf(" %-*s%s\n", jd_flag, "", month.weeks);
}
void
@@ -451,24 +517,22 @@
struct weekdays wds;
char s[MAX_WIDTH], t[MAX_WIDTH];
int i;
- int mw;
+ int mw,daywidth;
mkmonthb(y, m - 1, jd_flag, &month);
mkweekdays(&wds);
mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
+ daywidth = jd_flag ? 4 : 3;
sprintf(s, "%s %d", month.name, y);
printf("%s\n", center(t, s, mw));
if (jd_flag)
- printf(" %s %s %s %s %s %s %s\n", wds.names[6],
- wds.names[0], wds.names[1], wds.names[2], wds.names[3],
- wds.names[4], wds.names[5]);
- else
- printf("%s %s %s %s %s %s %s\n", wds.names[6], wds.names[0],
- wds.names[1], wds.names[2], wds.names[3],
- wds.names[4], wds.names[5]);
+ printf(" ");
+ printf("%-*s%-*s%-*s%-*s%-*s%-*s%-*s\n", daywidth, wds.names[6],
+ daywidth, wds.names[0], daywidth, wds.names[1], daywidth,
wds.names[2], daywidth, wds.names[3],
+ daywidth, wds.names[4], daywidth, wds.names[5]);
for (i = 0; i != 7; i++)
free(wds.names[i]);
for (i = 0; i != 6; i++)
@@ -476,29 +540,73 @@
}
void
-printmonthl(int y, int m)
+printmonthl(int y, int m, int jd_flag)
+{
+ struct monthlines month[3];
+ struct weekdays wds;
+ char s[MAX_WIDTH], t[MAX_WIDTH];
+ int i, j, n;
+ int mw,daywidth;
+
+ mkweekdays(&wds);
+ mw = (jd_flag ? MONTH_WIDTH_J : MONTH_WIDTH) + 2;
+ daywidth = jd_flag ? 4 : 3;
+
+ for (n = y * 12 + m - 2, i = 0; i < 3; n++, i++) {
+ mkmonth(n / 12, n % 12, jd_flag, &month[i]);
+
+ sprintf(s, "%s %d", month[i].name, n / 12);
+ printf("%s ", center(t, s, mw));
+ mw = jd_flag ? MONTH_WIDTH_J : MONTH_WIDTH;
+ }
+ printf("\n");
+
+ for (i = 0; i != 7; i++) {
+ printf("%-*s", daywidth, wds.names[i]);
+ for (j = 0; j < 3; j++) {
+ printf("%s ", month[j].lines[i]+1);
+ }
+ printf("\n");
+ }
+ if (flag_weeks) {
+ printf(" %-*s", jd_flag, "");
+ for (j = 0; j < 3; j++) {
+ printf("%-*s", mw+2, month[j].weeks);
+ }
+ printf("\n");
+ }
+ for (i = 0; i < 7; i++)
+ free(wds.names[i]);
+}
+
+void
+printmonthlb(int y, int m, int jd_flag)
{
struct monthlines month[3];
struct weekdays wds;
char s[MAX_WIDTH], t[MAX_WIDTH];
int i, n;
- int mw;
+ int mw,daywidth;
mkweekdays(&wds);
- mw = MONTH_WIDTH_B;
+ mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
+ daywidth = jd_flag ? 4 : 3;
for (n = y * 12 + m - 2, i = 0; i < 3; n++, i++) {
- mkmonthb(n / 12, n % 12, 0, &month[i]);
+ mkmonthb(n / 12, n % 12, jd_flag, &month[i]);
sprintf(s, "%s %d", month[i].name, n / 12);
printf("%s ", center(t, s, mw));
}
printf("\n");
+ if (jd_flag)
+ printf(" ");
for (i = 0; i < 3; i++)
- printf("%s %s %s %s %s %s %s ", wds.names[6], wds.names[0],
- wds.names[1], wds.names[2], wds.names[3],
- wds.names[4], wds.names[5]);
+ printf("%-*s%-*s%-*s%-*s%-*s%-*s%-*s ", daywidth, wds.names[6],
+ daywidth, wds.names[0], daywidth, wds.names[1],
+ daywidth, wds.names[2], daywidth, wds.names[3],
+ daywidth, wds.names[4], daywidth, wds.names[5]);
printf("\n");
for (i = 0; i < 7; i++)
free(wds.names[i]);
@@ -506,7 +614,7 @@
for (i = 0; i < 6; i++) {
int j;
for (j = 0; j < 3; j++)
- printf("%s ", align(t, month[j].lines[i]+1, mw, 1));
+ printf("%s ", month[j].lines[i]+1);
printf("\n");
}
}
@@ -554,12 +662,12 @@
}
if (flag_weeks) {
if (mpl == 3)
- printf(" %-*s%-*s%-s\n",
+ printf(" %-*s %-*s %-s\n",
mw, year[j].weeks,
mw, year[j + 1].weeks,
year[j + 2].weeks);
else
- printf(" %-*s%-*s%-*s%-s\n",
+ printf(" %-*s %-*s %-*s %-s\n",
mw, year[j].weeks,
mw, year[j + 1].weeks,
mw, year[j + 2].weeks,
@@ -650,8 +758,11 @@
int i, j, k; /* just indices */
int last; /* the first day of next month */
int jan1 = 0; /* the first day of this year */
+ int mw; /* how wide is this month */
char *ds; /* pointer to day strings (daystr or
* jdaystr) */
+ char colstr1[9]; /* opening ansi color escape codes */
+ char colstr2[6]; /* closing ansi color escape codes */
/* Set name of month. */
memset(&tm, 0, sizeof(tm));
@@ -659,6 +770,9 @@
strftime(mlines->name, sizeof(mlines->name), "%B", &tm);
mlines->name[0] = toupper((unsigned char)mlines->name[0]);
+ dt.y = y;
+ dt.m = m + 1;
+ dt.d = 1;
/*
* Set first and last to the day number of the first day of this
* month and the first day of next month respectively. Set jan1 to
@@ -688,24 +802,48 @@
dw = 3;
}
+ mw = jd_flag ? MONTH_WIDTH_J : MONTH_WIDTH;
/*
* Fill the lines with day of month or day of year (julian day)
* line index: i, each line is one weekday. column index: j, each
* column is one day number. print column index: k.
*/
for (i = 0; i != 7; i++) {
+ memset(mlines->lines[i], ' ', MAX_WIDTH);
+ int offset=0;
for (j = firstm + i, k = 0; j < last; j += 7, k += dw)
if (j >= first) {
- if (jd_flag)
+ strcpy(colstr1, "");
+ strcpy(colstr2, "");
+ if (jd_flag) {
dt.d = j - jan1 + 1;
- else
+ if (color_option && dt.d == cdoy &&
dt.y == cy) {
+ snprintf(colstr1, 9, "\33[%sm",
ncal_color);
+ snprintf(colstr2, 6, "\33[00m");
+ }
+ } else {
sdate(j, &dt);
- memcpy(mlines->lines[i] + k,
- ds + dt.d * dw, dw);
+ if (color_option && dt.d == cd && dt.m
== cm && dt.y == cy) {
+ snprintf(colstr1, 9, "\33[%sm",
ncal_color);
+ snprintf(colstr2, 6, "\33[00m");
+ }
+ }
+ (mlines->lines[i])[k]=' ';
+ /*k+1 and dw+1 in following is so we
+ * can get rid of the space at the
+ * start of the line, but have a space
+ * between all other digits*/
+ memcpy(mlines->lines[i] + k+1, colstr1,
strlen(colstr1));
+ offset+=strlen(colstr1);
+ k+=strlen(colstr1);
+ memcpy(mlines->lines[i] + k+1,
+ ds + dt.d * dw+1, dw);
+ memcpy(mlines->lines[i] + k + dw, colstr2,
strlen(colstr2));
+ offset+=strlen(colstr2);
+ k+=strlen(colstr2);
} else
memcpy(mlines->lines[i] + k, " ", dw);
- mlines->lines[i][k] = '\0';
-
+ mlines->lines[i][mw+offset+1] = '\0';
}
/* fill the weeknumbers */
@@ -731,10 +869,14 @@
int first; /* first day of month */
int firsts; /* sunday of first week of month */
int i, j, k; /* just indices */
+ int pos; /* position in memory */
int jan1 = 0; /* the first day of this year */
int last; /* the first day of next month */
+ int mw; /* how wide is this month */
char *ds; /* pointer to day strings (daystr or
* jdaystr) */
+ char colstr1[9]; /* opening ansi color escape codes */
+ char colstr2[6]; /* closing ansi color escape codes */
/* Set ds (daystring) and dw (daywidth) according to the jd_flag */
if (jd_flag) {
@@ -784,27 +926,49 @@
*/
firsts = first - (weekday(first)+(8-weekstart)) % 7;
+ mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
/*
* Fill the lines with day of month or day of year (Julian day)
* line index: i, each line is one week. column index: j, each
* column is one day number. print column index: k.
*/
for (i = 0; i != 6; i++) {
- for (j = firsts + 7 * i, k = 0; j < last && k != dw * 7;
- j++, k += dw)
+ memset(mlines->lines[i], ' ', MAX_WIDTH);
+ int offset=0;
+ for (j = firsts + 7 * i, k = 0, pos = 0; j < last && k != 7;
+ j++, k++, pos += dw)
if (j >= first) {
- if (jd_flag)
+ strcpy(colstr1, "");
+ strcpy(colstr2, "");
+ if (jd_flag) {
dt.d = j - jan1 + 1;
- else
+ if (color_option && dt.d == cdoy &&
dt.y == cy) {
+ snprintf(colstr1, 9, "\33[%sm",
ncal_color);
+ snprintf(colstr2, 6, "\33[00m");
+ }
+ } else {
sdateb(j, &dt);
- memcpy(mlines->lines[i] + k,
- ds + dt.d * dw, dw);
+ if (color_option && dt.d == cd && dt.m
== cm && dt.y == cy) {
+ snprintf(colstr1, 9, "\33[%sm",
ncal_color);
+ snprintf(colstr2, 6, "\33[00m");
+ }
+ }
+ (mlines->lines[i])[pos]=' ';
+ /*pos+1 and dw+1 in following is so we
+ * can get rid of the space at the
+ * start of the line, but have a space
+ * between all other digits*/
+ memcpy(mlines->lines[i] + pos+1, colstr1,
strlen(colstr1));
+ offset+=strlen(colstr1);
+ pos+=strlen(colstr1);
+ memcpy(mlines->lines[i] + pos+1,
+ ds + dt.d * dw+1, dw);
+ memcpy(mlines->lines[i] + pos + dw, colstr2,
strlen(colstr2));
+ offset+=strlen(colstr2);
+ pos+=strlen(colstr2);
} else
- memcpy(mlines->lines[i] + k, " ", dw);
- if (k == 0)
- mlines->lines[i][1] = '\0';
- else
- mlines->lines[i][k] = '\0';
+ memcpy(mlines->lines[i] + pos, " ", dw);
+ mlines->lines[i][mw+offset+1] = '\0';
}
}