/* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 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 * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * 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 "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; }; 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}, }; #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) static void arg(struct tbl_node *, int, const char *, int *, int); static void arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) { int len, want; while (p[*pos] == ' ' || p[*pos] == '\t') (*pos)++; /* Arguments are enclosed in parentheses. */ len = 0; if (p[*pos] == '(') { (*pos)++; while (p[*pos + len] != ')') len++; } switch (key) { case KEY_DELIM: mandoc_msg(MANDOCERR_TBLOPT_EQN, ln, *pos, "%.*s", len, p + *pos); want = 2; break; case KEY_TAB: want = 1; if (len == want) tbl->opts.tab = p[*pos]; break; case KEY_LINESIZE: want = 0; break; case KEY_DPOINT: want = 1; if (len == want) tbl->opts.decimal = p[*pos]; break; default: abort(); } 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); *pos += len; if (p[*pos] == ')') (*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, pos, len; pos = *offs; for (;;) { while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') pos++; if (p[pos] == ';') { *offs = pos + 1; return; } /* 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; } /* Look up the option name. */ i = 0; while (i < KEY_MAXKEYS && (strncasecmp(p + pos, keys[i].name, len) || keys[i].name[len] != '\0')) i++; if (i == KEY_MAXKEYS) { mandoc_msg(MANDOCERR_TBLOPT_BAD, ln, pos, "%.*s", len, p + pos); pos += len; continue; } /* Handle the option. */ pos += len; if (keys[i].key) tbl->opts.opts |= keys[i].key; else arg(tbl, ln, p, &pos, i); } }