summaryrefslogtreecommitdiffstats
path: root/tbl_data.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-06-16 20:01:06 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-06-16 20:01:06 +0000
commit867c61d7b14fadc354e0eb3ab21b8df4fc0fac56 (patch)
treef56a120f24fc4ecc8eca49847552f078fee3e988 /tbl_data.c
parent7a6175f17cfb7cc37dea1c98c65b6fccaf92f619 (diff)
downloadmandoc-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.c129
1 files changed, 79 insertions, 50 deletions
diff --git a/tbl_data.c b/tbl_data.c
index 19255b98..8dd032a3 100644
--- a/tbl_data.c
+++ b/tbl_data.c
@@ -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;
+ }
+ }
}