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
arg(struct tbl_node * tbl,int ln,const char * p,int * pos,int key)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
tbl_option(struct tbl_node * tbl,int ln,const char * p,int * offs)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