=================================================================== RCS file: /cvs/mandoc/tbl_layout.c,v retrieving revision 1.5 retrieving revision 1.20 diff -u -p -r1.5 -r1.20 --- mandoc/tbl_layout.c 2011/01/01 22:19:15 1.5 +++ mandoc/tbl_layout.c 2011/05/17 13:11:40 1.20 @@ -1,4 +1,4 @@ -/* $Id: tbl_layout.c,v 1.5 2011/01/01 22:19:15 kristaps Exp $ */ +/* $Id: tbl_layout.c,v 1.20 2011/05/17 13:11:40 kristaps Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons * @@ -14,6 +14,10 @@ * 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 @@ -29,6 +33,12 @@ struct tbl_phrase { enum tbl_cellt key; }; +/* + * FIXME: we can make this parse a lot nicer by, when an error is + * encountered in a layout key, bailing to the next key (i.e. to the + * next whitespace then continuing). + */ + #define KEYS_MAX 11 static const struct tbl_phrase keys[KEYS_MAX] = { @@ -45,23 +55,40 @@ static const struct tbl_phrase keys[KEYS_MAX] = { { '|', TBL_CELL_VERT } }; -static int mods(struct tbl *, struct tbl_cell *, +static int mods(struct tbl_node *, struct tbl_cell *, int, const char *, int *); -static int cell(struct tbl *, struct tbl_row *, +static int cell(struct tbl_node *, struct tbl_row *, int, const char *, int *); -static void row(struct tbl *, int, const char *, int *); -static struct tbl_cell *cell_alloc(struct tbl *, +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 int -mods(struct tbl *tbl, struct tbl_cell *cp, +mods(struct tbl_node *tbl, struct tbl_cell *cp, int ln, const char *p, int *pos) { char buf[5]; int i; + /* Not all types accept modifiers. */ + + switch (cp->pos) { + case (TBL_CELL_DOWN): + /* FALLTHROUGH */ + case (TBL_CELL_HORIZ): + /* FALLTHROUGH */ + case (TBL_CELL_DHORIZ): + /* FALLTHROUGH */ + case (TBL_CELL_VERT): + /* FALLTHROUGH */ + case (TBL_CELL_DVERT): + return(1); + default: + break; + } + mod: /* * XXX: since, at least for now, modifiers are non-conflicting @@ -84,6 +111,21 @@ mod: break; } + /* Throw away parenthesised expression. */ + + if ('(' == p[*pos]) { + (*pos)++; + while (p[*pos] && ')' != p[*pos]) + (*pos)++; + if (')' == p[*pos]) { + (*pos)++; + goto mod; + } + mandoc_msg(MANDOCERR_TBLLAYOUT, + tbl->parse, ln, *pos, NULL); + return(0); + } + /* Parse numerical spacing from modifier string. */ if (isdigit((unsigned char)p[*pos])) { @@ -97,12 +139,13 @@ mod: /* No greater than 4 digits. */ if (4 == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } *pos += i; - cp->spacing = atoi(buf); + cp->spacing = (size_t)atoi(buf); goto mod; /* NOTREACHED */ @@ -110,7 +153,7 @@ mod: /* TODO: GNU has many more extensions. */ - switch (tolower(p[(*pos)++])) { + switch (tolower((unsigned char)p[(*pos)++])) { case ('z'): cp->flags |= TBL_CELL_WIGN; goto mod; @@ -126,6 +169,8 @@ mod: case ('d'): cp->flags |= TBL_CELL_BALIGN; goto mod; + case ('w'): /* XXX for now, ignore minimal column width */ + goto mod; case ('f'): break; case ('b'): @@ -134,11 +179,12 @@ mod: (*pos)--; break; default: - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } - switch (tolower(p[(*pos)++])) { + switch (tolower((unsigned char)p[(*pos)++])) { case ('b'): cp->flags |= TBL_CELL_BOLD; goto mod; @@ -149,12 +195,13 @@ mod: break; } - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } static int -cell(struct tbl *tbl, struct tbl_row *rp, +cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { int i; @@ -163,17 +210,56 @@ cell(struct tbl *tbl, struct tbl_row *rp, /* Parse the column position (`r', `R', `|', ...). */ for (i = 0; i < KEYS_MAX; i++) - if (tolower(p[*pos]) == keys[i].name) + if (tolower((unsigned char)p[*pos]) == keys[i].name) break; if (KEYS_MAX == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } - (*pos)++; c = keys[i].key; + /* + * If a span cell is found first, raise a warning and abort the + * parse. If a span cell is found and the last layout element + * isn't a "normal" layout, bail. + * + * FIXME: recover from this somehow? + */ + + if (TBL_CELL_SPAN == c) { + if (NULL == rp->first) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + 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); + return(0); + default: + break; + } + } + + /* + * If a vertical spanner is found, we may not be in the first + * row. + */ + + if (TBL_CELL_DOWN == c && rp == tbl->first_row) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL); + return(0); + } + + (*pos)++; + /* Extra check for the double-vertical. */ if (TBL_CELL_VERT == c && '|' == p[*pos]) { @@ -186,7 +272,7 @@ cell(struct tbl *tbl, struct tbl_row *rp, if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && (TBL_CELL_VERT == rp->last->pos || TBL_CELL_DVERT == rp->last->pos)) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } @@ -197,7 +283,7 @@ cell(struct tbl *tbl, struct tbl_row *rp, static void -row(struct tbl *tbl, int ln, const char *p, int *pos) +row(struct tbl_node *tbl, int ln, const char *p, int *pos) { struct tbl_row *rp; @@ -227,7 +313,8 @@ cell: if ('.' == p[*pos]) { tbl->part = TBL_PART_DATA; if (NULL == tbl->first_row) - TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse, + ln, *pos, NULL); (*pos)++; return; } @@ -248,7 +335,7 @@ cell: } int -tbl_layout(struct tbl *tbl, int ln, const char *p) +tbl_layout(struct tbl_node *tbl, int ln, const char *p) { int pos; @@ -260,7 +347,7 @@ tbl_layout(struct tbl *tbl, int ln, const char *p) } static struct tbl_cell * -cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum tbl_cellt pos) +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) { struct tbl_cell *p, *pp; struct tbl_head *h, *hp; @@ -294,7 +381,7 @@ cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum t * ones. */ - h = pp ? pp->head->prev : tbl->first_head; + h = pp ? pp->head->next : tbl->first_head; if (h) { /* Re-use data header. */ @@ -319,9 +406,12 @@ cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum t (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); @@ -339,6 +429,7 @@ cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum t } hp = mandoc_calloc(1, sizeof(struct tbl_head)); + hp->ident = tbl->opts.cols++; if (tbl->last_head) { hp->prev = tbl->last_head; @@ -353,19 +444,19 @@ cell_alloc(struct tbl *tbl, struct tbl_row *rp, enum t } static void -head_adjust(const struct tbl_cell *cell, struct tbl_head *head) +head_adjust(const struct tbl_cell *cellp, struct tbl_head *head) { - if (TBL_CELL_VERT != cell->pos && - TBL_CELL_DVERT != cell->pos) { + if (TBL_CELL_VERT != cellp->pos && + TBL_CELL_DVERT != cellp->pos) { head->pos = TBL_HEAD_DATA; return; } - if (TBL_CELL_VERT == cell->pos) + if (TBL_CELL_VERT == cellp->pos) if (TBL_HEAD_DVERT != head->pos) head->pos = TBL_HEAD_VERT; - if (TBL_CELL_DVERT == cell->pos) + if (TBL_CELL_DVERT == cellp->pos) head->pos = TBL_HEAD_DVERT; }