From 27fafcf8a8e4c0360e772ec768a675cd11de8ca5 Mon Sep 17 00:00:00 2001 From: Aurelien LAJOIE Date: Mon, 13 Apr 2020 22:15:30 +0200 Subject: [PATCH] cal: Add column mode Add`-v` `--vertical` option to get a vertical output Add it into relative bash-completion For example `cal -yv` 2020 January February March Su 5 12 19 26 2 9 16 23 1 8 15 22 29 Mo 6 13 20 27 3 10 17 24 2 9 16 23 30 Tu 7 14 21 28 4 11 18 25 3 10 17 24 31 We 1 8 15 22 29 5 12 19 26 4 11 18 25 Th 2 9 16 23 30 6 13 20 27 5 12 19 26 Fr 3 10 17 24 31 7 14 21 28 6 13 20 27 Sa 4 11 18 25 1 8 15 22 29 7 14 21 28 April May June Su 5 12 19 26 3 10 17 24 31 7 14 21 28 Mo 6 13 20 27 4 11 18 25 1 8 15 22 29 Tu 7 14 21 28 5 12 19 26 2 9 16 23 30 We 1 8 15 22 29 6 13 20 27 3 10 17 24 Th 2 9 16 23 30 7 14 21 28 4 11 18 25 Fr 3 10 17 24 1 8 15 22 29 5 12 19 26 Sa 4 11 18 25 2 9 16 23 30 6 13 20 27 July August September Su 5 12 19 26 2 9 16 23 30 6 13 20 27 Mo 6 13 20 27 3 10 17 24 31 7 14 21 28 Tu 7 14 21 28 4 11 18 25 1 8 15 22 29 We 1 8 15 22 29 5 12 19 26 2 9 16 23 30 Th 2 9 16 23 30 6 13 20 27 3 10 17 24 Fr 3 10 17 24 31 7 14 21 28 4 11 18 25 Sa 4 11 18 25 1 8 15 22 29 5 12 19 26 October November December Su 4 11 18 25 1 8 15 22 29 6 13 20 27 Mo 5 12 19 26 2 9 16 23 30 7 14 21 28 Tu 6 13 20 27 3 10 17 24 1 8 15 22 29 We 7 14 21 28 4 11 18 25 2 9 16 23 30 Th 1 8 15 22 29 5 12 19 26 3 10 17 24 31 Fr 2 9 16 23 30 6 13 20 27 4 11 18 25 Sa 3 10 17 24 31 7 14 21 28 5 12 19 26 --- bash-completion/cal | 1 + misc-utils/cal.c | 146 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 141 insertions(+), 6 deletions(-) diff --git a/bash-completion/cal b/bash-completion/cal index e627bdb906..8791d123a8 100644 --- a/bash-completion/cal +++ b/bash-completion/cal @@ -18,6 +18,7 @@ _cal_module() --color=auto --color=always --color=never + --vertical --version --help" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) diff --git a/misc-utils/cal.c b/misc-utils/cal.c index dc636207d0..d2d68162a0 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -227,11 +227,13 @@ struct cal_control { int weektype; /* WEEK_TYPE_{NONE,ISO,US} */ size_t day_width; /* day width in characters in printout */ size_t week_width; /* 7 * day_width + possible week num */ + size_t month_width; /* width of a month (vertical mode) */ int gutter_width; /* spaces in between horizontal month outputs */ struct cal_request req; /* the times user is interested */ unsigned int julian:1, /* julian output */ header_year:1, /* print year number */ - header_hint:1; /* does month name + year need two lines to fit */ + header_hint:1, /* does month name + year need two lines to fit */ + vertical:1; /* display the output in vertical */ }; struct cal_month { @@ -241,7 +243,6 @@ struct cal_month { int32_t year; struct cal_month *next; }; - /* function prototypes */ static int leap_year(const struct cal_control *ctl, int32_t year); static int monthname_to_number(struct cal_control *ctl, const char *name); @@ -250,6 +251,7 @@ static void headers_init(struct cal_control *ctl); 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 cal_vert_output_months(struct cal_month *month, const struct cal_control *ctl); static void monthly(const struct cal_control *ctl); static void yearly(const struct cal_control *ctl); static int day_in_year(const struct cal_control *ctl, int day, @@ -261,7 +263,7 @@ static int week_to_day(const struct cal_control *ctl); static int center_str(const char *src, char *dest, size_t dest_size, size_t width); static void center(const char *str, size_t len, int separate); static int left_str(const char *src, char *dest, size_t dest_size, size_t width); -static void left(const char *str, size_t len, int separate) __attribute__ ((unused)); +static void left(const char *str, size_t len, int separate); static int parse_reform_year(const char *reform_year); static void __attribute__((__noreturn__)) usage(void); @@ -324,6 +326,7 @@ int main(int argc, char **argv) {"version", no_argument, NULL, 'V'}, {"twelve", no_argument, NULL, 'Y'}, {"help", no_argument, NULL, 'h'}, + {"vertical", no_argument, NULL,'v'}, {NULL, 0, NULL, 0} }; @@ -382,7 +385,7 @@ 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:sSywYVh", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "13mjn:sSywYvVh", longopts, NULL)) != -1) { err_exclusive_options(ch, longopts, excl, excl_st); @@ -438,6 +441,9 @@ int main(int argc, char **argv) case OPT_ISO: ctl.reform_year = ISO; break; + case 'v': + ctl.vertical = 1; + break; case 'V': print_version(EXIT_SUCCESS); case 'h': @@ -586,6 +592,9 @@ int main(int argc, char **argv) } } + if (ctl.vertical) + ctl.gutter_width = 1; + if (ctl.num_months > 1 && ctl.months_in_row == 0) { ctl.months_in_row = MONTHS_IN_YEAR_ROW; /* default */ @@ -807,6 +816,41 @@ static void cal_output_header(struct cal_month *month, const struct cal_control my_putstring("\n"); } +static void cal_vert_output_header(struct cal_month *month, + const struct cal_control *ctl) +{ + char out[FMT_ST_CHARS]; + struct cal_month *m; + int month_width; + + month_width = ctl->day_width * (MAXDAYS / DAYS_IN_WEEK); + /* Padding for the weekdays */ + snprintf(out, sizeof(out), "%*s", (int)ctl->day_width + 1, ""); + my_putstring(out); + if (ctl->header_hint || ctl->header_year) { + for (m = month; m; m = m->next) { + snprintf(out, sizeof(out), "%s", ctl->full_month[m->month - 1]); + left(out, month_width, ctl->gutter_width); + } + if (!ctl->header_year) { + my_putstring("\n"); + /* Padding for the weekdays */ + snprintf(out, sizeof(out), "%*s", (int)ctl->day_width + 1, ""); + my_putstring(out); + for (m = month; m; m = m->next) { + snprintf(out, sizeof(out), "%04d", m->year); + left(out, month_width, ctl->gutter_width); + } + } + } else { + for (m = month; m; m = m->next) { + snprintf(out, sizeof(out), "%s %04d", ctl->full_month[m->month - 1], m->year); + left(out, month_width, ctl->gutter_width); + } + } + my_putstring("\n"); +} + static void cal_output_months(struct cal_month *month, const struct cal_control *ctl) { char out[FMT_ST_CHARS]; @@ -871,6 +915,86 @@ static void cal_output_months(struct cal_month *month, const struct cal_control } } +static void +cal_vert_output_months(struct cal_month *month, const struct cal_control *ctl) +{ + char out[FMT_ST_CHARS]; + int i, reqday, week, d; + int skip; + struct cal_month *m; + + skip = ctl->day_width; + for (i = 0; i < DAYS_IN_WEEK; i++) { + left(ctl->weekdays[i], ctl->day_width - 1, 0); + for (m = month; m; m = m->next) { + reqday = 0; + if (m->month == ctl->req.month && m->year == ctl->req.year) { + if (ctl->julian) { + reqday = ctl->req.day; + } else { + reqday = ctl->req.day + 1 - + day_in_year(ctl, 1, m->month, m->year); + } + } + for (week = 0; week < MAXDAYS / DAYS_IN_WEEK; week++) { + d = i + DAYS_IN_WEEK * week; + if (0 < m->days[d]) { + if (reqday == m->days[d]) { + snprintf(out, sizeof(out), "%*s%s%*d%s", + skip - (ctl->julian ? 3 : 2), + "", Senter, (ctl->julian ? 3 : 2), + m->days[d], Sexit); + } else { + snprintf(out, sizeof(out), "%*d", + skip, m->days[d]); + } + } else { + snprintf(out, sizeof(out), "%*s", + skip, ""); + } + my_putstring(out); + skip = ctl->day_width; + } + if (m->next != NULL) { + snprintf(out, sizeof(out), "%*s", ctl->gutter_width, ""); + my_putstring(out); + } + } + my_putstring("\n"); + } + if (!ctl->weektype) + return; + + snprintf(out, sizeof(out), "%*s", (int)ctl->day_width - 1, ""); + my_putstring(out); + for (m = month; m; m = m->next) { + for (week = 0; week < MAXDAYS / DAYS_IN_WEEK; week++) { + if (0 < m->weeks[week]) { + if ((ctl->weektype & WEEK_NUM_MASK) == + m->weeks[week]) + { + snprintf(out, sizeof(out), "%s%*d%s", + Senter, + skip - (ctl->julian ? 3 : 2), + m->weeks[week], Sexit); + } else { + snprintf(out, sizeof(out), "%*d", + skip, m->weeks[week]); + } + } else { + snprintf(out, sizeof(out), "%*s", skip, ""); + } + my_putstring(out); + } + if (m->next != NULL) { + snprintf(out, sizeof(out), "%*s", ctl->gutter_width, ""); + my_putstring(out); + } + } + my_putstring("\n"); +} + + static void monthly(const struct cal_control *ctl) { struct cal_month m1,m2,m3, *m; @@ -916,8 +1040,17 @@ static void monthly(const struct cal_control *ctl) } cal_fill_month(m, ctl); } - cal_output_header(&m1, ctl); - cal_output_months(&m1, ctl); + if (ctl->vertical) { + if (i > 0) { + /* Add a line between row */ + my_putstring("\n"); + } + cal_vert_output_header(&m1, ctl); + cal_vert_output_months(&m1, ctl); + } else { + cal_output_header(&m1, ctl); + cal_output_months(&m1, ctl); + } } } @@ -1167,6 +1300,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -y, --year show the whole year\n"), out); fputs(_(" -Y, --twelve show the next twelve months\n"), out); fputs(_(" -w, --week[=] show US or ISO-8601 week numbers\n"), out); + fputs(_(" -v, --vertical show day vertically instead of line\n"), out); fprintf(out, _(" --color[=] colorize messages (%s, %s or %s)\n"), "auto", "always", "never"); fprintf(out, -- 2.47.2