Annotation of mandoc/mdocml.c, Revision 1.45
1.45 ! kristaps 1: /* $Id: mdocml.c,v 1.44 2009/01/15 17:38:57 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.44 kristaps 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. */
1.2 kristaps 38:
1.21 kristaps 39: struct md_parse {
1.44 kristaps 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. */
1.21 kristaps 51: };
1.17 kristaps 52:
1.44 kristaps 53: extern char *__progname;
54:
1.9 kristaps 55: static void usage(void);
56:
1.21 kristaps 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:
1.37 kristaps 64: static void msg_msg(void *, int, int, const char *);
1.44 kristaps 65: static int msg_err(void *, int, int, const char *);
66: static int msg_warn(void *, int, int,
67: enum mdoc_warn, const char *);
1.1 kristaps 68:
1.19 kristaps 69: #ifdef __linux__
70: extern int getsubopt(char **, char *const *, char **);
71: #endif
72:
1.1 kristaps 73: int
74: main(int argc, char *argv[])
75: {
76: int c;
1.21 kristaps 77: struct md_parse parser;
78: char *opts, *v;
1.18 kristaps 79: #define ALL 0
1.44 kristaps 80: #define COMPAT 1
81: #define SYNTAX 2
82: #define ERROR 3
83: char *toks[] = { "all", "compat", "syntax",
84: "error", NULL };
1.1 kristaps 85:
86: extern char *optarg;
87: extern int optind;
88:
1.21 kristaps 89: (void)memset(&parser, 0, sizeof(struct md_parse));
1.17 kristaps 90:
1.21 kristaps 91: while (-1 != (c = getopt(argc, argv, "vW:")))
1.1 kristaps 92: switch (c) {
1.13 kristaps 93: case ('v'):
1.21 kristaps 94: parser.dbg++;
1.13 kristaps 95: break;
96: case ('W'):
1.18 kristaps 97: opts = optarg;
98: while (*opts)
99: switch (getsubopt(&opts, toks, &v)) {
100: case (ALL):
1.21 kristaps 101: parser.warn |= MD_WARN_ALL;
1.18 kristaps 102: break;
1.44 kristaps 103: case (COMPAT):
104: parser.warn |= MD_WARN_COMPAT;
105: break;
106: case (SYNTAX):
107: parser.warn |= MD_WARN_SYNTAX;
108: break;
1.18 kristaps 109: case (ERROR):
1.21 kristaps 110: parser.warn |= MD_WARN_ERR;
1.18 kristaps 111: break;
112: default:
113: usage();
114: return(1);
115: }
1.13 kristaps 116: break;
1.1 kristaps 117: default:
118: usage();
119: return(1);
120: }
121:
122: argv += optind;
1.4 kristaps 123: argc -= optind;
1.1 kristaps 124:
1.21 kristaps 125: parser.name = "-";
1.4 kristaps 126: if (1 == argc)
1.21 kristaps 127: parser.name = *argv++;
128:
129: if ( ! io_begin(&parser))
130: return(EXIT_FAILURE);
1.1 kristaps 131:
1.21 kristaps 132: return(EXIT_SUCCESS);
1.1 kristaps 133: }
134:
135:
136: static int
1.21 kristaps 137: io_leave(struct md_parse *p, int code)
1.1 kristaps 138: {
139:
1.21 kristaps 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;
1.4 kristaps 146: }
1.21 kristaps 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: }
1.1 kristaps 161:
1.21 kristaps 162: return(io_leave(p, buf_begin(p)));
1.1 kristaps 163: }
164:
165:
166: static int
1.21 kristaps 167: buf_leave(struct md_parse *p, int code)
1.1 kristaps 168: {
1.4 kristaps 169:
1.21 kristaps 170: if (p->buf)
171: free(p->buf);
172: return(code);
173: }
1.1 kristaps 174:
175:
1.21 kristaps 176: static int
177: buf_begin(struct md_parse *p)
178: {
179: struct stat st;
1.1 kristaps 180:
1.21 kristaps 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: {
1.26 kristaps 200: const char *p, *t;
201: int i, j;
202: size_t argc, sz;
203: char **params;
204: struct mdoc_arg *argv;
1.24 kristaps 205:
206: argv = NULL;
1.44 kristaps 207: argc = sz = 0;
1.26 kristaps 208: params = NULL;
1.21 kristaps 209:
1.42 kristaps 210: t = mdoc_type2a(n->type);
211:
1.21 kristaps 212: switch (n->type) {
213: case (MDOC_TEXT):
1.25 kristaps 214: p = n->data.text.string;
1.21 kristaps 215: break;
216: case (MDOC_BODY):
1.40 kristaps 217: p = mdoc_macronames[n->tok];
1.21 kristaps 218: break;
219: case (MDOC_HEAD):
1.40 kristaps 220: p = mdoc_macronames[n->tok];
1.21 kristaps 221: break;
1.34 kristaps 222: case (MDOC_TAIL):
1.40 kristaps 223: p = mdoc_macronames[n->tok];
1.34 kristaps 224: break;
1.21 kristaps 225: case (MDOC_ELEM):
1.40 kristaps 226: p = mdoc_macronames[n->tok];
1.24 kristaps 227: argv = n->data.elem.argv;
228: argc = n->data.elem.argc;
1.21 kristaps 229: break;
230: case (MDOC_BLOCK):
1.40 kristaps 231: p = mdoc_macronames[n->tok];
1.24 kristaps 232: argv = n->data.block.argv;
233: argc = n->data.block.argc;
1.21 kristaps 234: break;
1.38 kristaps 235: case (MDOC_ROOT):
236: p = "root";
237: break;
1.22 kristaps 238: default:
239: abort();
240: /* NOTREACHED */
1.21 kristaps 241: }
242:
243: for (i = 0; i < indent; i++)
1.44 kristaps 244: xprintf(" ");
245: xprintf("%s (%s)", p, t);
1.24 kristaps 246:
247: for (i = 0; i < (int)argc; i++) {
1.44 kristaps 248: xprintf(" -%s", mdoc_argnames[argv[i].arg]);
1.42 kristaps 249: if (argv[i].sz > 0)
1.44 kristaps 250: xprintf(" [");
1.24 kristaps 251: for (j = 0; j < (int)argv[i].sz; j++)
1.44 kristaps 252: xprintf(" [%s]", argv[i].value[j]);
1.42 kristaps 253: if (argv[i].sz > 0)
1.44 kristaps 254: xprintf(" ]");
1.24 kristaps 255: }
256:
1.26 kristaps 257: for (i = 0; i < (int)sz; i++)
1.44 kristaps 258: xprintf(" [%s]", params[i]);
1.26 kristaps 259:
1.44 kristaps 260: xprintf(" %d:%d\n", n->line, n->pos);
1.21 kristaps 261:
262: if (n->child)
263: print_node(n->child, indent + 1);
264: if (n->next)
265: print_node(n->next, indent);
266: }
1.1 kristaps 267:
268:
1.21 kristaps 269: static int
270: parse_leave(struct md_parse *p, int code)
271: {
272: const struct mdoc_node *n;
273:
1.36 kristaps 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:
1.38 kristaps 282: mdoc_free(p->mdoc);
283:
1.21 kristaps 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;
1.44 kristaps 293: char line[MD_LINE_SZ];
1.21 kristaps 294: struct mdoc_cb cb;
1.43 kristaps 295: int lnn;
1.21 kristaps 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:
1.43 kristaps 304: for (lnn = 1, pos = 0; ; ) {
1.21 kristaps 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)) {
1.44 kristaps 314: line[(int)pos++] = p->buf[(int)i];
1.21 kristaps 315: continue;
316: }
317: warnx("%s: line %d too long",
1.43 kristaps 318: p->name, lnn);
1.21 kristaps 319: return(parse_leave(p, 0));
320: }
321:
1.44 kristaps 322: line[(int)pos] = 0;
1.43 kristaps 323: if ( ! mdoc_parseln(p->mdoc, lnn, line))
1.21 kristaps 324: return(parse_leave(p, 0));
1.1 kristaps 325:
1.43 kristaps 326: lnn++;
1.21 kristaps 327: pos = 0;
1.4 kristaps 328: }
1.21 kristaps 329: }
1.1 kristaps 330:
1.21 kristaps 331: return(parse_leave(p, 1));
1.4 kristaps 332: }
1.1 kristaps 333:
334:
1.4 kristaps 335: static int
1.44 kristaps 336: msg_err(void *arg, int line, int col, const char *msg)
1.21 kristaps 337: {
338: struct md_parse *p;
339:
340: p = (struct md_parse *)arg;
341:
1.45 ! kristaps 342: xfprintf(stderr, "%s:%d: error: %s (column %d)\n",
1.44 kristaps 343: p->name, line, msg, col);
1.21 kristaps 344: return(0);
345: }
346:
347:
348: static void
1.37 kristaps 349: msg_msg(void *arg, int line, int col, const char *msg)
1.4 kristaps 350: {
1.21 kristaps 351: struct md_parse *p;
352:
353: p = (struct md_parse *)arg;
354:
1.44 kristaps 355: if (0 == p->dbg)
1.21 kristaps 356: return;
357:
1.45 ! kristaps 358: xfprintf(stderr, "%s:%d: debug: %s (column %d)\n",
1.39 kristaps 359: p->name, line, msg, col);
1.1 kristaps 360: }
361:
362:
363: static int
1.44 kristaps 364: msg_warn(void *arg, int line, int col,
365: enum mdoc_warn type, const char *msg)
1.1 kristaps 366: {
1.21 kristaps 367: struct md_parse *p;
1.1 kristaps 368:
1.21 kristaps 369: p = (struct md_parse *)arg;
1.1 kristaps 370:
1.44 kristaps 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;
1.1 kristaps 379: return(1);
380: }
381:
1.44 kristaps 382: xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
383: p->name, line, msg, col);
1.21 kristaps 384:
1.44 kristaps 385: if ( ! (p->warn & MD_WARN_ERR))
386: return(1);
1.21 kristaps 387:
1.44 kristaps 388: xfprintf(stderr, "%s: considering warnings as errors\n",
389: __progname);
390: return(0);
1.1 kristaps 391: }
392:
393:
394: static void
395: usage(void)
396: {
397:
1.44 kristaps 398: xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19 kristaps 399: __progname);
1.1 kristaps 400: }
1.18 kristaps 401:
CVSweb