summaryrefslogtreecommitdiffstats
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
commit36060e6f93695c0dc996afbb3c9f53f6a825488b (patch)
treea2cd15e344c83690d76772d4bc5f31a634c9743d /tbl_layout.c
parent3d67560a814d88e4c50985ee952dfe42794e083b (diff)
downloadmandoc-36060e6f93695c0dc996afbb3c9f53f6a825488b.tar.gz
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.c138
1 files changed, 121 insertions, 17 deletions
diff --git a/tbl_layout.c b/tbl_layout.c
index 0750ca6d..f723aaee 100644
--- a/tbl_layout.c
+++ b/tbl_layout.c
@@ -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;
+}
+