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