Annotation of mandoc/mdocml.c, Revision 1.34
1.34 ! kristaps 1: /* $Id: mdocml.c,v 1.33 2009/01/03 22:10:22 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: {
1.26 kristaps 184: const char *p, *t;
185: int i, j;
186: size_t argc, sz;
187: char **params;
188: struct mdoc_arg *argv;
1.24 kristaps 189:
190: argv = NULL;
191: argc = 0;
1.26 kristaps 192: params = NULL;
193: sz = 0;
1.21 kristaps 194:
195: switch (n->type) {
196: case (MDOC_TEXT):
197: assert(NULL == n->child);
1.25 kristaps 198: p = n->data.text.string;
1.21 kristaps 199: t = "text";
200: break;
201: case (MDOC_BODY):
202: p = mdoc_macronames[n->data.body.tok];
203: t = "block-body";
204: break;
205: case (MDOC_HEAD):
206: p = mdoc_macronames[n->data.head.tok];
207: t = "block-head";
208: break;
1.34 ! kristaps 209: case (MDOC_TAIL):
! 210: p = mdoc_macronames[n->data.tail.tok];
! 211: t = "block-tail";
! 212: break;
1.21 kristaps 213: case (MDOC_ELEM):
214: p = mdoc_macronames[n->data.elem.tok];
215: t = "element";
1.24 kristaps 216: argv = n->data.elem.argv;
217: argc = n->data.elem.argc;
1.26 kristaps 218: params = n->data.elem.args;
219: sz = n->data.elem.sz;
1.21 kristaps 220: break;
221: case (MDOC_BLOCK):
222: p = mdoc_macronames[n->data.block.tok];
223: t = "block";
1.24 kristaps 224: argv = n->data.block.argv;
225: argc = n->data.block.argc;
1.21 kristaps 226: break;
1.22 kristaps 227: default:
228: abort();
229: /* NOTREACHED */
1.21 kristaps 230: }
231:
232: for (i = 0; i < indent; i++)
233: (void)printf(" ");
1.24 kristaps 234: (void)printf("%s (%s)", p, t);
235:
236: for (i = 0; i < (int)argc; i++) {
237: (void)printf(" -%s", mdoc_argnames[argv[i].arg]);
238: for (j = 0; j < (int)argv[i].sz; j++)
239: (void)printf(" \"%s\"", argv[i].value[j]);
240: }
241:
1.26 kristaps 242: for (i = 0; i < (int)sz; i++)
243: (void)printf(" \"%s\"", params[i]);
244:
1.24 kristaps 245: (void)printf("\n");
1.21 kristaps 246:
247: if (n->child)
248: print_node(n->child, indent + 1);
249: if (n->next)
250: print_node(n->next, indent);
251: }
1.1 kristaps 252:
253:
1.21 kristaps 254: static int
255: parse_leave(struct md_parse *p, int code)
256: {
257: const struct mdoc_node *n;
258:
259: if (p->mdoc) {
260: if ((n = mdoc_result(p->mdoc)))
261: print_node(n, 0);
262: mdoc_free(p->mdoc);
263: }
264: return(code);
265: }
266:
267:
268: static int
269: parse_begin(struct md_parse *p)
270: {
271: ssize_t sz, i;
272: size_t pos;
273: char line[256], sv[256];
274: struct mdoc_cb cb;
275:
276: cb.mdoc_err = msg_err;
277: cb.mdoc_warn = msg_warn;
278: cb.mdoc_msg = msg_msg;
279:
280: if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
281: return(parse_leave(p, 0));
282:
283: p->lnn = 1;
284: p->line = sv;
285:
286: for (pos = 0; ; ) {
287: if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
288: warn("%s", p->name);
289: return(parse_leave(p, 0));
290: } else if (0 == sz)
291: break;
292:
293: for (i = 0; i < sz; i++) {
294: if ('\n' != p->buf[i]) {
295: if (pos < sizeof(line)) {
1.23 kristaps 296: sv[(int)pos] = p->buf[(int)i];
297: line[(int)pos++] =
298: p->buf[(int)i];
1.21 kristaps 299: continue;
300: }
301: warnx("%s: line %d too long",
302: p->name, p->lnn);
303: return(parse_leave(p, 0));
304: }
305:
306: line[(int)pos] = sv[(int)pos] = 0;
307: if ( ! mdoc_parseln(p->mdoc, line))
308: return(parse_leave(p, 0));
1.1 kristaps 309:
1.21 kristaps 310: p->lnn++;
311: pos = 0;
1.4 kristaps 312: }
1.21 kristaps 313: }
1.1 kristaps 314:
1.21 kristaps 315: return(parse_leave(p, 1));
1.4 kristaps 316: }
1.1 kristaps 317:
318:
1.4 kristaps 319: static int
1.21 kristaps 320: msg_err(void *arg, int tok, int col, enum mdoc_err type)
321: {
322: char *fmt, *lit;
323: struct md_parse *p;
324: int i;
325:
326: p = (struct md_parse *)arg;
327:
328: fmt = lit = NULL;
329:
330: switch (type) {
331: case (ERR_SYNTAX_QUOTE):
1.24 kristaps 332: lit = "syntax: disallowed argument quotation";
333: break;
334: case (ERR_SYNTAX_UNQUOTE):
1.21 kristaps 335: lit = "syntax: unterminated quotation";
336: break;
337: case (ERR_SYNTAX_WS):
338: lit = "syntax: whitespace in argument";
339: break;
1.25 kristaps 340: case (ERR_SYNTAX_ARGFORM):
1.23 kristaps 341: fmt = "syntax: macro `%s' arguments malformed";
342: break;
1.28 kristaps 343: case (ERR_SYNTAX_NOPUNCT):
344: fmt = "syntax: macro `%s' doesn't understand punctuation";
345: break;
1.25 kristaps 346: case (ERR_SYNTAX_ARG):
1.24 kristaps 347: fmt = "syntax: unknown argument for macro `%s'";
348: break;
1.21 kristaps 349: case (ERR_SCOPE_BREAK):
350: /* Which scope is broken? */
1.24 kristaps 351: fmt = "scope: macro `%s' breaks prior explicit scope";
352: break;
353: case (ERR_SCOPE_NOCTX):
354: fmt = "scope: closure macro `%s' has no context";
1.21 kristaps 355: break;
1.25 kristaps 356: case (ERR_SCOPE_NONEST):
1.26 kristaps 357: fmt = "scope: macro `%s' may not be nested in the current context";
1.25 kristaps 358: break;
1.21 kristaps 359: case (ERR_MACRO_NOTSUP):
360: fmt = "macro `%s' not supported";
361: break;
362: case (ERR_MACRO_NOTCALL):
363: fmt = "macro `%s' not callable";
364: break;
1.23 kristaps 365: case (ERR_SEC_PROLOGUE):
366: fmt = "macro `%s' cannot be called in the prologue";
367: break;
368: case (ERR_SEC_NPROLOGUE):
369: fmt = "macro `%s' called outside of prologue";
370: break;
1.28 kristaps 371: case (ERR_ARGS_EQ0):
372: fmt = "macro `%s' expects zero arguments";
373: break;
1.29 kristaps 374: case (ERR_ARGS_EQ1):
375: fmt = "macro `%s' expects one argument";
376: break;
1.21 kristaps 377: case (ERR_ARGS_GE1):
378: fmt = "macro `%s' expects one or more arguments";
379: break;
1.28 kristaps 380: case (ERR_ARGS_LE2):
381: fmt = "macro `%s' expects two or fewer arguments";
382: break;
1.23 kristaps 383: case (ERR_ARGS_MANY):
384: fmt = "macro `%s' has too many arguments";
385: break;
386: case (ERR_SEC_PROLOGUE_OO):
387: fmt = "prologue macro `%s' is out-of-order";
388: break;
389: case (ERR_SEC_PROLOGUE_REP):
390: fmt = "prologue macro `%s' repeated";
391: break;
392: case (ERR_SEC_NAME):
393: lit = "`NAME' section must be first";
394: break;
1.24 kristaps 395: case (ERR_SYNTAX_ARGVAL):
396: lit = "syntax: expected value for macro argument";
397: break;
1.25 kristaps 398: case (ERR_SYNTAX_ARGBAD):
399: lit = "syntax: invalid value for macro argument";
400: break;
1.24 kristaps 401: case (ERR_SYNTAX_ARGMANY):
402: lit = "syntax: too many values for macro argument";
403: break;
1.32 kristaps 404: case (ERR_SYNTAX_CHILDHEAD):
405: lit = "syntax: expected only block-header section";
406: break;
407: case (ERR_SYNTAX_CHILDBODY):
408: lit = "syntax: expected only a block-body section";
409: break;
410: case (ERR_SYNTAX_EMPTYHEAD):
411: lit = "syntax: block-header section may not be empty";
412: break;
413: case (ERR_SYNTAX_EMPTYBODY):
414: lit = "syntax: block-body section may not be empty";
1.31 kristaps 415: break;
1.21 kristaps 416: default:
417: abort();
418: /* NOTREACHED */
419: }
420:
421: if (fmt) {
422: (void)fprintf(stderr, "%s:%d: error: ",
423: p->name, p->lnn);
424: (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
425: } else
426: (void)fprintf(stderr, "%s:%d: error: %s",
427: p->name, p->lnn, lit);
428:
429: if (p->dbg < 1) {
1.23 kristaps 430: if (-1 != col)
431: (void)fprintf(stderr, " (column %d)\n", col);
432: return(0);
433: } else if (-1 == col) {
434: (void)fprintf(stderr, "\nFrom: %s", p->line);
1.21 kristaps 435: return(0);
436: }
437:
438: (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
439: for (i = 0; i < col; i++)
440: (void)fprintf(stderr, " ");
441: (void)fprintf(stderr, "^\n");
442:
443: return(0);
444: }
445:
446:
447: static void
448: msg_msg(void *arg, int col, const char *msg)
1.4 kristaps 449: {
1.21 kristaps 450: struct md_parse *p;
451: int i;
452:
453: p = (struct md_parse *)arg;
454:
455: if (p->dbg < 2)
456: return;
457:
458: (void)printf("%s:%d: %s", p->name, p->lnn, msg);
459:
460: if (p->dbg < 3) {
1.23 kristaps 461: if (-1 != col)
462: (void)printf(" (column %d)\n", col);
463: return;
464: } else if (-1 == col) {
465: (void)printf("\nFrom %s\n", p->line);
1.21 kristaps 466: return;
467: }
468:
469: (void)printf("\nFrom: %s\n ", p->line);
470: for (i = 0; i < col; i++)
471: (void)printf(" ");
472: (void)printf("^\n");
1.1 kristaps 473: }
474:
475:
476: static int
1.21 kristaps 477: msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
1.1 kristaps 478: {
1.21 kristaps 479: char *fmt, *lit;
480: struct md_parse *p;
481: int i;
482: extern char *__progname;
1.1 kristaps 483:
1.21 kristaps 484: p = (struct md_parse *)arg;
1.1 kristaps 485:
1.21 kristaps 486: if ( ! (p->warn & MD_WARN_ALL))
1.1 kristaps 487: return(1);
1.21 kristaps 488:
489: fmt = lit = NULL;
490:
491: switch (type) {
492: case (WARN_SYNTAX_WS_EOLN):
493: lit = "syntax: whitespace at end-of-line";
494: break;
1.25 kristaps 495: case (WARN_SYNTAX_QUOTED):
496: lit = "syntax: quotation mark starting string";
497: break;
1.21 kristaps 498: case (WARN_SYNTAX_MACLIKE):
499: lit = "syntax: macro-like argument";
500: break;
1.24 kristaps 501: case (WARN_SYNTAX_ARGLIKE):
502: lit = "syntax: argument-like value";
503: break;
1.32 kristaps 504: case (WARN_SYNTAX_EMPTYBODY):
505: lit = "syntax: empty block-body section";
506: break;
1.23 kristaps 507: case (WARN_SEC_OO):
508: lit = "section is out of conventional order";
509: break;
1.21 kristaps 510: case (WARN_ARGS_GE1):
511: fmt = "macro `%s' suggests one or more arguments";
512: break;
1.25 kristaps 513: case (WARN_ARGS_EQ0):
514: fmt = "macro `%s' suggests zero arguments";
515: break;
516: case (WARN_IGN_AFTER_BLK):
517: fmt = "ignore: macro `%s' ignored after block macro";
518: break;
1.30 kristaps 519: case (WARN_IGN_OBSOLETE):
520: fmt = "ignore: macro `%s' is obsolete";
521: break;
1.25 kristaps 522: case (WARN_IGN_BEFORE_BLK):
523: fmt = "ignore: macro before block macro `%s' ignored";
524: break;
1.27 kristaps 525: case (WARN_COMPAT_TROFF):
526: fmt = "compat: macro `%s' behaves differently in troff and nroff";
527: break;
1.21 kristaps 528: default:
529: abort();
530: /* NOTREACHED */
1.1 kristaps 531: }
532:
1.21 kristaps 533: if (fmt) {
534: (void)fprintf(stderr, "%s:%d: warning: ",
535: p->name, p->lnn);
536: (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
537: } else
538: (void)fprintf(stderr, "%s:%d: warning: %s",
539: p->name, p->lnn, lit);
540:
541: if (p->dbg >= 1) {
542: (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
543: for (i = 0; i < col; i++)
544: (void)fprintf(stderr, " ");
545: (void)fprintf(stderr, "^\n");
546: } else
547: (void)fprintf(stderr, " (column %d)\n", col);
548:
549: if (p->warn & MD_WARN_ERR) {
550: (void)fprintf(stderr, "%s: considering warnings as "
551: "errors\n", __progname);
552: return(0);
1.1 kristaps 553: }
554:
1.21 kristaps 555: return(1);
1.1 kristaps 556: }
557:
558:
559: static void
560: usage(void)
561: {
562: extern char *__progname;
563:
1.21 kristaps 564: (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19 kristaps 565: __progname);
1.1 kristaps 566: }
1.18 kristaps 567:
CVSweb