=================================================================== RCS file: /cvs/mandoc/tbl_opts.c,v retrieving revision 1.1 retrieving revision 1.17 diff -u -p -r1.1 -r1.17 --- mandoc/tbl_opts.c 2010/12/28 13:46:07 1.1 +++ mandoc/tbl_opts.c 2015/01/26 00:57:22 1.17 @@ -1,6 +1,7 @@ -/* $Id: tbl_opts.c,v 1.1 2010/12/28 13:46:07 kristaps Exp $ */ +/* $Id: tbl_opts.c,v 1.17 2015/01/26 00:57:22 schwarze Exp $ */ /* - * Copyright (c) 2009 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,10 +15,17 @@ * 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 "libmandoc.h" #include "libroff.h" enum tbl_ident { @@ -49,10 +57,10 @@ struct tbl_phrase { static const struct tbl_phrase keys[KEY_MAXKEYS] = { { "center", TBL_OPT_CENTRE, KEY_CENTRE}, { "centre", TBL_OPT_CENTRE, KEY_CENTRE}, - { "delim", 0, KEY_DELIM}, + { "delim", 0, KEY_DELIM}, { "expand", TBL_OPT_EXPAND, KEY_EXPAND}, - { "box", TBL_OPT_BOX, KEY_BOX}, - { "doublebox", TBL_OPT_DBOX, KEY_DBOX}, + { "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}, @@ -63,134 +71,119 @@ static const struct tbl_phrase keys[KEY_MAXKEYS] = { { "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 void arg(struct tbl_node *, int, + const char *, int *, enum tbl_ident); -static int -arg(struct tbl *tbl, int ln, const char *p, int *pos, int key) + +static void +arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) { - int sv; + const char *optname; + int len, want; -again: - sv = *pos; + while (isspace((unsigned char)p[*pos])) + (*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); - } + /* Arguments are enclosed in parentheses. */ - sv = *pos; - - switch (tbl_next(tbl, p, pos)) { - case (TBL_TOK__MAX): - break; - default: - return(0); + 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: + optname = "delim"; + 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: + optname = "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: + optname = "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: + optname = "decimalpoint"; + want = 1; + if (len == want) + tbl->opts.decimal = p[*pos]; break; default: abort(); + /* NOTREACHED */ } - sv = *pos; + if (len == 0) + mandoc_msg(MANDOCERR_TBLOPT_NOARG, + tbl->parse, ln, *pos, optname); + else if (want && len != want) + mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, + tbl->parse, ln, *pos, + "%s want %d have %d", optname, 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 i, sv; + int i, pos, len; -again: - sv = *pos; + pos = 0; + for (;;) { + while (isspace((unsigned char)p[pos]) || 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] == ';') + 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, keys[i].ident); + } }