]> git.cameronkatri.com Git - mandoc.git/blob - mdocml.c
60bf8943773beb4d4c8372af3341e2bc00dbfc9d
[mandoc.git] / mdocml.c
1 /* $Id: mdocml.c,v 1.22 2008/12/15 02:23: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 MD_LINE_SZ (256)
34
35 struct md_parse {
36 int warn;
37 #define MD_WARN_ALL (1 << 0)
38 #define MD_WARN_ERR (1 << 1)
39 int dbg;
40 struct mdoc *mdoc;
41 char *buf;
42 u_long bufsz;
43 char *name;
44 int fd;
45 int lnn;
46 char *line;
47 };
48
49 static void usage(void);
50
51 static int parse_begin(struct md_parse *);
52 static int parse_leave(struct md_parse *, int);
53 static int io_begin(struct md_parse *);
54 static int io_leave(struct md_parse *, int);
55 static int buf_begin(struct md_parse *);
56 static int buf_leave(struct md_parse *, int);
57
58 static int msg_err(void *, int, int, enum mdoc_err);
59 static int msg_warn(void *, int, int, enum mdoc_warn);
60 static void msg_msg(void *, int, const char *);
61
62 #ifdef __linux__
63 extern int getsubopt(char **, char *const *, char **);
64 #endif
65
66 int
67 main(int argc, char *argv[])
68 {
69 int c;
70 struct md_parse parser;
71 char *opts, *v;
72 #define ALL 0
73 #define ERROR 1
74 char *toks[] = { "all", "error", NULL };
75
76 extern char *optarg;
77 extern int optind;
78
79 (void)memset(&parser, 0, sizeof(struct md_parse));
80
81 while (-1 != (c = getopt(argc, argv, "vW:")))
82 switch (c) {
83 case ('v'):
84 parser.dbg++;
85 break;
86 case ('W'):
87 opts = optarg;
88 while (*opts)
89 switch (getsubopt(&opts, toks, &v)) {
90 case (ALL):
91 parser.warn |= MD_WARN_ALL;
92 break;
93 case (ERROR):
94 parser.warn |= MD_WARN_ERR;
95 break;
96 default:
97 usage();
98 return(1);
99 }
100 break;
101 default:
102 usage();
103 return(1);
104 }
105
106 argv += optind;
107 argc -= optind;
108
109 parser.name = "-";
110 if (1 == argc)
111 parser.name = *argv++;
112
113 if ( ! io_begin(&parser))
114 return(EXIT_FAILURE);
115
116 return(EXIT_SUCCESS);
117 }
118
119
120 static int
121 io_leave(struct md_parse *p, int code)
122 {
123
124 if (-1 == p->fd || STDIN_FILENO == p->fd)
125 return(code);
126
127 if (-1 == close(p->fd)) {
128 warn("%s", p->name);
129 code = 0;
130 }
131 return(code);
132 }
133
134
135 static int
136 io_begin(struct md_parse *p)
137 {
138
139 p->fd = STDIN_FILENO;
140 if (0 != strncmp(p->name, "-", 1))
141 if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
142 warn("%s", p->name);
143 return(io_leave(p, 0));
144 }
145
146 return(io_leave(p, buf_begin(p)));
147 }
148
149
150 static int
151 buf_leave(struct md_parse *p, int code)
152 {
153
154 if (p->buf)
155 free(p->buf);
156 return(code);
157 }
158
159
160 static int
161 buf_begin(struct md_parse *p)
162 {
163 struct stat st;
164
165 if (-1 == fstat(p->fd, &st)) {
166 warn("%s", p->name);
167 return(1);
168 }
169
170 p->bufsz = MAX(st.st_blksize, BUFSIZ);
171
172 if (NULL == (p->buf = malloc(p->bufsz))) {
173 warn("malloc");
174 return(buf_leave(p, 0));
175 }
176
177 return(buf_leave(p, parse_begin(p)));
178 }
179
180
181 static void
182 print_node(const struct mdoc_node *n, int indent)
183 {
184 const char *p, *t;
185 int i;
186
187 switch (n->type) {
188 case (MDOC_TEXT):
189 assert(NULL == n->child);
190 p = "<text>";
191 t = "text";
192 break;
193 case (MDOC_BODY):
194 p = mdoc_macronames[n->data.body.tok];
195 t = "block-body";
196 break;
197 case (MDOC_HEAD):
198 p = mdoc_macronames[n->data.head.tok];
199 t = "block-head";
200 break;
201 case (MDOC_ELEM):
202 assert(NULL == n->child);
203 p = mdoc_macronames[n->data.elem.tok];
204 t = "element";
205 break;
206 case (MDOC_BLOCK):
207 p = mdoc_macronames[n->data.block.tok];
208 t = "block";
209 break;
210 default:
211 abort();
212 /* NOTREACHED */
213 }
214
215 for (i = 0; i < indent; i++)
216 (void)printf(" ");
217 (void)printf("%s (%s)\n", p, t);
218
219 if (n->child)
220 print_node(n->child, indent + 1);
221 if (n->next)
222 print_node(n->next, indent);
223 }
224
225
226 static int
227 parse_leave(struct md_parse *p, int code)
228 {
229 const struct mdoc_node *n;
230
231 if (p->mdoc) {
232 if ((n = mdoc_result(p->mdoc)))
233 print_node(n, 0);
234 mdoc_free(p->mdoc);
235 }
236 return(code);
237 }
238
239
240 static int
241 parse_begin(struct md_parse *p)
242 {
243 ssize_t sz, i;
244 size_t pos;
245 char line[256], sv[256];
246 struct mdoc_cb cb;
247
248 cb.mdoc_err = msg_err;
249 cb.mdoc_warn = msg_warn;
250 cb.mdoc_msg = msg_msg;
251
252 if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
253 return(parse_leave(p, 0));
254
255 p->lnn = 1;
256 p->line = sv;
257
258 for (pos = 0; ; ) {
259 if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
260 warn("%s", p->name);
261 return(parse_leave(p, 0));
262 } else if (0 == sz)
263 break;
264
265 for (i = 0; i < sz; i++) {
266 if ('\n' != p->buf[i]) {
267 if (pos < sizeof(line)) {
268 /* LINTED */
269 sv[pos] = p->buf[i];
270 line[pos++] = p->buf[i];
271 continue;
272 }
273 warnx("%s: line %d too long",
274 p->name, p->lnn);
275 return(parse_leave(p, 0));
276 }
277
278 line[(int)pos] = sv[(int)pos] = 0;
279 if ( ! mdoc_parseln(p->mdoc, line))
280 return(parse_leave(p, 0));
281
282 p->lnn++;
283 pos = 0;
284 }
285 }
286
287 return(parse_leave(p, 1));
288 }
289
290
291 static int
292 msg_err(void *arg, int tok, int col, enum mdoc_err type)
293 {
294 char *fmt, *lit;
295 struct md_parse *p;
296 int i;
297
298 p = (struct md_parse *)arg;
299
300 fmt = lit = NULL;
301
302 switch (type) {
303 case (ERR_SYNTAX_QUOTE):
304 lit = "syntax: unterminated quotation";
305 break;
306 case (ERR_SYNTAX_WS):
307 lit = "syntax: whitespace in argument";
308 break;
309 case (ERR_SCOPE_BREAK):
310 /* Which scope is broken? */
311 fmt = "macro `%s' breaks prior explicit scope";
312 break;
313 case (ERR_MACRO_NOTSUP):
314 fmt = "macro `%s' not supported";
315 break;
316 case (ERR_MACRO_NOTCALL):
317 fmt = "macro `%s' not callable";
318 break;
319 case (ERR_ARGS_GE1):
320 fmt = "macro `%s' expects one or more arguments";
321 break;
322 default:
323 abort();
324 /* NOTREACHED */
325 }
326
327 if (fmt) {
328 (void)fprintf(stderr, "%s:%d: error: ",
329 p->name, p->lnn);
330 (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
331 } else
332 (void)fprintf(stderr, "%s:%d: error: %s",
333 p->name, p->lnn, lit);
334
335 if (p->dbg < 1) {
336 (void)fprintf(stderr, " (column %d)\n", col);
337 return(0);
338 }
339
340 (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
341 for (i = 0; i < col; i++)
342 (void)fprintf(stderr, " ");
343 (void)fprintf(stderr, "^\n");
344
345 return(0);
346 }
347
348
349 static void
350 msg_msg(void *arg, int col, const char *msg)
351 {
352 struct md_parse *p;
353 int i;
354
355 p = (struct md_parse *)arg;
356
357 if (p->dbg < 2)
358 return;
359
360 (void)printf("%s:%d: %s", p->name, p->lnn, msg);
361
362 if (p->dbg < 3) {
363 (void)printf(" (column %d)\n", col);
364 return;
365 }
366
367 (void)printf("\nFrom: %s\n ", p->line);
368 for (i = 0; i < col; i++)
369 (void)printf(" ");
370 (void)printf("^\n");
371 }
372
373
374 static int
375 msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
376 {
377 char *fmt, *lit;
378 struct md_parse *p;
379 int i;
380 extern char *__progname;
381
382 p = (struct md_parse *)arg;
383
384 if ( ! (p->warn & MD_WARN_ALL))
385 return(1);
386
387 fmt = lit = NULL;
388
389 switch (type) {
390 case (WARN_SYNTAX_WS_EOLN):
391 lit = "syntax: whitespace at end-of-line";
392 break;
393 case (WARN_SYNTAX_MACLIKE):
394 lit = "syntax: macro-like argument";
395 break;
396 case (WARN_ARGS_GE1):
397 fmt = "macro `%s' suggests one or more arguments";
398 break;
399 default:
400 abort();
401 /* NOTREACHED */
402 }
403
404 if (fmt) {
405 (void)fprintf(stderr, "%s:%d: warning: ",
406 p->name, p->lnn);
407 (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
408 } else
409 (void)fprintf(stderr, "%s:%d: warning: %s",
410 p->name, p->lnn, lit);
411
412 if (p->dbg >= 1) {
413 (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
414 for (i = 0; i < col; i++)
415 (void)fprintf(stderr, " ");
416 (void)fprintf(stderr, "^\n");
417 } else
418 (void)fprintf(stderr, " (column %d)\n", col);
419
420 if (p->warn & MD_WARN_ERR) {
421 (void)fprintf(stderr, "%s: considering warnings as "
422 "errors\n", __progname);
423 return(0);
424 }
425
426 return(1);
427 }
428
429
430 static void
431 usage(void)
432 {
433 extern char *__progname;
434
435 (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
436 __progname);
437 }
438