svn commit: r213945 - stable/7/usr.bin/ncal

Edwin Groothuis edwin at FreeBSD.org
Sun Oct 17 07:11:41 UTC 2010


Author: edwin
Date: Sun Oct 17 07:11:40 2010
New Revision: 213945
URL: http://svn.freebsd.org/changeset/base/213945

Log:
  Mega-merge of ncal into stable/7:
  
  r186401:
  Implement a new feature for the "-m" option: if the month number is
  followed by 'f' or 'p', use the following or preceding month of that
  number, respectively.  Document this.  Also includes other minor
  grammatical and punctuation fixes to the manual page (capitalize
  Easter, etc.).
  
  r191330:
  Implement highlighting of today in month view of cal/ncal just like
  gnu cal does. This is currently disabled for year view because of hard
  coded padding in that case. This will hopefully be fixed soon.
  
  r191364:
  Couple of changes based on feedback
  o       Change mr/me to so/se [1].
  o       Introduce a -h option to disable highlighting. [2]
  o       Spell STDOUT_FILENO as such and pass NULL to tgetent()
  to handle the case of unset TERM. [3]
  
  r191687:
  Fixed missing dependency.
  
  r194366:
  Fix column width of weekday names for multibyte locales.
  
  r194447:
  Since the width is always 2, it is enough to put just one
  trailing space is enough.
  
  r204697:
  - Implement -3 option (show previous, this and next month) option.
  - Add -A option (months after this month).
  - Add -B option (months before this month).
  - Fix highlighting of today in year overview.
  - Fix aligning of "foreign" characters.
  
  r204706:
  Remove no-op of WARNS?=
  
  r204849:
  - document the -3, -A and -B properly in Synopsis.
  - add highlight of current date for non-terminals.
  - fix -J option.
  - code cleanup.
  
  r204908:
  - Fix the highlighting for non-terminals when the last week is not
    7 days long.
  - "-m <N> <YYYY>" now prints only the month, not the whole year.
  
  r205071:
  - With the introduction of -A, -B and -3, not all combinations of
    arguments makes sense anymore. For example, what would a combination
    of -3 (show three months) and -y (show the whole year) do?
    We will abort on these cases.
  - Move the debug option -d to -H (from highlight), while -d is now
    used for setting the day of "today" so that -y and friends can
    be tested.
  
  r205427:
  Replace -b with -C and -B (as proposed by Alexander).
  Add -3, -A and -B to the usage.
  Update regression test for the new parameters.
  
  r212032:
  Use basename(3) to determine the name of the program.

Modified:
  stable/7/usr.bin/ncal/Makefile
  stable/7/usr.bin/ncal/ncal.1
  stable/7/usr.bin/ncal/ncal.c
Directory Properties:
  stable/7/usr.bin/ncal/   (props changed)

Modified: stable/7/usr.bin/ncal/Makefile
==============================================================================
--- stable/7/usr.bin/ncal/Makefile	Sun Oct 17 03:13:30 2010	(r213944)
+++ stable/7/usr.bin/ncal/Makefile	Sun Oct 17 07:11:40 2010	(r213945)
@@ -2,9 +2,8 @@
 
 PROG=	ncal
 
-DPADD=	${LIBCALENDAR}
-LDADD=	-lcalendar
-WARNS?=	1
+DPADD=	${LIBCALENDAR} ${LIBTERMCAP}
+LDADD=	-lcalendar -ltermcap
 
 LINKS=	${BINDIR}/ncal ${BINDIR}/cal
 MLINKS=	ncal.1 cal.1

Modified: stable/7/usr.bin/ncal/ncal.1
==============================================================================
--- stable/7/usr.bin/ncal/ncal.1	Sun Oct 17 03:13:30 2010	(r213944)
+++ stable/7/usr.bin/ncal/ncal.1	Sun Oct 17 07:11:40 2010	(r213945)
@@ -30,34 +30,46 @@
 .Sh NAME
 .Nm cal ,
 .Nm ncal
-.Nd displays a calendar and the date of easter
+.Nd displays a calendar and the date of Easter
 .Sh SYNOPSIS
 .Nm
-.Op Fl jy
+.Op Fl 3hjy
+.Op Fl A Ar number
+.Op Fl B Ar number
 .Oo
 .Op Ar month
 .Ar year
 .Oc
 .Nm
-.Op Fl j
+.Op Fl 3hj
+.Op Fl A Ar number
+.Op Fl B Ar number
 .Fl m Ar month
 .Op Ar year
 .Nm ncal
-.Op Fl jJpwy
+.Op Fl 3hjJpwy
+.Op Fl A Ar number
+.Op Fl B Ar number
 .Op Fl s Ar country_code
 .Oo
 .Op Ar month
 .Ar year
 .Oc
 .Nm ncal
-.Op Fl Jeo
+.Op Fl 3hJeo
+.Op Fl A Ar number
+.Op Fl B Ar number
 .Op Ar year
+.Nm ncal
+.Op Fl CN
+.Op Fl H Ar yyyy-mm-dd
+.Op Fl d Ar yyyy-mm
 .Sh DESCRIPTION
 The
 .Nm
 utility displays a simple calendar in traditional format and
 .Nm ncal
-offers an alternative layout, more options and the date of easter.
+offers an alternative layout, more options and the date of Easter.
 The new format is a little cramped but it makes a year fit
 on a 25x80 terminal.
 If arguments are not specified,
@@ -65,19 +77,29 @@ the current month is displayed.
 .Pp
 The options are as follows:
 .Bl -tag -width indent
+.It Fl h
+Turns off highlighting of today.
 .It Fl J
 Display Julian Calendar, if combined with the
 .Fl e
-option, display date of easter according to the Julian Calendar.
+option, display date of Easter according to the Julian Calendar.
 .It Fl e
-Display date of easter (for western churches).
+Display date of Easter (for western churches).
 .It Fl j
 Display Julian days (days one-based, numbered from January 1).
 .It Fl m Ar month
 Display the specified
 .Ar month .
+If
+.Ar month
+is specified as a decimal number, it may be followed by the letter
+.Ql f
+or
+.Ql p
+to indicate the following or preceding month of that number,
+respectively.
 .It Fl o
-Display date of orthodox easter (Greek and Russian
+Display date of Orthodox Easter (Greek and Russian
 Orthodox Churches).
 .It Fl p
 Print the country codes and switching days from Julian to Gregorian
@@ -99,21 +121,56 @@ Britain and her colonies switched to the
 Print the number of the week below each week column.
 .It Fl y
 Display a calendar for the specified year.
+.It Fl 3
+Display the previous, current and next month surrounding today.
+.It Fl A Ar number
+Display the
+.Ar number
+of months after the current month.
+.It Fl B Ar number
+Display the
+.Ar number
+of months before the current month.
+.It Fl C
+Switch to
+.Nm cal
+mode.
+.It Fl N
+Switch to
+.Nm ncal
+mode.
+.It Fl d Ar yyyy-mm
+Use
+.Ar yyyy-mm
+as the current date (for debugging of date selection).
+.It Fl H Ar yyyy-mm-dd
+Use
+.Ar yyyy-mm-dd
+as the current date (for debugging of highlighting).
 .El
 .Pp
-A single parameter specifies the year (1 - 9999) to be displayed;
+A single parameter specifies the year (1\(en9999) to be displayed;
 note the year must be fully specified:
 .Dq Li cal 89
 will
 .Em not
-display a calendar for 1989.
-Two parameters denote the month and year; the month is either a number between
-1 and 12, or a full or abbreviated name as specified by the current locale.
-Month and year default to those of the current system clock and time zone (so
+display a calendar for 1989.  Two parameters denote the month and
+year; the month is either a number between 1 and 12, or a full or
+abbreviated name as specified by the current locale.  Month and
+year default to those of the current system clock and time zone (so
 .Dq Li cal -m 8
-will display a calendar for the month of August in the current year).
+will display a calendar for the month of August in the current
+year).
+.Pp
+Not all options can be used together. For example
+.Dq Li -3 -A 2 -B 3 -y -m 7
+would mean:
+show me the three months around the seventh month, three before
+that, two after that and the whole year.
+.Nm ncal
+will warn about these combinations.
 .Pp
-A year starts on Jan 1.
+A year starts on January 1.
 .Sh SEE ALSO
 .Xr calendar 3 ,
 .Xr strftime 3
@@ -132,5 +189,8 @@ The
 command and manual were written by
 .An Wolfgang Helbig Aq helbig at FreeBSD.org .
 .Sh BUGS
-The assignment of Julian\(emGregorian switching dates to
-country codes is historically naive for many countries.
+The assignment of Julian\(enGregorian switching dates to country
+codes is historically naive for many countries.
+.Pp
+Not all options are compatible and using them in different orders
+will give varying results.

Modified: stable/7/usr.bin/ncal/ncal.c
==============================================================================
--- stable/7/usr.bin/ncal/ncal.c	Sun Oct 17 03:13:30 2010	(r213944)
+++ stable/7/usr.bin/ncal/ncal.c	Sun Oct 17 07:11:40 2010	(r213945)
@@ -33,6 +33,7 @@ static const char rcsid[] =
 #include <ctype.h>
 #include <err.h>
 #include <langinfo.h>
+#include <libgen.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,15 +43,17 @@ static const char rcsid[] =
 #include <unistd.h>
 #include <wchar.h>
 #include <wctype.h>
+#include <term.h>
+#undef lines			/* term.h defines this */
 
-/* Width of one month with backward compatibility */
+/* Width of one month with backward compatibility and in regular mode*/
 #define MONTH_WIDTH_B_J 27
 #define MONTH_WIDTH_B 20
 
-#define MONTH_WIDTH_J 24
-#define MONTH_WIDTH 18
+#define MONTH_WIDTH_R_J 24
+#define MONTH_WIDTH_R 18
 
-#define MAX_WIDTH 28
+#define MAX_WIDTH 64
 
 typedef struct date date;
 
@@ -58,6 +61,7 @@ struct monthlines {
 	wchar_t name[MAX_WIDTH + 1];
 	char lines[7][MAX_WIDTH + 1];
 	char weeks[MAX_WIDTH + 1];
+	unsigned int extralen[7];
 };
 
 struct weekdays {
@@ -156,29 +160,29 @@ char jdaystr[] = "       1   2   3   4  
 		 " 350 351 352 353 354 355 356 357 358 359"
 		 " 360 361 362 363 364 365 366";
 
+int	flag_nohighlight;	/* user doesn't want a highlighted today */
 int     flag_weeks;		/* user wants number of week */
 int     nswitch;		/* user defined switch date */
 int	nswitchb;		/* switch date for backward compatibility */
+int	highlightdate;
 
-char   *center(char *s, char *t, int w);
+char	*center(char *s, char *t, int w);
 wchar_t *wcenter(wchar_t *s, wchar_t *t, int w);
-void	mkmonth(int year, int month, int jd_flag, struct monthlines * monthl);
-void    mkmonthb(int year, int month, int jd_flag, struct monthlines * monthl);
-void    mkweekdays(struct weekdays * wds);
-int     parsemonth(const char *s);
-void    printcc(void);
-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    printyear(int year, int jd_flag);
-void    printyearb(int year, int jd_flag);
 int	firstday(int y, int m);
-date   *sdate(int ndays, struct date * d);
-date   *sdateb(int ndays, struct date * d);
-int     sndays(struct date * d);
-int     sndaysb(struct date * d);
-static void usage(void);
-int     weekdayb(int nd);
+void	highlight(char *dst, char *src, int len, int *extraletters);
+void	mkmonthr(int year, int month, int jd_flag, struct monthlines * monthl);
+void	mkmonthb(int year, int month, int jd_flag, struct monthlines * monthl);
+void	mkweekdays(struct weekdays * wds);
+void	monthranger(int year, int m, int jd_flag, int before, int after);
+void	monthrangeb(int year, int m, int jd_flag, int before, int after);
+int	parsemonth(const char *s, int *m, int *y);
+void	printcc(void);
+void	printeaster(int year, int julian, int orthodox);
+date	*sdater(int ndays, struct date * d);
+date	*sdateb(int ndays, struct date * d);
+int	sndaysr(struct date * d);
+int	sndaysb(struct date * d);
+static void	usage(void);
 
 int
 main(int argc, char *argv[])
@@ -186,20 +190,32 @@ main(int argc, char *argv[])
 	struct  djswitch *p, *q;	/* to search user defined switch date */
 	date	never = {10000, 1, 1};	/* outside valid range of dates */
 	date	ukswitch = {1752, 9, 2};/* switch date for Great Britain */
+	date	dt;
 	int     ch;			/* holds the option character */
 	int     m = 0;			/* month */
 	int	y = 0;			/* year */
 	int     flag_backward = 0;	/* user called cal--backward compat. */
-	int     flag_hole_year = 0;	/* user wants the whole year */
+	int     flag_wholeyear = 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 */
-	int	flag_orthodox = 0;	/* use wants Orthodox easter */
-	int	flag_easter = 0;	/* use wants easter date */
+	int     flag_julian_day = 0;	/* user wants the Julian day numbers */
+	int	flag_orthodox = 0;	/* user wants Orthodox easter */
+	int	flag_easter = 0;	/* user wants easter date */
+	int	flag_3months = 0;	/* user wants 3 month display (-3) */
+	int	flag_after = 0;		/* user wants to see months after */
+	int	flag_before = 0;	/* user wants to see months before */
+	int	flag_specifiedmonth = 0;/* user wants to see this month (-m) */
+	int	flag_givenmonth = 0;	/* user has specified month [n] */
+	int	flag_givenyear = 0;	/* user has specified year [n] */
 	char	*cp;			/* character pointer */
+	char	*flag_today = NULL;	/* debug: use date as being today */
 	char	*flag_month = NULL;	/* requested month as string */
+	char	*flag_highlightdate = NULL; /* debug: date to highlight */
+	int	before, after;
 	const char    *locale;		/* locale to get country code */
 
+	flag_nohighlight = 0;
+	flag_weeks = 0;
+
 	/*
 	 * Use locale to determine the country code,
 	 * and use the country code to determine the default
@@ -230,23 +246,57 @@ main(int argc, char *argv[])
 	 * Get the filename portion of argv[0] and set flag_backward if
 	 * this program is called "cal".
 	 */
-	cp = strrchr(argv[0], '/');
-	cp = (cp == NULL) ? argv[0] : cp + 1;
-	if (strcmp("cal", cp) == 0)
+	if (strncmp(basename(argv[0]), "cal", strlen("cal")) == 0)
 		flag_backward = 1;
 
 	/* Set the switch date to United Kingdom if backwards compatible */
 	if (flag_backward)
 		nswitchb = ndaysj(&ukswitch);
 
-	while ((ch = getopt(argc, argv, "Jejm:ops:wy")) != -1)
+	before = after = -1;
+
+	while ((ch = getopt(argc, argv, "3A:B:Cd:eH:hjJm:Nops:wy")) != -1)
 		switch (ch) {
+		case '3':
+			flag_3months = 1;
+			break;
+		case 'A':
+			if (flag_after > 0)
+				errx(EX_USAGE, "Double -A specified");
+			flag_after = strtol(optarg, NULL, 10);
+			if (flag_after <= 0)
+				errx(EX_USAGE,
+				    "Argument to -A must be positive");
+			break;
+		case 'B':
+			if (flag_before > 0)
+				errx(EX_USAGE, "Double -A specified");
+			flag_before = strtol(optarg, NULL, 10);
+			if (flag_before <= 0)
+				errx(EX_USAGE,
+				    "Argument to -B must be positive");
+			break;
 		case 'J':
 			if (flag_backward)
 				usage();
 			nswitch = ndaysj(&never);
 			flag_julian_cal = 1;
 			break;
+		case 'C':
+			flag_backward = 1;
+			break;
+		case 'N':
+			flag_backward = 0;
+			break;
+		case 'd':
+			flag_today = optarg;
+			break;
+		case 'H':
+			flag_highlightdate = optarg;
+			break;
+		case 'h':
+			flag_nohighlight = 1;
+			break;
 		case 'e':
 			if (flag_backward)
 				usage();
@@ -256,7 +306,10 @@ main(int argc, char *argv[])
 			flag_julian_day = 1;
 			break;
 		case 'm':
+			if (flag_specifiedmonth)
+				errx(EX_USAGE, "Double -m specified");
 			flag_month = optarg;
+			flag_specifiedmonth = 1;
 			break;
 		case 'o':
 			if (flag_backward)
@@ -289,7 +342,7 @@ main(int argc, char *argv[])
 			flag_weeks = 1;
 			break;
 		case 'y':
-			flag_hole_year = 1;
+			flag_wholeyear = 1;
 			break;
 		default:
 			usage();
@@ -303,14 +356,21 @@ main(int argc, char *argv[])
 		if (flag_easter)
 			usage();
 		flag_month = *argv++;
+		flag_givenmonth = 1;
+		m = strtol(flag_month, NULL, 10);
 		/* FALLTHROUGH */
 	case 1:
-		y = atoi(*argv++);
+		y = atoi(*argv);
 		if (y < 1 || y > 9999)
-			errx(EX_USAGE, "year %d not in range 1..9999", y);
+			errx(EX_USAGE, "year `%s' not in range 1..9999", *argv);
+		argv++;
+		flag_givenyear = 1;
 		break;
 	case 0:
-		{
+		if (flag_today != NULL) {
+			y = strtol(flag_today, NULL, 10);
+			m = strtol(flag_today + 5, NULL, 10);
+		} else {
 			time_t t;
 			struct tm *tm;
 
@@ -325,26 +385,115 @@ main(int argc, char *argv[])
 	}
 
 	if (flag_month != NULL) {
-		m = parsemonth(flag_month);
-		if (m < 1 || m > 12)
+		if (parsemonth(flag_month, &m, &y)) {
 			errx(EX_USAGE,
 			    "%s is neither a month number (1..12) nor a name",
 			    flag_month);
+		}
+	}
+
+	/*
+	 * What is not supported:
+	 * -3 with -A or -B
+	 *	-3 displays 3 months, -A and -B change that behaviour.
+	 * -3 with -y
+	 *	-3 displays 3 months, -y says display a whole year.
+	 * -3 with a given year but no given month or without -m
+	 *	-3 displays 3 months, no month specified doesn't make clear
+	 *      which three months.
+	 * -m with a given month
+	 *	conflicting arguments, both specify the same field.
+	 * -y with -m
+	 *	-y displays the whole year, -m displays a single month.
+	 * -y with a given month
+	 *	-y displays the whole year, the given month displays a single
+	 *	month.
+	 * -y with -A or -B
+	 *	-y displays the whole year, -A and -B display extra months.
+	 */
+
+	/* -3 together with -A or -B. */
+	if (flag_3months && (flag_after || flag_before))
+		errx(EX_USAGE, "-3 together with -A and -B is not supported.");
+	/* -3 together with -y. */
+	if (flag_3months && flag_wholeyear)
+		errx(EX_USAGE, "-3 together with -y is not supported.");
+	/* -3 together with givenyear but no givenmonth. */
+	if (flag_3months && flag_givenyear &&
+	    !(flag_givenmonth || flag_specifiedmonth))
+		errx(EX_USAGE,
+		    "-3 together with a given year but no given month is "
+		    "not supported.");
+	/* -m together with xx xxxx. */
+	if (flag_specifiedmonth && flag_givenmonth)
+		errx(EX_USAGE,
+		    "-m together with a given month is not supported.");
+	/* -y together with -m. */
+	if (flag_wholeyear && flag_specifiedmonth)
+		errx(EX_USAGE, "-y together with -m is not supported.");
+	/* -y together with xx xxxx. */
+	if (flag_wholeyear && flag_givenmonth)
+		errx(EX_USAGE, "-y together a given month is not supported.");
+	/* -y together with -A or -B. */
+	if (flag_wholeyear && (flag_before > 0 || flag_after > 0))
+		errx(EX_USAGE, "-y together a -A or -B is not supported.");
+	/* The rest should be fine. */
+
+	/* Select the period to display, in order of increasing priority .*/
+	if (flag_wholeyear ||
+	    (flag_givenyear && !(flag_givenmonth || flag_specifiedmonth))) {
+		m = 1;
+		before = 0;
+		after = 11;
+	}
+	if (flag_givenyear && flag_givenmonth) {
+		before = 0;
+		after = 0;
+	}
+	if (flag_specifiedmonth) {
+		before = 0;
+		after = 0;
+	}
+	if (flag_before) {
+		before = flag_before;
+	}
+	if (flag_after) {
+		after = flag_after;
+	}
+	if (flag_3months) {
+		before = 1;
+		after = 1;
+	}
+	if (after == -1)
+		after = 0;
+	if (before == -1)
+		before = 0;
+
+	/* Highlight a specified day or today .*/
+	if (flag_highlightdate != NULL) {
+		dt.y = strtol(flag_highlightdate, NULL, 10);
+		dt.m = strtol(flag_highlightdate + 5, NULL, 10);
+		dt.d = strtol(flag_highlightdate + 8, NULL, 10);
+	} else {
+		time_t t;
+		struct tm *tm1;
+
+		t = time(NULL);
+		tm1 = localtime(&t);
+		dt.y = tm1->tm_year + 1900;
+		dt.m = tm1->tm_mon + 1;
+		dt.d = tm1->tm_mday;
 	}
+	highlightdate = sndaysb(&dt);
 
+	/* And now we finally start to calculate and output calendars. */
 	if (flag_easter)
 		printeaster(y, flag_julian_cal, flag_orthodox);
-	else if (argc == 1 || flag_hole_year)
-		if (flag_backward)
-			printyearb(y, flag_julian_day);
-		else
-			printyear(y, flag_julian_day);
 	else
 		if (flag_backward)
-			printmonthb(y, m, flag_julian_day);
+			monthrangeb(y, m, flag_julian_day, before, after);
 		else
-			printmonth(y, m, flag_julian_day);
-
+			monthranger(y, m, flag_julian_day, before, after);
 	return (0);
 }
 
@@ -353,14 +502,17 @@ usage(void)
 {
 
 	fputs(
-	    "usage: cal [-jy] [[month] year]\n"
-	    "       cal [-j] [-m month] [year]\n"
-	    "       ncal [-Jjpwy] [-s country_code] [[month] year]\n"
-	    "       ncal [-Jeo] [year]\n", stderr);
+"Usage: cal [general options] [-hjy] [[month] year]\n"
+"       cal [general options] [-hj] [-m month] [year]\n"
+"       ncal [general options] [-hJjpwy] [-s country_code] [[month] year]\n"
+"       ncal [general options] [-hJeo] [year]\n"
+"General options: [-NC3] [-A months] [-B months]\n"
+"For debug the highlighting: [-H yyyy-mm-dd] [-d yyyy-mm]\n",
+	    stderr);
 	exit(EX_USAGE);
 }
 
-/* print the assumed switches for all countries */
+/* Print the assumed switches for all countries. */
 void
 printcc(void)
 {
@@ -381,13 +533,13 @@ printcc(void)
 		printf(FSTR"\n", FSTRARG(p));
 }
 
-/* print the date of easter sunday */
+/* Print the date of easter sunday. */
 void
 printeaster(int y, int julian, int orthodox)
 {
 	date    dt;
 	struct tm tm;
-	char    buf[80];
+	char    buf[MAX_WIDTH];
 	static int d_first = -1;
 
 	if (d_first < 0)
@@ -412,183 +564,201 @@ printeaster(int y, int julian, int ortho
 	printf("%s\n", buf);
 }
 
-void
-printmonth(int y, int m, int jd_flag)
-{
-	struct monthlines month;
-	struct weekdays wds;
-	int i, len;
-
-	mkmonth(y, m - 1, jd_flag, &month);
-	mkweekdays(&wds);
-	printf("    %ls %d\n", month.name, y);
-	for (i = 0; i != 7; i++) {
-		len = wcslen(wds.names[i]);
-		if (wcswidth(wds.names[i], len) == len)
-			wprintf(L"%.2ls%s\n", wds.names[i], month.lines[i]);
-		else
-			wprintf(L"%.1ls%s\n", wds.names[i], month.lines[i]);
-	}
-	if (flag_weeks)
-		printf("  %s\n", month.weeks);
-}
-
-void
-printmonthb(int y, int m, int jd_flag)
-{
-	struct monthlines month;
-	struct weekdays wds;
-	wchar_t s[MAX_WIDTH], t[MAX_WIDTH];
-	int i;
-	int mw;
-
-	mkmonthb(y, m - 1, jd_flag, &month);
-	mkweekdays(&wds);
-
-	mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
-
-	swprintf(s, MAX_WIDTH, L"%ls %d", month.name, y);
-	wprintf(L"%ls\n", wcenter(t, s, mw));
-
-	if (jd_flag)
-		wprintf(L" %ls %ls %ls %ls %ls %ls %.2ls\n",
-			wds.names[6], wds.names[0],
-			wds.names[1], wds.names[2], wds.names[3],
-			wds.names[4], wds.names[5]);
-	else
-		wprintf(L"%ls%ls%ls%ls%ls%ls%.2ls\n", wds.names[6],
-			wds.names[0], wds.names[1], wds.names[2], wds.names[3],
-			wds.names[4], wds.names[5]);
-
-	for (i = 0; i != 6; i++)
-		printf("%s\n", month.lines[i]+1);
-}
+#define MW(mw, me)		((mw) + me)
+#define	DECREASEMONTH(m, y) 		\
+		if (--m == 0) {		\
+			m = 12;		\
+			y--;		\
+		}
+#define	INCREASEMONTH(m, y)		\
+		if (++(m) == 13) {	\
+			(m) = 1;	\
+			(y)++;		\
+		}
+#define	M2Y(m)	((m) / 12)
+#define	M2M(m)	(1 + (m) % 12) 
 
+/* Print all months for the period in the range [ before .. y-m .. after ]. */
 void
-printyear(int y, int jd_flag)
+monthrangeb(int y, int m, int jd_flag, int before, int after)
 {
 	struct monthlines year[12];
 	struct weekdays wds;
-	char    s[80], t[80];
+	char	s[MAX_WIDTH], t[MAX_WIDTH];
+	wchar_t	ws[MAX_WIDTH], ws1[MAX_WIDTH];
+	const char	*wdss;
 	int     i, j;
 	int     mpl;
 	int     mw;
+	int	m1, m2;
+	int	printyearheader;
+	int	prevyear = -1;
+
+	mpl = jd_flag ? 2 : 3;
+	mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
+	wdss = (mpl == 2) ? " " : "";
+
+	while (before != 0) {
+		DECREASEMONTH(m, y);
+		before--;
+		after++;
+	}
+	m1 = y * 12 + m - 1;
+	m2 = m1 + after;
 
-	for (i = 0; i != 12; i++)
-		mkmonth(y, i, jd_flag, year + i);
 	mkweekdays(&wds);
-	mpl = jd_flag ? 3 : 4;
-	mw = jd_flag ? MONTH_WIDTH_J : MONTH_WIDTH;
 
-	sprintf(s, "%d", y);
-	printf("%s\n", center(t, s, mpl * mw));
+	/*
+	 * The year header is printed when there are more than 'mpl' months
+	 * and if the first month is a multitude of 'mpl'.
+	 * If not, it will print the year behind every month.
+	 */
+	printyearheader = (after >= mpl - 1) && (M2M(m1) - 1) % mpl == 0;
 
-	for (j = 0; j != 12; j += mpl) {
-		wprintf(L"    %-*ls%-*ls",
-		    mw, year[j].name,
-		    mw, year[j + 1].name);
-		if (mpl == 3)
-			printf("%ls\n", year[j + 2].name);
-		else
-			wprintf(L"%-*ls%ls\n",
-		    	    mw, year[j + 2].name,
-		    	    year[j + 3].name);
-		for (i = 0; i != 7; i++) {
-			wprintf(L"%.2ls%-*s%-*s",
-			    wds.names[i],
-			    mw, year[j].lines[i],
-			    mw, year[j + 1].lines[i]);
-			if (mpl == 3)
-				printf("%s\n", year[j + 2].lines[i]);
-			else
-				printf("%-*s%s\n",
-			    	    mw, year[j + 2].lines[i],
-			    	    year[j + 3].lines[i]);
+	m = m1;
+	while (m <= m2) {
+		int count = 0;
+		for (i = 0; i != mpl && m + i <= m2; i++) {
+			mkmonthb(M2Y(m + i), M2M(m + i) - 1, jd_flag, year + i);
+			count++;
 		}
-		if (flag_weeks) {
-			if (mpl == 3)
-				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",
-				    mw, year[j].weeks,
-				    mw, year[j + 1].weeks,
-				    mw, year[j + 2].weeks,
-				    year[j + 3].weeks);
+
+		/* Empty line between two rows of months */
+		if (m != m1)
+			printf("\n");
+
+		/* Year at the top. */
+		if (printyearheader && M2Y(m) != prevyear) {
+			sprintf(s, "%d", M2Y(m));
+			printf("%s\n", center(t, s, mpl * mw));
+			prevyear = M2Y(m);
+		}
+
+		/* Month names. */
+		for (i = 0; i < count; i++)
+			if (printyearheader)
+				wprintf(L"%-*ls  ",
+				    mw, wcenter(ws, year[i].name, mw));
+			else {
+				swprintf(ws, sizeof(ws), L"%-ls %d",
+				    year[i].name, M2Y(m + i));
+				wprintf(L"%-*ls  ", mw, wcenter(ws1, ws, mw));
+			}
+		printf("\n");
+
+		/* Day of the week names. */
+		for (i = 0; i < count; i++) {
+			wprintf(L"%s%ls%s%ls%s%ls%s%ls%s%ls%s%ls%s%ls ",
+				wdss, wds.names[6], wdss, wds.names[0],
+				wdss, wds.names[1], wdss, wds.names[2],
+				wdss, wds.names[3], wdss, wds.names[4],
+				wdss, wds.names[5]);
+		}
+		printf("\n");
+
+		/* And the days of the month. */
+		for (i = 0; i != 6; i++) {
+			for (j = 0; j < count; j++)
+				printf("%-*s  ",
+				    MW(mw, year[j].extralen[i]),
+					year[j].lines[i]+1);
+			printf("\n");
 		}
+
+		m += mpl;
 	}
 }
 
 void
-printyearb(int y, int jd_flag)
+monthranger(int y, int m, int jd_flag, int before, int after)
 {
 	struct monthlines year[12];
 	struct weekdays wds;
-	char	s[80], t[80];
-	wchar_t	ws[80], wt[80];
+	char    s[MAX_WIDTH], t[MAX_WIDTH];
 	int     i, j;
 	int     mpl;
 	int     mw;
+	int	m1, m2;
+	int	prevyear = -1;
+	int	printyearheader;
+
+	mpl = jd_flag ? 3 : 4;
+	mw = jd_flag ? MONTH_WIDTH_R_J : MONTH_WIDTH_R;
+
+	while (before != 0) {
+		DECREASEMONTH(m, y);
+		before--;
+		after++;
+	}
+	m1 = y * 12 + m - 1;
+	m2 = m1 + after;
 
-	for (i = 0; i != 12; i++)
-		mkmonthb(y, i, jd_flag, year + i);
 	mkweekdays(&wds);
-	mpl = jd_flag ? 2 : 3;
-	mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
 
-	sprintf(s, "%d", y);
-	printf("%s\n\n", center(t, s, mw * mpl + mpl));
+	/*
+	 * The year header is printed when there are more than 'mpl' months
+	 * and if the first month is a multitude of 'mpl'.
+	 * If not, it will print the year behind every month.
+	 */
+	printyearheader = (after >= mpl - 1) && (M2M(m1) - 1) % mpl == 0;
 
-	for (j = 0; j != 12; j += mpl) {
-		wprintf(L"%-*ls  ", mw, wcenter(ws, year[j].name, mw));
-		if (mpl == 2)
-			printf("%ls\n", wcenter(ws, year[j + 1].name, mw));
-		else
-			wprintf(L"%-*ls  %ls\n", mw,
-			    wcenter(ws, year[j + 1].name, mw),
-			    wcenter(wt, year[j + 2].name, mw));
-
-		if (mpl == 2)
-			wprintf(L" %ls %ls %ls %ls %ls %ls %ls "
-				" %ls %ls %ls %ls %ls %ls %.2ls\n",
-				wds.names[6], wds.names[0], wds.names[1],
-				wds.names[2], wds.names[3], wds.names[4],
-				wds.names[5],
-				wds.names[6], wds.names[0], wds.names[1],
-				wds.names[2], wds.names[3], wds.names[4],
-				wds.names[5]);
-		else
-			wprintf(L"%ls%ls%ls%ls%ls%ls%ls "
-				"%ls%ls%ls%ls%ls%ls%ls "
-				"%ls%ls%ls%ls%ls%ls%.2ls\n",
-				wds.names[6], wds.names[0], wds.names[1],
-				wds.names[2], wds.names[3], wds.names[4],
-				wds.names[5],
-				wds.names[6], wds.names[0], wds.names[1],
-				wds.names[2], wds.names[3], wds.names[4],
-				wds.names[5],
-				wds.names[6], wds.names[0], wds.names[1],
-				wds.names[2], wds.names[3], wds.names[4],
-				wds.names[5]);
-		for (i = 0; i != 6; i++) {
-			if (mpl == 2)
-				printf("%-*s  %s\n",
-			    mw, year[j].lines[i]+1,
-			    year[j + 1].lines[i]+1);
+	m = m1;
+	while (m <= m2) {
+		int count = 0;
+		for (i = 0; i != mpl && m + i <= m2; i++) {
+			mkmonthr(M2Y(m + i), M2M(m + i) - 1, jd_flag, year + i);
+			count++;
+		}
+
+		/* Empty line between two rows of months. */
+		if (m != m1)
+			printf("\n");
+
+		/* Year at the top. */
+		if (printyearheader && M2Y(m) != prevyear) {
+			sprintf(s, "%d", M2Y(m));
+			printf("%s\n", center(t, s, mpl * mw));
+			prevyear = M2Y(m);
+		}
+
+		/* Month names. */
+		wprintf(L"    ");
+		for (i = 0; i < count; i++)
+			if (printyearheader)
+				wprintf(L"%-*ls", mw, year[i].name);
 			else
-				printf("%-*s  %-*s  %s\n",
-			    mw, year[j].lines[i]+1,
-			    mw, year[j + 1].lines[i]+1,
-			    year[j + 2].lines[i]+1);
+				wprintf(L"%-ls %-*d", year[i].name,
+				    mw - wcslen(year[i].name) - 1, M2Y(m + i));
+		printf("\n");
+
+		/* And the days of the month. */
+		for (i = 0; i != 7; i++) {
+			/* Week day */
+			wprintf(L"%.2ls", wds.names[i]);
 
+			/* Full months */
+			for (j = 0; j < count; j++)
+				printf("%-*s",
+				    MW(mw, year[j].extralen[i]),
+					year[j].lines[i]);
+			printf("\n");
+		}
+
+		/* Week numbers. */
+		if (flag_weeks) {
+			printf("  ");
+			for (i = 0; i < count; i++)
+				printf("%-*s", mw, year[i].weeks);
+			printf("\n");
 		}
+
+		m += mpl;
 	}
+	return;
 }
 
 void
-mkmonth(int y, int m, int jd_flag, struct monthlines *mlines)
+mkmonthr(int y, int m, int jd_flag, struct monthlines *mlines)
 {
 
 	struct tm tm;		/* for strftime printing local names of
@@ -597,7 +767,7 @@ mkmonth(int y, int m, int jd_flag, struc
 	int     dw;		/* width of numbers */
 	int     first;		/* first day of month */
 	int     firstm;		/* first day of first week of month */
-	int     i, j, k;	/* just indices */
+	int     i, j, k, l;	/* just indices */
 	int     last;		/* the first day of next month */
 	int     jan1 = 0;	/* the first day of this year */
 	char   *ds;		/* pointer to day strings (daystr or
@@ -630,7 +800,7 @@ mkmonth(int y, int m, int jd_flag, struc
 	 */
 	firstm = first - weekday(first);
 
-	/* Set ds (daystring) and dw (daywidth) according to the jd_flag */
+	/* Set ds (daystring) and dw (daywidth) according to the jd_flag. */
 	if (jd_flag) {
 		ds = jdaystr;
 		dw = 4;
@@ -645,21 +815,27 @@ mkmonth(int y, int m, int jd_flag, struc
 	 * column is one day number. print column index: k.
 	 */
 	for (i = 0; i != 7; i++) {
-		for (j = firstm + i, k = 0; j < last; j += 7, k += dw)
+		l = 0;
+		for (j = firstm + i, k = 0; j < last; j += 7, k += dw) {
 			if (j >= first) {
 				if (jd_flag)
 					dt.d = j - jan1 + 1;
 				else
-					sdate(j, &dt);
-				memcpy(mlines->lines[i] + k,
-				       ds + dt.d * dw, dw);
+					sdater(j, &dt);
+				if (j == highlightdate && !flag_nohighlight)
+					highlight(mlines->lines[i] + k,
+					    ds + dt.d * dw, dw, &l);
+				else
+					memcpy(mlines->lines[i] + k + l,
+					       ds + dt.d * dw, dw);
 			} else
-				memcpy(mlines->lines[i] + k, "    ", dw);
-		mlines->lines[i][k] = '\0';
-				
+				memcpy(mlines->lines[i] + k + l, "    ", dw);
+		}
+		mlines->lines[i][k + l] = '\0';
+		mlines->extralen[i] = l;
 	}
 
-	/* fill the weeknumbers */
+	/* fill the weeknumbers. */
 	if (flag_weeks) {
 		for (j = firstm, k = 0; j < last;  k += dw, j += 7)
 			if (j <= nswitch)
@@ -681,7 +857,7 @@ mkmonthb(int y, int m, int jd_flag, stru
 	int     dw;		/* width of numbers */
 	int     first;		/* first day of month */
 	int     firsts;		/* sunday of first week of month */
-	int     i, j, k;	/* just indices */
+	int     i, j, k, l;	/* just indices */
 	int     jan1 = 0;	/* the first day of this year */
 	int     last;		/* the first day of next month */
 	char   *ds;		/* pointer to day strings (daystr or
@@ -696,7 +872,7 @@ mkmonthb(int y, int m, int jd_flag, stru
 		dw = 3;
 	}
 
-	/* Set name of month centered */
+	/* Set name of month centered. */
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_mon = m;
 	wcsftime(mlines->name, sizeof(mlines->name) / sizeof(mlines->name[0]),
@@ -742,25 +918,32 @@ mkmonthb(int y, int m, int jd_flag, stru
 	 * column is one day number. print column index: k.
 	 */
 	for (i = 0; i != 6; i++) {
+		l = 0;
 		for (j = firsts + 7 * i, k = 0; j < last && k != dw * 7;
-		     j++, k += dw)
+		    j++, k += dw) { 
 			if (j >= first) {
 				if (jd_flag)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list