1 /* $Id: tbl_opts.c,v 1.20 2015/01/28 17:32:07 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 /* NOTREACHED */ 103 } 104 105 if (len == 0) 106 mandoc_msg(MANDOCERR_TBLOPT_NOARG, 107 tbl->parse, ln, *pos, keys[key].name); 108 else if (want && len != want) 109 mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, 110 tbl->parse, ln, *pos, "%s want %d have %d", 111 keys[key].name, want, len); 112 113 *pos += len; 114 if (p[*pos] == ')') 115 (*pos)++; 116 } 117 118 /* 119 * Parse one line of options up to the semicolon. 120 * Each option can be preceded by blanks and/or commas, 121 * and some options are followed by arguments. 122 */ 123 void 124 tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) 125 { 126 int i, pos, len; 127 128 pos = *offs; 129 for (;;) { 130 while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') 131 pos++; 132 133 if (p[pos] == ';') { 134 *offs = pos + 1; 135 return; 136 } 137 138 /* Parse one option name. */ 139 140 len = 0; 141 while (isalpha((unsigned char)p[pos + len])) 142 len++; 143 144 if (len == 0) { 145 mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, 146 tbl->parse, ln, pos, "%c", p[pos]); 147 pos++; 148 continue; 149 } 150 151 /* Look up the option name. */ 152 153 i = 0; 154 while (i < KEY_MAXKEYS && 155 (strncasecmp(p + pos, keys[i].name, len) || 156 keys[i].name[len] != '\0')) 157 i++; 158 159 if (i == KEY_MAXKEYS) { 160 mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, 161 ln, pos, "%.*s", len, p + pos); 162 pos += len; 163 continue; 164 } 165 166 /* Handle the option. */ 167 168 pos += len; 169 if (keys[i].key) 170 tbl->opts.opts |= keys[i].key; 171 else 172 arg(tbl, ln, p, &pos, i); 173 } 174 } 175