]> git.cameronkatri.com Git - mandoc.git/blobdiff - tbl_opts.c
do not crash when a tbl(7) cell uses roman font
[mandoc.git] / tbl_opts.c
index ca8d1288a5e8dc73f72703ea433d97190baf5987..e3a8373702996cff79a4b22792e9acfb176a79f8 100644 (file)
@@ -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.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);
+       }
 }