[PATCH 13/13] cal: use month contents structure for --year printing

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

misc-utils/cal.c | 229 +++++++++++--------------------------------------------
1 file changed, 45 insertions(+), 184 deletions(-)

diff --git a/misc-utils/cal.c b/misc-utils/cal.c
index a3c5c40..87e947a 100644
--- a/misc-utils/cal.c
+++ b/misc-utils/cal.c
@@ -244,6 +244,7 @@ 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 */
+ 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 */
@@ -267,16 +268,11 @@ static void cal_output_header(struct cal_month *month, const struct cal_control
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,
- const struct cal_control *ctl);
static void yearly(const struct cal_control *ctl);
-static void day_array(int day, int month, long year, int *days, const struct cal_control *ctl);
static int day_in_year(int day, int month, long year);
static int day_in_week(int day, int month, long year);
static int week_number(int day, int month, long year, const struct cal_control *ctl);
static int week_to_day(const struct cal_control *ctl);
-static char *ascii_day(char *p, int day, const struct cal_control *ctl);
-static char *ascii_weeknum(char *p, int weeknum, 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 void __attribute__((__noreturn__)) usage(FILE *out);
@@ -292,6 +288,7 @@ int main(int argc, char **argv)
.colormode = UL_COLORMODE_AUTO,
.weektype = WEEK_NUM_DISABLED,
.day_width = DAY_LEN,
+ .gutter_width = 2,
.req.day = 0,
.req.month = 0
};
@@ -446,8 +443,10 @@ int main(int argc, char **argv)
} else if ((long) (local_time->tm_year + 1900) == ctl.req.year) {
ctl.req.day = local_time->tm_yday + 1;
}
- if (!ctl.req.month && !ctl.req.week)
+ if (!ctl.req.month && !ctl.req.week) {
+ ctl.req.month = local_time->tm_mon + 1;
ctl.yflag = 1;
+ }
break;
case 0:
ctl.req.day = local_time->tm_yday + 1;
@@ -497,6 +496,7 @@ int main(int argc, char **argv)
ctl.num_months = MONTH_COLS - 1;
else
ctl.num_months = MONTH_COLS;
+ ctl.gutter_width = 3;
yearly(&ctl);
} else if (ctl.num_months == 1)
monthly(&ctl);
@@ -620,20 +620,22 @@ 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) {
+ if (ctl->header_hint || ctl->yflag) {
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);
+ center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
}
- 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);
+ if (!ctl->yflag) {
+ 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 : ctl->gutter_width);
+ }
}
} 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);
+ center(out, ctl->week_width - 1, i->next == NULL ? 0 : ctl->gutter_width);
}
}
puts("");
@@ -646,7 +648,7 @@ static void cal_output_header(struct cal_month *month, const struct cal_control
} else
fputs(day_headings, stdout);
if (i->next != NULL)
- fputs(" ", stdout);
+ printf("%*s", ctl->gutter_width, "");
}
puts("");
}
@@ -701,10 +703,10 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
skip++;
}
if (i->next != NULL)
- fputs(" ", stdout);
+ printf("%*s", ctl->gutter_width, "");
}
if (i == NULL)
- fputs(" \n", stdout);
+ printf("%*s\n", ctl->gutter_width - (ctl->yflag ? 0 : 1), "");
}
}

@@ -747,124 +749,39 @@ static void monthly3(const struct cal_control *ctl)
cal_output_months(&m1, ctl);
}

-static char *append_weeknum(char *p, int *dp,
- int month, long year, int cal,
- int row, const struct cal_control *ctl)
-{
- int col;
-
- for (col = 0; col < DAYS_IN_WEEK; col++) {
- int xd = dp[row * DAYS_IN_WEEK + col];
-
- if (xd != SPACE) {
- int weeknum = week_number(xd & ~TODAY_FLAG,
- month + cal + 1, year, ctl);
- p = ascii_weeknum(p, weeknum, ctl);
- break;
- } else if (col+1 == DAYS_IN_WEEK)
- p += sprintf(p," ");
- }
- return p;
-}
-
static void yearly(const struct cal_control *ctl)
{
- int col, i, month, row, which_cal;
- int days[MONTHS_IN_YEAR][MAXDAYS];
- char *p;
- /* three weeks + separators + \0 */
- int weeknumlen = (ctl->weektype ? WNUM_LEN : 0);
- char lineout[ weeknumlen + sizeof(day_headings) + 2 +
- weeknumlen + sizeof(day_headings) + 2 +
- weeknumlen + sizeof(day_headings) + 1 ];
-
- snprintf(lineout, sizeof(lineout), "%ld", ctl->req.year);
-
- /* 2013-04-28: The -1 near HEAD_SEP makes year header to be aligned
- * exactly how it has been aligned for long time, but it is
- * unexplainable. */
- center(lineout, (ctl->week_width + HEAD_SEP) * ctl->num_months - HEAD_SEP - 1, 0);
- my_putstring("\n\n");
-
- for (i = 0; i < MONTHS_IN_YEAR; i++)
- day_array(ctl->req.day, i + 1, ctl->req.year, days[i], ctl);
-
- for (month = 0; month < MONTHS_IN_YEAR; month += ctl->num_months) {
- center(ctl->full_month[month], ctl->week_width - 1, HEAD_SEP + 1);
- if (ctl->julian) {
- center(ctl->full_month[month + 1], ctl->week_width - 1, 0);
- } else {
- center(ctl->full_month[month + 1], ctl->week_width - 1, HEAD_SEP + 1);
- center(ctl->full_month[month + 2], ctl->week_width - 1, 0);
- }
- if (ctl->julian)
- snprintf(lineout, sizeof(lineout),
- "\n%*s%s%*s %*s%s\n",
- weeknumlen,"", day_headings, HEAD_SEP, "",
- weeknumlen,"", day_headings);
- else
- snprintf(lineout, sizeof(lineout),
- "\n%*s%s%*s %*s%s%*s %*s%s\n",
- weeknumlen,"", day_headings, HEAD_SEP, "",
- weeknumlen,"", day_headings, HEAD_SEP, "",
- weeknumlen,"", day_headings);
+ struct cal_month m1, m2, m3, *i;
+ int month;
+ char out[FMT_ST_CHARS];
+ int year_width = 0;

- my_putstring(lineout);
- for (row = 0; row < DAYS_IN_WEEK - 1; row++) {
- p = lineout;
- for (which_cal = 0; which_cal < ctl->num_months; which_cal++) {
- int *dp = &days[month + which_cal][row * DAYS_IN_WEEK];
-
- if (ctl->weektype)
- p = append_weeknum(p, days[month + which_cal],
- month, ctl->req.year, which_cal,
- row, ctl);
-
- for (col = 0; col < DAYS_IN_WEEK; col++)
- p = ascii_day(p, *dp++, ctl);
- p += sprintf(p, " ");
- }
- *p = '\0';
- my_putstring(lineout);
- my_putstring("\n");
- }
+ m1.next = &m2;
+ if (ctl->julian)
+ m2.next = NULL;
+ else {
+ m2.next = &m3;
+ m3.next = NULL;
}
- my_putstring("\n");
-}

-/*
- * day_array --
- * Fill in an array of 42 integers with a calendar. Assume for a moment
- * that you took the (maximum) 6 rows in a calendar and stretched them
- * out end to end. You would have 42 numbers or spaces. This routine
- * builds that array for any month from Jan. 1 through Dec. 9999.
- */
-static void day_array(int day, int month, long year, int *days, const struct cal_control *ctl)
-{
- int julday, daynum, dw, dm;
- const int *sep1752;
-
- memcpy(days, empty, MAXDAYS * sizeof(int));
- if (year == REFORMATION_YEAR && month == REFORMATION_MONTH) {
- sep1752 = ctl->julian ? j_sep1752 : d_sep1752;
- memcpy(days, sep1752 + ctl->weekstart,
- ((MAXDAYS / 2) - ctl->weekstart) * sizeof(int));
- for (dm = 0; dm < MAXDAYS / 2; dm++)
- if (j_sep1752[dm] == day)
- days[dm] |= TODAY_FLAG;
- return;
- }
- dm = days_in_month[leap_year(year)][month];
- dw = (day_in_week(1, month, year) - ctl->weekstart + DAYS_IN_WEEK) % DAYS_IN_WEEK;
- julday = day_in_year(1, month, year);
- daynum = ctl->julian ? julday : 1;
-
- while (dm--) {
- days[dw] = daynum++;
- if (julday++ == day)
- days[dw] |= TODAY_FLAG;
- dw++;
+ /* year header */
+ for (i = &m1; i; i = i->next)
+ year_width += ctl->week_width + 1;
+ if (ctl->julian)
+ year_width--;
+ sprintf(out, "%ld", ctl->req.year);
+ center(out, year_width, 0);
+ fputs("\n\n", stdout);
+
+ 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);
}
+ /* Is empty line at the end year output really needed? */
+ puts("");
}

/*
@@ -988,62 +905,6 @@ static int week_to_day(const struct cal_control *ctl)
return yday;
}

-static char *ascii_day(char *p, int day, const struct cal_control *ctl)
-{
- int display, val;
- int highlight = 0;
- static char *aday[] = {
- "",
- " 1", " 2", " 3", " 4", " 5", " 6", " 7",
- " 8", " 9", "10", "11", "12", "13", "14",
- "15", "16", "17", "18", "19", "20", "21",
- "22", "23", "24", "25", "26", "27", "28",
- "29", "30", "31",
- };
-
- if (day == SPACE) {
- memset(p, ' ', ctl->day_width);
- return p + ctl->day_width;
- }
- if (day & TODAY_FLAG) {
- day &= ~TODAY_FLAG;
- p += sprintf(p, "%s", Senter);
- highlight = 1;
- }
- if (ctl->julian) {
- if ((val = day / 100)) {
- day %= 100;
- *p++ = val + '0';
- display = 1;
- } else {
- *p++ = ' ';
- display = 0;
- }
- val = day / 10;
- if (val || display)
- *p++ = val + '0';
- else
- *p++ = ' ';
- *p++ = day % 10 + '0';
- } else {
- *p++ = aday[day][0];
- *p++ = aday[day][1];
- }
- if (highlight)
- p += sprintf(p, "%s", Sexit);
- *p++ = ' ';
- return p;
-}
-
-static char *ascii_weeknum(char *p, int weeknum, const struct cal_control *ctl)
-{
- if ((ctl->weektype & WEEK_NUM_MASK) == weeknum)
- p += sprintf(p, "%s%2d%s ", Senter, weeknum, Sexit);
- else
- p += sprintf(p, "%2d ", weeknum);
- return p;
-}
-
/*
* Center string, handling multibyte characters appropriately.
* In addition if the string is too large for the width it's truncated.
--
1.8.4.2