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