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