=================================================================== RCS file: /cvs/mandoc/tbl_term.c,v retrieving revision 1.62 retrieving revision 1.69 diff -u -p -r1.62 -r1.69 --- mandoc/tbl_term.c 2018/11/28 04:47:51 1.62 +++ mandoc/tbl_term.c 2019/03/16 21:35:48 1.69 @@ -1,7 +1,7 @@ -/* $Id: tbl_term.c,v 1.62 2018/11/28 04:47:51 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.69 2019/03/16 21:35:48 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2011-2018 Ingo Schwarze + * Copyright (c) 2011-2019 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,20 +26,14 @@ #include #include "mandoc.h" +#include "tbl.h" #include "out.h" #include "term.h" #define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \ (cp)->pos == TBL_CELL_DHORIZ) -/* Flags for tbl_hrule(). */ -#define HRULE_DBOX (1 << 0) /* Top and bottom, ASCII mode only. */ -#define HRULE_DATA (1 << 1) /* In the middle of the table. */ -#define HRULE_DOWN (1 << 2) /* Allow downward branches. */ -#define HRULE_UP (1 << 3) /* Allow upward branches. */ -#define HRULE_ENDS (1 << 4) /* Also generate left and right ends. */ - static size_t term_tbl_len(size_t, void *); static size_t term_tbl_strlen(const char *, void *); static size_t term_tbl_sulen(const struct roffsu *, void *); @@ -51,7 +45,9 @@ static void tbl_direct_border(struct termp *, int, siz static void tbl_fill_border(struct termp *, int, size_t); static void tbl_fill_char(struct termp *, char, size_t); static void tbl_fill_string(struct termp *, const char *, size_t); -static void tbl_hrule(struct termp *, const struct tbl_span *, int); +static void tbl_hrule(struct termp *, const struct tbl_span *, + const struct tbl_span *, const struct tbl_span *, + int); static void tbl_literal(struct termp *, const struct tbl_dat *, const struct roffcol *); static void tbl_number(struct termp *, const struct tbl_opts *, @@ -168,13 +164,15 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) const struct tbl_cell *cp, *cpn, *cpp, *cps; const struct tbl_dat *dp; static size_t offset; + size_t save_offset; size_t coloff, tsz; int hspans, ic, more; - int dvert, fc, horiz, line, uvert; + int dvert, fc, horiz, lhori, rhori, uvert; /* Inhibit printing of spaces: we do padding ourselves. */ tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; + save_offset = tp->tcol->offset; /* * The first time we're invoked for a given table block, @@ -216,22 +214,24 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tsz += tp->tbl.cols[sp->opts->cols - 1].width; if (offset + tsz > tp->tcol->rmargin) tsz -= 1; - tp->tcol->offset = offset + tp->tcol->rmargin > tsz ? + offset = offset + tp->tcol->rmargin > tsz ? (offset + tp->tcol->rmargin - tsz) / 2 : 0; + tp->tcol->offset = offset; } /* Horizontal frame at the start of boxed tables. */ if (tp->enc == TERMENC_ASCII && sp->opts->opts & TBL_OPT_DBOX) - tbl_hrule(tp, sp, HRULE_DBOX | HRULE_ENDS); + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_DBOX); if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) - tbl_hrule(tp, sp, HRULE_DOWN | HRULE_ENDS); + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_BOX); } /* Set up the columns. */ tp->flags |= TERMP_MULTICOL; + tp->tcol->offset = offset; horiz = 0; switch (sp->pos) { case TBL_SPAN_HORIZ: @@ -326,11 +326,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) (horiz || (IS_HORIZ(sp->layout->first) && !IS_HORIZ(sp->prev->layout->first)))) uvert = sp->prev->layout->vert; - line = sp->pos == TBL_SPAN_DHORIZ || + rhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_DHORIZ) || sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 : sp->pos == TBL_SPAN_HORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_HORIZ) || sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0; - fc = BUP * uvert + BDOWN * dvert + BRIGHT * line; + fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori; if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) { (*tp->advance)(tp, tp->tcols->offset); tp->viscol = tp->tcol->offset; @@ -341,7 +343,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) more = 0; if (horiz) - tbl_hrule(tp, sp, HRULE_DATA | HRULE_DOWN | HRULE_UP); + tbl_hrule(tp, sp->prev, sp, sp->next, 0); else { cp = sp->layout->first; cpn = sp->next == NULL ? NULL : @@ -403,6 +405,15 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) cpn = cpn->next; } + lhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; + /* * Skip later cells in a span, * figure out whether to start a span, @@ -437,11 +448,14 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) * but not after the last column. */ - if (fc == 0 && ((uvert == 0 && dvert == 0 && - (cp->next == NULL || + if (fc == 0 && + ((uvert == 0 && dvert == 0 && + cp != NULL && (cp->next == NULL || !IS_HORIZ(cp->next))) || - tp->tcol + 1 == tp->tcols + tp->lasttcol)) { - cp = cp->next; + tp->tcol + 1 == + tp->tcols + tp->lasttcol)) { + if (cp != NULL) + cp = cp->next; continue; } @@ -452,57 +466,36 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) } while (tp->viscol < tp->tcol->rmargin + tp->tbl.cols[ic].spacing / 2) - tbl_direct_border(tp, fc, 1); + tbl_direct_border(tp, + BHORIZ * lhori, 1); if (tp->tcol + 1 == tp->tcols + tp->lasttcol) continue; - if (cp != NULL) { - switch (cp->pos) { - case TBL_CELL_HORIZ: - fc = BLEFT; - break; - case TBL_CELL_DHORIZ: - fc = BLEFT * 2; - break; - default: - fc = 0; - break; - } + if (cp != NULL) cp = cp->next; - } - if (cp != NULL) { - switch (cp->pos) { - case TBL_CELL_HORIZ: - fc += BRIGHT; - break; - case TBL_CELL_DHORIZ: - fc += BRIGHT * 2; - break; - default: - break; - } - } + + rhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; + if (tp->tbl.cols[ic].spacing) - tbl_direct_border(tp, fc + + tbl_direct_border(tp, + BLEFT * lhori + BRIGHT * rhori + BUP * uvert + BDOWN * dvert, 1); if (tp->enc == TERMENC_UTF8) uvert = dvert = 0; - if (fc != 0) { - if (cp != NULL && - cp->pos == TBL_CELL_HORIZ) - fc = BHORIZ; - else if (cp != NULL && - cp->pos == TBL_CELL_DHORIZ) - fc = BHORIZ * 2; - else - fc = 0; - } if (tp->tbl.cols[ic].spacing > 2 && - (uvert > 1 || dvert > 1 || fc != 0)) - tbl_direct_border(tp, fc + + (uvert > 1 || dvert > 1 || rhori)) + tbl_direct_border(tp, + BHORIZ * rhori + BUP * (uvert > 1) + BDOWN * (dvert > 1), 1); } @@ -526,20 +519,27 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) (horiz || (IS_HORIZ(sp->layout->last) && !IS_HORIZ(sp->prev->layout->last)))) uvert = sp->prev->layout->last->vert; - line = sp->pos == TBL_SPAN_DHORIZ || + lhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_DHORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || (sp->layout->last->pos == TBL_CELL_DHORIZ && sp->layout->last->col + 1 == sp->opts->cols) ? 2 : sp->pos == TBL_SPAN_HORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_HORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || (sp->layout->last->pos == TBL_CELL_HORIZ && sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0; - fc = BUP * uvert + BDOWN * dvert + BLEFT * line; + fc = BUP * uvert + BDOWN * dvert + BLEFT * lhori; if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) { if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 || sp->layout->last->col + 1 < sp->opts->cols)) { tp->tcol++; - (*tp->advance)(tp, - tp->tcol->offset > tp->viscol ? - tp->tcol->offset - tp->viscol : 1); + do { + tbl_direct_border(tp, + BHORIZ * lhori, 1); + } while (tp->viscol < tp->tcol->offset); } tbl_direct_border(tp, fc, 1); } @@ -558,100 +558,158 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tcol->rmargin = tp->maxrmargin; if (sp->next == NULL) { if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { - tbl_hrule(tp, sp, HRULE_UP | HRULE_ENDS); + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_BOX); tp->skipvsp = 1; } if (tp->enc == TERMENC_ASCII && sp->opts->opts & TBL_OPT_DBOX) { - tbl_hrule(tp, sp, HRULE_DBOX | HRULE_ENDS); + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_DBOX); tp->skipvsp = 2; } assert(tp->tbl.cols); free(tp->tbl.cols); tp->tbl.cols = NULL; - tp->tcol->offset = offset; } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || sp->next->next != NULL)) - tbl_hrule(tp, sp, - HRULE_DATA | HRULE_DOWN | HRULE_UP | HRULE_ENDS); + tbl_hrule(tp, sp, sp, sp->next, TBL_OPT_ALLBOX); + tp->tcol->offset = save_offset; tp->flags &= ~TERMP_NONOSPACE; } static void -tbl_hrule(struct termp *tp, const struct tbl_span *sp, int flags) +tbl_hrule(struct termp *tp, const struct tbl_span *spp, + const struct tbl_span *sp, const struct tbl_span *spn, int flags) { - const struct tbl_cell *cp, *cpn, *cpp; - const struct roffcol *col; - int cross, dvert, line, linewidth, uvert; + const struct tbl_cell *cpp; /* Layout cell above this line. */ + const struct tbl_cell *cp; /* Layout cell in this line. */ + const struct tbl_cell *cpn; /* Layout cell below this line. */ + const struct tbl_dat *dpn; /* Data cell below this line. */ + const struct roffcol *col; /* Contains width and spacing. */ + int opts; /* For the table as a whole. */ + int bw; /* Box line width. */ + int hw; /* Horizontal line width. */ + int lw, rw; /* Left and right line widths. */ + int uw, dw; /* Vertical line widths. */ - cp = sp->layout->first; - cpn = cpp = NULL; - if (flags & HRULE_DATA) { - linewidth = sp->pos == TBL_SPAN_DHORIZ ? 2 : 1; - cpn = sp->next == NULL ? NULL : sp->next->layout->first; - if (cpn == cp) - cpn = NULL; - } else - linewidth = tp->enc == TERMENC_UTF8 && - sp->opts->opts & TBL_OPT_DBOX ? 2 : 1; + cpp = spp == NULL ? NULL : spp->layout->first; + cp = sp == NULL ? NULL : sp->layout->first; + cpn = spn == NULL ? NULL : spn->layout->first; + dpn = NULL; + if (spn != NULL) { + if (spn->pos == TBL_SPAN_DATA) + dpn = spn->first; + else if (spn->next != NULL) + dpn = spn->next->first; + } + opts = sp->opts->opts; + bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) : + opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0; + hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw : + sp->pos == TBL_SPAN_DHORIZ ? 2 : 1; + + /* Print the left end of the line. */ + if (tp->viscol == 0) { (*tp->advance)(tp, tp->tcols->offset); tp->viscol = tp->tcols->offset; } - if (flags & HRULE_ENDS) - tbl_direct_border(tp, linewidth * (BRIGHT + - (flags & (HRULE_UP | HRULE_DBOX) ? BUP : 0) + - (flags & (HRULE_DOWN | HRULE_DBOX) ? BDOWN : 0)), 1); - else { - cpp = sp->prev == NULL ? NULL : sp->prev->layout->first; - if (cpp == cp) - cpp = NULL; - } + if (flags != 0) + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || cpn == NULL || + cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1); + for (;;) { col = tp->tbl.cols + cp->col; - line = cpn == NULL || cpn->pos != TBL_CELL_DOWN ? - BHORIZ * linewidth : 0; - tbl_direct_border(tp, line, col->width + col->spacing / 2); - uvert = dvert = 0; - if (flags & HRULE_UP && - (tp->enc == TERMENC_ASCII || sp->pos == TBL_SPAN_DATA || - (sp->prev != NULL && sp->prev->layout == sp->layout))) - uvert = cp->vert; - if (flags & HRULE_DOWN) - dvert = cp->vert; - if ((cp = cp->next) == NULL) - break; + + /* Print the horizontal line inside this column. */ + + lw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + tbl_direct_border(tp, BHORIZ * lw, + col->width + col->spacing / 2); + + /* + * Figure out whether a vertical line is crossing + * at the end of this column, + * and advance to the next column. + */ + + uw = dw = 0; if (cpp != NULL) { - if (uvert < cpp->vert) - uvert = cpp->vert; + if (flags != TBL_OPT_DBOX) { + uw = cpp->vert; + if (uw == 0 && opts & TBL_OPT_ALLBOX) + uw = 1; + } cpp = cpp->next; } + if (cp != NULL) + cp = cp->next; if (cpn != NULL) { - if (dvert < cpn->vert) - dvert = cpn->vert; + if (flags != TBL_OPT_DBOX) { + dw = cpn->vert; + if (dw == 0 && opts & TBL_OPT_ALLBOX) + dw = 1; + } cpn = cpn->next; + while (dpn != NULL && dpn->layout != cpn) + dpn = dpn->next; } - if (sp->opts->opts & TBL_OPT_ALLBOX) { - if (flags & HRULE_UP && uvert == 0) - uvert = 1; - if (flags & HRULE_DOWN && dvert == 0) - dvert = 1; - } - cross = BHORIZ * linewidth + BUP * uvert + BDOWN * dvert; + if (cpp == NULL && cp == NULL && cpn == NULL) + break; + + /* Vertical lines do not cross spanned cells. */ + + if (cpp != NULL && cpp->pos == TBL_CELL_SPAN) + uw = 0; + if (cpn != NULL && cpn->pos == TBL_CELL_SPAN) + dw = 0; + + /* The horizontal line inside the next column. */ + + rw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + + /* The line crossing at the end of this column. */ + if (col->spacing) - tbl_direct_border(tp, cross, 1); + tbl_direct_border(tp, BLEFT * lw + + BRIGHT * rw + BUP * uw + BDOWN * dw, 1); + + /* + * In ASCII output, a crossing may print two characters. + */ + + if (tp->enc != TERMENC_ASCII || (uw < 2 && dw < 2)) + uw = dw = 0; if (col->spacing > 2) - tbl_direct_border(tp, tp->enc == TERMENC_ASCII && - (uvert > 1 || dvert > 1) ? cross : line, 1); + tbl_direct_border(tp, + BHORIZ * rw + BUP * uw + BDOWN * dw, 1); + + /* Padding before the start of the next column. */ + if (col->spacing > 4) - tbl_direct_border(tp, line, (col->spacing - 3) / 2); + tbl_direct_border(tp, + BHORIZ * rw, (col->spacing - 3) / 2); } - if (flags & HRULE_ENDS) { - tbl_direct_border(tp, linewidth * (BLEFT + - (flags & (HRULE_UP | HRULE_DBOX) ? BUP : 0) + - (flags & (HRULE_DOWN | HRULE_DBOX) ? BDOWN : 0)), 1); + + /* Print the right end of the line. */ + + if (flags != 0) { + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || spn == NULL || + spn->layout->last->pos != TBL_CELL_DOWN ? + BLEFT * hw : 0), 1); (*tp->endline)(tp); tp->viscol = 0; }