From f84f43ac69d50a906da01b272c5fae50a7e42c81 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 16 Feb 2022 23:17:38 -0800 Subject: [PATCH] drop an intermediate data structure --- ncal.c | 252 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 132 insertions(+), 120 deletions(-) diff --git a/ncal.c b/ncal.c index 3fb137a..cda6ccd 100644 --- a/ncal.c +++ b/ncal.c @@ -59,12 +59,6 @@ __FBSDID("$FreeBSD: head/usr.bin/ncal/ncal.c 326276 2017-11-27 15:37:16Z pfg $") typedef struct date date; -struct monthlines { - char lines[7][MAX_WIDTH + 1]; - char weeks[MAX_WIDTH + 1]; - unsigned int extralen[7]; -}; - struct weekdays { wchar_t names[7][4]; }; @@ -166,14 +160,15 @@ static int nswitch; /* user defined switch date */ static int nswitchb; /* switch date for backward compatibility */ int weekstart = -1; /* day the week starts on (Sun [0] - Sat [6]) */ -static char *center(char *s, char *t, int w); +static void printcentered(int line, char *s, int start, int end); static wchar_t *wcenter(wchar_t *s, wchar_t *t, int w); static int firstday(int y, int m); static void highlight(char *dst, char *src, int len, int *extraletters); -static void mkmonthr(int year, int month, int jd_flag, - struct monthlines * monthl, int highlightdate); -static void mkmonthb(int year, int month, int jd_flag, - struct monthlines * monthl, int highlightdate); +static void printweeknumber(int line, int y, int m, int jd_flag); +static void printmonthr(int line, int col, int y, int m, int jd_flag, + int highlightdate); +static void printmonthb(int line, int col, int y, int m, int jd_flag, + int highlightdate); static void mkweekdays(struct weekdays * wds); static void monthranger(int year, int m, int jd_flag, int before, int after, int highlightdate); @@ -666,7 +661,6 @@ static void compute_month_name(int month_index, wchar_t *month_name, int mlen) { static void monthrangeb(int y, int m, int jd_flag, int before, int after, int highlightdate) { - struct monthlines year[12]; struct weekdays wds; char s[MAX_WIDTH], t[MAX_WIDTH]; wchar_t ws[MAX_WIDTH], ws1[MAX_WIDTH]; @@ -677,10 +671,13 @@ monthrangeb(int y, int m, int jd_flag, int before, int after, int highlightdate) int m1, m2; int printyearheader; int prevyear = -1; + int startline = 0; + int screenlines, screencols; mpl = jd_flag ? 2 : 3; mw = jd_flag ? MONTH_WIDTH_B_J : (flag_weeks ? MONTH_WIDTH_B_WW : MONTH_WIDTH_B_NW ); wdss = (mpl == 2) ? " " : ""; + getmaxyx(stdscr, screenlines, screencols); while (before > 0) { DECREASEMONTH(m, y); @@ -706,25 +703,17 @@ monthrangeb(int y, int m, int jd_flag, int before, int after, int highlightdate) m = m1; while (m <= m2) { - int count = 0; - for (i = 0; i != mpl && m + i <= m2; i++) { - mkmonthb(M2Y(m + i), M2M(m + i) - 1, jd_flag, &year[i], highlightdate); - count++; - } - - /* Empty line between two rows of months */ - if (m != m1) - printw("\n"); - /* Year at the top. */ if (printyearheader && M2Y(m) != prevyear) { sprintf(s, "%d", M2Y(m)); - printw("%s\n", center(t, s, mpl * mw)); + printcentered(startline, s, 1, mpl * mw); prevyear = M2Y(m); + startline++; } /* Month names. */ - for (i = 0; i < count; i++) { + mvaddstr(startline, 0, ""); + for (i = 0; i != mpl && m + i <= m2; i++) { wchar_t month_name[MAX_WIDTH+1]; compute_month_name(M2M(m + i) - 1, month_name, sizeof(month_name)/sizeof(month_name[0])); if (printyearheader) @@ -736,10 +725,11 @@ monthrangeb(int y, int m, int jd_flag, int before, int after, int highlightdate) printw("%-*ls ", mw, wcenter(ws1, ws, mw)); } } - printw("\n"); + startline++; /* Day of the week names. */ - for (i = 0; i < count; i++) { + mvaddstr(startline, 0, ""); + for (i = 0; i != mpl && m + i <= m2; i++) { if (flag_weeks) printw(" w| %s%ls%s%ls%s%ls%s%ls%s%ls%s%ls%s%ls ", wdss, wds.names[6], wdss, wds.names[0], @@ -753,25 +743,22 @@ monthrangeb(int y, int m, int jd_flag, int before, int after, int highlightdate) wdss, wds.names[3], wdss, wds.names[4], wdss, wds.names[5]); } - printw("\n"); + startline++; /* And the days of the month. */ - for (i = 0; i != 6; i++) { - for (j = 0; j < count; j++) - printw("%-*s ", - MW(mw, year[j].extralen[i]), - year[j].lines[i]+1); - printw("\n"); - } + for (i = 0; i != mpl && m + i <= m2; i++) + printmonthb(startline, i*(mw+2), M2Y(m + i), M2M(m + i) - 1, jd_flag, highlightdate); m += mpl; + startline += 7; + if (startline >= screenlines) + break; } } static void monthranger(int y, int m, int jd_flag, int before, int after, int highlightdate) { - struct monthlines year[12]; struct weekdays wds; char s[MAX_WIDTH], t[MAX_WIDTH]; int i, j; @@ -780,9 +767,12 @@ monthranger(int y, int m, int jd_flag, int before, int after, int highlightdate) int m1, m2; int prevyear = -1; int printyearheader; + int startline = 0; + int screenlines, screencols; mpl = jd_flag ? 3 : 4; mw = jd_flag ? MONTH_WIDTH_R_J : MONTH_WIDTH_R; + getmaxyx(stdscr, screenlines, screencols); while (before > 0) { DECREASEMONTH(m, y); @@ -808,26 +798,17 @@ monthranger(int y, int m, int jd_flag, int before, int after, int highlightdate) m = m1; while (m <= m2) { - int count = 0; - for (i = 0; i != mpl && m + i <= m2; i++) { - mkmonthr(M2Y(m + i), M2M(m + i) - 1, jd_flag, &year[i], highlightdate); - count++; - } - - /* Empty line between two rows of months. */ - if (m != m1) - printw("\n"); - /* Year at the top. */ if (printyearheader && M2Y(m) != prevyear) { sprintf(s, "%d", M2Y(m)); - printw("%s\n", center(t, s, mpl * mw)); + printcentered(startline, s, 1, mpl * mw); prevyear = M2Y(m); + startline++; } /* Month names. */ - printw(" "); - for (i = 0; i < count; i++) { + mvaddstr(startline, 1, " "); + for (i = 0; i != mpl && m + i <= m2; i++) { wchar_t month_name[MAX_WIDTH+1]; compute_month_name(M2M(m + i) - 1, month_name, sizeof(month_name)/sizeof(month_name[0])); if (printyearheader) @@ -836,43 +817,42 @@ monthranger(int y, int m, int jd_flag, int before, int after, int highlightdate) printw("%-ls %-*d", month_name, mw - wcslen(month_name) - 1, M2Y(m + i)); } - printw("\n"); + startline++; - /* And the days of the month. */ - for (i = 0; i != 7; i++) { - /* Week day */ - printw("%.2ls", wds.names[i]); + /* Days of the week. */ + for (i = 0; i != 7; i++) + mvprintw(startline+i, 0, "%.2ls", wds.names[i]); - /* Full months */ - for (j = 0; j < count; j++) - printw("%-*s", - MW(mw, year[j].extralen[i]), - year[j].lines[i]); - printw("\n"); - } + /* Dates */ + for (i = 0; i != mpl && m + i <= m2; i++) + printmonthr(startline, 3+i*mw, M2Y(m + i), M2M(m + i) - 1, jd_flag, highlightdate); /* Week numbers. */ if (flag_weeks) { - printw(" "); - for (i = 0; i < count; i++) - printw("%-*s", mw, year[i].weeks); - printw("\n"); + mvprintw(startline+7, 0, " "); + for (i = 0; i != mpl && m + i <= m2; i++) + printweeknumber(startline, M2Y(m + i), M2M(m + i) - 1, jd_flag); } m += mpl; + startline += 8; + if (flag_weeks) + startline++; + if (startline >= screenlines) + break; } return; } static void -mkmonthr(int y, int m, int jd_flag, struct monthlines *mlines, int highlightdate) +printmonthr(int line, int col, int y, int m, int jd_flag, int highlightdate) { date dt; /* handy date */ int dw; /* width of numbers */ int first; /* first day of month */ int firstm; /* first day of first week of month */ - int i, j, k, l; /* just indices */ + int i, j, k; /* just indices */ int last; /* the first day of next month */ int jan1 = 0; /* the first day of this year */ char *ds; /* pointer to day strings (daystr or @@ -916,48 +896,95 @@ mkmonthr(int y, int m, int jd_flag, struct monthlines *mlines, int highlightdate * column is one day number. print column index: k. */ for (i = 0; i != 7; i++) { - l = 0; for (j = firstm + i, k = 0; j < last; j += 7, k += dw) { if (j >= first) { if (jd_flag) dt.d = j - jan1 + 1; else sdater(j, &dt); - if (j == highlightdate - && isatty(STDOUT_FILENO)) - highlight(mlines->lines[i] + k, - ds + dt.d * dw, dw, &l); - else - memcpy(mlines->lines[i] + k + l, - ds + dt.d * dw, dw); - } else - memcpy(mlines->lines[i] + k + l, " ", dw); + if (j == highlightdate && isatty(STDOUT_FILENO)) { + mvaddstr(line+i, col+k-1, " "); + attron(A_REVERSE); + printw("%-.*s", dw-1, ds + dt.d * dw + 1); + attroff(A_REVERSE); + } + else { + mvprintw(line+i, col+k-1, "%-.*s", dw, ds + dt.d * dw); + } + } else { + mvprintw(line+i, col+k-1, "%-.*s", dw, " "); + } } - mlines->lines[i][k + l] = '\0'; - mlines->extralen[i] = l; - } - - /* fill the weeknumbers. */ - if (flag_weeks) { - for (j = firstm, k = 0; j < last; k += dw, j += 7) - if (j <= nswitch) - memset(mlines->weeks + k, ' ', dw); - else - memcpy(mlines->weeks + k, - ds + week(j, &i)*dw, dw); - mlines->weeks[k] = '\0'; } } static void -mkmonthb(int y, int m, int jd_flag, struct monthlines *mlines, int highlightdate) +printweeknumber(int line, int y, int m, int jd_flag) +{ + date dt; /* handy date */ + int dw; /* width of numbers */ + int first; /* first day of month */ + int firstm; /* first day of first week of month */ + int i, j, k; /* just indices */ + int last; /* the first day of next month */ + int jan1 = 0; /* the first day of this year */ + char *ds; /* pointer to day strings (daystr or + * jdaystr) */ + + /* + * Set first and last to the day number of the first day of this + * month and the first day of next month respectively. Set jan1 to + * the day number of the first day of this year. + */ + first = firstday(y, m + 1); + if (m == 11) + last = firstday(y + 1, 1); + else + last = firstday(y, m + 2); + + if (jd_flag) + jan1 = firstday(y, 1); + + /* + * Set firstm to the day number of the day starting the first week of + * this month. (This might be in the last month) + */ + if (weekstart == 0) + firstm = first - (weekday(first) + 1) % 7; + else + firstm = first - weekday(first); + + /* Set ds (daystring) and dw (daywidth) according to the jd_flag. */ + if (jd_flag) { + ds = jdaystr; + dw = 4; + } else { + ds = daystr; + dw = 3; + } + + if (flag_weeks) { + for (j = firstm, k = 0; j < last; k += dw, j += 7) + if (j <= nswitch) + printw("%-.*s", dw, ""); + else + printw("%-.*s", dw, ds + week(j, &i)*dw); + k /= dw; + for (; k < 6; k++) + printw("%-.*s", dw, " "); + } +} + +/* Print all months for the period in the range [ before .. y-m .. after ]. */ +static void +printmonthb(int line, int col, int y, int m, int jd_flag, int highlightdate) { date dt; /* handy date */ int dw; /* width of numbers */ int first; /* first day of month */ int firsts; /* first day of first week of month */ - int i, j, k, l; /* just indices */ + int i, j, k; /* just indices */ int jan1 = 0; /* the first day of this year */ int last; /* the first day of next month */ char *ds; /* pointer to day strings (daystr or @@ -1016,8 +1043,6 @@ mkmonthb(int y, int m, int jd_flag, struct monthlines *mlines, int highlightdate * column is one day number. print column index: k. */ for (i = 0; i != 6; i++) { - /* additional shift to make space for weeks */ - l = flag_weeks ? 4 : 0; for (j = firsts + 7 * i, k = 0; j < last && k != dw * 7; j++, k += dw) { if (j >= first) { @@ -1025,27 +1050,18 @@ mkmonthb(int y, int m, int jd_flag, struct monthlines *mlines, int highlightdate dt.d = j - jan1 + 1; else sdateb(j, &dt); - if (j == highlightdate) - highlight(mlines->lines[i] + k + l, - ds + dt.d * dw, dw, &l); - else - memcpy(mlines->lines[i] + k + l, - ds + dt.d * dw, dw); - } else - memcpy(mlines->lines[i] + k + l, " ", dw); - } - if (k == 0) - mlines->lines[i][1] = '\0'; - else { - mlines->lines[i][k + l] = '\0'; - if (flag_weeks) { - int year; - memcpy(mlines->lines[i], ds + week(firsts + 7 * i, &year)*dw, dw); - memcpy(mlines->lines[i] + 3, "|", 1); + if (j == highlightdate) { + attron(A_REVERSE); + mvprintw(line+i, col+k, "%-.*s", dw-1, ds + dt.d*dw + 1); + attroff(A_REVERSE); + } + else { + mvprintw(line+i, col+k, "%-.*s", dw-1, ds + dt.d*dw + 1); + } + } else { + mvprintw(line+i, col+k, "%-.*s", dw, " "); } } - /* store only highlighting extralength */ - mlines->extralen[i] = l - (flag_weeks ? 4 : 0); } /* redo the shift from ncal_backward to correct week number assignment */ @@ -1154,15 +1170,11 @@ sdateb(int nd, struct date *d) return (jdate(nd, d)); } -/* Center string t in string s of length w by putting enough leading blanks. */ -static char * -center(char *s, char *t, int w) +/* Print string s centered between columns start and end. */ +static void +printcentered(int line, char *s, int start, int end) { - char blanks[MAX_WIDTH]; - - memset(blanks, ' ', sizeof(blanks)); - sprintf(s, "%.*s%s", (int)(w - strlen(t)) / 2, blanks, t); - return (s); + mvaddstr(line, start + (end - start - strlen(s))/2, s); } /* Center string t in string s of length w by putting enough leading blanks. */