diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | libroff.h | 36 | ||||
-rw-r--r-- | tbl.c | 69 | ||||
-rw-r--r-- | tbl_opts.c | 196 |
4 files changed, 294 insertions, 13 deletions
@@ -31,11 +31,11 @@ CFLAGS += -g $(WFLAGS) $(VFLAGS) -DHAVE_CONFIG_H LINTFLAGS += $(VFLAGS) -ROFFLNS = roff.ln tbl.ln +ROFFLNS = roff.ln tbl.ln tbl_opts.ln -ROFFSRCS = roff.c tbl.c +ROFFSRCS = roff.c tbl.c tbl_opts.c -ROFFOBJS = roff.o tbl.o +ROFFOBJS = roff.o tbl.o tbl_opts.o MANDOCLNS = mandoc.ln @@ -19,12 +19,46 @@ __BEGIN_DECLS -struct tbl; +enum tbl_tok { + TBL_TOK_OPENPAREN = 0, + TBL_TOK_CLOSEPAREN, + TBL_TOK_COMMA, + TBL_TOK_SEMICOLON, + TBL_TOK_PERIOD, + TBL_TOK_SPACE, + TBL_TOK_TAB, + TBL_TOK_NIL, + TBL_TOK__MAX +}; + +enum tbl_part { + TBL_PART_OPTS, /* in options (first line) */ + TBL_PART_LAYOUT, /* describing layout */ + TBL_PART_DATA /* creating data rows */ +}; + +struct tbl { + enum tbl_part part; + char buf[BUFSIZ]; + char tab; /* cell-separator */ + char decimal; /* decimal point */ + int linesize; + char delims[2]; + int opts; +#define TBL_OPT_CENTRE (1 << 0) +#define TBL_OPT_EXPAND (1 << 1) +#define TBL_OPT_BOX (1 << 2) +#define TBL_OPT_DBOX (1 << 3) +#define TBL_OPT_ALLBOX (1 << 4) +#define TBL_OPT_NOKEEP (1 << 5) +#define TBL_OPT_NOSPACE (1 << 6) +}; struct tbl *tbl_alloc(void); void tbl_free(struct tbl *); void tbl_reset(struct tbl *); enum rofferr tbl_read(struct tbl *, int, const char *, int); +enum tbl_tok tbl_next(struct tbl *, const char *, int *); __END_DECLS @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <assert.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> @@ -24,19 +25,14 @@ #include "libmandoc.h" #include "libroff.h" -enum tbl_part { - TBL_PART_OPTS, /* in options (first line) */ - TBL_PART_LAYOUT, /* describing layout */ - TBL_PART_DATA /* creating data rows */ -}; - - -struct tbl { - enum tbl_part part; +static const char tbl_toks[TBL_TOK__MAX] = { + '(', ')', ',', ';', '.', + ' ', '\t', '\0' }; static void tbl_init(struct tbl *); static void tbl_clear(struct tbl *); +static enum tbl_tok tbl_next_char(char); static void tbl_clear(struct tbl *tbl) @@ -92,3 +88,58 @@ tbl_reset(struct tbl *tbl) tbl_clear(tbl); tbl_init(tbl); } + +static enum tbl_tok +tbl_next_char(char c) +{ + int i; + + /* + * These are delimiting tokens. They separate out words in the + * token stream. + * + * FIXME: make this into a hashtable for faster lookup. + */ + for (i = 0; i < TBL_TOK__MAX; i++) + if (c == tbl_toks[i]) + return((enum tbl_tok)i); + + return(TBL_TOK__MAX); +} + +enum tbl_tok +tbl_next(struct tbl *tbl, const char *p, int *pos) +{ + int i; + enum tbl_tok c; + + tbl->buf[0] = '\0'; + + if (TBL_TOK__MAX != (c = tbl_next_char(p[*pos]))) { + if (TBL_TOK_NIL != c) { + tbl->buf[0] = p[*pos]; + tbl->buf[1] = '\0'; + (*pos)++; + } + return(c); + } + + /* + * Copy words into a nil-terminated buffer. For now, we use a + * static buffer. FIXME: eventually this should be made into a + * dynamic one living in struct tbl. + */ + + for (i = 0; i < BUFSIZ; i++, (*pos)++) + if (TBL_TOK__MAX == tbl_next_char(p[*pos])) + tbl->buf[i] = p[*pos]; + else + break; + + assert(i < BUFSIZ); + tbl->buf[i] = '\0'; + + return(TBL_TOK__MAX); +} + + diff --git a/tbl_opts.c b/tbl_opts.c new file mode 100644 index 00000000..cb2f69e2 --- /dev/null +++ b/tbl_opts.c @@ -0,0 +1,196 @@ +/* $Id$ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "libroff.h" + +enum tbl_ident { + KEY_CENTRE = 0, + KEY_DELIM, + KEY_EXPAND, + KEY_BOX, + KEY_DBOX, + KEY_ALLBOX, + KEY_TAB, + KEY_LINESIZE, + KEY_NOKEEP, + KEY_DPOINT, + KEY_NOSPACE, + KEY_FRAME, + KEY_DFRAME, + KEY_MAX +}; + +struct tbl_phrase { + const char *name; + int key; + enum tbl_ident ident; +}; + +/* Handle Commonwealth/American spellings. */ +#define KEY_MAXKEYS 14 + +static const struct tbl_phrase keys[KEY_MAXKEYS] = { + { "center", TBL_OPT_CENTRE, KEY_CENTRE}, + { "centre", TBL_OPT_CENTRE, KEY_CENTRE}, + { "delim", 0, KEY_DELIM}, + { "expand", TBL_OPT_EXPAND, KEY_EXPAND}, + { "box", TBL_OPT_BOX, KEY_BOX}, + { "doublebox", TBL_OPT_DBOX, KEY_DBOX}, + { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX}, + { "frame", TBL_OPT_BOX, KEY_FRAME}, + { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME}, + { "tab", 0, KEY_TAB}, + { "linesize", 0, KEY_LINESIZE}, + { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP}, + { "decimalpoint", 0, KEY_DPOINT}, + { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE}, +}; + +static int arg(struct tbl *, int, const char *, int *, int); +static int opt(struct tbl *, int, const char *, int *); + +static int +arg(struct tbl *tbl, int ln, const char *p, int *pos, int key) +{ + int sv; + +again: + sv = *pos; + + switch (tbl_next(tbl, p, pos)) { + case (TBL_TOK_OPENPAREN): + break; + case (TBL_TOK_SPACE): + /* FALLTHROUGH */ + case (TBL_TOK_TAB): + goto again; + default: + return(0); + } + + sv = *pos; + + switch (tbl_next(tbl, p, pos)) { + case (TBL_TOK__MAX): + break; + default: + return(0); + } + + switch (key) { + case (KEY_DELIM): + /* FIXME: cache this value. */ + if (2 != strlen(tbl->buf)) + return(0); + tbl->delims[0] = tbl->buf[0]; + tbl->delims[1] = tbl->buf[1]; + break; + case (KEY_TAB): + /* FIXME: cache this value. */ + if (1 != strlen(tbl->buf)) + return(0); + tbl->tab = tbl->buf[0]; + break; + case (KEY_LINESIZE): + if ((tbl->linesize = atoi(tbl->buf)) <= 0) + return(0); + break; + case (KEY_DPOINT): + /* FIXME: cache this value. */ + if (1 != strlen(tbl->buf)) + return(0); + tbl->decimal = tbl->buf[0]; + break; + default: + abort(); + } + + sv = *pos; + + switch (tbl_next(tbl, p, pos)) { + case (TBL_TOK_CLOSEPAREN): + break; + default: + return(0); + } + + return(1); +} + + +static int +opt(struct tbl *tbl, int ln, const char *p, int *pos) +{ + int i, sv; + +again: + sv = *pos; + + /* + * EBNF describing this section: + * + * options ::= option_list [:space:]* [;][\n] + * option_list ::= option option_tail + * option_tail ::= [:space:]+ option_list | + * ::= epsilon + * option ::= [:alpha:]+ args + * args ::= [:space:]* [(] [:alpha:]+ [)] + */ + + switch (tbl_next(tbl, p, pos)) { + case (TBL_TOK__MAX): + break; + case (TBL_TOK_SPACE): + /* FALLTHROUGH */ + case (TBL_TOK_TAB): + goto again; + case (TBL_TOK_SEMICOLON): + tbl->part = TBL_PART_LAYOUT; + return(1); + default: + return(0); + } + + for (i = 0; i < KEY_MAXKEYS; i++) { + /* FIXME: hashtable this? */ + if (strcasecmp(tbl->buf, keys[i].name)) + continue; + if (keys[i].key) + tbl->opts |= keys[i].key; + else if ( ! arg(tbl, ln, p, pos, keys[i].ident)) + return(0); + + break; + } + + if (KEY_MAXKEYS == i) + return(0); + + return(opt(tbl, ln, p, pos)); +} + +int +tbl_option(struct tbl *tbl, int ln, const char *p) +{ + int pos; + + pos = 0; + return(opt(tbl, ln, p, &pos)); +} |