=================================================================== RCS file: /cvs/mandoc/tbl_opts.c,v retrieving revision 1.2 retrieving revision 1.22 diff -u -p -r1.2 -r1.22 --- mandoc/tbl_opts.c 2010/12/28 13:47:38 1.2 +++ mandoc/tbl_opts.c 2018/12/12 21:54:35 1.22 @@ -1,6 +1,7 @@ -/* $Id: tbl_opts.c,v 1.2 2010/12/28 13:47:38 kristaps Exp $ */ +/* $Id: tbl_opts.c,v 1.22 2018/12/12 21:54:35 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2015 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,183 +15,160 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" + +#include + +#include #include #include #include +#include "mandoc.h" +#include "tbl.h" +#include "libmandoc.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 -}; +#define KEY_DPOINT 0 +#define KEY_DELIM 1 +#define KEY_LINESIZE 2 +#define KEY_TAB 3 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 const struct tbl_phrase keys[] = { + {"decimalpoint", 0}, + {"delim", 0}, + {"linesize", 0}, + {"tab", 0}, + {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, + {"box", TBL_OPT_BOX}, + {"frame", TBL_OPT_BOX}, + {"center", TBL_OPT_CENTRE}, + {"centre", TBL_OPT_CENTRE}, + {"doublebox", TBL_OPT_DBOX}, + {"doubleframe", TBL_OPT_DBOX}, + {"expand", TBL_OPT_EXPAND}, + {"nokeep", TBL_OPT_NOKEEP}, + {"nospaces", TBL_OPT_NOSPACE}, + {"nowarn", TBL_OPT_NOWARN}, }; -static int arg(struct tbl *, int, const char *, int *, int); -static int opt(struct tbl *, int, const char *, int *); +#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) -static int -arg(struct tbl *tbl, int ln, const char *p, int *pos, int key) -{ - int sv; +static void arg(struct tbl_node *, int, const char *, int *, int); -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); - } +static void +arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) +{ + int len, want; - sv = *pos; + while (p[*pos] == ' ' || p[*pos] == '\t') + (*pos)++; - switch (tbl_next(tbl, p, pos)) { - case (TBL_TOK__MAX): - break; - default: - return(0); + /* Arguments are enclosed in parentheses. */ + + len = 0; + if (p[*pos] == '(') { + (*pos)++; + while (p[*pos + len] != ')') + len++; } 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]; + case KEY_DELIM: + mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, + ln, *pos, "%.*s", len, p + *pos); + want = 2; break; - case (KEY_TAB): - /* FIXME: cache this value. */ - if (1 != strlen(tbl->buf)) - return(0); - tbl->tab = tbl->buf[0]; + case KEY_TAB: + want = 1; + if (len == want) + tbl->opts.tab = p[*pos]; break; - case (KEY_LINESIZE): - if ((tbl->linesize = atoi(tbl->buf)) <= 0) - return(0); + case KEY_LINESIZE: + want = 0; break; - case (KEY_DPOINT): - /* FIXME: cache this value. */ - if (1 != strlen(tbl->buf)) - return(0); - tbl->decimal = tbl->buf[0]; + case KEY_DPOINT: + want = 1; + if (len == want) + tbl->opts.decimal = p[*pos]; break; default: abort(); } - sv = *pos; + if (len == 0) + mandoc_msg(MANDOCERR_TBLOPT_NOARG, + tbl->parse, ln, *pos, keys[key].name); + else if (want && len != want) + mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, + tbl->parse, ln, *pos, "%s want %d have %d", + keys[key].name, want, len); - switch (tbl_next(tbl, p, pos)) { - case (TBL_TOK_CLOSEPAREN): - break; - default: - return(0); - } - - return(1); + *pos += len; + if (p[*pos] == ')') + (*pos)++; } - -static int -opt(struct tbl *tbl, int ln, const char *p, int *pos) +/* + * Parse one line of options up to the semicolon. + * Each option can be preceded by blanks and/or commas, + * and some options are followed by arguments. + */ +void +tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) { - int i, sv; + int i, pos, len; -again: - sv = *pos; + pos = *offs; + for (;;) { + while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') + 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:]+ [)] - */ + if (p[pos] == ';') { + *offs = pos + 1; + return; + } - 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); - } + /* Parse one option name. */ - for (i = 0; i < KEY_MAXKEYS; i++) { - /* FIXME: hashtable this? */ - if (strcasecmp(tbl->buf, keys[i].name)) + len = 0; + while (isalpha((unsigned char)p[pos + len])) + len++; + + if (len == 0) { + mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, + tbl->parse, ln, pos, "%c", p[pos]); + pos++; continue; - if (keys[i].key) - tbl->opts |= keys[i].key; - else if ( ! arg(tbl, ln, p, pos, keys[i].ident)) - return(0); + } - break; - } + /* Look up the option name. */ - if (KEY_MAXKEYS == i) - return(0); + i = 0; + while (i < KEY_MAXKEYS && + (strncasecmp(p + pos, keys[i].name, len) || + keys[i].name[len] != '\0')) + i++; - return(opt(tbl, ln, p, pos)); -} + if (i == KEY_MAXKEYS) { + mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, + ln, pos, "%.*s", len, p + pos); + pos += len; + continue; + } -int -tbl_option(struct tbl *tbl, int ln, const char *p) -{ - int pos; + /* Handle the option. */ - pos = 0; - return(opt(tbl, ln, p, &pos)); + pos += len; + if (keys[i].key) + tbl->opts.opts |= keys[i].key; + else + arg(tbl, ln, p, &pos, i); + } }