This changes determination of calendar month content completely, as well as outputing. Signed-off-by: Sami Kerola <kerolasa@xxxxxx> --- misc-utils/cal.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 169 insertions(+), 7 deletions(-) diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 0a6cd8d..a3eff48 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -251,11 +251,22 @@ struct cal_control { header_hint:1; /* does month name + year need two lines to fit */ }; +struct cal_month { + int days[MAXDAYS]; /* the day numbers, or SPACE */ + int weeks[MAXDAYS / DAYS_IN_WEEK]; + int month; + long year; + struct cal_month *next; +}; + /* function prototypes */ static int leap_year(long year); static void headers_init(struct cal_control *ctl); static int do_monthly(int day, int month, long year, struct fmt_st *out, const 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 monthly(const struct cal_control *ctl); static void monthly3(const struct cal_control *ctl); static char *append_weeknum(char *p, int *dp, int month, long year, int cal, int row, @@ -597,18 +608,169 @@ static int do_monthly(int day, int month, long year, struct fmt_st *out, return pos; } -static void monthly(const struct cal_control *ctl) +static void cal_fill_month(struct cal_month *month, const struct cal_control *ctl) { - int i, rows; - struct fmt_st out; + int first_week_day = day_in_week(1, month->month, month->year); + int month_days; + int i, j, weeklines = 0; + + if (ctl->julian) + j = day_in_year(1, month->month, month->year); + else + j = 1; + month_days = j + days_in_month[leap_year(month->year)][month->month]; + + /* True when Sunday is not first day in the output week. */ + if (ctl->weekstart) { + first_week_day -= ctl->weekstart; + if (first_week_day < 0) + first_week_day = DAYS_IN_WEEK - ctl->weekstart; + month_days += ctl->weekstart - 1; + } + + /* Fill day array. */ + for (i = 0; i < MAXDAYS; i++) { + if (0 < first_week_day) { + month->days[i] = SPACE; + first_week_day--; + continue; + } + if (j < month_days) { + if (month->year == 1752 && month->month == 9 && (j == 3 || j == 247)) + j += NUMBER_MISSING_DAYS; + month->days[i] = j; + j++; + continue; + } + month->days[i] = SPACE; + weeklines++; + } - rows = do_monthly(ctl->req.day, ctl->req.month, ctl->req.year, &out, ctl); - for (i = 0; i < rows; i++) { - my_putstring(out.s[i]); - my_putstring("\n"); + /* Add week numbers */ + if (ctl->weektype) { + int weeknum = week_number(1, month->month, month->year, ctl); + weeklines = MAXDAYS / DAYS_IN_WEEK - weeklines / DAYS_IN_WEEK; + for (i = 0; i < MAXDAYS / DAYS_IN_WEEK; i++) { + if (0 < weeklines) + month->weeks[i] = weeknum++; + else + month->weeks[i] = SPACE; + weeklines--; + if (52 < weeknum && i == 0) + weeknum = week_number(month->days[DAYS_IN_WEEK * (i + 1)], 1, month->year, ctl); + else if (52 < weeknum) + weeknum = week_number(31, 12, month->year, ctl); + } } } +static void cal_output_header(struct cal_month *month, const struct cal_control *ctl) +{ + char out[FMT_ST_CHARS]; + struct cal_month *i; + + if (ctl->header_hint) { + 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 : 2); + } + fputs("\n", stdout); + for (i = month; i; i = i->next) { + sprintf(out, _("%ld"), i->year); + center(out, ctl->week_width - 1, i->next == NULL ? 0 : 2); + } + } else { + for (i = month; i; i = i->next) { + sprintf(out, _("%s %ld"), ctl->full_month[i->month - 1], i->year); + center(out, ctl->week_width - 1, i->next == NULL ? 0 : 2); + } + } + puts(""); + for (i = month; i; i = i->next) { + if (ctl->weektype) { + if (ctl->julian) + printf("%*s%s", (int)ctl->day_width - 1, "", day_headings); + else + printf("%*s%s", (int)ctl->day_width, "", day_headings); + } else + fputs(day_headings, stdout); + if (i->next != NULL) + fputs(" ", stdout); + } + puts(""); +} + +static void cal_output_months(struct cal_month *month, const struct cal_control *ctl) +{ + int reqday, week_line, d; + int skip; + struct cal_month *i; + + for (week_line = 0; week_line < MAXDAYS / DAYS_IN_WEEK; week_line++) { + for (i = month; i; i = i->next) { + /* Determine the day that should be highlighted. */ + reqday = 0; + if (i->month == ctl->req.month && i->year == ctl->req.year) { + if (ctl->julian) + reqday = ctl->req.day; + else + reqday = + ctl->req.day + 1 - day_in_year(1, i->month, + i->year); + } + + if (ctl->weektype) { + if (0 < i->weeks[week_line]) { + if ((ctl->weektype & WEEK_NUM_MASK) == + i->weeks[week_line]) + printf("%s%2d%s", Senter, i->weeks[week_line], + Sexit); + else + printf("%2d", i->weeks[week_line]); + } else + printf("%2s", ""); + skip = ctl->day_width; + } else + /* First day of the week is one char narrower than the other days, + * unless week number is printed. */ + skip = ctl->day_width - 1; + + for (d = DAYS_IN_WEEK * week_line; + d < DAYS_IN_WEEK * week_line + DAYS_IN_WEEK; d++) { + if (0 < i->days[d]) { + if (reqday == i->days[d]) + printf("%*s%s%*d%s", skip - (ctl->julian ? 3 : 2), + "", Senter, (ctl->julian ? 3 : 2), + i->days[d], Sexit); + else + printf("%*d", skip, i->days[d]); + } else + printf("%*s", skip, ""); + if (skip < (int)ctl->day_width) + skip++; + } + if (i->next != NULL) + fputs(" ", stdout); + } + if (i == NULL) + fputs(" \n", stdout); + } +} + +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) { char lineout[FMT_ST_CHARS]; -- 1.8.4.2 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html