]> git.cameronkatri.com Git - mandoc.git/blob - mdocml.c
Boolean validation.
[mandoc.git] / mdocml.c
1 /* $Id: mdocml.c,v 1.46 2009/01/16 14:15:12 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <sys/stat.h>
20 #include <sys/param.h>
21
22 #include <assert.h>
23 #include <fcntl.h>
24 #include <err.h>
25 #include <getopt.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "mdoc.h"
32
33 #define xfprintf (void)fprintf
34 #define xprintf (void)printf
35 #define xvfprintf (void)fvprintf
36
37 #define MD_LINE_SZ (256) /* Max input line size. */
38
39 struct md_parse {
40 int warn; /* Warning flags. */
41 #define MD_WARN_SYNTAX (1 << 0) /* Show syntax warnings. */
42 #define MD_WARN_COMPAT (1 << 1) /* Show compat warnings. */
43 #define MD_WARN_ALL (0x03) /* Show all warnings. */
44 #define MD_WARN_ERR (1 << 2) /* Make warnings->errors. */
45 int dbg; /* Debug level. */
46 struct mdoc *mdoc; /* Active parser. */
47 char *buf; /* Input buffer. */
48 u_long bufsz; /* Input buffer size. */
49 char *name; /* Input file name. */
50 int fd; /* Input file desc. */
51 };
52
53 extern char *__progname;
54
55 static void usage(void);
56
57 static int parse_begin(struct md_parse *);
58 static int parse_leave(struct md_parse *, int);
59 static int io_begin(struct md_parse *);
60 static int io_leave(struct md_parse *, int);
61 static int buf_begin(struct md_parse *);
62 static int buf_leave(struct md_parse *, int);
63
64 static void msg_msg(void *, int, int, const char *);
65 static int msg_err(void *, int, int, const char *);
66 static int msg_warn(void *, int, int,
67 enum mdoc_warn, const char *);
68
69 #ifdef __linux__
70 extern int getsubopt(char **, char *const *, char **);
71 #endif
72
73 int
74 main(int argc, char *argv[])
75 {
76 int c;
77 struct md_parse parser;
78 char *opts, *v;
79 #define ALL 0
80 #define COMPAT 1
81 #define SYNTAX 2
82 #define ERROR 3
83 char *toks[] = { "all", "compat", "syntax",
84 "error", NULL };
85
86 extern char *optarg;
87 extern int optind;
88
89 (void)memset(&parser, 0, sizeof(struct md_parse));
90
91 while (-1 != (c = getopt(argc, argv, "vW:")))
92 switch (c) {
93 case ('v'):
94 parser.dbg++;
95 break;
96 case ('W'):
97 opts = optarg;
98 while (*opts)
99 switch (getsubopt(&opts, toks, &v)) {
100 case (ALL):
101 parser.warn |= MD_WARN_ALL;
102 break;
103 case (COMPAT):
104 parser.warn |= MD_WARN_COMPAT;
105 break;
106 case (SYNTAX):
107 parser.warn |= MD_WARN_SYNTAX;
108 break;
109 case (ERROR):
110 parser.warn |= MD_WARN_ERR;
111 break;
112 default:
113 usage();
114 return(1);
115 }
116 break;
117 default:
118 usage();
119 return(1);
120 }
121
122 argv += optind;
123 argc -= optind;
124
125 parser.name = "-";
126 if (1 == argc)
127 parser.name = *argv++;
128
129 if ( ! io_begin(&parser))
130 return(EXIT_FAILURE);
131
132 return(EXIT_SUCCESS);
133 }
134
135
136 static int
137 io_leave(struct md_parse *p, int code)
138 {
139
140 if (-1 == p->fd || STDIN_FILENO == p->fd)
141 return(code);
142
143 if (-1 == close(p->fd)) {
144 warn("%s", p->name);
145 code = 0;
146 }
147 return(code);
148 }
149
150
151 static int
152 io_begin(struct md_parse *p)
153 {
154
155 p->fd = STDIN_FILENO;
156 if (0 != strncmp(p->name, "-", 1))
157 if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
158 warn("%s", p->name);
159 return(io_leave(p, 0));
160 }
161
162 return(io_leave(p, buf_begin(p)));
163 }
164
165
166 static int
167 buf_leave(struct md_parse *p, int code)
168 {
169
170 if (p->buf)
171 free(p->buf);
172 return(code);
173 }
174
175
176 static int
177 buf_begin(struct md_parse *p)
178 {
179 struct stat st;
180
181 if (-1 == fstat(p->fd, &st)) {
182 warn("%s", p->name);
183 return(1);
184 }
185
186 p->bufsz = MAX(st.st_blksize, BUFSIZ);
187
188 if (NULL == (p->buf = malloc(p->bufsz))) {
189 warn("malloc");
190 return(buf_leave(p, 0));
191 }
192
193 return(buf_leave(p, parse_begin(p)));
194 }
195
196
197 /* TODO: remove this to a print-tree output filter. */
198 static void
199 print_node(const struct mdoc_node *n, int indent)
200 {
201 const char *p, *t;
202 int i, j;
203 size_t argc, sz;
204 char **params;
205 struct mdoc_arg *argv;
206
207 argv = NULL;
208 argc = sz = 0;
209 params = NULL;
210
211 t = mdoc_type2a(n->type);
212
213 switch (n->type) {
214 case (MDOC_TEXT):
215 p = n->data.text.string;
216 break;
217 case (MDOC_BODY):
218 p = mdoc_macronames[n->tok];
219 break;
220 case (MDOC_HEAD):
221 p = mdoc_macronames[n->tok];
222 break;
223 case (MDOC_TAIL):
224 p = mdoc_macronames[n->tok];
225 break;
226 case (MDOC_ELEM):
227 p = mdoc_macronames[n->tok];
228 argv = n->data.elem.argv;
229 argc = n->data.elem.argc;
230 break;
231 case (MDOC_BLOCK):
232 p = mdoc_macronames[n->tok];
233 argv = n->data.block.argv;
234 argc = n->data.block.argc;
235 break;
236 case (MDOC_ROOT):
237 p = "root";
238 break;
239 default:
240 abort();
241 /* NOTREACHED */
242 }
243
244 for (i = 0; i < indent; i++)
245 xprintf(" ");
246 xprintf("%s (%s)", p, t);
247
248 for (i = 0; i < (int)argc; i++) {
249 xprintf(" -%s", mdoc_argnames[argv[i].arg]);
250 if (argv[i].sz > 0)
251 xprintf(" [");
252 for (j = 0; j < (int)argv[i].sz; j++)
253 xprintf(" [%s]", argv[i].value[j]);
254 if (argv[i].sz > 0)
255 xprintf(" ]");
256 }
257
258 for (i = 0; i < (int)sz; i++)
259 xprintf(" [%s]", params[i]);
260
261 xprintf(" %d:%d\n", n->line, n->pos);
262
263 if (n->child)
264 print_node(n->child, indent + 1);
265 if (n->next)
266 print_node(n->next, indent);
267 }
268
269
270 static int
271 parse_leave(struct md_parse *p, int code)
272 {
273 const struct mdoc_node *n;
274
275 if (NULL == p->mdoc)
276 return(code);
277
278 if ( ! mdoc_endparse(p->mdoc))
279 code = 0;
280 if ((n = mdoc_result(p->mdoc)))
281 print_node(n, 0);
282
283 mdoc_free(p->mdoc);
284
285 return(code);
286 }
287
288
289 static int
290 parse_begin(struct md_parse *p)
291 {
292 ssize_t sz, i;
293 size_t pos;
294 char line[MD_LINE_SZ];
295 struct mdoc_cb cb;
296 int lnn;
297
298 cb.mdoc_err = msg_err;
299 cb.mdoc_warn = msg_warn;
300 cb.mdoc_msg = msg_msg;
301
302 if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
303 return(parse_leave(p, 0));
304
305 for (lnn = 1, pos = 0; ; ) {
306 if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
307 warn("%s", p->name);
308 return(parse_leave(p, 0));
309 } else if (0 == sz)
310 break;
311
312 for (i = 0; i < sz; i++) {
313 if ('\n' != p->buf[i]) {
314 if (pos < sizeof(line)) {
315 line[(int)pos++] = p->buf[(int)i];
316 continue;
317 }
318 warnx("%s: line %d too long",
319 p->name, lnn);
320 return(parse_leave(p, 0));
321 }
322
323 line[(int)pos] = 0;
324 if ( ! mdoc_parseln(p->mdoc, lnn, line))
325 return(parse_leave(p, 0));
326
327 lnn++;
328 pos = 0;
329 }
330 }
331
332 return(parse_leave(p, 1));
333 }
334
335
336 static int
337 msg_err(void *arg, int line, int col, const char *msg)
338 {
339 struct md_parse *p;
340
341 p = (struct md_parse *)arg;
342
343 xfprintf(stderr, "%s:%d: error: %s (column %d)\n",
344 p->name, line, msg, col);
345 return(0);
346 }
347
348
349 static void
350 msg_msg(void *arg, int line, int col, const char *msg)
351 {
352 struct md_parse *p;
353
354 p = (struct md_parse *)arg;
355
356 if (0 == p->dbg)
357 return;
358
359 xfprintf(stderr, "%s:%d: debug: %s (column %d)\n",
360 p->name, line, msg, col);
361 }
362
363
364 static int
365 msg_warn(void *arg, int line, int col,
366 enum mdoc_warn type, const char *msg)
367 {
368 struct md_parse *p;
369
370 p = (struct md_parse *)arg;
371
372 switch (type) {
373 case (WARN_COMPAT):
374 if (p->warn & MD_WARN_COMPAT)
375 break;
376 return(1);
377 case (WARN_SYNTAX):
378 if (p->warn & MD_WARN_SYNTAX)
379 break;
380 return(1);
381 }
382
383 xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
384 p->name, line, msg, col);
385
386 if ( ! (p->warn & MD_WARN_ERR))
387 return(1);
388
389 xfprintf(stderr, "%s: considering warnings as errors\n",
390 __progname);
391 return(0);
392 }
393
394
395 static void
396 usage(void)
397 {
398
399 xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
400 __progname);
401 }
402