diff options
author | Kristaps Dzonsons <kristaps@bsd.lv> | 2010-12-29 14:38:14 +0000 |
---|---|---|
committer | Kristaps Dzonsons <kristaps@bsd.lv> | 2010-12-29 14:38:14 +0000 |
commit | 9864cb8baea0db37f74a5bca120318017b215c1f (patch) | |
tree | 1e83dc769ff95f78b842ab6934449c8f0d893c9b /tbl_layout.c | |
parent | 48a02365daa47036d1d8a13c10650bb8f67bded6 (diff) | |
download | mandoc-9864cb8baea0db37f74a5bca120318017b215c1f.tar.gz |
Merge, with considerable changes, tbl.bsd.lv's layout-handling code.
Diffstat (limited to 'tbl_layout.c')
-rw-r--r-- | tbl_layout.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/tbl_layout.c b/tbl_layout.c new file mode 100644 index 00000000..004b3337 --- /dev/null +++ b/tbl_layout.c @@ -0,0 +1,289 @@ +/* $Id$ */ +/* + * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc.h" +#include "libmandoc.h" +#include "libroff.h" + +struct tbl_phrase { + char name; + enum tbl_cellt key; +}; + +#define KEYS_MAX 17 + +static const struct tbl_phrase keys[KEYS_MAX] = { + { 'c', TBL_CELL_CENTRE }, + { 'C', TBL_CELL_CENTRE }, + { 'r', TBL_CELL_RIGHT }, + { 'R', TBL_CELL_RIGHT }, + { 'l', TBL_CELL_LEFT }, + { 'L', TBL_CELL_LEFT }, + { 'n', TBL_CELL_NUMBER }, + { 'N', TBL_CELL_NUMBER }, + { 's', TBL_CELL_SPAN }, + { 'S', TBL_CELL_SPAN }, + { 'a', TBL_CELL_LONG }, + { 'A', TBL_CELL_LONG }, + { '^', TBL_CELL_DOWN }, + { '-', TBL_CELL_HORIZ }, + { '_', TBL_CELL_HORIZ }, + { '=', TBL_CELL_DHORIZ }, + { '|', 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 *tbl, struct tbl_cell *cp, + int ln, const char *p, int *pos) +{ + char buf[5]; + int i; + +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'): + /* FALLTHROUGH */ + case (' '): + /* FALLTHROUGH */ + case ('\t'): + /* FALLTHROUGH */ + case (','): + /* FALLTHROUGH */ + case ('.'): + return(1); + default: + break; + } + + /* Parse numerical spacing from modifier string. */ + + if (isdigit((unsigned char)p[*pos])) { + for (i = 0; i < 4; i++) { + if ( ! isdigit((unsigned char)p[*pos + i])) + break; + buf[i] = p[*pos + i]; + } + buf[i] = '\0'; + + /* No greater than 4 digits. */ + + if (4 == i) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + return(0); + } + + *pos += i; + cp->spacing = atoi(buf); + + goto mod; + /* NOTREACHED */ + } + + /* TODO: GNU has many more extensions. */ + + switch (p[(*pos)++]) { + case ('z'): + /* FALLTHROUGH */ + case ('Z'): + cp->flags |= TBL_CELL_WIGN; + goto mod; + case ('u'): + /* FALLTHROUGH */ + case ('U'): + cp->flags |= TBL_CELL_UP; + goto mod; + case ('e'): + /* FALLTHROUGH */ + case ('E'): + cp->flags |= TBL_CELL_EQUAL; + goto mod; + case ('t'): + /* FALLTHROUGH */ + case ('T'): + cp->flags |= TBL_CELL_TALIGN; + goto mod; + case ('d'): + /* FALLTHROUGH */ + case ('D'): + cp->flags |= TBL_CELL_BALIGN; + goto mod; + case ('f'): + /* FALLTHROUGH */ + case ('B'): + /* FALLTHROUGH */ + case ('I'): + /* FALLTHROUGH */ + case ('b'): + /* FALLTHROUGH */ + case ('i'): + break; + default: + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); + } + + switch (p[(*pos)++]) { + case ('b'): + /* FALLTHROUGH */ + case ('B'): + cp->flags |= TBL_CELL_BOLD; + goto mod; + case ('i'): + /* FALLTHROUGH */ + case ('I'): + cp->flags |= TBL_CELL_ITALIC; + goto mod; + default: + break; + } + + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); +} + +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; + + /* Parse the column position (`r', `R', `|', ...). */ + + for (i = 0; i < KEYS_MAX; i++) + if (p[*pos] == keys[i].name) + break; + + if (KEYS_MAX == i) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + return(0); + } + + (*pos)++; + c = keys[i].key; + + /* 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)) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); + } + + /* 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)); +} + + +static void +row(struct tbl *tbl, int ln, const char *p, int *pos) +{ + struct tbl_row *rp; + +row: /* + * EBNF describing this section: + * + * row ::= row_list [:space:]* [.]?[\n] + * row_list ::= [:space:]* row_elem row_tail + * row_tail ::= [:space:]*[,] row_list | + * epsilon + * row_elem ::= [\t\ ]*[:alpha:]+ + */ + + rp = mandoc_calloc(1, sizeof(struct tbl_row)); + if (tbl->last) { + tbl->last->next = rp; + tbl->last = rp; + } else + tbl->last = tbl->first = rp; + +cell: + while (isspace((unsigned char)p[*pos])) + (*pos)++; + + /* Safely exit layout context. */ + + if ('.' == p[*pos]) { + tbl->part = TBL_PART_DATA; + if (NULL == tbl->first) + TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos); + (*pos)++; + return; + } + + /* End (and possibly restart) a row. */ + + if (',' == p[*pos]) { + (*pos)++; + goto row; + } else if ('\0' == p[*pos]) + return; + + if ( ! cell(tbl, rp, ln, p, pos)) + return; + + goto cell; + /* NOTREACHED */ +} + + +int +tbl_layout(struct tbl *tbl, int ln, const char *p) +{ + int pos; + + pos = 0; + row(tbl, ln, p, &pos); + + /* Always succeed. */ + return(1); +} |