Annotation of mandoc/mdocml.c, Revision 1.22
1.22 ! kristaps 1: /* $Id: mdocml.c,v 1.21 2008/12/15 01:54:58 kristaps Exp $ */
1.1 kristaps 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: */
1.21 kristaps 19: #include <sys/stat.h>
1.1 kristaps 20: #include <sys/param.h>
21:
22: #include <assert.h>
1.21 kristaps 23: #include <fcntl.h>
1.1 kristaps 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:
1.21 kristaps 31: #include "mdoc.h"
1.1 kristaps 32:
1.21 kristaps 33: #define MD_LINE_SZ (256)
1.2 kristaps 34:
1.21 kristaps 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: };
1.17 kristaps 48:
1.9 kristaps 49: static void usage(void);
50:
1.21 kristaps 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 *);
1.1 kristaps 61:
1.19 kristaps 62: #ifdef __linux__
63: extern int getsubopt(char **, char *const *, char **);
64: #endif
65:
1.1 kristaps 66: int
67: main(int argc, char *argv[])
68: {
69: int c;
1.21 kristaps 70: struct md_parse parser;
71: char *opts, *v;
1.18 kristaps 72: #define ALL 0
73: #define ERROR 1
74: char *toks[] = { "all", "error", NULL };
1.1 kristaps 75:
76: extern char *optarg;
77: extern int optind;
78:
1.21 kristaps 79: (void)memset(&parser, 0, sizeof(struct md_parse));
1.17 kristaps 80:
1.21 kristaps 81: while (-1 != (c = getopt(argc, argv, "vW:")))
1.1 kristaps 82: switch (c) {
1.13 kristaps 83: case ('v'):
1.21 kristaps 84: parser.dbg++;
1.13 kristaps 85: break;
86: case ('W'):
1.18 kristaps 87: opts = optarg;
88: while (*opts)
89: switch (getsubopt(&opts, toks, &v)) {
90: case (ALL):
1.21 kristaps 91: parser.warn |= MD_WARN_ALL;
1.18 kristaps 92: break;
93: case (ERROR):
1.21 kristaps 94: parser.warn |= MD_WARN_ERR;
1.18 kristaps 95: break;
96: default:
97: usage();
98: return(1);
99: }
1.13 kristaps 100: break;
1.1 kristaps 101: default:
102: usage();
103: return(1);
104: }
105:
106: argv += optind;
1.4 kristaps 107: argc -= optind;
1.1 kristaps 108:
1.21 kristaps 109: parser.name = "-";
1.4 kristaps 110: if (1 == argc)
1.21 kristaps 111: parser.name = *argv++;
112:
113: if ( ! io_begin(&parser))
114: return(EXIT_FAILURE);
1.1 kristaps 115:
1.21 kristaps 116: return(EXIT_SUCCESS);
1.1 kristaps 117: }
118:
119:
120: static int
1.21 kristaps 121: io_leave(struct md_parse *p, int code)
1.1 kristaps 122: {
123:
1.21 kristaps 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;
1.4 kristaps 130: }
1.21 kristaps 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: }
1.1 kristaps 145:
1.21 kristaps 146: return(io_leave(p, buf_begin(p)));
1.1 kristaps 147: }
148:
149:
150: static int
1.21 kristaps 151: buf_leave(struct md_parse *p, int code)
1.1 kristaps 152: {
1.4 kristaps 153:
1.21 kristaps 154: if (p->buf)
155: free(p->buf);
156: return(code);
157: }
1.1 kristaps 158:
159:
1.21 kristaps 160: static int
161: buf_begin(struct md_parse *p)
162: {
163: struct stat st;
1.1 kristaps 164:
1.21 kristaps 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;
1.22 ! kristaps 210: default:
! 211: abort();
! 212: /* NOTREACHED */
1.21 kristaps 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: }
1.1 kristaps 224:
225:
1.21 kristaps 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));
1.1 kristaps 281:
1.21 kristaps 282: p->lnn++;
283: pos = 0;
1.4 kristaps 284: }
1.21 kristaps 285: }
1.1 kristaps 286:
1.21 kristaps 287: return(parse_leave(p, 1));
1.4 kristaps 288: }
1.1 kristaps 289:
290:
1.4 kristaps 291: static int
1.21 kristaps 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)
1.4 kristaps 351: {
1.21 kristaps 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");
1.1 kristaps 371: }
372:
373:
374: static int
1.21 kristaps 375: msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
1.1 kristaps 376: {
1.21 kristaps 377: char *fmt, *lit;
378: struct md_parse *p;
379: int i;
380: extern char *__progname;
1.1 kristaps 381:
1.21 kristaps 382: p = (struct md_parse *)arg;
1.1 kristaps 383:
1.21 kristaps 384: if ( ! (p->warn & MD_WARN_ALL))
1.1 kristaps 385: return(1);
1.21 kristaps 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 */
1.1 kristaps 402: }
403:
1.21 kristaps 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);
1.1 kristaps 424: }
425:
1.21 kristaps 426: return(1);
1.1 kristaps 427: }
428:
429:
430: static void
431: usage(void)
432: {
433: extern char *__progname;
434:
1.21 kristaps 435: (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19 kristaps 436: __progname);
1.1 kristaps 437: }
1.18 kristaps 438:
CVSweb