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