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