]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/cal.c
findmnt: keep it easy for static analyzers
[thirdparty/util-linux.git] / misc-utils / cal.c
index a110b1b8f6653ef5cfe4d8f6a0a42f2d0d9888d0..1d4d241345659969f1b5df4e377befe5125dd07b 100644 (file)
@@ -261,6 +261,24 @@ static void center(const char *str, size_t len, int separate);
 static int parse_reform_year(const char *reform_year);
 static void __attribute__((__noreturn__)) usage(void);
 
+#ifdef TEST_CAL
+static time_t cal_time(time_t *t)
+{
+       char *str = getenv("CAL_TEST_TIME");
+
+       if (str) {
+               uint64_t x = strtou64_or_err(str, "failed to parse CAL_TEST_TIME");
+
+               *t = x;
+               return *t;
+       }
+
+       return time(t);
+}
+#else
+# define cal_time(t)   time(t)
+#endif
+
 int main(int argc, char **argv)
 {
        struct tm *local_time;
@@ -314,7 +332,7 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        term = getenv("TERM");
        if (term) {
@@ -417,8 +435,7 @@ int main(int argc, char **argv)
                        ctl.reform_year = ISO;
                        break;
                case 'V':
-                       printf(UTIL_LINUX_VERSION);
-                       return EXIT_SUCCESS;
+                       print_version(EXIT_SUCCESS);
                case 'h':
                        usage();
                default:
@@ -443,12 +460,12 @@ int main(int argc, char **argv)
                        now = (time_t) (x / 1000000);
                /* cal <monthname> */
                else if ((ctl.req.month = monthname_to_number(&ctl, *argv)) > 0)
-                       time(&now);     /* this year */
+                       cal_time(&now); /* this year */
                else
                        errx(EXIT_FAILURE, _("failed to parse timestamp or unknown month name: %s"), *argv);
                argc = 0;
        } else
-               time(&now);
+               cal_time(&now);
 
        local_time = localtime(&now);
 
@@ -532,9 +549,21 @@ int main(int argc, char **argv)
 
        headers_init(&ctl);
 
-       if (!colors_init(ctl.colormode, "cal")) {
-               ctl.req.day = 0;
-               ctl.weektype &= ~WEEK_NUM_MASK;
+       if (colors_init(ctl.colormode, "cal") == 0) {
+               /*
+                * If standout mode available (Senter and Sexit are set) and
+                * user or terminal-colors.d do not disable colors than
+                * ignore colors_init().
+                */
+               if (*Senter && *Sexit && colors_mode() != UL_COLORMODE_NEVER) {
+                       /* let use standout mode */
+                       ;
+               } else {
+                       /* disable */
+                       Senter = ""; Sexit = "";
+                       ctl.req.day = 0;
+                       ctl.weektype &= ~WEEK_NUM_MASK;
+               }
        }
 
        if (yflag || Yflag) {
@@ -551,13 +580,19 @@ int main(int argc, char **argv)
                ctl.months_in_row = MONTHS_IN_YEAR_ROW;         /* default */
 
                if (isatty(STDOUT_FILENO)) {
-                       int w = get_terminal_width(STDOUT_FILENO);
-                       int mw = ctl.julian ? DOY_MONTH_WIDTH : DOM_MONTH_WIDTH;
-                       int extra = ((w / mw) - 1) * ctl.gutter_width;
-                       int new_n = (w - extra) / mw;
+                       int w, mw, extra, new_n;
+
+                       w = get_terminal_width(80);
+                       mw = ctl.julian ? DOY_MONTH_WIDTH : DOM_MONTH_WIDTH;
+
+                       if (w < mw)
+                               w = mw;
+
+                       extra = ((w / mw) - 1) * ctl.gutter_width;
+                       new_n = (w - extra) / mw;
 
                        if (new_n < MONTHS_IN_YEAR_ROW)
-                               ctl.months_in_row = new_n;
+                               ctl.months_in_row = new_n > 0 ? new_n : 1;
                }
        } else if (!ctl.months_in_row)
                ctl.months_in_row = 1;
@@ -721,19 +756,19 @@ static void cal_output_header(struct cal_month *month, const struct cal_control
 
        if (ctl->header_hint || ctl->header_year) {
                for (i = month; i; i = i->next) {
-                       sprintf(out, _("%s"), ctl->full_month[i->month - 1]);
+                       snprintf(out, sizeof(out), "%s", ctl->full_month[i->month - 1]);
                        center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
                }
                if (!ctl->header_year) {
                        my_putstring("\n");
                        for (i = month; i; i = i->next) {
-                               sprintf(out, _("%04d"), i->year);
+                               snprintf(out, sizeof(out), "%04d", i->year);
                                center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
                        }
                }
        } else {
                for (i = month; i; i = i->next) {
-                       sprintf(out, _("%s %04d"), ctl->full_month[i->month - 1], i->year);
+                       snprintf(out, sizeof(out), "%s %04d", ctl->full_month[i->month - 1], i->year);
                        center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
                }
        }
@@ -741,14 +776,14 @@ static void cal_output_header(struct cal_month *month, const struct cal_control
        for (i = month; i; i = i->next) {
                if (ctl->weektype) {
                        if (ctl->julian)
-                               sprintf(out, "%*s%s", (int)ctl->day_width - 1, "", day_headings);
+                               snprintf(out, sizeof(out), "%*s%s", (int)ctl->day_width - 1, "", day_headings);
                        else
-                               sprintf(out, "%*s%s", (int)ctl->day_width, "", day_headings);
+                               snprintf(out, sizeof(out), "%*s%s", (int)ctl->day_width, "", day_headings);
                        my_putstring(out);
                } else
                        my_putstring(day_headings);
                if (i->next != NULL) {
-                       sprintf(out, "%*s", ctl->gutter_width, "");
+                       snprintf(out, sizeof(out), "%*s", ctl->gutter_width, "");
                        my_putstring(out);
                }
        }
@@ -779,12 +814,13 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
                                if (0 < i->weeks[week_line]) {
                                        if ((ctl->weektype & WEEK_NUM_MASK) ==
                                            i->weeks[week_line])
-                                               sprintf(out, "%s%2d%s", Senter, i->weeks[week_line],
-                                                      Sexit);
+                                               snprintf(out, sizeof(out), "%s%2d%s",
+                                                               Senter, i->weeks[week_line],
+                                                               Sexit);
                                        else
-                                               sprintf(out, "%2d", i->weeks[week_line]);
+                                               snprintf(out, sizeof(out), "%2d", i->weeks[week_line]);
                                } else
-                                       sprintf(out, "%2s", "");
+                                       snprintf(out, sizeof(out), "%2s", "");
                                my_putstring(out);
                                skip = ctl->day_width;
                        } else
@@ -796,19 +832,20 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
                             d < DAYS_IN_WEEK * week_line + DAYS_IN_WEEK; d++) {
                                if (0 < i->days[d]) {
                                        if (reqday == i->days[d])
-                                               sprintf(out, "%*s%s%*d%s", skip - (ctl->julian ? 3 : 2),
+                                               snprintf(out, sizeof(out), "%*s%s%*d%s",
+                                                      skip - (ctl->julian ? 3 : 2),
                                                       "", Senter, (ctl->julian ? 3 : 2),
                                                       i->days[d], Sexit);
                                        else
-                                               sprintf(out, "%*d", skip, i->days[d]);
+                                               snprintf(out, sizeof(out), "%*d", skip, i->days[d]);
                                } else
-                                       sprintf(out, "%*s", skip, "");
+                                       snprintf(out, sizeof(out), "%*s", skip, "");
                                my_putstring(out);
                                if (skip < (int)ctl->day_width)
                                        skip++;
                        }
                        if (i->next != NULL) {
-                               sprintf(out, "%*s", ctl->gutter_width, "");
+                               snprintf(out, sizeof(out), "%*s", ctl->gutter_width, "");
                                my_putstring(out);
                        }
                }
@@ -820,17 +857,20 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
 static void monthly(const struct cal_control *ctl)
 {
        struct cal_month m1,m2,m3, *m;
-       int i, rows, new_month, month = ctl->req.start_month ? ctl->req.start_month : ctl->req.month;
+       int i, rows, month = ctl->req.start_month ? ctl->req.start_month : ctl->req.month;
        int32_t year = ctl->req.year;
 
        /* cal -3, cal -Y --span, etc. */
        if (ctl->span_months) {
-               new_month = month - ctl->num_months / 2;
+               int new_month = month - ctl->num_months / 2;
                if (new_month < 1) {
-                       month = new_month + MONTHS_IN_YEAR;
-                       year--;
-               }
-               else
+                       new_month *= -1;
+                       year -= (new_month / MONTHS_IN_YEAR) + 1;
+
+                       if (new_month > MONTHS_IN_YEAR)
+                               new_month %= MONTHS_IN_YEAR;
+                       month = MONTHS_IN_YEAR - new_month;
+               } else
                        month = new_month;
        }
 
@@ -874,7 +914,7 @@ static void yearly(const struct cal_control *ctl)
                year_width--;
 
        if (ctl->header_year) {
-               sprintf(out, "%04d", ctl->req.year);
+               snprintf(out, sizeof(out), "%04d", ctl->req.year);
                center(out, year_width, 0);
                my_putstring("\n\n");
        }