Annotation of mandoc/mmain.c, Revision 1.9
1.9 ! kristaps 1: /* $Id: mmain.c,v 1.8 2009/03/08 18:50:40 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: */
19: #include <sys/stat.h>
20: #include <sys/param.h>
21:
22: #include <assert.h>
23: #include <fcntl.h>
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:
31: #include "mmain.h"
32:
1.8 kristaps 33: #define MD_LINE_SZ (256) /* Input line step-size. */
1.1 kristaps 34:
35: struct mmain {
36: int warn; /* Warning flags. */
37: #define MD_WARN_SYNTAX (1 << 0) /* Show syntax warnings. */
38: #define MD_WARN_COMPAT (1 << 1) /* Show compat warnings. */
39: #define MD_WARN_ALL (0x03) /* Show all warnings. */
40: #define MD_WARN_ERR (1 << 2) /* Make warnings->errors. */
41: int dbg; /* Debug level. */
42: struct mdoc *mdoc; /* Active parser. */
43: char *buf; /* Input buffer. */
1.9 ! kristaps 44: size_t bufsz; /* Input buffer size. */
1.2 kristaps 45: char *in; /* Input file name. */
1.1 kristaps 46: int fdin; /* Input file desc. */
1.6 kristaps 47: int pflags; /* Parse flags. */
1.1 kristaps 48: };
49:
50: extern char *__progname;
51:
1.6 kristaps 52: static int optswarn(struct mmain *, char *);
53: static int optsopt(struct mmain *, char *);
1.1 kristaps 54: static int parse(struct mmain *);
55: static void msg_msg(void *, int, int, const char *);
56: static int msg_err(void *, int, int, const char *);
57: static int msg_warn(void *, int, int,
58: enum mdoc_warn, const char *);
59:
60: #ifdef __linux__
61: extern int getsubopt(char **, char *const *, char **);
1.3 kristaps 62: extern size_t strlcpy(char *, const char *, size_t);
63: extern size_t strlcat(char *, const char *, size_t);
1.1 kristaps 64: #endif
65:
66:
1.2 kristaps 67: /*
68: * Print our and our caller's usage message.
69: */
1.1 kristaps 70: void
71: mmain_usage(const char *help)
72: {
73:
1.7 kristaps 74: warnx("usage: %s %s%s[-v] [-foption...] [-Wwarn...] [infile]", __progname,
1.1 kristaps 75: help ? help : "", help ? " " : "");
76: }
77:
78:
1.2 kristaps 79: /*
80: * Allocate the convenience library and initialise some values.
81: */
1.1 kristaps 82: struct mmain *
83: mmain_alloc(void)
84: {
85: struct mmain *p;
86:
87: if (NULL == (p = calloc(1, sizeof(struct mmain))))
88: err(1, "malloc");
89:
1.2 kristaps 90: p->in = "-";
1.1 kristaps 91: p->fdin = STDIN_FILENO;
92:
93: return(p);
94: }
95:
96:
1.2 kristaps 97: /*
98: * Parse command-line options. Accepts a small (<28 char) opstring "u"
99: * parameter (e.g. "ho:") or NULL, a corresponding "help" string (e.g.
100: * "[-h] [-o output]" or NULL, a callback function for parsed arguments
101: * and an opaque pointer argument for that function.
102: */
1.1 kristaps 103: int
1.2 kristaps 104: mmain_getopt(struct mmain *p, int argc, char *argv[],
105: const char *help, const char *u, void *arg,
106: int (*getopt_cb)(void *, int, const char *))
1.1 kristaps 107: {
1.2 kristaps 108: int c;
109: char opts[32]; /* XXX */
110: size_t sz;
111:
112: extern int optind;
1.1 kristaps 113:
1.6 kristaps 114: sz = strlcpy(opts, "VvW:f:", 32);
1.2 kristaps 115: assert(sz < 32);
1.1 kristaps 116:
1.2 kristaps 117: if (u) {
118: sz = strlcat(opts, u, 32);
119: assert(sz < 32);
120: }
1.1 kristaps 121:
1.3 kristaps 122: optind = 1;
123:
1.2 kristaps 124: /* LINTED */
125: while (-1 != (c = getopt(argc, argv, opts)))
1.1 kristaps 126: switch (c) {
1.6 kristaps 127: case ('f'):
128: if ( ! optsopt(p, optarg))
129: return(-1);
130: break;
1.1 kristaps 131: case ('v'):
132: p->dbg++;
133: break;
1.5 kristaps 134: case ('V'):
135: (void)printf("%s %s\n", __progname, VERSION);
136: return(0);
1.1 kristaps 137: case ('W'):
1.6 kristaps 138: if ( ! optswarn(p, optarg))
1.5 kristaps 139: return(-1);
1.1 kristaps 140: break;
141: case ('?'):
1.2 kristaps 142: mmain_usage(help);
1.5 kristaps 143: return(-1);
1.1 kristaps 144: default:
1.2 kristaps 145: assert(getopt_cb);
146: if ((*getopt_cb)(arg, c, optarg))
147: break;
1.5 kristaps 148: return(-1);
1.1 kristaps 149: }
150:
151: argv += optind;
1.2 kristaps 152: if ((argc -= optind) > 0)
153: p->in = *argv++;
1.1 kristaps 154:
1.2 kristaps 155: return(1);
1.1 kristaps 156: }
157:
158:
1.4 kristaps 159: dead_pre void
160: mmain_exit(struct mmain *p, int code)
1.1 kristaps 161: {
162:
163: if (p->mdoc)
164: mdoc_free(p->mdoc);
165: free(p);
166: exit(code);
167: }
168:
169:
170: struct mdoc *
171: mmain_mdoc(struct mmain *p)
172: {
173: struct stat st;
174: int c;
175: struct mdoc_cb cb;
176:
177: cb.mdoc_err = msg_err;
178: cb.mdoc_warn = msg_warn;
179: cb.mdoc_msg = msg_msg;
180:
181: if (0 != strcmp(p->in, "-"))
182: if (-1 == (p->fdin = open(p->in, O_RDONLY, 0))) {
183: warn("%s", p->in);
184: return(0);
185: }
186:
187: /* Allocate a buffer to be BUFSIZ/block size. */
188:
189: if (-1 == fstat(p->fdin, &st)) {
190: warn("%s", p->in);
191: p->bufsz = BUFSIZ;
192: } else
1.9 ! kristaps 193: p->bufsz = (size_t)MAX(st.st_blksize, BUFSIZ);
1.1 kristaps 194:
195: p->buf = malloc(p->bufsz);
196: if (NULL == p->buf)
197: err(1, "malloc");
198:
199: /* Allocate the parser. */
200:
1.7 kristaps 201: p->mdoc = mdoc_alloc(p, p->pflags, &cb);
1.1 kristaps 202:
203: /* Parse the input file. */
204:
205: c = parse(p);
206: free(p->buf);
207:
208: if (STDIN_FILENO != p->fdin)
209: if (-1 == close(p->fdin))
210: warn("%s", p->in);
211:
212: return(c ? p->mdoc : NULL);
213: }
214:
215:
216: static int
1.6 kristaps 217: optsopt(struct mmain *p, char *arg)
218: {
219: char *v;
1.7 kristaps 220: char *toks[] = { "ign-scope", "ign-escape", NULL };
1.6 kristaps 221:
222: while (*arg)
223: switch (getsubopt(&arg, toks, &v)) {
224: case (0):
225: p->pflags |= MDOC_IGN_SCOPE;
226: break;
1.7 kristaps 227: case (1):
228: p->pflags |= MDOC_IGN_ESCAPE;
229: break;
1.6 kristaps 230: default:
1.7 kristaps 231: /* FIXME: report? */
1.6 kristaps 232: return(0);
233: }
234:
235: return(1);
236: }
237:
238:
239: static int
240: optswarn(struct mmain *p, char *arg)
1.1 kristaps 241: {
242: char *v;
243: char *toks[] = { "all", "compat",
244: "syntax", "error", NULL };
245:
246: while (*arg)
247: switch (getsubopt(&arg, toks, &v)) {
248: case (0):
249: p->warn |= MD_WARN_ALL;
250: break;
251: case (1):
252: p->warn |= MD_WARN_COMPAT;
253: break;
254: case (2):
255: p->warn |= MD_WARN_SYNTAX;
256: break;
257: case (3):
258: p->warn |= MD_WARN_ERR;
259: break;
260: default:
1.7 kristaps 261: /* FIXME: report? */
1.1 kristaps 262: return(0);
263: }
264:
265: return(1);
266: }
267:
268:
269: static int
270: parse(struct mmain *p)
271: {
1.8 kristaps 272: ssize_t sz;
273: int i, pos, len, lnn;
274: char *line;
1.1 kristaps 275:
1.8 kristaps 276: for (line = NULL, lnn = 1, len = pos = 0; ; ) {
1.1 kristaps 277: if (-1 == (sz = read(p->fdin, p->buf, p->bufsz))) {
278: warn("%s", p->in);
279: return(0);
280: } else if (0 == sz)
281: break;
282:
1.8 kristaps 283: for (i = 0; i < (int)sz; i++) {
284: if (pos >= len) {
285: len += MD_LINE_SZ;
1.9 ! kristaps 286: line = realloc(line, (size_t)len);
1.8 kristaps 287: if (NULL == line)
288: err(1, "realloc");
289: }
290:
1.1 kristaps 291: if ('\n' != p->buf[i]) {
1.8 kristaps 292: line[pos++] = p->buf[i];
293: continue;
1.1 kristaps 294: }
1.8 kristaps 295:
296: line[pos] = 0;
1.1 kristaps 297: if ( ! mdoc_parseln(p->mdoc, lnn, line))
298: return(0);
299:
300: lnn++;
301: pos = 0;
302: }
303: }
304:
1.8 kristaps 305: if (line)
306: free(line);
1.1 kristaps 307: return(mdoc_endparse(p->mdoc));
308: }
309:
310:
311: static int
312: msg_err(void *arg, int line, int col, const char *msg)
313: {
314: struct mmain *p;
315:
316: p = (struct mmain *)arg;
317:
318: warnx("%s:%d: error: %s (column %d)",
319: p->in, line, msg, col);
320: return(0);
321: }
322:
323:
324: static void
325: msg_msg(void *arg, int line, int col, const char *msg)
326: {
327: struct mmain *p;
328:
329: p = (struct mmain *)arg;
330:
331: if (0 == p->dbg)
332: return;
333:
334: warnx("%s:%d: debug: %s (column %d)",
335: p->in, line, msg, col);
336: }
337:
338:
339: static int
340: msg_warn(void *arg, int line, int col,
341: enum mdoc_warn type, const char *msg)
342: {
343: struct mmain *p;
344:
345: p = (struct mmain *)arg;
346:
347: switch (type) {
348: case (WARN_COMPAT):
349: if (p->warn & MD_WARN_COMPAT)
350: break;
351: return(1);
352: case (WARN_SYNTAX):
353: if (p->warn & MD_WARN_SYNTAX)
354: break;
355: return(1);
356: }
357:
358: warnx("%s:%d: warning: %s (column %d)",
359: p->in, line, msg, col);
360:
361: if ( ! (p->warn & MD_WARN_ERR))
362: return(1);
363:
364: warnx("%s: considering warnings as errors", __progname);
365: return(0);
366: }
CVSweb