=================================================================== RCS file: /cvs/mandoc/tbl_layout.c,v retrieving revision 1.20 retrieving revision 1.28 diff -u -p -r1.20 -r1.28 --- mandoc/tbl_layout.c 2011/05/17 13:11:40 1.20 +++ mandoc/tbl_layout.c 2014/10/07 14:07:03 1.28 @@ -1,6 +1,7 @@ -/* $Id: tbl_layout.c,v 1.20 2011/05/17 13:11:40 kristaps Exp $ */ +/* $Id: tbl_layout.c,v 1.28 2014/10/07 14:07:03 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2012, 2014 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 @@ -14,17 +15,17 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif -#include +#include + #include #include #include #include #include "mandoc.h" +#include "mandoc_aux.h" #include "libmandoc.h" #include "libroff.h" @@ -51,22 +52,20 @@ static const struct tbl_phrase keys[KEYS_MAX] = { { '^', TBL_CELL_DOWN }, { '-', TBL_CELL_HORIZ }, { '_', TBL_CELL_HORIZ }, - { '=', TBL_CELL_DHORIZ }, - { '|', TBL_CELL_VERT } + { '=', TBL_CELL_DHORIZ } }; -static int mods(struct tbl_node *, struct tbl_cell *, +static int mods(struct tbl_node *, struct tbl_cell *, int, const char *, int *); -static int cell(struct tbl_node *, struct tbl_row *, +static int cell(struct tbl_node *, struct tbl_row *, int, const char *, int *); static void row(struct tbl_node *, int, const char *, int *); -static struct tbl_cell *cell_alloc(struct tbl_node *, - struct tbl_row *, enum tbl_cellt); -static void head_adjust(const struct tbl_cell *, - struct tbl_head *); +static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *, + enum tbl_cellt, int vert); + static int -mods(struct tbl_node *tbl, struct tbl_cell *cp, +mods(struct tbl_node *tbl, struct tbl_cell *cp, int ln, const char *p, int *pos) { char buf[5]; @@ -75,37 +74,35 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp, /* Not all types accept modifiers. */ switch (cp->pos) { - case (TBL_CELL_DOWN): + case TBL_CELL_DOWN: /* FALLTHROUGH */ - case (TBL_CELL_HORIZ): + case TBL_CELL_HORIZ: /* FALLTHROUGH */ - case (TBL_CELL_DHORIZ): - /* FALLTHROUGH */ - case (TBL_CELL_VERT): - /* FALLTHROUGH */ - case (TBL_CELL_DVERT): + case TBL_CELL_DHORIZ: return(1); default: break; } mod: - /* + /* * XXX: since, at least for now, modifiers are non-conflicting * (are separable by value, regardless of position), we let * modifiers come in any order. The existing tbl doesn't let * this happen. */ switch (p[*pos]) { - case ('\0'): + case '\0': /* FALLTHROUGH */ - case (' '): + case ' ': /* FALLTHROUGH */ - case ('\t'): + case '\t': /* FALLTHROUGH */ - case (','): + case ',': /* FALLTHROUGH */ - case ('.'): + case '.': + /* FALLTHROUGH */ + case '|': return(1); default: break; @@ -121,8 +118,8 @@ mod: (*pos)++; goto mod; } - mandoc_msg(MANDOCERR_TBLLAYOUT, - tbl->parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } @@ -139,8 +136,8 @@ mod: /* No greater than 4 digits. */ if (4 == i) { - mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT, + tbl->parse, ln, *pos, NULL); return(0); } @@ -149,73 +146,102 @@ mod: goto mod; /* NOTREACHED */ - } + } /* TODO: GNU has many more extensions. */ switch (tolower((unsigned char)p[(*pos)++])) { - case ('z'): + case 'z': cp->flags |= TBL_CELL_WIGN; goto mod; - case ('u'): + case 'u': cp->flags |= TBL_CELL_UP; goto mod; - case ('e'): + case 'e': cp->flags |= TBL_CELL_EQUAL; goto mod; - case ('t'): + case 't': cp->flags |= TBL_CELL_TALIGN; goto mod; - case ('d'): + case 'd': cp->flags |= TBL_CELL_BALIGN; goto mod; - case ('w'): /* XXX for now, ignore minimal column width */ + case 'w': /* XXX for now, ignore minimal column width */ goto mod; - case ('f'): + case 'f': break; - case ('b'): + case 'r': /* FALLTHROUGH */ - case ('i'): + case 'b': + /* FALLTHROUGH */ + case 'i': (*pos)--; break; default: mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos - 1, NULL); + ln, *pos - 1, NULL); return(0); } switch (tolower((unsigned char)p[(*pos)++])) { - case ('b'): + case '3': + /* FALLTHROUGH */ + case 'b': cp->flags |= TBL_CELL_BOLD; goto mod; - case ('i'): + case '2': + /* FALLTHROUGH */ + case 'i': cp->flags |= TBL_CELL_ITALIC; goto mod; + case '1': + /* FALLTHROUGH */ + case 'r': + goto mod; default: break; } + if (isalnum((unsigned char)p[*pos - 1])) { + mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, + ln, *pos - 1, "TS f%c", p[*pos - 1]); + goto mod; + } mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos - 1, NULL); + ln, *pos - 1, NULL); return(0); } static int -cell(struct tbl_node *tbl, struct tbl_row *rp, +cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { - int i; + int vert, i; enum tbl_cellt c; - /* Parse the column position (`r', `R', `|', ...). */ + /* Handle vertical lines. */ + for (vert = 0; '|' == p[*pos]; ++*pos) + vert++; + while (' ' == p[*pos]) + (*pos)++; + + /* Handle trailing vertical lines */ + + if ('.' == p[*pos] || '\0' == p[*pos]) { + rp->vert = vert; + return(1); + } + + /* Parse the column position (`c', `l', `r', ...). */ + for (i = 0; i < KEYS_MAX; i++) if (tolower((unsigned char)p[*pos]) == keys[i].name) break; if (KEYS_MAX == i) { - mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } @@ -232,16 +258,15 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, if (TBL_CELL_SPAN == c) { if (NULL == rp->first) { mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos, NULL); + ln, *pos, NULL); return(0); } else if (rp->last) switch (rp->last->pos) { - case (TBL_CELL_VERT): - case (TBL_CELL_DVERT): - case (TBL_CELL_HORIZ): - case (TBL_CELL_DHORIZ): - mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, - ln, *pos, NULL); + case TBL_CELL_HORIZ: + /* FALLTHROUGH */ + case TBL_CELL_DHORIZ: + mandoc_msg(MANDOCERR_TBLLAYOUT, + tbl->parse, ln, *pos, NULL); return(0); default: break; @@ -260,28 +285,18 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, (*pos)++; - /* Extra check for the double-vertical. */ - - if (TBL_CELL_VERT == c && '|' == p[*pos]) { - (*pos)++; - c = TBL_CELL_DVERT; - } - /* Disallow adjacent spacers. */ - if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && - (TBL_CELL_VERT == rp->last->pos || - TBL_CELL_DVERT == rp->last->pos)) { + if (vert > 2) { mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } /* Allocate cell then parse its modifiers. */ - return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos)); + return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos)); } - static void row(struct tbl_node *tbl, int ln, const char *p, int *pos) { @@ -298,11 +313,11 @@ row: /* */ rp = mandoc_calloc(1, sizeof(struct tbl_row)); - if (tbl->last_row) { + if (tbl->last_row) tbl->last_row->next = rp; - tbl->last_row = rp; - } else - tbl->last_row = tbl->first_row = rp; + else + tbl->first_row = rp; + tbl->last_row = rp; cell: while (isspace((unsigned char)p[*pos])) @@ -312,9 +327,9 @@ cell: if ('.' == p[*pos]) { tbl->part = TBL_PART_DATA; - if (NULL == tbl->first_row) - mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse, - ln, *pos, NULL); + if (NULL == tbl->first_row) + mandoc_msg(MANDOCERR_TBLNOLAYOUT, + tbl->parse, ln, *pos, NULL); (*pos)++; return; } @@ -347,7 +362,8 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p } static struct tbl_cell * -cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos, + int vert) { struct tbl_cell *p, *pp; struct tbl_head *h, *hp; @@ -355,108 +371,35 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, e 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; + pp->next = p; + h = pp->head->next; + } else { + rp->first = p; + h = tbl->first_head; + } + rp->last = p; p->pos = pos; + p->vert = vert; - /* - * 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. - */ + /* Re-use header. */ - h = pp ? pp->head->next : 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->ident = tbl->opts.cols++; - hp->prev = h->prev; - if (h->prev) - h->prev->next = hp; - if (h == tbl->first_head) - tbl->first_head = 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... */ + p->head = h; + return(p); } hp = mandoc_calloc(1, sizeof(struct tbl_head)); hp->ident = tbl->opts.cols++; + hp->vert = vert; 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; + tbl->first_head = hp; + tbl->last_head = hp; - head_adjust(p, hp); p->head = hp; return(p); } - -static void -head_adjust(const struct tbl_cell *cellp, struct tbl_head *head) -{ - if (TBL_CELL_VERT != cellp->pos && - TBL_CELL_DVERT != cellp->pos) { - head->pos = TBL_HEAD_DATA; - return; - } - - if (TBL_CELL_VERT == cellp->pos) - if (TBL_HEAD_DVERT != head->pos) - head->pos = TBL_HEAD_VERT; - - if (TBL_CELL_DVERT == cellp->pos) - head->pos = TBL_HEAD_DVERT; -} -