[PATCH 11/13] cal: add month contents structure

Sami Kerola
2013-11-10T18:25:13Z

This changes determination of calendar month content completely, as well
as outputing.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
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