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