1 /* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 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 "config.h" 19 20 #include <sys/types.h> 21 22 #include <ctype.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "mandoc.h" 28 #include "tbl.h" 29 #include "libmandoc.h" 30 #include "tbl_int.h" 31 32 #define KEY_DPOINT 0 33 #define KEY_DELIM 1 34 #define KEY_LINESIZE 2 35 #define KEY_TAB 3 36 37 struct tbl_phrase { 38 const char *name; 39 int key; 40 }; 41 42 static const struct tbl_phrase keys[] = { 43 {"decimalpoint", 0}, 44 {"delim", 0}, 45 {"linesize", 0}, 46 {"tab", 0}, 47 {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, 48 {"box", TBL_OPT_BOX}, 49 {"frame", TBL_OPT_BOX}, 50 {"center", TBL_OPT_CENTRE}, 51 {"centre", TBL_OPT_CENTRE}, 52 {"doublebox", TBL_OPT_DBOX}, 53 {"doubleframe", TBL_OPT_DBOX}, 54 {"expand", TBL_OPT_EXPAND}, 55 {"nokeep", TBL_OPT_NOKEEP}, 56 {"nospaces", TBL_OPT_NOSPACE}, 57 {"nowarn", TBL_OPT_NOWARN}, 58 }; 59 60 #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) 61 62 static void arg(struct tbl_node *, int, const char *, int *, int); 63 64 65 static void 66 arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) 67 { 68 int len, want; 69 70 while (p[*pos] == ' ' || p[*pos] == '\t') 71 (*pos)++; 72 73 /* Arguments are enclosed in parentheses. */ 74 75 len = 0; 76 if (p[*pos] == '(') { 77 (*pos)++; 78 while (p[*pos + len] != ')') 79 len++; 80 } 81 82 switch (key) { 83 case KEY_DELIM: 84 mandoc_msg(MANDOCERR_TBLOPT_EQN, 85 ln, *pos, "%.*s", len, p + *pos); 86 want = 2; 87 break; 88 case KEY_TAB: 89 want = 1; 90 if (len == want) 91 tbl->opts.tab = p[*pos]; 92 break; 93 case KEY_LINESIZE: 94 want = 0; 95 break; 96 case KEY_DPOINT: 97 want = 1; 98 if (len == want) 99 tbl->opts.decimal = p[*pos]; 100 break; 101 default: 102 abort(); 103 } 104 105 if (len == 0) 106 mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos, 107 "%s", keys[key].name); 108 else if (want && len != want) 109 mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos, 110 "%s want %d have %d", keys[key].name, want, len); 111 112 *pos += len; 113 if (p[*pos] == ')') 114 (*pos)++; 115 } 116 117 /* 118 * Parse one line of options up to the semicolon. 119 * Each option can be preceded by blanks and/or commas, 120 * and some options are followed by arguments. 121 */ 122 void 123 tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) 124 { 125 int i, pos, len; 126 127 pos = *offs; 128 for (;;) { 129 while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') 130 pos++; 131 132 if (p[pos] == ';') { 133 *offs = pos + 1; 134 return; 135 } 136 137 /* Parse one option name. */ 138 139 len = 0; 140 while (isalpha((unsigned char)p[pos + len])) 141 len++; 142 143 if (len == 0) { 144 mandoc_msg(MANDOCERR_TBLOPT_ALPHA, 145 ln, pos, "%c", p[pos]); 146 pos++; 147 continue; 148 } 149 150 /* Look up the option name. */ 151 152 i = 0; 153 while (i < KEY_MAXKEYS && 154 (strncasecmp(p + pos, keys[i].name, len) || 155 keys[i].name[len] != '\0')) 156 i++; 157 158 if (i == KEY_MAXKEYS) { 159 mandoc_msg(MANDOCERR_TBLOPT_BAD, 160 ln, pos, "%.*s", len, p + pos); 161 pos += len; 162 continue; 163 } 164 165 /* Handle the option. */ 166 167 pos += len; 168 if (keys[i].key) 169 tbl->opts.opts |= keys[i].key; 170 else 171 arg(tbl, ln, p, &pos, i); 172 } 173 } 174