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