-/* $Id: tbl_opts.c,v 1.1 2010/12/28 13:46:07 kristaps Exp $ */
+/* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */
/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* 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 <sys/types.h>
+
+#include <ctype.h>
#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
-};
+#include "mandoc.h"
+#include "tbl.h"
+#include "libmandoc.h"
+#include "tbl_int.h"
+
+#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_msg(MANDOCERR_TBLOPT_EQN,
+ 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;
-
- switch (tbl_next(tbl, p, pos)) {
- case (TBL_TOK_CLOSEPAREN):
- break;
- default:
- return(0);
- }
+ if (len == 0)
+ mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
+ "%s", keys[key].name);
+ else if (want && len != want)
+ mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
+ "%s want %d have %d", keys[key].name, want, len);
- 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;
-
-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);
- }
+ int i, pos, len;
+
+ pos = *offs;
+ for (;;) {
+ while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
+ pos++;
+
+ if (p[pos] == ';') {
+ *offs = pos + 1;
+ return;
+ }
- for (i = 0; i < KEY_MAXKEYS; i++) {
- /* FIXME: hashtable this? */
- if (strcasecmp(tbl->buf, keys[i].name))
+ /* Parse one option name. */
+
+ len = 0;
+ while (isalpha((unsigned char)p[pos + len]))
+ len++;
+
+ if (len == 0) {
+ mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
+ 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_msg(MANDOCERR_TBLOPT_BAD,
+ 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);
+ }
}