Disconnect hostapd from building in base
[dragonfly.git] / contrib / mdocml / tbl_opts.c
1 /*      $Id: tbl_opts.c,v 1.13 2014/04/20 16:46:05 schwarze Exp $ */
2 /*
3  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "mandoc.h"
27 #include "libmandoc.h"
28 #include "libroff.h"
29
30 enum    tbl_ident {
31         KEY_CENTRE = 0,
32         KEY_DELIM,
33         KEY_EXPAND,
34         KEY_BOX,
35         KEY_DBOX,
36         KEY_ALLBOX,
37         KEY_TAB,
38         KEY_LINESIZE,
39         KEY_NOKEEP,
40         KEY_DPOINT,
41         KEY_NOSPACE,
42         KEY_FRAME,
43         KEY_DFRAME,
44         KEY_MAX
45 };
46
47 struct  tbl_phrase {
48         const char      *name;
49         int              key;
50         enum tbl_ident   ident;
51 };
52
53 /* Handle Commonwealth/American spellings. */
54 #define KEY_MAXKEYS      14
55
56 /* Maximum length of key name string. */
57 #define KEY_MAXNAME      13
58
59 /* Maximum length of key number size. */
60 #define KEY_MAXNUMSZ     10
61
62 static  const struct tbl_phrase keys[KEY_MAXKEYS] = {
63         { "center",      TBL_OPT_CENTRE,        KEY_CENTRE},
64         { "centre",      TBL_OPT_CENTRE,        KEY_CENTRE},
65         { "delim",       0,                     KEY_DELIM},
66         { "expand",      TBL_OPT_EXPAND,        KEY_EXPAND},
67         { "box",         TBL_OPT_BOX,           KEY_BOX},
68         { "doublebox",   TBL_OPT_DBOX,          KEY_DBOX},
69         { "allbox",      TBL_OPT_ALLBOX,        KEY_ALLBOX},
70         { "frame",       TBL_OPT_BOX,           KEY_FRAME},
71         { "doubleframe", TBL_OPT_DBOX,          KEY_DFRAME},
72         { "tab",         0,                     KEY_TAB},
73         { "linesize",    0,                     KEY_LINESIZE},
74         { "nokeep",      TBL_OPT_NOKEEP,        KEY_NOKEEP},
75         { "decimalpoint", 0,                    KEY_DPOINT},
76         { "nospaces",    TBL_OPT_NOSPACE,       KEY_NOSPACE},
77 };
78
79 static  int              arg(struct tbl_node *, int,
80                                 const char *, int *, enum tbl_ident);
81 static  void             opt(struct tbl_node *, int,
82                                 const char *, int *);
83
84
85 static int
86 arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
87 {
88         int              i;
89         char             buf[KEY_MAXNUMSZ];
90
91         while (isspace((unsigned char)p[*pos]))
92                 (*pos)++;
93
94         /* Arguments always begin with a parenthesis. */
95
96         if ('(' != p[*pos]) {
97                 mandoc_msg(MANDOCERR_TBL, tbl->parse,
98                     ln, *pos, NULL);
99                 return(0);
100         }
101
102         (*pos)++;
103
104         /*
105          * The arguments can be ANY value, so we can't just stop at the
106          * next close parenthesis (the argument can be a closed
107          * parenthesis itself).
108          */
109
110         switch (key) {
111         case KEY_DELIM:
112                 if ('\0' == p[(*pos)++]) {
113                         mandoc_msg(MANDOCERR_TBL, tbl->parse,
114                             ln, *pos - 1, NULL);
115                         return(0);
116                 }
117
118                 if ('\0' == p[(*pos)++]) {
119                         mandoc_msg(MANDOCERR_TBL, tbl->parse,
120                             ln, *pos - 1, NULL);
121                         return(0);
122                 }
123                 break;
124         case KEY_TAB:
125                 if ('\0' != (tbl->opts.tab = p[(*pos)++]))
126                         break;
127
128                 mandoc_msg(MANDOCERR_TBL, tbl->parse,
129                     ln, *pos - 1, NULL);
130                 return(0);
131         case KEY_LINESIZE:
132                 for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
133                         buf[i] = p[*pos];
134                         if ( ! isdigit((unsigned char)buf[i]))
135                                 break;
136                 }
137
138                 if (i < KEY_MAXNUMSZ) {
139                         buf[i] = '\0';
140                         tbl->opts.linesize = atoi(buf);
141                         break;
142                 }
143
144                 mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
145                 return(0);
146         case KEY_DPOINT:
147                 if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
148                         break;
149
150                 mandoc_msg(MANDOCERR_TBL, tbl->parse,
151                     ln, *pos - 1, NULL);
152                 return(0);
153         default:
154                 abort();
155                 /* NOTREACHED */
156         }
157
158         /* End with a close parenthesis. */
159
160         if (')' == p[(*pos)++])
161                 return(1);
162
163         mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);
164         return(0);
165 }
166
167 static void
168 opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
169 {
170         int              i, sv;
171         char             buf[KEY_MAXNAME];
172
173         /*
174          * Parse individual options from the stream as surrounded by
175          * this goto.  Each pass through the routine parses out a single
176          * option and registers it.  Option arguments are processed in
177          * the arg() function.
178          */
179
180 again:  /*
181          * EBNF describing this section:
182          *
183          * options      ::= option_list [:space:]* [;][\n]
184          * option_list  ::= option option_tail
185          * option_tail  ::= [:space:]+ option_list |
186          *              ::= epsilon
187          * option       ::= [:alpha:]+ args
188          * args         ::= [:space:]* [(] [:alpha:]+ [)]
189          */
190
191         while (isspace((unsigned char)p[*pos]))
192                 (*pos)++;
193
194         /* Safe exit point. */
195
196         if (';' == p[*pos])
197                 return;
198
199         /* Copy up to first non-alpha character. */
200
201         for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {
202                 buf[i] = (char)tolower((unsigned char)p[*pos]);
203                 if ( ! isalpha((unsigned char)buf[i]))
204                         break;
205         }
206
207         /* Exit if buffer is empty (or overrun). */
208
209         if (KEY_MAXNAME == i || 0 == i) {
210                 mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
211                 return;
212         }
213
214         buf[i] = '\0';
215
216         while (isspace((unsigned char)p[*pos]))
217                 (*pos)++;
218
219         /*
220          * Look through all of the available keys to find one that
221          * matches the input.  FIXME: hashtable this.
222          */
223
224         for (i = 0; i < KEY_MAXKEYS; i++) {
225                 if (strcmp(buf, keys[i].name))
226                         continue;
227
228                 /*
229                  * Note: this is more difficult to recover from, as we
230                  * can be anywhere in the option sequence and it's
231                  * harder to jump to the next.  Meanwhile, just bail out
232                  * of the sequence altogether.
233                  */
234
235                 if (keys[i].key)
236                         tbl->opts.opts |= keys[i].key;
237                 else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
238                         return;
239
240                 break;
241         }
242
243         /*
244          * Allow us to recover from bad options by continuing to another
245          * parse sequence.
246          */
247
248         if (KEY_MAXKEYS == i)
249                 mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);
250
251         goto again;
252         /* NOTREACHED */
253 }
254
255 int
256 tbl_option(struct tbl_node *tbl, int ln, const char *p)
257 {
258         int              pos;
259
260         /*
261          * Table options are always on just one line, so automatically
262          * switch into the next input mode here.
263          */
264         tbl->part = TBL_PART_LAYOUT;
265
266         pos = 0;
267         opt(tbl, ln, p, &pos);
268
269         /* Always succeed. */
270         return(1);
271 }