diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2017-06-16 20:01:06 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2017-06-16 20:01:06 +0000 |
commit | 867c61d7b14fadc354e0eb3ab21b8df4fc0fac56 (patch) | |
tree | f56a120f24fc4ecc8eca49847552f078fee3e988 /tbl_data.c | |
parent | 7a6175f17cfb7cc37dea1c98c65b6fccaf92f619 (diff) | |
download | mandoc-867c61d7b14fadc354e0eb3ab21b8df4fc0fac56.tar.gz |
Multiple tbl(7) improvements:
* Do not discard data that lacks a matching layout cell but remains
within the number of columns of the table as a whole.
* Do not insert dummy data rows for any layout row starting with a
horizontal line, but only for layout rows that would discard all
the data on a matching non-empty data row.
* Print horizontal lines specified in the layout even if there is
no matching data cell.
* Improve the logic for extending vertical lines to adjacent rows,
for choosing cross marks versus line segments, and some related details.
Diffstat (limited to 'tbl_data.c')
-rw-r--r-- | tbl_data.c | 129 |
1 files changed, 79 insertions, 50 deletions
@@ -51,17 +51,26 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp, cp = cp->next; /* - * Stop processing when we reach the end of the available layout - * cells. This means that we have extra input. + * If the current layout row is out of cells, allocate + * a new cell if another row of the table has at least + * this number of columns, or discard the input if we + * are beyond the last column of the table as a whole. */ if (cp == NULL) { - mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse, - ln, *pos, p + *pos); - /* Skip to the end... */ - while (p[*pos]) - (*pos)++; - return; + if (dp->layout->last->col + 1 < dp->opts->cols) { + cp = mandoc_calloc(1, sizeof(*cp)); + cp->pos = TBL_CELL_LEFT; + dp->layout->last->next = cp; + cp->col = dp->layout->last->col + 1; + dp->layout->last = cp; + } else { + mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse, + ln, *pos, p + *pos); + while (p[*pos]) + (*pos)++; + return; + } } dat = mandoc_calloc(1, sizeof(*dat)); @@ -185,58 +194,78 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) void tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos) { - struct tbl_span *dp; struct tbl_row *rp; + struct tbl_cell *cp; + struct tbl_span *sp, *spi; + struct tbl_dat *dp; + int have_data, spans; - /* - * Choose a layout row: take the one following the last parsed - * span's. If that doesn't exist, use the last parsed span's. - * If there's no last parsed span, use the first row. Lastly, - * if the last span was a horizontal line, use the same layout - * (it doesn't "consume" the layout). - */ - - if (tbl->last_span != NULL) { - if (tbl->last_span->pos == TBL_SPAN_DATA) { - for (rp = tbl->last_span->layout->next; - rp != NULL && rp->first != NULL; - rp = rp->next) { - switch (rp->first->pos) { - case TBL_CELL_HORIZ: - dp = newspan(tbl, ln, rp); - dp->pos = TBL_SPAN_HORIZ; - continue; - case TBL_CELL_DHORIZ: - dp = newspan(tbl, ln, rp); - dp->pos = TBL_SPAN_DHORIZ; - continue; - default: - break; - } - break; - } - } else - rp = tbl->last_span->layout; - - if (rp == NULL) - rp = tbl->last_span->layout; - } else - rp = tbl->first_row; + rp = (sp = tbl->last_span) == NULL ? tbl->first_row : + sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ? + sp->layout->next : sp->layout; - assert(rp); + assert(rp != NULL); - dp = newspan(tbl, ln, rp); + sp = newspan(tbl, ln, rp); if ( ! strcmp(p, "_")) { - dp->pos = TBL_SPAN_HORIZ; + sp->pos = TBL_SPAN_HORIZ; return; } else if ( ! strcmp(p, "=")) { - dp->pos = TBL_SPAN_DHORIZ; + sp->pos = TBL_SPAN_DHORIZ; return; } - - dp->pos = TBL_SPAN_DATA; + sp->pos = TBL_SPAN_DATA; while (p[pos] != '\0') - getdata(tbl, dp, ln, p, &pos); + getdata(tbl, sp, ln, p, &pos); + + /* + * If this span contains some data, + * make sure at least part of it gets printed. + */ + + have_data = 0; + cp = rp->first; + for (dp = sp->first; dp != NULL; dp = dp->next) { + if (dp->pos == TBL_DATA_DATA && *dp->string != '\0') { + if (cp == NULL || + (cp->pos != TBL_CELL_HORIZ && + cp->pos != TBL_CELL_DHORIZ)) + return; + have_data = 1; + } + spans = dp->spans; + while (spans-- >= 0) { + if (cp != NULL) + cp = cp->next; + } + } + if (have_data == 0 || rp->next == NULL) + return; + + /* + * There is some data, but it would all get lost + * due to horizontal lines in the layout. + * Insert an empty span to consume the layout row. + */ + + tbl->last_span = sp->prev; + spi = newspan(tbl, ln, rp); + spi->pos = TBL_SPAN_DATA; + spi->next = sp; + tbl->last_span = sp; + sp->prev = spi; + sp->layout = rp->next; + cp = sp->layout->first; + for (dp = sp->first; dp != NULL; dp = dp->next) { + dp->layout = cp; + dp->spans = 0; + if (cp != NULL) + cp = cp->next; + while (cp != NULL && cp->pos == TBL_CELL_SPAN) { + dp->spans++; + cp = cp->next; + } + } } |