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 RHOD
Index: 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';
        }
 }
 

Reply via email to