1 /* $OpenBSD: tbl_opts.c,v 1.16 2018/12/14 05:17:45 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <sys/types.h> 19 20 #include <ctype.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "mandoc.h" 26 #include "tbl.h" 27 #include "libmandoc.h" 28 #include "tbl_int.h" 29 30 #define KEY_DPOINT 0 31 #define KEY_DELIM 1 32 #define KEY_LINESIZE 2 33 #define KEY_TAB 3 34 35 struct tbl_phrase { 36 const char *name; 37 int key; 38 }; 39 40 static const struct tbl_phrase keys[] = { 41 {"decimalpoint", 0}, 42 {"delim", 0}, 43 {"linesize", 0}, 44 {"tab", 0}, 45 {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, 46 {"box", TBL_OPT_BOX}, 47 {"frame", TBL_OPT_BOX}, 48 {"center", TBL_OPT_CENTRE}, 49 {"centre", TBL_OPT_CENTRE}, 50 {"doublebox", TBL_OPT_DBOX}, 51 {"doubleframe", TBL_OPT_DBOX}, 52 {"expand", TBL_OPT_EXPAND}, 53 {"nokeep", TBL_OPT_NOKEEP}, 54 {"nospaces", TBL_OPT_NOSPACE}, 55 {"nowarn", TBL_OPT_NOWARN}, 56 }; 57 58 #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) 59 60 static void arg(struct tbl_node *, int, const char *, int *, int); 61 62 63 static void 64 arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) 65 { 66 int len, want; 67 68 while (p[*pos] == ' ' || p[*pos] == '\t') 69 (*pos)++; 70 71 /* Arguments are enclosed in parentheses. */ 72 73 len = 0; 74 if (p[*pos] == '(') { 75 (*pos)++; 76 while (p[*pos + len] != ')') 77 len++; 78 } 79 80 switch (key) { 81 case KEY_DELIM: 82 mandoc_msg(MANDOCERR_TBLOPT_EQN, 83 ln, *pos, "%.*s", len, p + *pos); 84 want = 2; 85 break; 86 case KEY_TAB: 87 want = 1; 88 if (len == want) 89 tbl->opts.tab = p[*pos]; 90 break; 91 case KEY_LINESIZE: 92 want = 0; 93 break; 94 case KEY_DPOINT: 95 want = 1; 96 if (len == want) 97 tbl->opts.decimal = p[*pos]; 98 break; 99 default: 100 abort(); 101 } 102 103 if (len == 0) 104 mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos, 105 "%s", keys[key].name); 106 else if (want && len != want) 107 mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos, 108 "%s want %d have %d", keys[key].name, want, len); 109 110 *pos += len; 111 if (p[*pos] == ')') 112 (*pos)++; 113 } 114 115 /* 116 * Parse one line of options up to the semicolon. 117 * Each option can be preceded by blanks and/or commas, 118 * and some options are followed by arguments. 119 */ 120 void 121 tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) 122 { 123 int i, pos, len; 124 125 pos = *offs; 126 for (;;) { 127 while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') 128 pos++; 129 130 if (p[pos] == ';') { 131 *offs = pos + 1; 132 return; 133 } 134 135 /* Parse one option name. */ 136 137 len = 0; 138 while (isalpha((unsigned char)p[pos + len])) 139 len++; 140 141 if (len == 0) { 142 mandoc_msg(MANDOCERR_TBLOPT_ALPHA, 143 ln, pos, "%c", p[pos]); 144 pos++; 145 continue; 146 } 147 148 /* Look up the option name. */ 149 150 i = 0; 151 while (i < KEY_MAXKEYS && 152 (strncasecmp(p + pos, keys[i].name, len) || 153 keys[i].name[len] != '\0')) 154 i++; 155 156 if (i == KEY_MAXKEYS) { 157 mandoc_msg(MANDOCERR_TBLOPT_BAD, 158 ln, pos, "%.*s", len, p + pos); 159 pos += len; 160 continue; 161 } 162 163 /* Handle the option. */ 164 165 pos += len; 166 if (keys[i].key) 167 tbl->opts.opts |= keys[i].key; 168 else 169 arg(tbl, ln, p, &pos, i); 170 } 171 } 172