]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
cal: add -Y and -n <num>
authorMax Klinger <max@fs.lmu.de>
Tue, 7 Apr 2015 11:05:39 +0000 (13:05 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 7 Apr 2015 13:18:38 +0000 (15:18 +0200)
[kzak@redhat.com: - add month_in_row to avoid extra meaning of num_month=-3,
                  - add header_year
                  - add long option for -Y
                  - define conflicts between -Y, -y and -n
                  - remove ctl.yflag]

Co-Author: Karel Zak <kzak@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/cal.1
misc-utils/cal.c

index 0a1600d0e94f85cacff4d02b09631dceedb48dbb..50b0859d880294c59e3f64234283d7137f62138d 100644 (file)
@@ -54,6 +54,9 @@ Display single month output.
 \fB\-3\fR, \fB\-\-three\fR
 Display three months spanning the date.
 .TP
+\fB\-n , \-\-months\fR \fInumber\fR
+Display number months starting from month containing the date.
+.TP
 \fB\-s\fR, \fB\-\-sunday\fR
 Display Sunday as the first day of the week.
 .TP
@@ -66,6 +69,9 @@ Display Julian dates (days one-based, numbered from January 1).
 \fB\-y\fR, \fB\-\-year\fR
 Display a calendar for the whole year.
 .TP
+\fB\-Y, \fB\-\-twelve\fR
+Display a calendar for the next twelve months.
+.TP
 \fB\-w\fR, \fB\-\-week\fR[\fI=number\fR]
 Display week numbers in the calendar (US or ISO-8601).
 .TP
index 96c9e78a01f9a2a679c1c72e11f4d86788f94c93..f1df759f108e5c89c72a3c7147c2a2adf04c8475 100644 (file)
@@ -41,7 +41,7 @@
  *
  * 2000-09-01  Michael Charles Pruznick <dummy@netwiz.net>
  *             Added "-3" option to print prev/next month with current.
- *             Added over-ridable default NUM_MONTHS and "-1" option to
+ *             Added over-ridable default MONTHS_IN_ROW and "-1" option to
  *             get traditional output when -3 is the default.  I hope that
  *             enough people will like -3 as the default that one day the
  *             product can be shipped that way.
@@ -73,6 +73,7 @@
 #include "nls.h"
 #include "mbsalign.h"
 #include "strutils.h"
+#include "optutils.h"
 
 static int has_term = 0;
 static const char *Senter = "", *Sexit = "";   /* enter and exit standout mode */
@@ -158,15 +159,6 @@ static void my_putstring(char *s)
 
 #include "widechar.h"
 
-/* allow compile-time define to over-ride default */
-#ifndef NUM_MONTHS
-# define NUM_MONTHS 1
-#endif
-
-#if ( NUM_MONTHS != 1 && NUM_MONTHS !=3 )
-# error NUM_MONTHS must be 1 or 3
-#endif
-
 enum {
        SUNDAY = 0,
        MONDAY,
@@ -197,7 +189,7 @@ enum {
 #define        DAY_LEN                 3               /* 3 spaces per day */
 #define        WEEK_LEN                (DAYS_IN_WEEK * DAY_LEN)
 #define        HEAD_SEP                2
-#define MONTH_COLS             3               /* month columns in year view */
+#define MONTHS_IN_YEAR_ROW     3               /* month columns in year view */
 #define WNUM_LEN                3
 
 #define TODAY_FLAG             0x400           /* flag day for highlighting */
@@ -224,12 +216,14 @@ struct cal_request {
        int month;
        int32_t year;
        int week;
+       int start_month;
 };
 
 struct cal_control {
        const char *full_month[MONTHS_IN_YEAR]; /* month names */
        int colormode;                  /* day and week number highlight */
-       int num_months;                 /* number of months horizontally in print out */
+       int num_months;                 /* number of requested mounths */
+       int months_in_row;              /* number of months horizontally in print out */
        int weekstart;                  /* day the week starts, often Sun or Mon */
        int weektype;                   /* WEEK_TYPE_{NONE,ISO,US} */
        size_t day_width;               /* day width in characters in printout */
@@ -237,7 +231,7 @@ struct cal_control {
        int gutter_width;               /* spaces in between horizontal month outputs */
        struct cal_request req;         /* the times user is interested */
        unsigned int    julian:1,       /* julian output */
-                       yflag:1,        /* print whole year */
+                       header_year:1,  /* print year number */
                        header_hint:1;  /* does month name + year need two lines to fit */
 };
 
@@ -252,12 +246,10 @@ struct cal_month {
 /* function prototypes */
 static int leap_year(int32_t year);
 static void headers_init(struct cal_control *ctl);
-static void set_consecutive_months(struct cal_month *month, int m, int32_t y);
 static void cal_fill_month(struct cal_month *month, const struct cal_control *ctl);
 static void cal_output_header(struct cal_month *month, const struct cal_control *ctl);
 static void cal_output_months(struct cal_month *month, const struct cal_control *ctl);
 static void monthly(const struct cal_control *ctl);
-static void monthly3(const struct cal_control *ctl);
 static void yearly(const struct cal_control *ctl);
 static int day_in_year(int day, int month, int32_t year);
 static int day_in_week(int day, int month, int32_t year);
@@ -271,10 +263,10 @@ int main(int argc, char **argv)
 {
        struct tm *local_time;
        time_t now;
-       int ch;
+       int ch = 0, yflag = 0, Yflag = 0;
        static struct cal_control ctl = {
                .weekstart = SUNDAY,
-               .num_months = NUM_MONTHS,
+               .num_months = 1,                /* default is "cal -1" */
                .colormode = UL_COLORMODE_UNDEF,
                .weektype = WEEK_NUM_DISABLED,
                .day_width = DAY_LEN,
@@ -293,14 +285,22 @@ int main(int argc, char **argv)
                {"sunday", no_argument, NULL, 's'},
                {"monday", no_argument, NULL, 'm'},
                {"julian", no_argument, NULL, 'j'},
+               {"months", required_argument, NULL, 'n'},
                {"year", no_argument, NULL, 'y'},
                {"week", optional_argument, NULL, 'w'},
                {"color", optional_argument, NULL, OPT_COLOR},
                {"version", no_argument, NULL, 'V'},
+               {"twelve", no_argument, NULL, 'Y'},
                {"help", no_argument, NULL, 'h'},
                {NULL, 0, NULL, 0}
        };
 
+       static const ul_excl_t excl[] = {       /* rows and cols in in ASCII order */
+               { 'Y','n','y' },
+               { 0 }
+       };
+       int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
@@ -354,14 +354,17 @@ int main(int argc, char **argv)
                ctl.weekstart = (wfd + *nl_langinfo(_NL_TIME_FIRST_WEEKDAY) - 1) % DAYS_IN_WEEK;
        }
 #endif
+       while ((ch = getopt_long(argc, argv, "13mjn:sywYVh", longopts, NULL)) != -1) {
+
+               err_exclusive_options(ch, longopts, excl, excl_st);
 
-       while ((ch = getopt_long(argc, argv, "13mjsywVh", longopts, NULL)) != -1)
                switch(ch) {
                case '1':
-                       ctl.num_months = 1;             /* default */
+                       /* default */
                        break;
                case '3':
                        ctl.num_months = 3;
+                       ctl.months_in_row = 3;
                        break;
                case 's':
                        ctl.weekstart = SUNDAY;         /* default */
@@ -374,7 +377,14 @@ int main(int argc, char **argv)
                        ctl.day_width = DAY_LEN + 1;
                        break;
                case 'y':
-                       ctl.yflag = 1;
+                       yflag = 1;
+                       break;
+               case 'Y':
+                       Yflag = 1;
+                       break;
+               case 'n':
+                       ctl.num_months = strtou32_or_err(optarg,
+                                               _("invalid month argument"));
                        break;
                case 'w':
                        if (optarg) {
@@ -400,6 +410,8 @@ int main(int argc, char **argv)
                default:
                        usage(stderr);
                }
+       }
+
        argc -= optind;
        argv += optind;
 
@@ -440,7 +452,7 @@ int main(int argc, char **argv)
                }
                if (!ctl.req.month && !ctl.req.week) {
                        ctl.req.month = local_time->tm_mon + 1;
-                       ctl.yflag = 1;
+                       yflag = 1;
                }
                break;
        case 0:
@@ -476,7 +488,7 @@ int main(int argc, char **argv)
                                        ctl.req.year, ctl.req.week);
                }
                if (!ctl.req.month)
-                       ctl.req.month = 12 < m ? 1 : m;
+                       ctl.req.month = MONTHS_IN_YEAR < m ? 1 : m;
        }
 
        headers_init(&ctl);
@@ -486,17 +498,25 @@ int main(int argc, char **argv)
                ctl.weektype &= ~WEEK_NUM_MASK;
        }
 
-       if (ctl.yflag) {
-               if (ctl.julian)
-                       ctl.num_months = MONTH_COLS - 1;
-               else
-                       ctl.num_months = MONTH_COLS;
+       if (yflag || Yflag) {
                ctl.gutter_width = 3;
+               ctl.num_months = MONTHS_IN_YEAR;
+               if (yflag) {
+                       ctl.req.start_month = 1;        /* start from Jan */
+                       ctl.header_year = 1;            /* print year number */
+               }
+       }
+
+       if (ctl.num_months > 1 && ctl.months_in_row == 0)
+               ctl.months_in_row = ctl.julian ? MONTHS_IN_YEAR_ROW - 1 :
+                                                MONTHS_IN_YEAR_ROW;
+       else if (!ctl.months_in_row)
+               ctl.months_in_row = 1;
+
+       if (yflag || Yflag)
                yearly(&ctl);
-       } else if (ctl.num_months == 1)
+       else
                monthly(&ctl);
-       else if (ctl.num_months == 3)
-               monthly3(&ctl);
 
        return EXIT_SUCCESS;
 }
@@ -541,19 +561,6 @@ static void headers_init(struct cal_control *ctl)
        }
 }
 
-static void set_consecutive_months(struct cal_month *month, int m, int32_t y)
-{
-       struct cal_month *i;
-       for (i = month; i; i = i->next) {
-               i->month = m++;
-               i->year = y;
-               if (MONTHS_IN_YEAR < m) {
-                       m = 1;
-                       y++;
-               }
-       }
-}
-
 static void cal_fill_month(struct cal_month *month, const struct cal_control *ctl)
 {
        int first_week_day = day_in_week(1, month->month, month->year);
@@ -615,12 +622,12 @@ static void cal_output_header(struct cal_month *month, const struct cal_control
        char out[FMT_ST_CHARS];
        struct cal_month *i;
 
-       if (ctl->header_hint || ctl->yflag) {
+       if (ctl->header_hint || ctl->header_year) {
                for (i = month; i; i = i->next) {
                        sprintf(out, _("%s"), ctl->full_month[i->month - 1]);
                        center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
                }
-               if (!ctl->yflag) {
+               if (!ctl->header_year) {
                        my_putstring("\n");
                        for (i = month; i; i = i->next) {
                                sprintf(out, _("%d"), i->year);
@@ -709,7 +716,8 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
                        }
                }
                if (i == NULL) {
-                       sprintf(out, "%*s\n", ctl->gutter_width - (ctl->yflag ? 0 : 1), "");
+                       int extra = ctl->num_months > 3 ? 0 : 1;
+                       sprintf(out, "%*s\n", ctl->gutter_width - extra, "");
                        my_putstring(out);
                }
        }
@@ -717,74 +725,65 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
 
 static void monthly(const struct cal_control *ctl)
 {
-       struct cal_month month;
-
-       month.month = ctl->req.month;
-       month.year = ctl->req.year;
-       month.next = NULL;
-
-       cal_fill_month(&month, ctl);
-
-       cal_output_header(&month, ctl);
-       cal_output_months(&month, ctl);
-}
-
-static void monthly3(const struct cal_control *ctl)
-{
-       struct cal_month m1, m2, m3, *i;
-       int first_month;
-       int32_t first_year;
+       struct cal_month m1,m2,m3, *m;
+       int i, rows, month = ctl->req.start_month ? ctl->req.start_month : ctl->req.month;
+       int32_t year = ctl->req.year;
+
+       /* cal -3 */
+       if (ctl->num_months == 3 && ctl->months_in_row == 3) {
+               if (month == 1){
+                       month = MONTHS_IN_YEAR;
+                       year--;
+               } else
+                       month--;
+       }
 
-       m1.next = &m2;
-       m2.next = &m3;
+       m1.next = (ctl->months_in_row > 1) ? &m2 : NULL;
+       m2.next = (ctl->months_in_row > 2) ? &m3 : NULL;
        m3.next = NULL;
 
-       if (ctl->req.month == 1) {
-               first_month = MONTHS_IN_YEAR;
-               first_year = ctl->req.year - 1;
-       } else {
-               first_month = ctl->req.month - 1;
-               first_year = ctl->req.year;
+       rows = (ctl->num_months - 1) / ctl->months_in_row;
+       for (i = 0; i < rows + 1 ; i++){
+               if (i == rows){
+                       switch (ctl->num_months % ctl->months_in_row){
+                               case 1:
+                                       m1.next = NULL;
+                                       /* fallthrough */
+                               case 2:
+                                       m2.next = NULL;
+                                       /* fallthrough */
+                       }
+               }
+               for (m = &m1; m; m = m->next){
+                       m->month = month++;
+                       m->year = year;
+                       if (MONTHS_IN_YEAR < month) {
+                               year++;
+                               month = 1;
+                       }
+                       cal_fill_month(m, ctl);
+               }
+               cal_output_header(&m1, ctl);
+               cal_output_months(&m1, ctl);
        }
-
-       set_consecutive_months(&m1, first_month, first_year);
-       for (i = &m1; i; i = i->next)
-               cal_fill_month(i, ctl);
-       cal_output_header(&m1, ctl);
-       cal_output_months(&m1, ctl);
 }
 
 static void yearly(const struct cal_control *ctl)
 {
-       struct cal_month m1, m2, m3, *i;
-       int month;
        char out[FMT_ST_CHARS];
        int year_width = 0;
 
-       m1.next = &m2;
-       if (ctl->julian)
-               m2.next = NULL;
-       else {
-               m2.next = &m3;
-               m3.next = NULL;
-       }
-
-       /* year header */
-       for (i = &m1; i; i = i->next)
-               year_width += ctl->week_width + 1;
+       year_width += (ctl->week_width + 1) * (ctl->julian ? 2 : 3);
        if (ctl->julian)
                year_width--;
-       sprintf(out, "%d", ctl->req.year);
-       center(out, year_width, 0);
-       my_putstring("\n\n");
-
-       for (month = 1; month < MONTHS_IN_YEAR; month += ctl->julian ? 2 : 3) {
-               set_consecutive_months(&m1, month, ctl->req.year);
-               for (i = &m1; i; i = i->next)
-                       cal_fill_month(i, ctl);
-               cal_output_header(&m1, ctl);
-               cal_output_months(&m1, ctl);
+
+       if (ctl->header_year) {
+               sprintf(out, "%d", ctl->req.year);
+               center(out, year_width, 0);
+               my_putstring("\n\n");
        }
+       monthly(ctl);
+
        /* Is empty line at the end year output really needed? */
        my_putstring("\n");
 }
@@ -949,10 +948,12 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
        fputs(USAGE_OPTIONS, out);
        fputs(_(" -1, --one             show only a single month (default)\n"), out);
        fputs(_(" -3, --three           show three months spanning the date\n"), out);
+       fputs(_(" -n, --months <num>    show num months starting with date's month\n"), out);
        fputs(_(" -s, --sunday          Sunday as first day of week\n"), out);
        fputs(_(" -m, --monday          Monday as first day of week\n"), out);
        fputs(_(" -j, --julian          output Julian dates\n"), out);
        fputs(_(" -y, --year            show the whole year\n"), out);
+       fputs(_(" -Y, --twelve          show the next twelve months\n"), out);
        fputs(_(" -w, --week[=<num>]    show US or ISO-8601 week numbers\n"), out);
        fputs(_("     --color[=<when>]  colorize messages (auto, always or never)\n"), out);
        fprintf(out,