]> git.cameronkatri.com Git - mandoc.git/blob - mdocml.c
Finished re-fitting err/warn/msg routines.
[mandoc.git] / mdocml.c
1 /* $Id: mdocml.c,v 1.45 2009/01/16 11:50:54 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 static void
198 print_node(const struct mdoc_node *n, int indent)
199 {
200 const char *p, *t;
201 int i, j;
202 size_t argc, sz;
203 char **params;
204 struct mdoc_arg *argv;
205
206 argv = NULL;
207 argc = sz = 0;
208 params = NULL;
209
210 t = mdoc_type2a(n->type);
211
212 switch (n->type) {
213 case (MDOC_TEXT):
214 p = n->data.text.string;
215 break;
216 case (MDOC_BODY):
217 p = mdoc_macronames[n->tok];
218 break;
219 case (MDOC_HEAD):
220 p = mdoc_macronames[n->tok];
221 break;
222 case (MDOC_TAIL):
223 p = mdoc_macronames[n->tok];
224 break;
225 case (MDOC_ELEM):
226 p = mdoc_macronames[n->tok];
227 argv = n->data.elem.argv;
228 argc = n->data.elem.argc;
229 break;
230 case (MDOC_BLOCK):
231 p = mdoc_macronames[n->tok];
232 argv = n->data.block.argv;
233 argc = n->data.block.argc;
234 break;
235 case (MDOC_ROOT):
236 p = "root";
237 break;
238 default:
239 abort();
240 /* NOTREACHED */
241 }
242
243 for (i = 0; i < indent; i++)
244 xprintf(" ");
245 xprintf("%s (%s)", p, t);
246
247 for (i = 0; i < (int)argc; i++) {
248 xprintf(" -%s", mdoc_argnames[argv[i].arg]);
249 if (argv[i].sz > 0)
250 xprintf(" [");
251 for (j = 0; j < (int)argv[i].sz; j++)
252 xprintf(" [%s]", argv[i].value[j]);
253 if (argv[i].sz > 0)
254 xprintf(" ]");
255 }
256
257 for (i = 0; i < (int)sz; i++)
258 xprintf(" [%s]", params[i]);
259
260 xprintf(" %d:%d\n", n->line, n->pos);
261
262 if (n->child)
263 print_node(n->child, indent + 1);
264 if (n->next)
265 print_node(n->next, indent);
266 }
267
268
269 static int
270 parse_leave(struct md_parse *p, int code)
271 {
272 const struct mdoc_node *n;
273
274 if (NULL == p->mdoc)
275 return(code);
276
277 if ( ! mdoc_endparse(p->mdoc))
278 code = 0;
279 if ((n = mdoc_result(p->mdoc)))
280 print_node(n, 0);
281
282 mdoc_free(p->mdoc);
283
284 return(code);
285 }
286
287
288 static int
289 parse_begin(struct md_parse *p)
290 {
291 ssize_t sz, i;
292 size_t pos;
293 char line[MD_LINE_SZ];
294 struct mdoc_cb cb;
295 int lnn;
296
297 cb.mdoc_err = msg_err;
298 cb.mdoc_warn = msg_warn;
299 cb.mdoc_msg = msg_msg;
300
301 if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
302 return(parse_leave(p, 0));
303
304 for (lnn = 1, pos = 0; ; ) {
305 if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
306 warn("%s", p->name);
307 return(parse_leave(p, 0));
308 } else if (0 == sz)
309 break;
310
311 for (i = 0; i < sz; i++) {
312 if ('\n' != p->buf[i]) {
313 if (pos < sizeof(line)) {
314 line[(int)pos++] = p->buf[(int)i];
315 continue;
316 }
317 warnx("%s: line %d too long",
318 p->name, lnn);
319 return(parse_leave(p, 0));
320 }
321
322 line[(int)pos] = 0;
323 if ( ! mdoc_parseln(p->mdoc, lnn, line))
324 return(parse_leave(p, 0));
325
326 lnn++;
327 pos = 0;
328 }
329 }
330
331 return(parse_leave(p, 1));
332 }
333
334
335 static int
336 msg_err(void *arg, int line, int col, const char *msg)
337 {
338 struct md_parse *p;
339
340 p = (struct md_parse *)arg;
341
342 xfprintf(stderr, "%s:%d: error: %s (column %d)\n",
343 p->name, line, msg, col);
344 return(0);
345 }
346
347
348 static void
349 msg_msg(void *arg, int line, int col, const char *msg)
350 {
351 struct md_parse *p;
352
353 p = (struct md_parse *)arg;
354
355 if (0 == p->dbg)
356 return;
357
358 xfprintf(stderr, "%s:%d: debug: %s (column %d)\n",
359 p->name, line, msg, col);
360 }
361
362
363 static int
364 msg_warn(void *arg, int line, int col,
365 enum mdoc_warn type, const char *msg)
366 {
367 struct md_parse *p;
368
369 p = (struct md_parse *)arg;
370
371 switch (type) {
372 case (WARN_COMPAT):
373 if (p->warn & MD_WARN_COMPAT)
374 break;
375 return(1);
376 case (WARN_SYNTAX):
377 if (p->warn & MD_WARN_SYNTAX)
378 break;
379 return(1);
380 }
381
382 xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
383 p->name, line, msg, col);
384
385 if ( ! (p->warn & MD_WARN_ERR))
386 return(1);
387
388 xfprintf(stderr, "%s: considering warnings as errors\n",
389 __progname);
390 return(0);
391 }
392
393
394 static void
395 usage(void)
396 {
397
398 xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
399 __progname);
400 }
401