aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tbl_layout.c
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2011-01-01 22:19:15 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2011-01-01 22:19:15 +0000
commit1e982599c7f339de5711a30d937e9f4ab18a529f (patch)
tree82a1fce6498226b5bbd1a76a2551424ce451193d /tbl_layout.c
parent59cd23842b32e78c3cdc0afc0deafb3b7529e470 (diff)
downloadmandoc-1e982599c7f339de5711a30d937e9f4ab18a529f.tar.gz
mandoc-1e982599c7f339de5711a30d937e9f4ab18a529f.tar.zst
mandoc-1e982599c7f339de5711a30d937e9f4ab18a529f.zip
Plug in the "head" concept for tables. A tbl_head specifies the full
layout for each row, including vertical spacers. One grabs the tbl_head for a row and iterates through each entry, plugging data from the tbl_span into the header as appropriate. This is pulled in more or less verbatim from tbl.bsd.lv. In fact, this is verbatim except that lists macros are made into hard-coded lists (for compatibility, as long-ago noted by joerg@).
Diffstat (limited to 'tbl_layout.c')
-rw-r--r--tbl_layout.c140
1 files changed, 122 insertions, 18 deletions
diff --git a/tbl_layout.c b/tbl_layout.c
index e482328d..05018f3e 100644
--- a/tbl_layout.c
+++ b/tbl_layout.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_layout.c,v 1.4 2011/01/01 21:23:01 kristaps Exp $ */
+/* $Id: tbl_layout.c,v 1.5 2011/01/01 22:19:15 kristaps Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -45,11 +45,15 @@ static const struct tbl_phrase keys[KEYS_MAX] = {
{ '|', TBL_CELL_VERT }
};
-static int mods(struct tbl *, struct tbl_cell *,
- int, const char *, int *);
-static int cell(struct tbl *, struct tbl_row *,
- int, const char *, int *);
-static void row(struct tbl *, int, const char *, int *);
+static int mods(struct tbl *, struct tbl_cell *,
+ int, const char *, int *);
+static int cell(struct tbl *, struct tbl_row *,
+ int, const char *, int *);
+static void row(struct tbl *, int, const char *, int *);
+static struct tbl_cell *cell_alloc(struct tbl *,
+ struct tbl_row *, enum tbl_cellt);
+static void head_adjust(const struct tbl_cell *,
+ struct tbl_head *);
static int
mods(struct tbl *tbl, struct tbl_cell *cp,
@@ -153,7 +157,6 @@ static int
cell(struct tbl *tbl, struct tbl_row *rp,
int ln, const char *p, int *pos)
{
- struct tbl_cell *cp;
int i;
enum tbl_cellt c;
@@ -189,16 +192,7 @@ cell(struct tbl *tbl, struct tbl_row *rp,
/* Allocate cell then parse its modifiers. */
- cp = mandoc_calloc(1, sizeof(struct tbl_cell));
- cp->pos = c;
-
- if (rp->last) {
- rp->last->next = cp;
- rp->last = cp;
- } else
- rp->last = rp->first = cp;
-
- return(mods(tbl, cp, ln, p, pos));
+ return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos));
}
@@ -253,7 +247,6 @@ cell:
/* NOTREACHED */
}
-
int
tbl_layout(struct tbl *tbl, int ln, const char *p)
{
@@ -265,3 +258,114 @@ tbl_layout(struct tbl *tbl, int ln, const char *p)
/* Always succeed. */
return(1);
}
+
+static struct tbl_cell *
+cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum tbl_cellt pos)
+{
+ struct tbl_cell *p, *pp;
+ struct tbl_head *h, *hp;
+
+ p = mandoc_calloc(1, sizeof(struct tbl_cell));
+
+ if (NULL != (pp = rp->last)) {
+ rp->last->next = p;
+ rp->last = p;
+ } else
+ rp->last = rp->first = p;
+
+ p->pos = pos;
+
+ /*
+ * This is a little bit complicated. Here we determine the
+ * header the corresponds to a cell. We add headers dynamically
+ * when need be or re-use them, otherwise. As an example, given
+ * the following:
+ *
+ * 1 c || l
+ * 2 | c | l
+ * 3 l l
+ * 3 || c | l |.
+ *
+ * We first add the new headers (as there are none) in (1); then
+ * in (2) we insert the first spanner (as it doesn't match up
+ * with the header); then we re-use the prior data headers,
+ * skipping over the spanners; then we re-use everything and add
+ * a last spanner. Note that VERT headers are made into DVERT
+ * ones.
+ */
+
+ h = pp ? pp->head->prev : tbl->first_head;
+
+ if (h) {
+ /* Re-use data header. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT != p->pos &&
+ TBL_CELL_DVERT != p->pos)) {
+ p->head = h;
+ return(p);
+ }
+
+ /* Re-use spanner header. */
+ if (TBL_HEAD_DATA != h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ head_adjust(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Right-shift headers with a new spanner. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ hp = mandoc_calloc(1, sizeof(struct tbl_head));
+ hp->prev = h->prev;
+ if (h->prev)
+ h->prev->next = hp;
+ h->prev = hp;
+ hp->next = h;
+ head_adjust(p, hp);
+ p->head = hp;
+ return(p);
+ }
+
+ if (NULL != (h = h->next)) {
+ head_adjust(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Fall through to default case... */
+ }
+
+ hp = mandoc_calloc(1, sizeof(struct tbl_head));
+
+ if (tbl->last_head) {
+ hp->prev = tbl->last_head;
+ tbl->last_head->next = hp;
+ tbl->last_head = hp;
+ } else
+ tbl->last_head = tbl->first_head = hp;
+
+ head_adjust(p, hp);
+ p->head = hp;
+ return(p);
+}
+
+static void
+head_adjust(const struct tbl_cell *cell, struct tbl_head *head)
+{
+ if (TBL_CELL_VERT != cell->pos &&
+ TBL_CELL_DVERT != cell->pos) {
+ head->pos = TBL_HEAD_DATA;
+ return;
+ }
+
+ if (TBL_CELL_VERT == cell->pos)
+ if (TBL_HEAD_DVERT != head->pos)
+ head->pos = TBL_HEAD_VERT;
+
+ if (TBL_CELL_DVERT == cell->pos)
+ head->pos = TBL_HEAD_DVERT;
+}
+