1 /* $OpenBSD: tbl_opts.c,v 1.13 2015/09/26 00:53:15 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 "libmandoc.h" 27 #include "libroff.h" 28 29 #define KEY_DPOINT 0 30 #define KEY_DELIM 1 31 #define KEY_LINESIZE 2 32 #define KEY_TAB 3 33 34 struct tbl_phrase { 35 const char *name; 36 int key; 37 }; 38 39 static const struct tbl_phrase keys[] = { 40 {"decimalpoint", 0}, 41 {"delim", 0}, 42 {"linesize", 0}, 43 {"tab", 0}, 44 {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, 45 {"box", TBL_OPT_BOX}, 46 {"frame", TBL_OPT_BOX}, 47 {"center", TBL_OPT_CENTRE}, 48 {"centre", TBL_OPT_CENTRE}, 49 {"doublebox", TBL_OPT_DBOX}, 50 {"doubleframe", TBL_OPT_DBOX}, 51 {"expand", TBL_OPT_EXPAND}, 52 {"nokeep", TBL_OPT_NOKEEP}, 53 {"nospaces", TBL_OPT_NOSPACE}, 54 {"nowarn", TBL_OPT_NOWARN}, 55 }; 56 57 #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) 58 59 static void arg(struct tbl_node *, int, const char *, int *, int); 60 61 62 static void 63 arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) 64 { 65 int len, want; 66 67 while (p[*pos] == ' ' || p[*pos] == '\t') 68 (*pos)++; 69 70 /* Arguments are enclosed in parentheses. */ 71 72 len = 0; 73 if (p[*pos] == '(') { 74 (*pos)++; 75 while (p[*pos + len] != ')') 76 len++; 77 } 78 79 switch (key) { 80 case KEY_DELIM: 81 mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, 82 ln, *pos, "%.*s", len, p + *pos); 83 want = 2; 84 break; 85 case KEY_TAB: 86 want = 1; 87 if (len == want) 88 tbl->opts.tab = p[*pos]; 89 break; 90 case KEY_LINESIZE: 91 want = 0; 92 break; 93 case KEY_DPOINT: 94 want = 1; 95 if (len == want) 96 tbl->opts.decimal = p[*pos]; 97 break; 98 default: 99 abort(); 100 } 101 102 if (len == 0) 103 mandoc_msg(MANDOCERR_TBLOPT_NOARG, 104 tbl->parse, ln, *pos, keys[key].name); 105 else if (want && len != want) 106 mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, 107 tbl->parse, ln, *pos, "%s want %d have %d", 108 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_vmsg(MANDOCERR_TBLOPT_ALPHA, 143 tbl->parse, 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_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, 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