From owner-svn-src-all@FreeBSD.ORG Sun Oct 17 07:11:41 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0FD59106566C; Sun, 17 Oct 2010 07:11:41 +0000 (UTC) (envelope-from edwin@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id F00DC8FC12; Sun, 17 Oct 2010 07:11:40 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o9H7Bei4008400; Sun, 17 Oct 2010 07:11:40 GMT (envelope-from edwin@svn.freebsd.org) Received: (from edwin@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o9H7Be8w008396; Sun, 17 Oct 2010 07:11:40 GMT (envelope-from edwin@svn.freebsd.org) Message-Id: <201010170711.o9H7Be8w008396@svn.freebsd.org> From: Edwin Groothuis Date: Sun, 17 Oct 2010 07:11:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213945 - stable/7/usr.bin/ncal X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Oct 2010 07:11:41 -0000 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 " 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@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 #include #include +#include #include #include #include @@ -42,15 +43,17 @@ static const char rcsid[] = #include #include #include +#include +#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 ***