Annotation of mandoc/mdocml.c, Revision 1.48
1.48 ! kristaps 1: /* $Id: mdocml.c,v 1.47 2009/01/16 15:58:50 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:
35: #define MD_LINE_SZ (256) /* Max input line size. */
1.2 kristaps 36:
1.48 ! kristaps 37: /*
! 38: * Put this into a mdoctrans.h, which has:
! 39: *
! 40: * struct mdoc_trans; (opaque)
! 41: *
! 42: * struct mdoc_trans *mdoc_trans_alloc(const char *filter);
! 43: *
! 44: * mdoc_trans_free(struct mdoc_trans *);
! 45: *
! 46: * int mdoc_trans_getopt(struct mdoc_trans *, char *);
! 47: *
! 48: * int mdoc_trans_print(struct mdoc_trans *, const struct mdoc_node *);
! 49: */
! 50:
! 51: typedef int (*mdocprint)(const struct mdoc_node *);
! 52:
1.47 kristaps 53:
1.21 kristaps 54: struct md_parse {
1.47 kristaps 55: int warn; /* Warning flags. */
56: #define MD_WARN_SYNTAX (1 << 0) /* Show syntax warnings. */
57: #define MD_WARN_COMPAT (1 << 1) /* Show compat warnings. */
58: #define MD_WARN_ALL (0x03) /* Show all warnings. */
59: #define MD_WARN_ERR (1 << 2) /* Make warnings->errors. */
60: int dbg; /* Debug level. */
61: struct mdoc *mdoc; /* Active parser. */
62: char *buf; /* Input buffer. */
63: u_long bufsz; /* Input buffer size. */
64: char *name; /* Input file name. */
65: int fd; /* Input file desc. */
1.48 ! kristaps 66: mdocprint print; /* Node-print function. */
1.21 kristaps 67: };
1.17 kristaps 68:
1.47 kristaps 69: extern char *__progname;
70:
1.48 ! kristaps 71: extern int treeprint(const struct mdoc_node *);
1.44 kristaps 72:
1.47 kristaps 73: static void usage(void);
1.9 kristaps 74:
1.47 kristaps 75: static int parse_begin(struct md_parse *);
76: static int parse_leave(struct md_parse *, int);
77: static int io_begin(struct md_parse *);
78: static int io_leave(struct md_parse *, int);
79: static int buf_begin(struct md_parse *);
80: static int buf_leave(struct md_parse *, int);
81:
82: static void msg_msg(void *, int, int, const char *);
83: static int msg_err(void *, int, int, const char *);
84: static int msg_warn(void *, int, int,
1.44 kristaps 85: enum mdoc_warn, const char *);
1.1 kristaps 86:
1.19 kristaps 87: #ifdef __linux__
1.47 kristaps 88: extern int getsubopt(char **, char *const *, char **);
1.19 kristaps 89: #endif
90:
1.1 kristaps 91: int
92: main(int argc, char *argv[])
93: {
94: int c;
1.21 kristaps 95: struct md_parse parser;
1.48 ! kristaps 96: char *opts, *v, *filter;
1.18 kristaps 97: #define ALL 0
1.44 kristaps 98: #define COMPAT 1
99: #define SYNTAX 2
100: #define ERROR 3
101: char *toks[] = { "all", "compat", "syntax",
102: "error", NULL };
1.1 kristaps 103:
104: extern char *optarg;
105: extern int optind;
106:
1.48 ! kristaps 107: filter = NULL;
1.47 kristaps 108:
1.21 kristaps 109: (void)memset(&parser, 0, sizeof(struct md_parse));
1.17 kristaps 110:
1.48 ! kristaps 111: while (-1 != (c = getopt(argc, argv, "f:vW:")))
1.1 kristaps 112: switch (c) {
1.47 kristaps 113: case ('f'):
114: filter = optarg;
115: break;
1.13 kristaps 116: case ('v'):
1.21 kristaps 117: parser.dbg++;
1.13 kristaps 118: break;
119: case ('W'):
1.18 kristaps 120: opts = optarg;
121: while (*opts)
122: switch (getsubopt(&opts, toks, &v)) {
123: case (ALL):
1.21 kristaps 124: parser.warn |= MD_WARN_ALL;
1.18 kristaps 125: break;
1.44 kristaps 126: case (COMPAT):
127: parser.warn |= MD_WARN_COMPAT;
128: break;
129: case (SYNTAX):
130: parser.warn |= MD_WARN_SYNTAX;
131: break;
1.18 kristaps 132: case (ERROR):
1.21 kristaps 133: parser.warn |= MD_WARN_ERR;
1.18 kristaps 134: break;
135: default:
136: usage();
137: return(1);
138: }
1.13 kristaps 139: break;
1.1 kristaps 140: default:
141: usage();
142: return(1);
143: }
144:
145: argv += optind;
1.4 kristaps 146: argc -= optind;
1.1 kristaps 147:
1.21 kristaps 148: parser.name = "-";
1.4 kristaps 149: if (1 == argc)
1.21 kristaps 150: parser.name = *argv++;
151:
1.48 ! kristaps 152: if (filter) {
! 153: if (0 == strcmp(filter, "tree"))
! 154: parser.print = treeprint;
! 155: }
! 156:
1.21 kristaps 157: if ( ! io_begin(&parser))
158: return(EXIT_FAILURE);
1.1 kristaps 159:
1.21 kristaps 160: return(EXIT_SUCCESS);
1.1 kristaps 161: }
162:
163:
164: static int
1.21 kristaps 165: io_leave(struct md_parse *p, int code)
1.1 kristaps 166: {
167:
1.21 kristaps 168: if (-1 == p->fd || STDIN_FILENO == p->fd)
169: return(code);
170:
171: if (-1 == close(p->fd)) {
172: warn("%s", p->name);
173: code = 0;
1.4 kristaps 174: }
1.21 kristaps 175: return(code);
176: }
177:
178:
179: static int
180: io_begin(struct md_parse *p)
181: {
182:
183: p->fd = STDIN_FILENO;
184: if (0 != strncmp(p->name, "-", 1))
185: if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
186: warn("%s", p->name);
187: return(io_leave(p, 0));
188: }
1.1 kristaps 189:
1.21 kristaps 190: return(io_leave(p, buf_begin(p)));
1.1 kristaps 191: }
192:
193:
194: static int
1.21 kristaps 195: buf_leave(struct md_parse *p, int code)
1.1 kristaps 196: {
1.4 kristaps 197:
1.21 kristaps 198: if (p->buf)
199: free(p->buf);
200: return(code);
201: }
1.1 kristaps 202:
203:
1.21 kristaps 204: static int
205: buf_begin(struct md_parse *p)
206: {
207: struct stat st;
1.1 kristaps 208:
1.21 kristaps 209: if (-1 == fstat(p->fd, &st)) {
210: warn("%s", p->name);
211: return(1);
212: }
213:
214: p->bufsz = MAX(st.st_blksize, BUFSIZ);
215:
216: if (NULL == (p->buf = malloc(p->bufsz))) {
217: warn("malloc");
218: return(buf_leave(p, 0));
219: }
220:
221: return(buf_leave(p, parse_begin(p)));
222: }
223:
224:
225: static int
226: parse_leave(struct md_parse *p, int code)
227: {
228: const struct mdoc_node *n;
229:
1.36 kristaps 230: if (NULL == p->mdoc)
231: return(code);
232:
233: if ( ! mdoc_endparse(p->mdoc))
234: code = 0;
1.48 ! kristaps 235: if (p->print && (n = mdoc_result(p->mdoc)))
! 236: (*p->print)(n);
1.36 kristaps 237:
1.38 kristaps 238: mdoc_free(p->mdoc);
239:
1.21 kristaps 240: return(code);
241: }
242:
243:
244: static int
245: parse_begin(struct md_parse *p)
246: {
247: ssize_t sz, i;
248: size_t pos;
1.44 kristaps 249: char line[MD_LINE_SZ];
1.21 kristaps 250: struct mdoc_cb cb;
1.43 kristaps 251: int lnn;
1.21 kristaps 252:
253: cb.mdoc_err = msg_err;
254: cb.mdoc_warn = msg_warn;
255: cb.mdoc_msg = msg_msg;
256:
257: if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
258: return(parse_leave(p, 0));
259:
1.43 kristaps 260: for (lnn = 1, pos = 0; ; ) {
1.21 kristaps 261: if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
262: warn("%s", p->name);
263: return(parse_leave(p, 0));
264: } else if (0 == sz)
265: break;
266:
267: for (i = 0; i < sz; i++) {
268: if ('\n' != p->buf[i]) {
269: if (pos < sizeof(line)) {
1.44 kristaps 270: line[(int)pos++] = p->buf[(int)i];
1.21 kristaps 271: continue;
272: }
273: warnx("%s: line %d too long",
1.43 kristaps 274: p->name, lnn);
1.21 kristaps 275: return(parse_leave(p, 0));
276: }
277:
1.44 kristaps 278: line[(int)pos] = 0;
1.43 kristaps 279: if ( ! mdoc_parseln(p->mdoc, lnn, line))
1.21 kristaps 280: return(parse_leave(p, 0));
1.1 kristaps 281:
1.43 kristaps 282: lnn++;
1.21 kristaps 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.44 kristaps 292: msg_err(void *arg, int line, int col, const char *msg)
1.21 kristaps 293: {
294: struct md_parse *p;
295:
296: p = (struct md_parse *)arg;
297:
1.45 kristaps 298: xfprintf(stderr, "%s:%d: error: %s (column %d)\n",
1.44 kristaps 299: p->name, line, msg, col);
1.21 kristaps 300: return(0);
301: }
302:
303:
304: static void
1.37 kristaps 305: msg_msg(void *arg, int line, int col, const char *msg)
1.4 kristaps 306: {
1.21 kristaps 307: struct md_parse *p;
308:
309: p = (struct md_parse *)arg;
310:
1.44 kristaps 311: if (0 == p->dbg)
1.21 kristaps 312: return;
313:
1.45 kristaps 314: xfprintf(stderr, "%s:%d: debug: %s (column %d)\n",
1.39 kristaps 315: p->name, line, msg, col);
1.1 kristaps 316: }
317:
318:
319: static int
1.44 kristaps 320: msg_warn(void *arg, int line, int col,
321: enum mdoc_warn type, const char *msg)
1.1 kristaps 322: {
1.21 kristaps 323: struct md_parse *p;
1.1 kristaps 324:
1.21 kristaps 325: p = (struct md_parse *)arg;
1.1 kristaps 326:
1.44 kristaps 327: switch (type) {
328: case (WARN_COMPAT):
329: if (p->warn & MD_WARN_COMPAT)
330: break;
331: return(1);
332: case (WARN_SYNTAX):
333: if (p->warn & MD_WARN_SYNTAX)
334: break;
1.1 kristaps 335: return(1);
336: }
337:
1.44 kristaps 338: xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
339: p->name, line, msg, col);
1.21 kristaps 340:
1.44 kristaps 341: if ( ! (p->warn & MD_WARN_ERR))
342: return(1);
1.21 kristaps 343:
1.44 kristaps 344: xfprintf(stderr, "%s: considering warnings as errors\n",
345: __progname);
346: return(0);
1.1 kristaps 347: }
348:
349:
350: static void
351: usage(void)
352: {
353:
1.47 kristaps 354: xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [-ffilter] "
1.48 ! kristaps 355: "[infile]\n", __progname);
1.1 kristaps 356: }
1.18 kristaps 357:
CVSweb