1*cec8643bSMichal Nowak /* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4260e9a87SYuri Pankov * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore */
1895c635efSGarrett D'Amore #include "config.h"
19260e9a87SYuri Pankov
20260e9a87SYuri Pankov #include <sys/types.h>
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #include <ctype.h>
2395c635efSGarrett D'Amore #include <stdio.h>
2495c635efSGarrett D'Amore #include <stdlib.h>
2595c635efSGarrett D'Amore #include <string.h>
2695c635efSGarrett D'Amore
2795c635efSGarrett D'Amore #include "mandoc.h"
28*cec8643bSMichal Nowak #include "tbl.h"
2995c635efSGarrett D'Amore #include "libmandoc.h"
30*cec8643bSMichal Nowak #include "tbl_int.h"
3195c635efSGarrett D'Amore
32260e9a87SYuri Pankov #define KEY_DPOINT 0
33260e9a87SYuri Pankov #define KEY_DELIM 1
34260e9a87SYuri Pankov #define KEY_LINESIZE 2
35260e9a87SYuri Pankov #define KEY_TAB 3
3695c635efSGarrett D'Amore
3795c635efSGarrett D'Amore struct tbl_phrase {
3895c635efSGarrett D'Amore const char *name;
3995c635efSGarrett D'Amore int key;
4095c635efSGarrett D'Amore };
4195c635efSGarrett D'Amore
42260e9a87SYuri Pankov static const struct tbl_phrase keys[] = {
43260e9a87SYuri Pankov {"decimalpoint", 0},
44260e9a87SYuri Pankov {"delim", 0},
45260e9a87SYuri Pankov {"linesize", 0},
46260e9a87SYuri Pankov {"tab", 0},
47260e9a87SYuri Pankov {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX},
48260e9a87SYuri Pankov {"box", TBL_OPT_BOX},
49260e9a87SYuri Pankov {"frame", TBL_OPT_BOX},
50260e9a87SYuri Pankov {"center", TBL_OPT_CENTRE},
51260e9a87SYuri Pankov {"centre", TBL_OPT_CENTRE},
52260e9a87SYuri Pankov {"doublebox", TBL_OPT_DBOX},
53260e9a87SYuri Pankov {"doubleframe", TBL_OPT_DBOX},
54260e9a87SYuri Pankov {"expand", TBL_OPT_EXPAND},
55260e9a87SYuri Pankov {"nokeep", TBL_OPT_NOKEEP},
56260e9a87SYuri Pankov {"nospaces", TBL_OPT_NOSPACE},
57260e9a87SYuri Pankov {"nowarn", TBL_OPT_NOWARN},
58260e9a87SYuri Pankov };
5995c635efSGarrett D'Amore
60260e9a87SYuri Pankov #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
6195c635efSGarrett D'Amore
62260e9a87SYuri Pankov static void arg(struct tbl_node *, int, const char *, int *, int);
6395c635efSGarrett D'Amore
6495c635efSGarrett D'Amore
65260e9a87SYuri Pankov static void
arg(struct tbl_node * tbl,int ln,const char * p,int * pos,int key)66260e9a87SYuri Pankov arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
6795c635efSGarrett D'Amore {
68260e9a87SYuri Pankov int len, want;
6995c635efSGarrett D'Amore
70260e9a87SYuri Pankov while (p[*pos] == ' ' || p[*pos] == '\t')
7195c635efSGarrett D'Amore (*pos)++;
7295c635efSGarrett D'Amore
73260e9a87SYuri Pankov /* Arguments are enclosed in parentheses. */
7495c635efSGarrett D'Amore
75260e9a87SYuri Pankov len = 0;
76260e9a87SYuri Pankov if (p[*pos] == '(') {
77260e9a87SYuri Pankov (*pos)++;
78260e9a87SYuri Pankov while (p[*pos + len] != ')')
79260e9a87SYuri Pankov len++;
8095c635efSGarrett D'Amore }
8195c635efSGarrett D'Amore
8295c635efSGarrett D'Amore switch (key) {
83260e9a87SYuri Pankov case KEY_DELIM:
84*cec8643bSMichal Nowak mandoc_msg(MANDOCERR_TBLOPT_EQN,
85260e9a87SYuri Pankov ln, *pos, "%.*s", len, p + *pos);
86260e9a87SYuri Pankov want = 2;
87260e9a87SYuri Pankov break;
88260e9a87SYuri Pankov case KEY_TAB:
89260e9a87SYuri Pankov want = 1;
90260e9a87SYuri Pankov if (len == want)
91260e9a87SYuri Pankov tbl->opts.tab = p[*pos];
92260e9a87SYuri Pankov break;
93260e9a87SYuri Pankov case KEY_LINESIZE:
94260e9a87SYuri Pankov want = 0;
95260e9a87SYuri Pankov break;
96260e9a87SYuri Pankov case KEY_DPOINT:
97260e9a87SYuri Pankov want = 1;
98260e9a87SYuri Pankov if (len == want)
99260e9a87SYuri Pankov tbl->opts.decimal = p[*pos];
10095c635efSGarrett D'Amore break;
10195c635efSGarrett D'Amore default:
10295c635efSGarrett D'Amore abort();
10395c635efSGarrett D'Amore }
10495c635efSGarrett D'Amore
105260e9a87SYuri Pankov if (len == 0)
106*cec8643bSMichal Nowak mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
107*cec8643bSMichal Nowak "%s", keys[key].name);
108260e9a87SYuri Pankov else if (want && len != want)
109*cec8643bSMichal Nowak mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
110*cec8643bSMichal Nowak "%s want %d have %d", keys[key].name, want, len);
11195c635efSGarrett D'Amore
112260e9a87SYuri Pankov *pos += len;
113260e9a87SYuri Pankov if (p[*pos] == ')')
114260e9a87SYuri Pankov (*pos)++;
11595c635efSGarrett D'Amore }
11695c635efSGarrett D'Amore
117260e9a87SYuri Pankov /*
118260e9a87SYuri Pankov * Parse one line of options up to the semicolon.
119260e9a87SYuri Pankov * Each option can be preceded by blanks and/or commas,
120260e9a87SYuri Pankov * and some options are followed by arguments.
121260e9a87SYuri Pankov */
122260e9a87SYuri Pankov void
tbl_option(struct tbl_node * tbl,int ln,const char * p,int * offs)123260e9a87SYuri Pankov tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
12495c635efSGarrett D'Amore {
125260e9a87SYuri Pankov int i, pos, len;
12695c635efSGarrett D'Amore
127260e9a87SYuri Pankov pos = *offs;
128260e9a87SYuri Pankov for (;;) {
129260e9a87SYuri Pankov while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
130260e9a87SYuri Pankov pos++;
13195c635efSGarrett D'Amore
132260e9a87SYuri Pankov if (p[pos] == ';') {
133260e9a87SYuri Pankov *offs = pos + 1;
134260e9a87SYuri Pankov return;
135260e9a87SYuri Pankov }
13695c635efSGarrett D'Amore
137260e9a87SYuri Pankov /* Parse one option name. */
13895c635efSGarrett D'Amore
139260e9a87SYuri Pankov len = 0;
140260e9a87SYuri Pankov while (isalpha((unsigned char)p[pos + len]))
141260e9a87SYuri Pankov len++;
14295c635efSGarrett D'Amore
143260e9a87SYuri Pankov if (len == 0) {
144*cec8643bSMichal Nowak mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
145*cec8643bSMichal Nowak ln, pos, "%c", p[pos]);
146260e9a87SYuri Pankov pos++;
147260e9a87SYuri Pankov continue;
148260e9a87SYuri Pankov }
14995c635efSGarrett D'Amore
150260e9a87SYuri Pankov /* Look up the option name. */
15195c635efSGarrett D'Amore
152260e9a87SYuri Pankov i = 0;
153260e9a87SYuri Pankov while (i < KEY_MAXKEYS &&
154260e9a87SYuri Pankov (strncasecmp(p + pos, keys[i].name, len) ||
155260e9a87SYuri Pankov keys[i].name[len] != '\0'))
156260e9a87SYuri Pankov i++;
15795c635efSGarrett D'Amore
158260e9a87SYuri Pankov if (i == KEY_MAXKEYS) {
159*cec8643bSMichal Nowak mandoc_msg(MANDOCERR_TBLOPT_BAD,
160260e9a87SYuri Pankov ln, pos, "%.*s", len, p + pos);
161260e9a87SYuri Pankov pos += len;
16295c635efSGarrett D'Amore continue;
163260e9a87SYuri Pankov }
16495c635efSGarrett D'Amore
165260e9a87SYuri Pankov /* Handle the option. */
16695c635efSGarrett D'Amore
167260e9a87SYuri Pankov pos += len;
168260e9a87SYuri Pankov if (keys[i].key)
16995c635efSGarrett D'Amore tbl->opts.opts |= keys[i].key;
170260e9a87SYuri Pankov else
171260e9a87SYuri Pankov arg(tbl, ln, p, &pos, i);
17295c635efSGarrett D'Amore }
17395c635efSGarrett D'Amore }
174