summaryrefslogtreecommitdiffstats
path: root/contrib/mdocml/tbl_opts.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/mdocml/tbl_opts.c')
-rw-r--r--contrib/mdocml/tbl_opts.c295
1 files changed, 99 insertions, 196 deletions
diff --git a/contrib/mdocml/tbl_opts.c b/contrib/mdocml/tbl_opts.c
index d5ad42f..c012a3c 100644
--- a/contrib/mdocml/tbl_opts.c
+++ b/contrib/mdocml/tbl_opts.c
@@ -1,6 +1,7 @@
-/* $Id: tbl_opts.c,v 1.15 2014/11/26 17:51:55 schwarze Exp $ */
+/* $Id: tbl_opts.c,v 1.20 2015/01/28 17:32:07 schwarze Exp $ */
/*
* 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
@@ -27,245 +28,147 @@
#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
-
-/* Maximum length of key name string. */
-#define KEY_MAXNAME 13
-
-/* Maximum length of key number size. */
-#define KEY_MAXNUMSZ 10
-
-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_node *, int,
- const char *, int *, enum tbl_ident);
-static void opt(struct tbl_node *, int,
- const char *, int *);
+#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
+static void arg(struct tbl_node *, int, const char *, int *, int);
-static int
-arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
+
+static void
+arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
{
- int i;
- char buf[KEY_MAXNUMSZ];
+ int len, want;
- while (isspace((unsigned char)p[*pos]))
+ while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
- /* Arguments always begin with a parenthesis. */
+ /* Arguments are enclosed in parentheses. */
- if ('(' != p[*pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos, NULL);
- return(0);
+ len = 0;
+ if (p[*pos] == '(') {
+ (*pos)++;
+ while (p[*pos + len] != ')')
+ len++;
}
- (*pos)++;
-
- /*
- * The arguments can be ANY value, so we can't just stop at the
- * next close parenthesis (the argument can be a closed
- * parenthesis itself).
- */
-
switch (key) {
case KEY_DELIM:
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
-
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
+ mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
+ ln, *pos, "%.*s", len, p + *pos);
+ want = 2;
break;
case KEY_TAB:
- if ('\0' != (tbl->opts.tab = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ want = 1;
+ if (len == want)
+ tbl->opts.tab = p[*pos];
+ break;
case KEY_LINESIZE:
- for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
- buf[i] = p[*pos];
- if ( ! isdigit((unsigned char)buf[i]))
- break;
- }
-
- if (i < KEY_MAXNUMSZ) {
- buf[i] = '\0';
- tbl->opts.linesize = atoi(buf);
- break;
- }
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return(0);
+ want = 0;
+ break;
case KEY_DPOINT:
- if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ want = 1;
+ if (len == want)
+ tbl->opts.decimal = p[*pos];
+ break;
default:
abort();
/* NOTREACHED */
}
- /* End with a close parenthesis. */
-
- if (')' == p[(*pos)++])
- return(1);
+ 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);
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);
- return(0);
+ *pos += len;
+ if (p[*pos] == ')')
+ (*pos)++;
}
-static void
-opt(struct tbl_node *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;
- char buf[KEY_MAXNAME];
+ int i, pos, len;
- /*
- * Parse individual options from the stream as surrounded by
- * this goto. Each pass through the routine parses out a single
- * option and registers it. Option arguments are processed in
- * the arg() function.
- */
+ pos = *offs;
+ for (;;) {
+ while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
+ pos++;
-again: /*
- * 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:]+ [)]
- */
-
- while (isspace((unsigned char)p[*pos]))
- (*pos)++;
-
- /* Safe exit point. */
-
- if (';' == p[*pos])
- return;
-
- /* Copy up to first non-alpha character. */
-
- for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {
- buf[i] = (char)tolower((unsigned char)p[*pos]);
- if ( ! isalpha((unsigned char)buf[i]))
- break;
- }
+ if (p[pos] == ';') {
+ *offs = pos + 1;
+ return;
+ }
- /* Exit if buffer is empty (or overrun). */
+ /* Parse one option name. */
- if (KEY_MAXNAME == i || 0 == i) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return;
- }
+ len = 0;
+ while (isalpha((unsigned char)p[pos + len]))
+ len++;
- buf[i] = '\0';
+ if (len == 0) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
+ tbl->parse, ln, pos, "%c", p[pos]);
+ pos++;
+ continue;
+ }
- while (isspace((unsigned char)p[*pos]) || p[*pos] == ',')
- (*pos)++;
+ /* Look up the option name. */
- /*
- * Look through all of the available keys to find one that
- * matches the input. FIXME: hashtable this.
- */
+ i = 0;
+ while (i < KEY_MAXKEYS &&
+ (strncasecmp(p + pos, keys[i].name, len) ||
+ keys[i].name[len] != '\0'))
+ i++;
- for (i = 0; i < KEY_MAXKEYS; i++) {
- if (strcmp(buf, keys[i].name))
+ if (i == KEY_MAXKEYS) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
+ ln, pos, "%.*s", len, p + pos);
+ pos += len;
continue;
+ }
- /*
- * Note: this is more difficult to recover from, as we
- * can be anywhere in the option sequence and it's
- * harder to jump to the next. Meanwhile, just bail out
- * of the sequence altogether.
- */
+ /* Handle the option. */
+ pos += len;
if (keys[i].key)
tbl->opts.opts |= keys[i].key;
- else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
- return;
-
- break;
+ else
+ arg(tbl, ln, p, &pos, i);
}
-
- /*
- * Allow us to recover from bad options by continuing to another
- * parse sequence.
- */
-
- if (KEY_MAXKEYS == i)
- mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);
-
- goto again;
- /* NOTREACHED */
-}
-
-int
-tbl_option(struct tbl_node *tbl, int ln, const char *p)
-{
- int pos;
-
- /*
- * Table options are always on just one line, so automatically
- * switch into the next input mode here.
- */
- tbl->part = TBL_PART_LAYOUT;
-
- pos = 0;
- opt(tbl, ln, p, &pos);
-
- /* Always succeed. */
- return(1);
}
OpenPOWER on IntegriCloud