xref: /titanic_51/usr/src/cmd/mandoc/read.c (revision 95c635efb7c3b86efc493e0447eaec7aecca3f0f)
1*95c635efSGarrett D'Amore /*	$Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */
2*95c635efSGarrett D'Amore /*
3*95c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*95c635efSGarrett D'Amore  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5*95c635efSGarrett D'Amore  *
6*95c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
7*95c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
8*95c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
9*95c635efSGarrett D'Amore  *
10*95c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*95c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*95c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*95c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*95c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*95c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*95c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*95c635efSGarrett D'Amore  */
18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
19*95c635efSGarrett D'Amore #include "config.h"
20*95c635efSGarrett D'Amore #endif
21*95c635efSGarrett D'Amore 
22*95c635efSGarrett D'Amore #ifdef HAVE_MMAP
23*95c635efSGarrett D'Amore # include <sys/stat.h>
24*95c635efSGarrett D'Amore # include <sys/mman.h>
25*95c635efSGarrett D'Amore #endif
26*95c635efSGarrett D'Amore 
27*95c635efSGarrett D'Amore #include <assert.h>
28*95c635efSGarrett D'Amore #include <ctype.h>
29*95c635efSGarrett D'Amore #include <fcntl.h>
30*95c635efSGarrett D'Amore #include <stdarg.h>
31*95c635efSGarrett D'Amore #include <stdint.h>
32*95c635efSGarrett D'Amore #include <stdio.h>
33*95c635efSGarrett D'Amore #include <stdlib.h>
34*95c635efSGarrett D'Amore #include <string.h>
35*95c635efSGarrett D'Amore #include <unistd.h>
36*95c635efSGarrett D'Amore 
37*95c635efSGarrett D'Amore #include "mandoc.h"
38*95c635efSGarrett D'Amore #include "libmandoc.h"
39*95c635efSGarrett D'Amore #include "mdoc.h"
40*95c635efSGarrett D'Amore #include "man.h"
41*95c635efSGarrett D'Amore #include "main.h"
42*95c635efSGarrett D'Amore 
43*95c635efSGarrett D'Amore #ifndef MAP_FILE
44*95c635efSGarrett D'Amore #define	MAP_FILE	0
45*95c635efSGarrett D'Amore #endif
46*95c635efSGarrett D'Amore 
47*95c635efSGarrett D'Amore #define	REPARSE_LIMIT	1000
48*95c635efSGarrett D'Amore 
49*95c635efSGarrett D'Amore struct	buf {
50*95c635efSGarrett D'Amore 	char	 	 *buf; /* binary input buffer */
51*95c635efSGarrett D'Amore 	size_t		  sz; /* size of binary buffer */
52*95c635efSGarrett D'Amore };
53*95c635efSGarrett D'Amore 
54*95c635efSGarrett D'Amore struct	mparse {
55*95c635efSGarrett D'Amore 	enum mandoclevel  file_status; /* status of current parse */
56*95c635efSGarrett D'Amore 	enum mandoclevel  wlevel; /* ignore messages below this */
57*95c635efSGarrett D'Amore 	int		  line; /* line number in the file */
58*95c635efSGarrett D'Amore 	enum mparset	  inttype; /* which parser to use */
59*95c635efSGarrett D'Amore 	struct man	 *pman; /* persistent man parser */
60*95c635efSGarrett D'Amore 	struct mdoc	 *pmdoc; /* persistent mdoc parser */
61*95c635efSGarrett D'Amore 	struct man	 *man; /* man parser */
62*95c635efSGarrett D'Amore 	struct mdoc	 *mdoc; /* mdoc parser */
63*95c635efSGarrett D'Amore 	struct roff	 *roff; /* roff parser (!NULL) */
64*95c635efSGarrett D'Amore 	int		  reparse_count; /* finite interp. stack */
65*95c635efSGarrett D'Amore 	mandocmsg	  mmsg; /* warning/error message handler */
66*95c635efSGarrett D'Amore 	void		 *arg; /* argument to mmsg */
67*95c635efSGarrett D'Amore 	const char	 *file;
68*95c635efSGarrett D'Amore 	struct buf	 *secondary;
69*95c635efSGarrett D'Amore };
70*95c635efSGarrett D'Amore 
71*95c635efSGarrett D'Amore static	void	  resize_buf(struct buf *, size_t);
72*95c635efSGarrett D'Amore static	void	  mparse_buf_r(struct mparse *, struct buf, int);
73*95c635efSGarrett D'Amore static	void	  mparse_readfd_r(struct mparse *, int, const char *, int);
74*95c635efSGarrett D'Amore static	void	  pset(const char *, int, struct mparse *);
75*95c635efSGarrett D'Amore static	int	  read_whole_file(const char *, int, struct buf *, int *);
76*95c635efSGarrett D'Amore static	void	  mparse_end(struct mparse *);
77*95c635efSGarrett D'Amore 
78*95c635efSGarrett D'Amore static	const enum mandocerr	mandoclimits[MANDOCLEVEL_MAX] = {
79*95c635efSGarrett D'Amore 	MANDOCERR_OK,
80*95c635efSGarrett D'Amore 	MANDOCERR_WARNING,
81*95c635efSGarrett D'Amore 	MANDOCERR_WARNING,
82*95c635efSGarrett D'Amore 	MANDOCERR_ERROR,
83*95c635efSGarrett D'Amore 	MANDOCERR_FATAL,
84*95c635efSGarrett D'Amore 	MANDOCERR_MAX,
85*95c635efSGarrett D'Amore 	MANDOCERR_MAX
86*95c635efSGarrett D'Amore };
87*95c635efSGarrett D'Amore 
88*95c635efSGarrett D'Amore static	const char * const	mandocerrs[MANDOCERR_MAX] = {
89*95c635efSGarrett D'Amore 	"ok",
90*95c635efSGarrett D'Amore 
91*95c635efSGarrett D'Amore 	"generic warning",
92*95c635efSGarrett D'Amore 
93*95c635efSGarrett D'Amore 	/* related to the prologue */
94*95c635efSGarrett D'Amore 	"no title in document",
95*95c635efSGarrett D'Amore 	"document title should be all caps",
96*95c635efSGarrett D'Amore 	"unknown manual section",
97*95c635efSGarrett D'Amore 	"date missing, using today's date",
98*95c635efSGarrett D'Amore 	"cannot parse date, using it verbatim",
99*95c635efSGarrett D'Amore 	"prologue macros out of order",
100*95c635efSGarrett D'Amore 	"duplicate prologue macro",
101*95c635efSGarrett D'Amore 	"macro not allowed in prologue",
102*95c635efSGarrett D'Amore 	"macro not allowed in body",
103*95c635efSGarrett D'Amore 
104*95c635efSGarrett D'Amore 	/* related to document structure */
105*95c635efSGarrett D'Amore 	".so is fragile, better use ln(1)",
106*95c635efSGarrett D'Amore 	"NAME section must come first",
107*95c635efSGarrett D'Amore 	"bad NAME section contents",
108*95c635efSGarrett D'Amore 	"manual name not yet set",
109*95c635efSGarrett D'Amore 	"sections out of conventional order",
110*95c635efSGarrett D'Amore 	"duplicate section name",
111*95c635efSGarrett D'Amore 	"section not in conventional manual section",
112*95c635efSGarrett D'Amore 
113*95c635efSGarrett D'Amore 	/* related to macros and nesting */
114*95c635efSGarrett D'Amore 	"skipping obsolete macro",
115*95c635efSGarrett D'Amore 	"skipping paragraph macro",
116*95c635efSGarrett D'Amore 	"skipping no-space macro",
117*95c635efSGarrett D'Amore 	"blocks badly nested",
118*95c635efSGarrett D'Amore 	"child violates parent syntax",
119*95c635efSGarrett D'Amore 	"nested displays are not portable",
120*95c635efSGarrett D'Amore 	"already in literal mode",
121*95c635efSGarrett D'Amore 	"line scope broken",
122*95c635efSGarrett D'Amore 
123*95c635efSGarrett D'Amore 	/* related to missing macro arguments */
124*95c635efSGarrett D'Amore 	"skipping empty macro",
125*95c635efSGarrett D'Amore 	"argument count wrong",
126*95c635efSGarrett D'Amore 	"missing display type",
127*95c635efSGarrett D'Amore 	"list type must come first",
128*95c635efSGarrett D'Amore 	"tag lists require a width argument",
129*95c635efSGarrett D'Amore 	"missing font type",
130*95c635efSGarrett D'Amore 	"skipping end of block that is not open",
131*95c635efSGarrett D'Amore 
132*95c635efSGarrett D'Amore 	/* related to bad macro arguments */
133*95c635efSGarrett D'Amore 	"skipping argument",
134*95c635efSGarrett D'Amore 	"duplicate argument",
135*95c635efSGarrett D'Amore 	"duplicate display type",
136*95c635efSGarrett D'Amore 	"duplicate list type",
137*95c635efSGarrett D'Amore 	"unknown AT&T UNIX version",
138*95c635efSGarrett D'Amore 	"bad Boolean value",
139*95c635efSGarrett D'Amore 	"unknown font",
140*95c635efSGarrett D'Amore 	"unknown standard specifier",
141*95c635efSGarrett D'Amore 	"bad width argument",
142*95c635efSGarrett D'Amore 
143*95c635efSGarrett D'Amore 	/* related to plain text */
144*95c635efSGarrett D'Amore 	"blank line in non-literal context",
145*95c635efSGarrett D'Amore 	"tab in non-literal context",
146*95c635efSGarrett D'Amore 	"end of line whitespace",
147*95c635efSGarrett D'Amore 	"bad comment style",
148*95c635efSGarrett D'Amore 	"bad escape sequence",
149*95c635efSGarrett D'Amore 	"unterminated quoted string",
150*95c635efSGarrett D'Amore 
151*95c635efSGarrett D'Amore 	/* related to equations */
152*95c635efSGarrett D'Amore 	"unexpected literal in equation",
153*95c635efSGarrett D'Amore 
154*95c635efSGarrett D'Amore 	"generic error",
155*95c635efSGarrett D'Amore 
156*95c635efSGarrett D'Amore 	/* related to equations */
157*95c635efSGarrett D'Amore 	"unexpected equation scope closure",
158*95c635efSGarrett D'Amore 	"equation scope open on exit",
159*95c635efSGarrett D'Amore 	"overlapping equation scopes",
160*95c635efSGarrett D'Amore 	"unexpected end of equation",
161*95c635efSGarrett D'Amore 	"equation syntax error",
162*95c635efSGarrett D'Amore 
163*95c635efSGarrett D'Amore 	/* related to tables */
164*95c635efSGarrett D'Amore 	"bad table syntax",
165*95c635efSGarrett D'Amore 	"bad table option",
166*95c635efSGarrett D'Amore 	"bad table layout",
167*95c635efSGarrett D'Amore 	"no table layout cells specified",
168*95c635efSGarrett D'Amore 	"no table data cells specified",
169*95c635efSGarrett D'Amore 	"ignore data in cell",
170*95c635efSGarrett D'Amore 	"data block still open",
171*95c635efSGarrett D'Amore 	"ignoring extra data cells",
172*95c635efSGarrett D'Amore 
173*95c635efSGarrett D'Amore 	"input stack limit exceeded, infinite loop?",
174*95c635efSGarrett D'Amore 	"skipping bad character",
175*95c635efSGarrett D'Amore 	"escaped character not allowed in a name",
176*95c635efSGarrett D'Amore 	"skipping text before the first section header",
177*95c635efSGarrett D'Amore 	"skipping unknown macro",
178*95c635efSGarrett D'Amore 	"NOT IMPLEMENTED, please use groff: skipping request",
179*95c635efSGarrett D'Amore 	"argument count wrong",
180*95c635efSGarrett D'Amore 	"skipping end of block that is not open",
181*95c635efSGarrett D'Amore 	"missing end of block",
182*95c635efSGarrett D'Amore 	"scope open on exit",
183*95c635efSGarrett D'Amore 	"uname(3) system call failed",
184*95c635efSGarrett D'Amore 	"macro requires line argument(s)",
185*95c635efSGarrett D'Amore 	"macro requires body argument(s)",
186*95c635efSGarrett D'Amore 	"macro requires argument(s)",
187*95c635efSGarrett D'Amore 	"missing list type",
188*95c635efSGarrett D'Amore 	"line argument(s) will be lost",
189*95c635efSGarrett D'Amore 	"body argument(s) will be lost",
190*95c635efSGarrett D'Amore 
191*95c635efSGarrett D'Amore 	"generic fatal error",
192*95c635efSGarrett D'Amore 
193*95c635efSGarrett D'Amore 	"not a manual",
194*95c635efSGarrett D'Amore 	"column syntax is inconsistent",
195*95c635efSGarrett D'Amore 	"NOT IMPLEMENTED: .Bd -file",
196*95c635efSGarrett D'Amore 	"argument count wrong, violates syntax",
197*95c635efSGarrett D'Amore 	"child violates parent syntax",
198*95c635efSGarrett D'Amore 	"argument count wrong, violates syntax",
199*95c635efSGarrett D'Amore 	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
200*95c635efSGarrett D'Amore 	"no document body",
201*95c635efSGarrett D'Amore 	"no document prologue",
202*95c635efSGarrett D'Amore 	"static buffer exhausted",
203*95c635efSGarrett D'Amore };
204*95c635efSGarrett D'Amore 
205*95c635efSGarrett D'Amore static	const char * const	mandoclevels[MANDOCLEVEL_MAX] = {
206*95c635efSGarrett D'Amore 	"SUCCESS",
207*95c635efSGarrett D'Amore 	"RESERVED",
208*95c635efSGarrett D'Amore 	"WARNING",
209*95c635efSGarrett D'Amore 	"ERROR",
210*95c635efSGarrett D'Amore 	"FATAL",
211*95c635efSGarrett D'Amore 	"BADARG",
212*95c635efSGarrett D'Amore 	"SYSERR"
213*95c635efSGarrett D'Amore };
214*95c635efSGarrett D'Amore 
215*95c635efSGarrett D'Amore static void
216*95c635efSGarrett D'Amore resize_buf(struct buf *buf, size_t initial)
217*95c635efSGarrett D'Amore {
218*95c635efSGarrett D'Amore 
219*95c635efSGarrett D'Amore 	buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
220*95c635efSGarrett D'Amore 	buf->buf = mandoc_realloc(buf->buf, buf->sz);
221*95c635efSGarrett D'Amore }
222*95c635efSGarrett D'Amore 
223*95c635efSGarrett D'Amore static void
224*95c635efSGarrett D'Amore pset(const char *buf, int pos, struct mparse *curp)
225*95c635efSGarrett D'Amore {
226*95c635efSGarrett D'Amore 	int		 i;
227*95c635efSGarrett D'Amore 
228*95c635efSGarrett D'Amore 	/*
229*95c635efSGarrett D'Amore 	 * Try to intuit which kind of manual parser should be used.  If
230*95c635efSGarrett D'Amore 	 * passed in by command-line (-man, -mdoc), then use that
231*95c635efSGarrett D'Amore 	 * explicitly.  If passed as -mandoc, then try to guess from the
232*95c635efSGarrett D'Amore 	 * line: either skip dot-lines, use -mdoc when finding `.Dt', or
233*95c635efSGarrett D'Amore 	 * default to -man, which is more lenient.
234*95c635efSGarrett D'Amore 	 *
235*95c635efSGarrett D'Amore 	 * Separate out pmdoc/pman from mdoc/man: the first persists
236*95c635efSGarrett D'Amore 	 * through all parsers, while the latter is used per-parse.
237*95c635efSGarrett D'Amore 	 */
238*95c635efSGarrett D'Amore 
239*95c635efSGarrett D'Amore 	if ('.' == buf[0] || '\'' == buf[0]) {
240*95c635efSGarrett D'Amore 		for (i = 1; buf[i]; i++)
241*95c635efSGarrett D'Amore 			if (' ' != buf[i] && '\t' != buf[i])
242*95c635efSGarrett D'Amore 				break;
243*95c635efSGarrett D'Amore 		if ('\0' == buf[i])
244*95c635efSGarrett D'Amore 			return;
245*95c635efSGarrett D'Amore 	}
246*95c635efSGarrett D'Amore 
247*95c635efSGarrett D'Amore 	switch (curp->inttype) {
248*95c635efSGarrett D'Amore 	case (MPARSE_MDOC):
249*95c635efSGarrett D'Amore 		if (NULL == curp->pmdoc)
250*95c635efSGarrett D'Amore 			curp->pmdoc = mdoc_alloc(curp->roff, curp);
251*95c635efSGarrett D'Amore 		assert(curp->pmdoc);
252*95c635efSGarrett D'Amore 		curp->mdoc = curp->pmdoc;
253*95c635efSGarrett D'Amore 		return;
254*95c635efSGarrett D'Amore 	case (MPARSE_MAN):
255*95c635efSGarrett D'Amore 		if (NULL == curp->pman)
256*95c635efSGarrett D'Amore 			curp->pman = man_alloc(curp->roff, curp);
257*95c635efSGarrett D'Amore 		assert(curp->pman);
258*95c635efSGarrett D'Amore 		curp->man = curp->pman;
259*95c635efSGarrett D'Amore 		return;
260*95c635efSGarrett D'Amore 	default:
261*95c635efSGarrett D'Amore 		break;
262*95c635efSGarrett D'Amore 	}
263*95c635efSGarrett D'Amore 
264*95c635efSGarrett D'Amore 	if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
265*95c635efSGarrett D'Amore 		if (NULL == curp->pmdoc)
266*95c635efSGarrett D'Amore 			curp->pmdoc = mdoc_alloc(curp->roff, curp);
267*95c635efSGarrett D'Amore 		assert(curp->pmdoc);
268*95c635efSGarrett D'Amore 		curp->mdoc = curp->pmdoc;
269*95c635efSGarrett D'Amore 		return;
270*95c635efSGarrett D'Amore 	}
271*95c635efSGarrett D'Amore 
272*95c635efSGarrett D'Amore 	if (NULL == curp->pman)
273*95c635efSGarrett D'Amore 		curp->pman = man_alloc(curp->roff, curp);
274*95c635efSGarrett D'Amore 	assert(curp->pman);
275*95c635efSGarrett D'Amore 	curp->man = curp->pman;
276*95c635efSGarrett D'Amore }
277*95c635efSGarrett D'Amore 
278*95c635efSGarrett D'Amore /*
279*95c635efSGarrett D'Amore  * Main parse routine for an opened file.  This is called for each
280*95c635efSGarrett D'Amore  * opened file and simply loops around the full input file, possibly
281*95c635efSGarrett D'Amore  * nesting (i.e., with `so').
282*95c635efSGarrett D'Amore  */
283*95c635efSGarrett D'Amore static void
284*95c635efSGarrett D'Amore mparse_buf_r(struct mparse *curp, struct buf blk, int start)
285*95c635efSGarrett D'Amore {
286*95c635efSGarrett D'Amore 	const struct tbl_span	*span;
287*95c635efSGarrett D'Amore 	struct buf	 ln;
288*95c635efSGarrett D'Amore 	enum rofferr	 rr;
289*95c635efSGarrett D'Amore 	int		 i, of, rc;
290*95c635efSGarrett D'Amore 	int		 pos; /* byte number in the ln buffer */
291*95c635efSGarrett D'Amore 	int		 lnn; /* line number in the real file */
292*95c635efSGarrett D'Amore 	unsigned char	 c;
293*95c635efSGarrett D'Amore 
294*95c635efSGarrett D'Amore 	memset(&ln, 0, sizeof(struct buf));
295*95c635efSGarrett D'Amore 
296*95c635efSGarrett D'Amore 	lnn = curp->line;
297*95c635efSGarrett D'Amore 	pos = 0;
298*95c635efSGarrett D'Amore 
299*95c635efSGarrett D'Amore 	for (i = 0; i < (int)blk.sz; ) {
300*95c635efSGarrett D'Amore 		if (0 == pos && '\0' == blk.buf[i])
301*95c635efSGarrett D'Amore 			break;
302*95c635efSGarrett D'Amore 
303*95c635efSGarrett D'Amore 		if (start) {
304*95c635efSGarrett D'Amore 			curp->line = lnn;
305*95c635efSGarrett D'Amore 			curp->reparse_count = 0;
306*95c635efSGarrett D'Amore 		}
307*95c635efSGarrett D'Amore 
308*95c635efSGarrett D'Amore 		while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
309*95c635efSGarrett D'Amore 
310*95c635efSGarrett D'Amore 			/*
311*95c635efSGarrett D'Amore 			 * When finding an unescaped newline character,
312*95c635efSGarrett D'Amore 			 * leave the character loop to process the line.
313*95c635efSGarrett D'Amore 			 * Skip a preceding carriage return, if any.
314*95c635efSGarrett D'Amore 			 */
315*95c635efSGarrett D'Amore 
316*95c635efSGarrett D'Amore 			if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
317*95c635efSGarrett D'Amore 			    '\n' == blk.buf[i + 1])
318*95c635efSGarrett D'Amore 				++i;
319*95c635efSGarrett D'Amore 			if ('\n' == blk.buf[i]) {
320*95c635efSGarrett D'Amore 				++i;
321*95c635efSGarrett D'Amore 				++lnn;
322*95c635efSGarrett D'Amore 				break;
323*95c635efSGarrett D'Amore 			}
324*95c635efSGarrett D'Amore 
325*95c635efSGarrett D'Amore 			/*
326*95c635efSGarrett D'Amore 			 * Warn about bogus characters.  If you're using
327*95c635efSGarrett D'Amore 			 * non-ASCII encoding, you're screwing your
328*95c635efSGarrett D'Amore 			 * readers.  Since I'd rather this not happen,
329*95c635efSGarrett D'Amore 			 * I'll be helpful and replace these characters
330*95c635efSGarrett D'Amore 			 * with "?", so we don't display gibberish.
331*95c635efSGarrett D'Amore 			 * Note to manual writers: use special characters.
332*95c635efSGarrett D'Amore 			 */
333*95c635efSGarrett D'Amore 
334*95c635efSGarrett D'Amore 			c = (unsigned char) blk.buf[i];
335*95c635efSGarrett D'Amore 
336*95c635efSGarrett D'Amore 			if ( ! (isascii(c) &&
337*95c635efSGarrett D'Amore 					(isgraph(c) || isblank(c)))) {
338*95c635efSGarrett D'Amore 				mandoc_msg(MANDOCERR_BADCHAR, curp,
339*95c635efSGarrett D'Amore 						curp->line, pos, NULL);
340*95c635efSGarrett D'Amore 				i++;
341*95c635efSGarrett D'Amore 				if (pos >= (int)ln.sz)
342*95c635efSGarrett D'Amore 					resize_buf(&ln, 256);
343*95c635efSGarrett D'Amore 				ln.buf[pos++] = '?';
344*95c635efSGarrett D'Amore 				continue;
345*95c635efSGarrett D'Amore 			}
346*95c635efSGarrett D'Amore 
347*95c635efSGarrett D'Amore 			/* Trailing backslash = a plain char. */
348*95c635efSGarrett D'Amore 
349*95c635efSGarrett D'Amore 			if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
350*95c635efSGarrett D'Amore 				if (pos >= (int)ln.sz)
351*95c635efSGarrett D'Amore 					resize_buf(&ln, 256);
352*95c635efSGarrett D'Amore 				ln.buf[pos++] = blk.buf[i++];
353*95c635efSGarrett D'Amore 				continue;
354*95c635efSGarrett D'Amore 			}
355*95c635efSGarrett D'Amore 
356*95c635efSGarrett D'Amore 			/*
357*95c635efSGarrett D'Amore 			 * Found escape and at least one other character.
358*95c635efSGarrett D'Amore 			 * When it's a newline character, skip it.
359*95c635efSGarrett D'Amore 			 * When there is a carriage return in between,
360*95c635efSGarrett D'Amore 			 * skip that one as well.
361*95c635efSGarrett D'Amore 			 */
362*95c635efSGarrett D'Amore 
363*95c635efSGarrett D'Amore 			if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
364*95c635efSGarrett D'Amore 			    '\n' == blk.buf[i + 2])
365*95c635efSGarrett D'Amore 				++i;
366*95c635efSGarrett D'Amore 			if ('\n' == blk.buf[i + 1]) {
367*95c635efSGarrett D'Amore 				i += 2;
368*95c635efSGarrett D'Amore 				++lnn;
369*95c635efSGarrett D'Amore 				continue;
370*95c635efSGarrett D'Amore 			}
371*95c635efSGarrett D'Amore 
372*95c635efSGarrett D'Amore 			if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
373*95c635efSGarrett D'Amore 				i += 2;
374*95c635efSGarrett D'Amore 				/* Comment, skip to end of line */
375*95c635efSGarrett D'Amore 				for (; i < (int)blk.sz; ++i) {
376*95c635efSGarrett D'Amore 					if ('\n' == blk.buf[i]) {
377*95c635efSGarrett D'Amore 						++i;
378*95c635efSGarrett D'Amore 						++lnn;
379*95c635efSGarrett D'Amore 						break;
380*95c635efSGarrett D'Amore 					}
381*95c635efSGarrett D'Amore 				}
382*95c635efSGarrett D'Amore 
383*95c635efSGarrett D'Amore 				/* Backout trailing whitespaces */
384*95c635efSGarrett D'Amore 				for (; pos > 0; --pos) {
385*95c635efSGarrett D'Amore 					if (ln.buf[pos - 1] != ' ')
386*95c635efSGarrett D'Amore 						break;
387*95c635efSGarrett D'Amore 					if (pos > 2 && ln.buf[pos - 2] == '\\')
388*95c635efSGarrett D'Amore 						break;
389*95c635efSGarrett D'Amore 				}
390*95c635efSGarrett D'Amore 				break;
391*95c635efSGarrett D'Amore 			}
392*95c635efSGarrett D'Amore 
393*95c635efSGarrett D'Amore 			/* Some other escape sequence, copy & cont. */
394*95c635efSGarrett D'Amore 
395*95c635efSGarrett D'Amore 			if (pos + 1 >= (int)ln.sz)
396*95c635efSGarrett D'Amore 				resize_buf(&ln, 256);
397*95c635efSGarrett D'Amore 
398*95c635efSGarrett D'Amore 			ln.buf[pos++] = blk.buf[i++];
399*95c635efSGarrett D'Amore 			ln.buf[pos++] = blk.buf[i++];
400*95c635efSGarrett D'Amore 		}
401*95c635efSGarrett D'Amore 
402*95c635efSGarrett D'Amore  		if (pos >= (int)ln.sz)
403*95c635efSGarrett D'Amore 			resize_buf(&ln, 256);
404*95c635efSGarrett D'Amore 
405*95c635efSGarrett D'Amore 		ln.buf[pos] = '\0';
406*95c635efSGarrett D'Amore 
407*95c635efSGarrett D'Amore 		/*
408*95c635efSGarrett D'Amore 		 * A significant amount of complexity is contained by
409*95c635efSGarrett D'Amore 		 * the roff preprocessor.  It's line-oriented but can be
410*95c635efSGarrett D'Amore 		 * expressed on one line, so we need at times to
411*95c635efSGarrett D'Amore 		 * readjust our starting point and re-run it.  The roff
412*95c635efSGarrett D'Amore 		 * preprocessor can also readjust the buffers with new
413*95c635efSGarrett D'Amore 		 * data, so we pass them in wholesale.
414*95c635efSGarrett D'Amore 		 */
415*95c635efSGarrett D'Amore 
416*95c635efSGarrett D'Amore 		of = 0;
417*95c635efSGarrett D'Amore 
418*95c635efSGarrett D'Amore 		/*
419*95c635efSGarrett D'Amore 		 * Maintain a lookaside buffer of all parsed lines.  We
420*95c635efSGarrett D'Amore 		 * only do this if mparse_keep() has been invoked (the
421*95c635efSGarrett D'Amore 		 * buffer may be accessed with mparse_getkeep()).
422*95c635efSGarrett D'Amore 		 */
423*95c635efSGarrett D'Amore 
424*95c635efSGarrett D'Amore 		if (curp->secondary) {
425*95c635efSGarrett D'Amore 			curp->secondary->buf =
426*95c635efSGarrett D'Amore 				mandoc_realloc
427*95c635efSGarrett D'Amore 				(curp->secondary->buf,
428*95c635efSGarrett D'Amore 				 curp->secondary->sz + pos + 2);
429*95c635efSGarrett D'Amore 			memcpy(curp->secondary->buf +
430*95c635efSGarrett D'Amore 					curp->secondary->sz,
431*95c635efSGarrett D'Amore 					ln.buf, pos);
432*95c635efSGarrett D'Amore 			curp->secondary->sz += pos;
433*95c635efSGarrett D'Amore 			curp->secondary->buf
434*95c635efSGarrett D'Amore 				[curp->secondary->sz] = '\n';
435*95c635efSGarrett D'Amore 			curp->secondary->sz++;
436*95c635efSGarrett D'Amore 			curp->secondary->buf
437*95c635efSGarrett D'Amore 				[curp->secondary->sz] = '\0';
438*95c635efSGarrett D'Amore 		}
439*95c635efSGarrett D'Amore rerun:
440*95c635efSGarrett D'Amore 		rr = roff_parseln
441*95c635efSGarrett D'Amore 			(curp->roff, curp->line,
442*95c635efSGarrett D'Amore 			 &ln.buf, &ln.sz, of, &of);
443*95c635efSGarrett D'Amore 
444*95c635efSGarrett D'Amore 		switch (rr) {
445*95c635efSGarrett D'Amore 		case (ROFF_REPARSE):
446*95c635efSGarrett D'Amore 			if (REPARSE_LIMIT >= ++curp->reparse_count)
447*95c635efSGarrett D'Amore 				mparse_buf_r(curp, ln, 0);
448*95c635efSGarrett D'Amore 			else
449*95c635efSGarrett D'Amore 				mandoc_msg(MANDOCERR_ROFFLOOP, curp,
450*95c635efSGarrett D'Amore 					curp->line, pos, NULL);
451*95c635efSGarrett D'Amore 			pos = 0;
452*95c635efSGarrett D'Amore 			continue;
453*95c635efSGarrett D'Amore 		case (ROFF_APPEND):
454*95c635efSGarrett D'Amore 			pos = (int)strlen(ln.buf);
455*95c635efSGarrett D'Amore 			continue;
456*95c635efSGarrett D'Amore 		case (ROFF_RERUN):
457*95c635efSGarrett D'Amore 			goto rerun;
458*95c635efSGarrett D'Amore 		case (ROFF_IGN):
459*95c635efSGarrett D'Amore 			pos = 0;
460*95c635efSGarrett D'Amore 			continue;
461*95c635efSGarrett D'Amore 		case (ROFF_ERR):
462*95c635efSGarrett D'Amore 			assert(MANDOCLEVEL_FATAL <= curp->file_status);
463*95c635efSGarrett D'Amore 			break;
464*95c635efSGarrett D'Amore 		case (ROFF_SO):
465*95c635efSGarrett D'Amore 			/*
466*95c635efSGarrett D'Amore 			 * We remove `so' clauses from our lookaside
467*95c635efSGarrett D'Amore 			 * buffer because we're going to descend into
468*95c635efSGarrett D'Amore 			 * the file recursively.
469*95c635efSGarrett D'Amore 			 */
470*95c635efSGarrett D'Amore 			if (curp->secondary)
471*95c635efSGarrett D'Amore 				curp->secondary->sz -= pos + 1;
472*95c635efSGarrett D'Amore 			mparse_readfd_r(curp, -1, ln.buf + of, 1);
473*95c635efSGarrett D'Amore 			if (MANDOCLEVEL_FATAL <= curp->file_status)
474*95c635efSGarrett D'Amore 				break;
475*95c635efSGarrett D'Amore 			pos = 0;
476*95c635efSGarrett D'Amore 			continue;
477*95c635efSGarrett D'Amore 		default:
478*95c635efSGarrett D'Amore 			break;
479*95c635efSGarrett D'Amore 		}
480*95c635efSGarrett D'Amore 
481*95c635efSGarrett D'Amore 		/*
482*95c635efSGarrett D'Amore 		 * If we encounter errors in the recursive parse, make
483*95c635efSGarrett D'Amore 		 * sure we don't continue parsing.
484*95c635efSGarrett D'Amore 		 */
485*95c635efSGarrett D'Amore 
486*95c635efSGarrett D'Amore 		if (MANDOCLEVEL_FATAL <= curp->file_status)
487*95c635efSGarrett D'Amore 			break;
488*95c635efSGarrett D'Amore 
489*95c635efSGarrett D'Amore 		/*
490*95c635efSGarrett D'Amore 		 * If input parsers have not been allocated, do so now.
491*95c635efSGarrett D'Amore 		 * We keep these instanced between parsers, but set them
492*95c635efSGarrett D'Amore 		 * locally per parse routine since we can use different
493*95c635efSGarrett D'Amore 		 * parsers with each one.
494*95c635efSGarrett D'Amore 		 */
495*95c635efSGarrett D'Amore 
496*95c635efSGarrett D'Amore 		if ( ! (curp->man || curp->mdoc))
497*95c635efSGarrett D'Amore 			pset(ln.buf + of, pos - of, curp);
498*95c635efSGarrett D'Amore 
499*95c635efSGarrett D'Amore 		/*
500*95c635efSGarrett D'Amore 		 * Lastly, push down into the parsers themselves.  One
501*95c635efSGarrett D'Amore 		 * of these will have already been set in the pset()
502*95c635efSGarrett D'Amore 		 * routine.
503*95c635efSGarrett D'Amore 		 * If libroff returns ROFF_TBL, then add it to the
504*95c635efSGarrett D'Amore 		 * currently open parse.  Since we only get here if
505*95c635efSGarrett D'Amore 		 * there does exist data (see tbl_data.c), we're
506*95c635efSGarrett D'Amore 		 * guaranteed that something's been allocated.
507*95c635efSGarrett D'Amore 		 * Do the same for ROFF_EQN.
508*95c635efSGarrett D'Amore 		 */
509*95c635efSGarrett D'Amore 
510*95c635efSGarrett D'Amore 		rc = -1;
511*95c635efSGarrett D'Amore 
512*95c635efSGarrett D'Amore 		if (ROFF_TBL == rr)
513*95c635efSGarrett D'Amore 			while (NULL != (span = roff_span(curp->roff))) {
514*95c635efSGarrett D'Amore 				rc = curp->man ?
515*95c635efSGarrett D'Amore 					man_addspan(curp->man, span) :
516*95c635efSGarrett D'Amore 					mdoc_addspan(curp->mdoc, span);
517*95c635efSGarrett D'Amore 				if (0 == rc)
518*95c635efSGarrett D'Amore 					break;
519*95c635efSGarrett D'Amore 			}
520*95c635efSGarrett D'Amore 		else if (ROFF_EQN == rr)
521*95c635efSGarrett D'Amore 			rc = curp->mdoc ?
522*95c635efSGarrett D'Amore 				mdoc_addeqn(curp->mdoc,
523*95c635efSGarrett D'Amore 					roff_eqn(curp->roff)) :
524*95c635efSGarrett D'Amore 				man_addeqn(curp->man,
525*95c635efSGarrett D'Amore 					roff_eqn(curp->roff));
526*95c635efSGarrett D'Amore 		else if (curp->man || curp->mdoc)
527*95c635efSGarrett D'Amore 			rc = curp->man ?
528*95c635efSGarrett D'Amore 				man_parseln(curp->man,
529*95c635efSGarrett D'Amore 					curp->line, ln.buf, of) :
530*95c635efSGarrett D'Amore 				mdoc_parseln(curp->mdoc,
531*95c635efSGarrett D'Amore 					curp->line, ln.buf, of);
532*95c635efSGarrett D'Amore 
533*95c635efSGarrett D'Amore 		if (0 == rc) {
534*95c635efSGarrett D'Amore 			assert(MANDOCLEVEL_FATAL <= curp->file_status);
535*95c635efSGarrett D'Amore 			break;
536*95c635efSGarrett D'Amore 		}
537*95c635efSGarrett D'Amore 
538*95c635efSGarrett D'Amore 		/* Temporary buffers typically are not full. */
539*95c635efSGarrett D'Amore 
540*95c635efSGarrett D'Amore 		if (0 == start && '\0' == blk.buf[i])
541*95c635efSGarrett D'Amore 			break;
542*95c635efSGarrett D'Amore 
543*95c635efSGarrett D'Amore 		/* Start the next input line. */
544*95c635efSGarrett D'Amore 
545*95c635efSGarrett D'Amore 		pos = 0;
546*95c635efSGarrett D'Amore 	}
547*95c635efSGarrett D'Amore 
548*95c635efSGarrett D'Amore 	free(ln.buf);
549*95c635efSGarrett D'Amore }
550*95c635efSGarrett D'Amore 
551*95c635efSGarrett D'Amore static int
552*95c635efSGarrett D'Amore read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
553*95c635efSGarrett D'Amore {
554*95c635efSGarrett D'Amore 	size_t		 off;
555*95c635efSGarrett D'Amore 	ssize_t		 ssz;
556*95c635efSGarrett D'Amore 
557*95c635efSGarrett D'Amore #ifdef	HAVE_MMAP
558*95c635efSGarrett D'Amore 	struct stat	 st;
559*95c635efSGarrett D'Amore 	if (-1 == fstat(fd, &st)) {
560*95c635efSGarrett D'Amore 		perror(file);
561*95c635efSGarrett D'Amore 		return(0);
562*95c635efSGarrett D'Amore 	}
563*95c635efSGarrett D'Amore 
564*95c635efSGarrett D'Amore 	/*
565*95c635efSGarrett D'Amore 	 * If we're a regular file, try just reading in the whole entry
566*95c635efSGarrett D'Amore 	 * via mmap().  This is faster than reading it into blocks, and
567*95c635efSGarrett D'Amore 	 * since each file is only a few bytes to begin with, I'm not
568*95c635efSGarrett D'Amore 	 * concerned that this is going to tank any machines.
569*95c635efSGarrett D'Amore 	 */
570*95c635efSGarrett D'Amore 
571*95c635efSGarrett D'Amore 	if (S_ISREG(st.st_mode)) {
572*95c635efSGarrett D'Amore 		if (st.st_size >= (1U << 31)) {
573*95c635efSGarrett D'Amore 			fprintf(stderr, "%s: input too large\n", file);
574*95c635efSGarrett D'Amore 			return(0);
575*95c635efSGarrett D'Amore 		}
576*95c635efSGarrett D'Amore 		*with_mmap = 1;
577*95c635efSGarrett D'Amore 		fb->sz = (size_t)st.st_size;
578*95c635efSGarrett D'Amore 		fb->buf = mmap(NULL, fb->sz, PROT_READ,
579*95c635efSGarrett D'Amore 				MAP_FILE|MAP_SHARED, fd, 0);
580*95c635efSGarrett D'Amore 		if (fb->buf != MAP_FAILED)
581*95c635efSGarrett D'Amore 			return(1);
582*95c635efSGarrett D'Amore 	}
583*95c635efSGarrett D'Amore #endif
584*95c635efSGarrett D'Amore 
585*95c635efSGarrett D'Amore 	/*
586*95c635efSGarrett D'Amore 	 * If this isn't a regular file (like, say, stdin), then we must
587*95c635efSGarrett D'Amore 	 * go the old way and just read things in bit by bit.
588*95c635efSGarrett D'Amore 	 */
589*95c635efSGarrett D'Amore 
590*95c635efSGarrett D'Amore 	*with_mmap = 0;
591*95c635efSGarrett D'Amore 	off = 0;
592*95c635efSGarrett D'Amore 	fb->sz = 0;
593*95c635efSGarrett D'Amore 	fb->buf = NULL;
594*95c635efSGarrett D'Amore 	for (;;) {
595*95c635efSGarrett D'Amore 		if (off == fb->sz) {
596*95c635efSGarrett D'Amore 			if (fb->sz == (1U << 31)) {
597*95c635efSGarrett D'Amore 				fprintf(stderr, "%s: input too large\n", file);
598*95c635efSGarrett D'Amore 				break;
599*95c635efSGarrett D'Amore 			}
600*95c635efSGarrett D'Amore 			resize_buf(fb, 65536);
601*95c635efSGarrett D'Amore 		}
602*95c635efSGarrett D'Amore 		ssz = read(fd, fb->buf + (int)off, fb->sz - off);
603*95c635efSGarrett D'Amore 		if (ssz == 0) {
604*95c635efSGarrett D'Amore 			fb->sz = off;
605*95c635efSGarrett D'Amore 			return(1);
606*95c635efSGarrett D'Amore 		}
607*95c635efSGarrett D'Amore 		if (ssz == -1) {
608*95c635efSGarrett D'Amore 			perror(file);
609*95c635efSGarrett D'Amore 			break;
610*95c635efSGarrett D'Amore 		}
611*95c635efSGarrett D'Amore 		off += (size_t)ssz;
612*95c635efSGarrett D'Amore 	}
613*95c635efSGarrett D'Amore 
614*95c635efSGarrett D'Amore 	free(fb->buf);
615*95c635efSGarrett D'Amore 	fb->buf = NULL;
616*95c635efSGarrett D'Amore 	return(0);
617*95c635efSGarrett D'Amore }
618*95c635efSGarrett D'Amore 
619*95c635efSGarrett D'Amore static void
620*95c635efSGarrett D'Amore mparse_end(struct mparse *curp)
621*95c635efSGarrett D'Amore {
622*95c635efSGarrett D'Amore 
623*95c635efSGarrett D'Amore 	if (MANDOCLEVEL_FATAL <= curp->file_status)
624*95c635efSGarrett D'Amore 		return;
625*95c635efSGarrett D'Amore 
626*95c635efSGarrett D'Amore 	if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
627*95c635efSGarrett D'Amore 		assert(MANDOCLEVEL_FATAL <= curp->file_status);
628*95c635efSGarrett D'Amore 		return;
629*95c635efSGarrett D'Amore 	}
630*95c635efSGarrett D'Amore 
631*95c635efSGarrett D'Amore 	if (curp->man && ! man_endparse(curp->man)) {
632*95c635efSGarrett D'Amore 		assert(MANDOCLEVEL_FATAL <= curp->file_status);
633*95c635efSGarrett D'Amore 		return;
634*95c635efSGarrett D'Amore 	}
635*95c635efSGarrett D'Amore 
636*95c635efSGarrett D'Amore 	if ( ! (curp->man || curp->mdoc)) {
637*95c635efSGarrett D'Amore 		mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
638*95c635efSGarrett D'Amore 		curp->file_status = MANDOCLEVEL_FATAL;
639*95c635efSGarrett D'Amore 		return;
640*95c635efSGarrett D'Amore 	}
641*95c635efSGarrett D'Amore 
642*95c635efSGarrett D'Amore 	roff_endparse(curp->roff);
643*95c635efSGarrett D'Amore }
644*95c635efSGarrett D'Amore 
645*95c635efSGarrett D'Amore static void
646*95c635efSGarrett D'Amore mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file,
647*95c635efSGarrett D'Amore 		int re)
648*95c635efSGarrett D'Amore {
649*95c635efSGarrett D'Amore 	const char	*svfile;
650*95c635efSGarrett D'Amore 
651*95c635efSGarrett D'Amore 	/* Line number is per-file. */
652*95c635efSGarrett D'Amore 	svfile = curp->file;
653*95c635efSGarrett D'Amore 	curp->file = file;
654*95c635efSGarrett D'Amore 	curp->line = 1;
655*95c635efSGarrett D'Amore 
656*95c635efSGarrett D'Amore 	mparse_buf_r(curp, blk, 1);
657*95c635efSGarrett D'Amore 
658*95c635efSGarrett D'Amore 	if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
659*95c635efSGarrett D'Amore 		mparse_end(curp);
660*95c635efSGarrett D'Amore 
661*95c635efSGarrett D'Amore 	curp->file = svfile;
662*95c635efSGarrett D'Amore }
663*95c635efSGarrett D'Amore 
664*95c635efSGarrett D'Amore enum mandoclevel
665*95c635efSGarrett D'Amore mparse_readmem(struct mparse *curp, const void *buf, size_t len,
666*95c635efSGarrett D'Amore 		const char *file)
667*95c635efSGarrett D'Amore {
668*95c635efSGarrett D'Amore 	struct buf blk;
669*95c635efSGarrett D'Amore 
670*95c635efSGarrett D'Amore 	blk.buf = UNCONST(buf);
671*95c635efSGarrett D'Amore 	blk.sz = len;
672*95c635efSGarrett D'Amore 
673*95c635efSGarrett D'Amore 	mparse_parse_buffer(curp, blk, file, 0);
674*95c635efSGarrett D'Amore 	return(curp->file_status);
675*95c635efSGarrett D'Amore }
676*95c635efSGarrett D'Amore 
677*95c635efSGarrett D'Amore static void
678*95c635efSGarrett D'Amore mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
679*95c635efSGarrett D'Amore {
680*95c635efSGarrett D'Amore 	struct buf	 blk;
681*95c635efSGarrett D'Amore 	int		 with_mmap;
682*95c635efSGarrett D'Amore 
683*95c635efSGarrett D'Amore 	if (-1 == fd)
684*95c635efSGarrett D'Amore 		if (-1 == (fd = open(file, O_RDONLY, 0))) {
685*95c635efSGarrett D'Amore 			perror(file);
686*95c635efSGarrett D'Amore 			curp->file_status = MANDOCLEVEL_SYSERR;
687*95c635efSGarrett D'Amore 			return;
688*95c635efSGarrett D'Amore 		}
689*95c635efSGarrett D'Amore 	/*
690*95c635efSGarrett D'Amore 	 * Run for each opened file; may be called more than once for
691*95c635efSGarrett D'Amore 	 * each full parse sequence if the opened file is nested (i.e.,
692*95c635efSGarrett D'Amore 	 * from `so').  Simply sucks in the whole file and moves into
693*95c635efSGarrett D'Amore 	 * the parse phase for the file.
694*95c635efSGarrett D'Amore 	 */
695*95c635efSGarrett D'Amore 
696*95c635efSGarrett D'Amore 	if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
697*95c635efSGarrett D'Amore 		curp->file_status = MANDOCLEVEL_SYSERR;
698*95c635efSGarrett D'Amore 		return;
699*95c635efSGarrett D'Amore 	}
700*95c635efSGarrett D'Amore 
701*95c635efSGarrett D'Amore 	mparse_parse_buffer(curp, blk, file, re);
702*95c635efSGarrett D'Amore 
703*95c635efSGarrett D'Amore #ifdef	HAVE_MMAP
704*95c635efSGarrett D'Amore 	if (with_mmap)
705*95c635efSGarrett D'Amore 		munmap(blk.buf, blk.sz);
706*95c635efSGarrett D'Amore 	else
707*95c635efSGarrett D'Amore #endif
708*95c635efSGarrett D'Amore 		free(blk.buf);
709*95c635efSGarrett D'Amore 
710*95c635efSGarrett D'Amore 	if (STDIN_FILENO != fd && -1 == close(fd))
711*95c635efSGarrett D'Amore 		perror(file);
712*95c635efSGarrett D'Amore }
713*95c635efSGarrett D'Amore 
714*95c635efSGarrett D'Amore enum mandoclevel
715*95c635efSGarrett D'Amore mparse_readfd(struct mparse *curp, int fd, const char *file)
716*95c635efSGarrett D'Amore {
717*95c635efSGarrett D'Amore 
718*95c635efSGarrett D'Amore 	mparse_readfd_r(curp, fd, file, 0);
719*95c635efSGarrett D'Amore 	return(curp->file_status);
720*95c635efSGarrett D'Amore }
721*95c635efSGarrett D'Amore 
722*95c635efSGarrett D'Amore struct mparse *
723*95c635efSGarrett D'Amore mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg)
724*95c635efSGarrett D'Amore {
725*95c635efSGarrett D'Amore 	struct mparse	*curp;
726*95c635efSGarrett D'Amore 
727*95c635efSGarrett D'Amore 	assert(wlevel <= MANDOCLEVEL_FATAL);
728*95c635efSGarrett D'Amore 
729*95c635efSGarrett D'Amore 	curp = mandoc_calloc(1, sizeof(struct mparse));
730*95c635efSGarrett D'Amore 
731*95c635efSGarrett D'Amore 	curp->wlevel = wlevel;
732*95c635efSGarrett D'Amore 	curp->mmsg = mmsg;
733*95c635efSGarrett D'Amore 	curp->arg = arg;
734*95c635efSGarrett D'Amore 	curp->inttype = inttype;
735*95c635efSGarrett D'Amore 
736*95c635efSGarrett D'Amore 	curp->roff = roff_alloc(curp);
737*95c635efSGarrett D'Amore 	return(curp);
738*95c635efSGarrett D'Amore }
739*95c635efSGarrett D'Amore 
740*95c635efSGarrett D'Amore void
741*95c635efSGarrett D'Amore mparse_reset(struct mparse *curp)
742*95c635efSGarrett D'Amore {
743*95c635efSGarrett D'Amore 
744*95c635efSGarrett D'Amore 	roff_reset(curp->roff);
745*95c635efSGarrett D'Amore 
746*95c635efSGarrett D'Amore 	if (curp->mdoc)
747*95c635efSGarrett D'Amore 		mdoc_reset(curp->mdoc);
748*95c635efSGarrett D'Amore 	if (curp->man)
749*95c635efSGarrett D'Amore 		man_reset(curp->man);
750*95c635efSGarrett D'Amore 	if (curp->secondary)
751*95c635efSGarrett D'Amore 		curp->secondary->sz = 0;
752*95c635efSGarrett D'Amore 
753*95c635efSGarrett D'Amore 	curp->file_status = MANDOCLEVEL_OK;
754*95c635efSGarrett D'Amore 	curp->mdoc = NULL;
755*95c635efSGarrett D'Amore 	curp->man = NULL;
756*95c635efSGarrett D'Amore }
757*95c635efSGarrett D'Amore 
758*95c635efSGarrett D'Amore void
759*95c635efSGarrett D'Amore mparse_free(struct mparse *curp)
760*95c635efSGarrett D'Amore {
761*95c635efSGarrett D'Amore 
762*95c635efSGarrett D'Amore 	if (curp->pmdoc)
763*95c635efSGarrett D'Amore 		mdoc_free(curp->pmdoc);
764*95c635efSGarrett D'Amore 	if (curp->pman)
765*95c635efSGarrett D'Amore 		man_free(curp->pman);
766*95c635efSGarrett D'Amore 	if (curp->roff)
767*95c635efSGarrett D'Amore 		roff_free(curp->roff);
768*95c635efSGarrett D'Amore 	if (curp->secondary)
769*95c635efSGarrett D'Amore 		free(curp->secondary->buf);
770*95c635efSGarrett D'Amore 
771*95c635efSGarrett D'Amore 	free(curp->secondary);
772*95c635efSGarrett D'Amore 	free(curp);
773*95c635efSGarrett D'Amore }
774*95c635efSGarrett D'Amore 
775*95c635efSGarrett D'Amore void
776*95c635efSGarrett D'Amore mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
777*95c635efSGarrett D'Amore {
778*95c635efSGarrett D'Amore 
779*95c635efSGarrett D'Amore 	if (mdoc)
780*95c635efSGarrett D'Amore 		*mdoc = curp->mdoc;
781*95c635efSGarrett D'Amore 	if (man)
782*95c635efSGarrett D'Amore 		*man = curp->man;
783*95c635efSGarrett D'Amore }
784*95c635efSGarrett D'Amore 
785*95c635efSGarrett D'Amore void
786*95c635efSGarrett D'Amore mandoc_vmsg(enum mandocerr t, struct mparse *m,
787*95c635efSGarrett D'Amore 		int ln, int pos, const char *fmt, ...)
788*95c635efSGarrett D'Amore {
789*95c635efSGarrett D'Amore 	char		 buf[256];
790*95c635efSGarrett D'Amore 	va_list		 ap;
791*95c635efSGarrett D'Amore 
792*95c635efSGarrett D'Amore 	va_start(ap, fmt);
793*95c635efSGarrett D'Amore 	vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
794*95c635efSGarrett D'Amore 	va_end(ap);
795*95c635efSGarrett D'Amore 
796*95c635efSGarrett D'Amore 	mandoc_msg(t, m, ln, pos, buf);
797*95c635efSGarrett D'Amore }
798*95c635efSGarrett D'Amore 
799*95c635efSGarrett D'Amore void
800*95c635efSGarrett D'Amore mandoc_msg(enum mandocerr er, struct mparse *m,
801*95c635efSGarrett D'Amore 		int ln, int col, const char *msg)
802*95c635efSGarrett D'Amore {
803*95c635efSGarrett D'Amore 	enum mandoclevel level;
804*95c635efSGarrett D'Amore 
805*95c635efSGarrett D'Amore 	level = MANDOCLEVEL_FATAL;
806*95c635efSGarrett D'Amore 	while (er < mandoclimits[level])
807*95c635efSGarrett D'Amore 		level--;
808*95c635efSGarrett D'Amore 
809*95c635efSGarrett D'Amore 	if (level < m->wlevel)
810*95c635efSGarrett D'Amore 		return;
811*95c635efSGarrett D'Amore 
812*95c635efSGarrett D'Amore 	if (m->mmsg)
813*95c635efSGarrett D'Amore 		(*m->mmsg)(er, level, m->file, ln, col, msg);
814*95c635efSGarrett D'Amore 
815*95c635efSGarrett D'Amore 	if (m->file_status < level)
816*95c635efSGarrett D'Amore 		m->file_status = level;
817*95c635efSGarrett D'Amore }
818*95c635efSGarrett D'Amore 
819*95c635efSGarrett D'Amore const char *
820*95c635efSGarrett D'Amore mparse_strerror(enum mandocerr er)
821*95c635efSGarrett D'Amore {
822*95c635efSGarrett D'Amore 
823*95c635efSGarrett D'Amore 	return(mandocerrs[er]);
824*95c635efSGarrett D'Amore }
825*95c635efSGarrett D'Amore 
826*95c635efSGarrett D'Amore const char *
827*95c635efSGarrett D'Amore mparse_strlevel(enum mandoclevel lvl)
828*95c635efSGarrett D'Amore {
829*95c635efSGarrett D'Amore 	return(mandoclevels[lvl]);
830*95c635efSGarrett D'Amore }
831*95c635efSGarrett D'Amore 
832*95c635efSGarrett D'Amore void
833*95c635efSGarrett D'Amore mparse_keep(struct mparse *p)
834*95c635efSGarrett D'Amore {
835*95c635efSGarrett D'Amore 
836*95c635efSGarrett D'Amore 	assert(NULL == p->secondary);
837*95c635efSGarrett D'Amore 	p->secondary = mandoc_calloc(1, sizeof(struct buf));
838*95c635efSGarrett D'Amore }
839*95c635efSGarrett D'Amore 
840*95c635efSGarrett D'Amore const char *
841*95c635efSGarrett D'Amore mparse_getkeep(const struct mparse *p)
842*95c635efSGarrett D'Amore {
843*95c635efSGarrett D'Amore 
844*95c635efSGarrett D'Amore 	assert(p->secondary);
845*95c635efSGarrett D'Amore 	return(p->secondary->sz ? p->secondary->buf : NULL);
846*95c635efSGarrett D'Amore }
847