1*698f87a4SGarrett D'Amore /* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #ifdef HAVE_MMAP
2395c635efSGarrett D'Amore # include <sys/stat.h>
2495c635efSGarrett D'Amore # include <sys/mman.h>
2595c635efSGarrett D'Amore #endif
2695c635efSGarrett D'Amore
2795c635efSGarrett D'Amore #include <assert.h>
2895c635efSGarrett D'Amore #include <ctype.h>
2995c635efSGarrett D'Amore #include <fcntl.h>
3095c635efSGarrett D'Amore #include <stdarg.h>
3195c635efSGarrett D'Amore #include <stdint.h>
3295c635efSGarrett D'Amore #include <stdio.h>
3395c635efSGarrett D'Amore #include <stdlib.h>
3495c635efSGarrett D'Amore #include <string.h>
3595c635efSGarrett D'Amore #include <unistd.h>
3695c635efSGarrett D'Amore
3795c635efSGarrett D'Amore #include "mandoc.h"
3895c635efSGarrett D'Amore #include "libmandoc.h"
3995c635efSGarrett D'Amore #include "mdoc.h"
4095c635efSGarrett D'Amore #include "man.h"
4195c635efSGarrett D'Amore #include "main.h"
4295c635efSGarrett D'Amore
4395c635efSGarrett D'Amore #define REPARSE_LIMIT 1000
4495c635efSGarrett D'Amore
4595c635efSGarrett D'Amore struct buf {
4695c635efSGarrett D'Amore char *buf; /* binary input buffer */
4795c635efSGarrett D'Amore size_t sz; /* size of binary buffer */
4895c635efSGarrett D'Amore };
4995c635efSGarrett D'Amore
5095c635efSGarrett D'Amore struct mparse {
5195c635efSGarrett D'Amore enum mandoclevel file_status; /* status of current parse */
5295c635efSGarrett D'Amore enum mandoclevel wlevel; /* ignore messages below this */
5395c635efSGarrett D'Amore int line; /* line number in the file */
5495c635efSGarrett D'Amore enum mparset inttype; /* which parser to use */
5595c635efSGarrett D'Amore struct man *pman; /* persistent man parser */
5695c635efSGarrett D'Amore struct mdoc *pmdoc; /* persistent mdoc parser */
5795c635efSGarrett D'Amore struct man *man; /* man parser */
5895c635efSGarrett D'Amore struct mdoc *mdoc; /* mdoc parser */
5995c635efSGarrett D'Amore struct roff *roff; /* roff parser (!NULL) */
6095c635efSGarrett D'Amore int reparse_count; /* finite interp. stack */
6195c635efSGarrett D'Amore mandocmsg mmsg; /* warning/error message handler */
6295c635efSGarrett D'Amore void *arg; /* argument to mmsg */
6395c635efSGarrett D'Amore const char *file;
6495c635efSGarrett D'Amore struct buf *secondary;
65*698f87a4SGarrett D'Amore char *defos; /* default operating system */
6695c635efSGarrett D'Amore };
6795c635efSGarrett D'Amore
6895c635efSGarrett D'Amore static void resize_buf(struct buf *, size_t);
6995c635efSGarrett D'Amore static void mparse_buf_r(struct mparse *, struct buf, int);
7095c635efSGarrett D'Amore static void pset(const char *, int, struct mparse *);
7195c635efSGarrett D'Amore static int read_whole_file(const char *, int, struct buf *, int *);
7295c635efSGarrett D'Amore static void mparse_end(struct mparse *);
73*698f87a4SGarrett D'Amore static void mparse_parse_buffer(struct mparse *, struct buf,
74*698f87a4SGarrett D'Amore const char *);
7595c635efSGarrett D'Amore
7695c635efSGarrett D'Amore static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
7795c635efSGarrett D'Amore MANDOCERR_OK,
7895c635efSGarrett D'Amore MANDOCERR_WARNING,
7995c635efSGarrett D'Amore MANDOCERR_WARNING,
8095c635efSGarrett D'Amore MANDOCERR_ERROR,
8195c635efSGarrett D'Amore MANDOCERR_FATAL,
8295c635efSGarrett D'Amore MANDOCERR_MAX,
8395c635efSGarrett D'Amore MANDOCERR_MAX
8495c635efSGarrett D'Amore };
8595c635efSGarrett D'Amore
8695c635efSGarrett D'Amore static const char * const mandocerrs[MANDOCERR_MAX] = {
8795c635efSGarrett D'Amore "ok",
8895c635efSGarrett D'Amore
8995c635efSGarrett D'Amore "generic warning",
9095c635efSGarrett D'Amore
9195c635efSGarrett D'Amore /* related to the prologue */
9295c635efSGarrett D'Amore "no title in document",
9395c635efSGarrett D'Amore "document title should be all caps",
9495c635efSGarrett D'Amore "unknown manual section",
95*698f87a4SGarrett D'Amore "unknown manual volume or arch",
9695c635efSGarrett D'Amore "date missing, using today's date",
9795c635efSGarrett D'Amore "cannot parse date, using it verbatim",
9895c635efSGarrett D'Amore "prologue macros out of order",
9995c635efSGarrett D'Amore "duplicate prologue macro",
10095c635efSGarrett D'Amore "macro not allowed in prologue",
10195c635efSGarrett D'Amore "macro not allowed in body",
10295c635efSGarrett D'Amore
10395c635efSGarrett D'Amore /* related to document structure */
10495c635efSGarrett D'Amore ".so is fragile, better use ln(1)",
10595c635efSGarrett D'Amore "NAME section must come first",
10695c635efSGarrett D'Amore "bad NAME section contents",
10795c635efSGarrett D'Amore "sections out of conventional order",
10895c635efSGarrett D'Amore "duplicate section name",
109*698f87a4SGarrett D'Amore "section header suited to sections 2, 3, and 9 only",
11095c635efSGarrett D'Amore
11195c635efSGarrett D'Amore /* related to macros and nesting */
11295c635efSGarrett D'Amore "skipping obsolete macro",
11395c635efSGarrett D'Amore "skipping paragraph macro",
114*698f87a4SGarrett D'Amore "moving paragraph macro out of list",
11595c635efSGarrett D'Amore "skipping no-space macro",
11695c635efSGarrett D'Amore "blocks badly nested",
11795c635efSGarrett D'Amore "child violates parent syntax",
11895c635efSGarrett D'Amore "nested displays are not portable",
11995c635efSGarrett D'Amore "already in literal mode",
12095c635efSGarrett D'Amore "line scope broken",
12195c635efSGarrett D'Amore
12295c635efSGarrett D'Amore /* related to missing macro arguments */
12395c635efSGarrett D'Amore "skipping empty macro",
12495c635efSGarrett D'Amore "argument count wrong",
12595c635efSGarrett D'Amore "missing display type",
12695c635efSGarrett D'Amore "list type must come first",
12795c635efSGarrett D'Amore "tag lists require a width argument",
12895c635efSGarrett D'Amore "missing font type",
12995c635efSGarrett D'Amore "skipping end of block that is not open",
13095c635efSGarrett D'Amore
13195c635efSGarrett D'Amore /* related to bad macro arguments */
13295c635efSGarrett D'Amore "skipping argument",
13395c635efSGarrett D'Amore "duplicate argument",
13495c635efSGarrett D'Amore "duplicate display type",
13595c635efSGarrett D'Amore "duplicate list type",
13695c635efSGarrett D'Amore "unknown AT&T UNIX version",
13795c635efSGarrett D'Amore "bad Boolean value",
13895c635efSGarrett D'Amore "unknown font",
13995c635efSGarrett D'Amore "unknown standard specifier",
14095c635efSGarrett D'Amore "bad width argument",
14195c635efSGarrett D'Amore
14295c635efSGarrett D'Amore /* related to plain text */
14395c635efSGarrett D'Amore "blank line in non-literal context",
14495c635efSGarrett D'Amore "tab in non-literal context",
14595c635efSGarrett D'Amore "end of line whitespace",
14695c635efSGarrett D'Amore "bad comment style",
14795c635efSGarrett D'Amore "bad escape sequence",
14895c635efSGarrett D'Amore "unterminated quoted string",
14995c635efSGarrett D'Amore
15095c635efSGarrett D'Amore /* related to equations */
15195c635efSGarrett D'Amore "unexpected literal in equation",
15295c635efSGarrett D'Amore
15395c635efSGarrett D'Amore "generic error",
15495c635efSGarrett D'Amore
15595c635efSGarrett D'Amore /* related to equations */
15695c635efSGarrett D'Amore "unexpected equation scope closure",
15795c635efSGarrett D'Amore "equation scope open on exit",
15895c635efSGarrett D'Amore "overlapping equation scopes",
15995c635efSGarrett D'Amore "unexpected end of equation",
16095c635efSGarrett D'Amore "equation syntax error",
16195c635efSGarrett D'Amore
16295c635efSGarrett D'Amore /* related to tables */
16395c635efSGarrett D'Amore "bad table syntax",
16495c635efSGarrett D'Amore "bad table option",
16595c635efSGarrett D'Amore "bad table layout",
16695c635efSGarrett D'Amore "no table layout cells specified",
16795c635efSGarrett D'Amore "no table data cells specified",
16895c635efSGarrett D'Amore "ignore data in cell",
16995c635efSGarrett D'Amore "data block still open",
17095c635efSGarrett D'Amore "ignoring extra data cells",
17195c635efSGarrett D'Amore
17295c635efSGarrett D'Amore "input stack limit exceeded, infinite loop?",
17395c635efSGarrett D'Amore "skipping bad character",
17495c635efSGarrett D'Amore "escaped character not allowed in a name",
175*698f87a4SGarrett D'Amore "manual name not yet set",
17695c635efSGarrett D'Amore "skipping text before the first section header",
17795c635efSGarrett D'Amore "skipping unknown macro",
17895c635efSGarrett D'Amore "NOT IMPLEMENTED, please use groff: skipping request",
17995c635efSGarrett D'Amore "argument count wrong",
180*698f87a4SGarrett D'Amore "skipping column outside column list",
18195c635efSGarrett D'Amore "skipping end of block that is not open",
18295c635efSGarrett D'Amore "missing end of block",
18395c635efSGarrett D'Amore "scope open on exit",
18495c635efSGarrett D'Amore "uname(3) system call failed",
18595c635efSGarrett D'Amore "macro requires line argument(s)",
18695c635efSGarrett D'Amore "macro requires body argument(s)",
18795c635efSGarrett D'Amore "macro requires argument(s)",
188*698f87a4SGarrett D'Amore "request requires a numeric argument",
18995c635efSGarrett D'Amore "missing list type",
19095c635efSGarrett D'Amore "line argument(s) will be lost",
19195c635efSGarrett D'Amore "body argument(s) will be lost",
19295c635efSGarrett D'Amore
19395c635efSGarrett D'Amore "generic fatal error",
19495c635efSGarrett D'Amore
19595c635efSGarrett D'Amore "not a manual",
19695c635efSGarrett D'Amore "column syntax is inconsistent",
19795c635efSGarrett D'Amore "NOT IMPLEMENTED: .Bd -file",
19895c635efSGarrett D'Amore "argument count wrong, violates syntax",
19995c635efSGarrett D'Amore "child violates parent syntax",
20095c635efSGarrett D'Amore "argument count wrong, violates syntax",
20195c635efSGarrett D'Amore "NOT IMPLEMENTED: .so with absolute path or \"..\"",
20295c635efSGarrett D'Amore "no document body",
20395c635efSGarrett D'Amore "no document prologue",
20495c635efSGarrett D'Amore "static buffer exhausted",
20595c635efSGarrett D'Amore };
20695c635efSGarrett D'Amore
20795c635efSGarrett D'Amore static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
20895c635efSGarrett D'Amore "SUCCESS",
20995c635efSGarrett D'Amore "RESERVED",
21095c635efSGarrett D'Amore "WARNING",
21195c635efSGarrett D'Amore "ERROR",
21295c635efSGarrett D'Amore "FATAL",
21395c635efSGarrett D'Amore "BADARG",
21495c635efSGarrett D'Amore "SYSERR"
21595c635efSGarrett D'Amore };
21695c635efSGarrett D'Amore
21795c635efSGarrett D'Amore static void
resize_buf(struct buf * buf,size_t initial)21895c635efSGarrett D'Amore resize_buf(struct buf *buf, size_t initial)
21995c635efSGarrett D'Amore {
22095c635efSGarrett D'Amore
22195c635efSGarrett D'Amore buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
22295c635efSGarrett D'Amore buf->buf = mandoc_realloc(buf->buf, buf->sz);
22395c635efSGarrett D'Amore }
22495c635efSGarrett D'Amore
22595c635efSGarrett D'Amore static void
pset(const char * buf,int pos,struct mparse * curp)22695c635efSGarrett D'Amore pset(const char *buf, int pos, struct mparse *curp)
22795c635efSGarrett D'Amore {
22895c635efSGarrett D'Amore int i;
22995c635efSGarrett D'Amore
23095c635efSGarrett D'Amore /*
23195c635efSGarrett D'Amore * Try to intuit which kind of manual parser should be used. If
23295c635efSGarrett D'Amore * passed in by command-line (-man, -mdoc), then use that
23395c635efSGarrett D'Amore * explicitly. If passed as -mandoc, then try to guess from the
23495c635efSGarrett D'Amore * line: either skip dot-lines, use -mdoc when finding `.Dt', or
23595c635efSGarrett D'Amore * default to -man, which is more lenient.
23695c635efSGarrett D'Amore *
23795c635efSGarrett D'Amore * Separate out pmdoc/pman from mdoc/man: the first persists
23895c635efSGarrett D'Amore * through all parsers, while the latter is used per-parse.
23995c635efSGarrett D'Amore */
24095c635efSGarrett D'Amore
24195c635efSGarrett D'Amore if ('.' == buf[0] || '\'' == buf[0]) {
24295c635efSGarrett D'Amore for (i = 1; buf[i]; i++)
24395c635efSGarrett D'Amore if (' ' != buf[i] && '\t' != buf[i])
24495c635efSGarrett D'Amore break;
24595c635efSGarrett D'Amore if ('\0' == buf[i])
24695c635efSGarrett D'Amore return;
24795c635efSGarrett D'Amore }
24895c635efSGarrett D'Amore
24995c635efSGarrett D'Amore switch (curp->inttype) {
25095c635efSGarrett D'Amore case (MPARSE_MDOC):
25195c635efSGarrett D'Amore if (NULL == curp->pmdoc)
252*698f87a4SGarrett D'Amore curp->pmdoc = mdoc_alloc(curp->roff, curp,
253*698f87a4SGarrett D'Amore curp->defos);
25495c635efSGarrett D'Amore assert(curp->pmdoc);
25595c635efSGarrett D'Amore curp->mdoc = curp->pmdoc;
25695c635efSGarrett D'Amore return;
25795c635efSGarrett D'Amore case (MPARSE_MAN):
25895c635efSGarrett D'Amore if (NULL == curp->pman)
25995c635efSGarrett D'Amore curp->pman = man_alloc(curp->roff, curp);
26095c635efSGarrett D'Amore assert(curp->pman);
26195c635efSGarrett D'Amore curp->man = curp->pman;
26295c635efSGarrett D'Amore return;
26395c635efSGarrett D'Amore default:
26495c635efSGarrett D'Amore break;
26595c635efSGarrett D'Amore }
26695c635efSGarrett D'Amore
26795c635efSGarrett D'Amore if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
26895c635efSGarrett D'Amore if (NULL == curp->pmdoc)
269*698f87a4SGarrett D'Amore curp->pmdoc = mdoc_alloc(curp->roff, curp,
270*698f87a4SGarrett D'Amore curp->defos);
27195c635efSGarrett D'Amore assert(curp->pmdoc);
27295c635efSGarrett D'Amore curp->mdoc = curp->pmdoc;
27395c635efSGarrett D'Amore return;
27495c635efSGarrett D'Amore }
27595c635efSGarrett D'Amore
27695c635efSGarrett D'Amore if (NULL == curp->pman)
27795c635efSGarrett D'Amore curp->pman = man_alloc(curp->roff, curp);
27895c635efSGarrett D'Amore assert(curp->pman);
27995c635efSGarrett D'Amore curp->man = curp->pman;
28095c635efSGarrett D'Amore }
28195c635efSGarrett D'Amore
28295c635efSGarrett D'Amore /*
28395c635efSGarrett D'Amore * Main parse routine for an opened file. This is called for each
28495c635efSGarrett D'Amore * opened file and simply loops around the full input file, possibly
28595c635efSGarrett D'Amore * nesting (i.e., with `so').
28695c635efSGarrett D'Amore */
28795c635efSGarrett D'Amore static void
mparse_buf_r(struct mparse * curp,struct buf blk,int start)28895c635efSGarrett D'Amore mparse_buf_r(struct mparse *curp, struct buf blk, int start)
28995c635efSGarrett D'Amore {
29095c635efSGarrett D'Amore const struct tbl_span *span;
29195c635efSGarrett D'Amore struct buf ln;
29295c635efSGarrett D'Amore enum rofferr rr;
29395c635efSGarrett D'Amore int i, of, rc;
29495c635efSGarrett D'Amore int pos; /* byte number in the ln buffer */
29595c635efSGarrett D'Amore int lnn; /* line number in the real file */
29695c635efSGarrett D'Amore unsigned char c;
29795c635efSGarrett D'Amore
29895c635efSGarrett D'Amore memset(&ln, 0, sizeof(struct buf));
29995c635efSGarrett D'Amore
30095c635efSGarrett D'Amore lnn = curp->line;
30195c635efSGarrett D'Amore pos = 0;
30295c635efSGarrett D'Amore
30395c635efSGarrett D'Amore for (i = 0; i < (int)blk.sz; ) {
30495c635efSGarrett D'Amore if (0 == pos && '\0' == blk.buf[i])
30595c635efSGarrett D'Amore break;
30695c635efSGarrett D'Amore
30795c635efSGarrett D'Amore if (start) {
30895c635efSGarrett D'Amore curp->line = lnn;
30995c635efSGarrett D'Amore curp->reparse_count = 0;
31095c635efSGarrett D'Amore }
31195c635efSGarrett D'Amore
31295c635efSGarrett D'Amore while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
31395c635efSGarrett D'Amore
31495c635efSGarrett D'Amore /*
31595c635efSGarrett D'Amore * When finding an unescaped newline character,
31695c635efSGarrett D'Amore * leave the character loop to process the line.
31795c635efSGarrett D'Amore * Skip a preceding carriage return, if any.
31895c635efSGarrett D'Amore */
31995c635efSGarrett D'Amore
32095c635efSGarrett D'Amore if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
32195c635efSGarrett D'Amore '\n' == blk.buf[i + 1])
32295c635efSGarrett D'Amore ++i;
32395c635efSGarrett D'Amore if ('\n' == blk.buf[i]) {
32495c635efSGarrett D'Amore ++i;
32595c635efSGarrett D'Amore ++lnn;
32695c635efSGarrett D'Amore break;
32795c635efSGarrett D'Amore }
32895c635efSGarrett D'Amore
32995c635efSGarrett D'Amore /*
330*698f87a4SGarrett D'Amore * Make sure we have space for at least
331*698f87a4SGarrett D'Amore * one backslash and one other character
332*698f87a4SGarrett D'Amore * and the trailing NUL byte.
333*698f87a4SGarrett D'Amore */
334*698f87a4SGarrett D'Amore
335*698f87a4SGarrett D'Amore if (pos + 2 >= (int)ln.sz)
336*698f87a4SGarrett D'Amore resize_buf(&ln, 256);
337*698f87a4SGarrett D'Amore
338*698f87a4SGarrett D'Amore /*
33995c635efSGarrett D'Amore * Warn about bogus characters. If you're using
34095c635efSGarrett D'Amore * non-ASCII encoding, you're screwing your
34195c635efSGarrett D'Amore * readers. Since I'd rather this not happen,
34295c635efSGarrett D'Amore * I'll be helpful and replace these characters
34395c635efSGarrett D'Amore * with "?", so we don't display gibberish.
34495c635efSGarrett D'Amore * Note to manual writers: use special characters.
34595c635efSGarrett D'Amore */
34695c635efSGarrett D'Amore
34795c635efSGarrett D'Amore c = (unsigned char) blk.buf[i];
34895c635efSGarrett D'Amore
34995c635efSGarrett D'Amore if ( ! (isascii(c) &&
35095c635efSGarrett D'Amore (isgraph(c) || isblank(c)))) {
35195c635efSGarrett D'Amore mandoc_msg(MANDOCERR_BADCHAR, curp,
35295c635efSGarrett D'Amore curp->line, pos, NULL);
35395c635efSGarrett D'Amore i++;
35495c635efSGarrett D'Amore ln.buf[pos++] = '?';
35595c635efSGarrett D'Amore continue;
35695c635efSGarrett D'Amore }
35795c635efSGarrett D'Amore
35895c635efSGarrett D'Amore /* Trailing backslash = a plain char. */
35995c635efSGarrett D'Amore
36095c635efSGarrett D'Amore if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
36195c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++];
36295c635efSGarrett D'Amore continue;
36395c635efSGarrett D'Amore }
36495c635efSGarrett D'Amore
36595c635efSGarrett D'Amore /*
36695c635efSGarrett D'Amore * Found escape and at least one other character.
36795c635efSGarrett D'Amore * When it's a newline character, skip it.
36895c635efSGarrett D'Amore * When there is a carriage return in between,
36995c635efSGarrett D'Amore * skip that one as well.
37095c635efSGarrett D'Amore */
37195c635efSGarrett D'Amore
37295c635efSGarrett D'Amore if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
37395c635efSGarrett D'Amore '\n' == blk.buf[i + 2])
37495c635efSGarrett D'Amore ++i;
37595c635efSGarrett D'Amore if ('\n' == blk.buf[i + 1]) {
37695c635efSGarrett D'Amore i += 2;
37795c635efSGarrett D'Amore ++lnn;
37895c635efSGarrett D'Amore continue;
37995c635efSGarrett D'Amore }
38095c635efSGarrett D'Amore
38195c635efSGarrett D'Amore if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
38295c635efSGarrett D'Amore i += 2;
38395c635efSGarrett D'Amore /* Comment, skip to end of line */
38495c635efSGarrett D'Amore for (; i < (int)blk.sz; ++i) {
38595c635efSGarrett D'Amore if ('\n' == blk.buf[i]) {
38695c635efSGarrett D'Amore ++i;
38795c635efSGarrett D'Amore ++lnn;
38895c635efSGarrett D'Amore break;
38995c635efSGarrett D'Amore }
39095c635efSGarrett D'Amore }
39195c635efSGarrett D'Amore
39295c635efSGarrett D'Amore /* Backout trailing whitespaces */
39395c635efSGarrett D'Amore for (; pos > 0; --pos) {
39495c635efSGarrett D'Amore if (ln.buf[pos - 1] != ' ')
39595c635efSGarrett D'Amore break;
39695c635efSGarrett D'Amore if (pos > 2 && ln.buf[pos - 2] == '\\')
39795c635efSGarrett D'Amore break;
39895c635efSGarrett D'Amore }
39995c635efSGarrett D'Amore break;
40095c635efSGarrett D'Amore }
40195c635efSGarrett D'Amore
402*698f87a4SGarrett D'Amore /* Catch escaped bogus characters. */
40395c635efSGarrett D'Amore
404*698f87a4SGarrett D'Amore c = (unsigned char) blk.buf[i+1];
405*698f87a4SGarrett D'Amore
406*698f87a4SGarrett D'Amore if ( ! (isascii(c) &&
407*698f87a4SGarrett D'Amore (isgraph(c) || isblank(c)))) {
408*698f87a4SGarrett D'Amore mandoc_msg(MANDOCERR_BADCHAR, curp,
409*698f87a4SGarrett D'Amore curp->line, pos, NULL);
410*698f87a4SGarrett D'Amore i += 2;
411*698f87a4SGarrett D'Amore ln.buf[pos++] = '?';
412*698f87a4SGarrett D'Amore continue;
413*698f87a4SGarrett D'Amore }
414*698f87a4SGarrett D'Amore
415*698f87a4SGarrett D'Amore /* Some other escape sequence, copy & cont. */
41695c635efSGarrett D'Amore
41795c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++];
41895c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++];
41995c635efSGarrett D'Amore }
42095c635efSGarrett D'Amore
42195c635efSGarrett D'Amore if (pos >= (int)ln.sz)
42295c635efSGarrett D'Amore resize_buf(&ln, 256);
42395c635efSGarrett D'Amore
42495c635efSGarrett D'Amore ln.buf[pos] = '\0';
42595c635efSGarrett D'Amore
42695c635efSGarrett D'Amore /*
42795c635efSGarrett D'Amore * A significant amount of complexity is contained by
42895c635efSGarrett D'Amore * the roff preprocessor. It's line-oriented but can be
42995c635efSGarrett D'Amore * expressed on one line, so we need at times to
43095c635efSGarrett D'Amore * readjust our starting point and re-run it. The roff
43195c635efSGarrett D'Amore * preprocessor can also readjust the buffers with new
43295c635efSGarrett D'Amore * data, so we pass them in wholesale.
43395c635efSGarrett D'Amore */
43495c635efSGarrett D'Amore
43595c635efSGarrett D'Amore of = 0;
43695c635efSGarrett D'Amore
43795c635efSGarrett D'Amore /*
43895c635efSGarrett D'Amore * Maintain a lookaside buffer of all parsed lines. We
43995c635efSGarrett D'Amore * only do this if mparse_keep() has been invoked (the
44095c635efSGarrett D'Amore * buffer may be accessed with mparse_getkeep()).
44195c635efSGarrett D'Amore */
44295c635efSGarrett D'Amore
44395c635efSGarrett D'Amore if (curp->secondary) {
44495c635efSGarrett D'Amore curp->secondary->buf =
44595c635efSGarrett D'Amore mandoc_realloc
44695c635efSGarrett D'Amore (curp->secondary->buf,
44795c635efSGarrett D'Amore curp->secondary->sz + pos + 2);
44895c635efSGarrett D'Amore memcpy(curp->secondary->buf +
44995c635efSGarrett D'Amore curp->secondary->sz,
45095c635efSGarrett D'Amore ln.buf, pos);
45195c635efSGarrett D'Amore curp->secondary->sz += pos;
45295c635efSGarrett D'Amore curp->secondary->buf
45395c635efSGarrett D'Amore [curp->secondary->sz] = '\n';
45495c635efSGarrett D'Amore curp->secondary->sz++;
45595c635efSGarrett D'Amore curp->secondary->buf
45695c635efSGarrett D'Amore [curp->secondary->sz] = '\0';
45795c635efSGarrett D'Amore }
45895c635efSGarrett D'Amore rerun:
45995c635efSGarrett D'Amore rr = roff_parseln
46095c635efSGarrett D'Amore (curp->roff, curp->line,
46195c635efSGarrett D'Amore &ln.buf, &ln.sz, of, &of);
46295c635efSGarrett D'Amore
46395c635efSGarrett D'Amore switch (rr) {
46495c635efSGarrett D'Amore case (ROFF_REPARSE):
46595c635efSGarrett D'Amore if (REPARSE_LIMIT >= ++curp->reparse_count)
46695c635efSGarrett D'Amore mparse_buf_r(curp, ln, 0);
46795c635efSGarrett D'Amore else
46895c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ROFFLOOP, curp,
46995c635efSGarrett D'Amore curp->line, pos, NULL);
47095c635efSGarrett D'Amore pos = 0;
47195c635efSGarrett D'Amore continue;
47295c635efSGarrett D'Amore case (ROFF_APPEND):
47395c635efSGarrett D'Amore pos = (int)strlen(ln.buf);
47495c635efSGarrett D'Amore continue;
47595c635efSGarrett D'Amore case (ROFF_RERUN):
47695c635efSGarrett D'Amore goto rerun;
47795c635efSGarrett D'Amore case (ROFF_IGN):
47895c635efSGarrett D'Amore pos = 0;
47995c635efSGarrett D'Amore continue;
48095c635efSGarrett D'Amore case (ROFF_ERR):
48195c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status);
48295c635efSGarrett D'Amore break;
48395c635efSGarrett D'Amore case (ROFF_SO):
48495c635efSGarrett D'Amore /*
48595c635efSGarrett D'Amore * We remove `so' clauses from our lookaside
48695c635efSGarrett D'Amore * buffer because we're going to descend into
48795c635efSGarrett D'Amore * the file recursively.
48895c635efSGarrett D'Amore */
48995c635efSGarrett D'Amore if (curp->secondary)
49095c635efSGarrett D'Amore curp->secondary->sz -= pos + 1;
491*698f87a4SGarrett D'Amore mparse_readfd(curp, -1, ln.buf + of);
49295c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status)
49395c635efSGarrett D'Amore break;
49495c635efSGarrett D'Amore pos = 0;
49595c635efSGarrett D'Amore continue;
49695c635efSGarrett D'Amore default:
49795c635efSGarrett D'Amore break;
49895c635efSGarrett D'Amore }
49995c635efSGarrett D'Amore
50095c635efSGarrett D'Amore /*
50195c635efSGarrett D'Amore * If we encounter errors in the recursive parse, make
50295c635efSGarrett D'Amore * sure we don't continue parsing.
50395c635efSGarrett D'Amore */
50495c635efSGarrett D'Amore
50595c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status)
50695c635efSGarrett D'Amore break;
50795c635efSGarrett D'Amore
50895c635efSGarrett D'Amore /*
50995c635efSGarrett D'Amore * If input parsers have not been allocated, do so now.
51095c635efSGarrett D'Amore * We keep these instanced between parsers, but set them
51195c635efSGarrett D'Amore * locally per parse routine since we can use different
51295c635efSGarrett D'Amore * parsers with each one.
51395c635efSGarrett D'Amore */
51495c635efSGarrett D'Amore
51595c635efSGarrett D'Amore if ( ! (curp->man || curp->mdoc))
51695c635efSGarrett D'Amore pset(ln.buf + of, pos - of, curp);
51795c635efSGarrett D'Amore
51895c635efSGarrett D'Amore /*
51995c635efSGarrett D'Amore * Lastly, push down into the parsers themselves. One
52095c635efSGarrett D'Amore * of these will have already been set in the pset()
52195c635efSGarrett D'Amore * routine.
52295c635efSGarrett D'Amore * If libroff returns ROFF_TBL, then add it to the
52395c635efSGarrett D'Amore * currently open parse. Since we only get here if
52495c635efSGarrett D'Amore * there does exist data (see tbl_data.c), we're
52595c635efSGarrett D'Amore * guaranteed that something's been allocated.
52695c635efSGarrett D'Amore * Do the same for ROFF_EQN.
52795c635efSGarrett D'Amore */
52895c635efSGarrett D'Amore
52995c635efSGarrett D'Amore rc = -1;
53095c635efSGarrett D'Amore
53195c635efSGarrett D'Amore if (ROFF_TBL == rr)
53295c635efSGarrett D'Amore while (NULL != (span = roff_span(curp->roff))) {
53395c635efSGarrett D'Amore rc = curp->man ?
53495c635efSGarrett D'Amore man_addspan(curp->man, span) :
53595c635efSGarrett D'Amore mdoc_addspan(curp->mdoc, span);
53695c635efSGarrett D'Amore if (0 == rc)
53795c635efSGarrett D'Amore break;
53895c635efSGarrett D'Amore }
53995c635efSGarrett D'Amore else if (ROFF_EQN == rr)
54095c635efSGarrett D'Amore rc = curp->mdoc ?
54195c635efSGarrett D'Amore mdoc_addeqn(curp->mdoc,
54295c635efSGarrett D'Amore roff_eqn(curp->roff)) :
54395c635efSGarrett D'Amore man_addeqn(curp->man,
54495c635efSGarrett D'Amore roff_eqn(curp->roff));
54595c635efSGarrett D'Amore else if (curp->man || curp->mdoc)
54695c635efSGarrett D'Amore rc = curp->man ?
54795c635efSGarrett D'Amore man_parseln(curp->man,
54895c635efSGarrett D'Amore curp->line, ln.buf, of) :
54995c635efSGarrett D'Amore mdoc_parseln(curp->mdoc,
55095c635efSGarrett D'Amore curp->line, ln.buf, of);
55195c635efSGarrett D'Amore
55295c635efSGarrett D'Amore if (0 == rc) {
55395c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status);
55495c635efSGarrett D'Amore break;
55595c635efSGarrett D'Amore }
55695c635efSGarrett D'Amore
55795c635efSGarrett D'Amore /* Temporary buffers typically are not full. */
55895c635efSGarrett D'Amore
55995c635efSGarrett D'Amore if (0 == start && '\0' == blk.buf[i])
56095c635efSGarrett D'Amore break;
56195c635efSGarrett D'Amore
56295c635efSGarrett D'Amore /* Start the next input line. */
56395c635efSGarrett D'Amore
56495c635efSGarrett D'Amore pos = 0;
56595c635efSGarrett D'Amore }
56695c635efSGarrett D'Amore
56795c635efSGarrett D'Amore free(ln.buf);
56895c635efSGarrett D'Amore }
56995c635efSGarrett D'Amore
57095c635efSGarrett D'Amore static int
read_whole_file(const char * file,int fd,struct buf * fb,int * with_mmap)57195c635efSGarrett D'Amore read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
57295c635efSGarrett D'Amore {
57395c635efSGarrett D'Amore size_t off;
57495c635efSGarrett D'Amore ssize_t ssz;
57595c635efSGarrett D'Amore
57695c635efSGarrett D'Amore #ifdef HAVE_MMAP
57795c635efSGarrett D'Amore struct stat st;
57895c635efSGarrett D'Amore if (-1 == fstat(fd, &st)) {
57995c635efSGarrett D'Amore perror(file);
58095c635efSGarrett D'Amore return(0);
58195c635efSGarrett D'Amore }
58295c635efSGarrett D'Amore
58395c635efSGarrett D'Amore /*
58495c635efSGarrett D'Amore * If we're a regular file, try just reading in the whole entry
58595c635efSGarrett D'Amore * via mmap(). This is faster than reading it into blocks, and
58695c635efSGarrett D'Amore * since each file is only a few bytes to begin with, I'm not
58795c635efSGarrett D'Amore * concerned that this is going to tank any machines.
58895c635efSGarrett D'Amore */
58995c635efSGarrett D'Amore
59095c635efSGarrett D'Amore if (S_ISREG(st.st_mode)) {
59195c635efSGarrett D'Amore if (st.st_size >= (1U << 31)) {
59295c635efSGarrett D'Amore fprintf(stderr, "%s: input too large\n", file);
59395c635efSGarrett D'Amore return(0);
59495c635efSGarrett D'Amore }
59595c635efSGarrett D'Amore *with_mmap = 1;
59695c635efSGarrett D'Amore fb->sz = (size_t)st.st_size;
597*698f87a4SGarrett D'Amore fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
59895c635efSGarrett D'Amore if (fb->buf != MAP_FAILED)
59995c635efSGarrett D'Amore return(1);
60095c635efSGarrett D'Amore }
60195c635efSGarrett D'Amore #endif
60295c635efSGarrett D'Amore
60395c635efSGarrett D'Amore /*
60495c635efSGarrett D'Amore * If this isn't a regular file (like, say, stdin), then we must
60595c635efSGarrett D'Amore * go the old way and just read things in bit by bit.
60695c635efSGarrett D'Amore */
60795c635efSGarrett D'Amore
60895c635efSGarrett D'Amore *with_mmap = 0;
60995c635efSGarrett D'Amore off = 0;
61095c635efSGarrett D'Amore fb->sz = 0;
61195c635efSGarrett D'Amore fb->buf = NULL;
61295c635efSGarrett D'Amore for (;;) {
61395c635efSGarrett D'Amore if (off == fb->sz) {
61495c635efSGarrett D'Amore if (fb->sz == (1U << 31)) {
61595c635efSGarrett D'Amore fprintf(stderr, "%s: input too large\n", file);
61695c635efSGarrett D'Amore break;
61795c635efSGarrett D'Amore }
61895c635efSGarrett D'Amore resize_buf(fb, 65536);
61995c635efSGarrett D'Amore }
62095c635efSGarrett D'Amore ssz = read(fd, fb->buf + (int)off, fb->sz - off);
62195c635efSGarrett D'Amore if (ssz == 0) {
62295c635efSGarrett D'Amore fb->sz = off;
62395c635efSGarrett D'Amore return(1);
62495c635efSGarrett D'Amore }
62595c635efSGarrett D'Amore if (ssz == -1) {
62695c635efSGarrett D'Amore perror(file);
62795c635efSGarrett D'Amore break;
62895c635efSGarrett D'Amore }
62995c635efSGarrett D'Amore off += (size_t)ssz;
63095c635efSGarrett D'Amore }
63195c635efSGarrett D'Amore
63295c635efSGarrett D'Amore free(fb->buf);
63395c635efSGarrett D'Amore fb->buf = NULL;
63495c635efSGarrett D'Amore return(0);
63595c635efSGarrett D'Amore }
63695c635efSGarrett D'Amore
63795c635efSGarrett D'Amore static void
mparse_end(struct mparse * curp)63895c635efSGarrett D'Amore mparse_end(struct mparse *curp)
63995c635efSGarrett D'Amore {
64095c635efSGarrett D'Amore
64195c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status)
64295c635efSGarrett D'Amore return;
64395c635efSGarrett D'Amore
64495c635efSGarrett D'Amore if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
64595c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status);
64695c635efSGarrett D'Amore return;
64795c635efSGarrett D'Amore }
64895c635efSGarrett D'Amore
64995c635efSGarrett D'Amore if (curp->man && ! man_endparse(curp->man)) {
65095c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status);
65195c635efSGarrett D'Amore return;
65295c635efSGarrett D'Amore }
65395c635efSGarrett D'Amore
65495c635efSGarrett D'Amore if ( ! (curp->man || curp->mdoc)) {
65595c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
65695c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_FATAL;
65795c635efSGarrett D'Amore return;
65895c635efSGarrett D'Amore }
65995c635efSGarrett D'Amore
66095c635efSGarrett D'Amore roff_endparse(curp->roff);
66195c635efSGarrett D'Amore }
66295c635efSGarrett D'Amore
66395c635efSGarrett D'Amore static void
mparse_parse_buffer(struct mparse * curp,struct buf blk,const char * file)664*698f87a4SGarrett D'Amore mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
66595c635efSGarrett D'Amore {
66695c635efSGarrett D'Amore const char *svfile;
667*698f87a4SGarrett D'Amore static int recursion_depth;
668*698f87a4SGarrett D'Amore
669*698f87a4SGarrett D'Amore if (64 < recursion_depth) {
670*698f87a4SGarrett D'Amore mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
671*698f87a4SGarrett D'Amore return;
672*698f87a4SGarrett D'Amore }
67395c635efSGarrett D'Amore
67495c635efSGarrett D'Amore /* Line number is per-file. */
67595c635efSGarrett D'Amore svfile = curp->file;
67695c635efSGarrett D'Amore curp->file = file;
67795c635efSGarrett D'Amore curp->line = 1;
678*698f87a4SGarrett D'Amore recursion_depth++;
67995c635efSGarrett D'Amore
68095c635efSGarrett D'Amore mparse_buf_r(curp, blk, 1);
68195c635efSGarrett D'Amore
682*698f87a4SGarrett D'Amore if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
68395c635efSGarrett D'Amore mparse_end(curp);
68495c635efSGarrett D'Amore
68595c635efSGarrett D'Amore curp->file = svfile;
68695c635efSGarrett D'Amore }
68795c635efSGarrett D'Amore
68895c635efSGarrett D'Amore enum mandoclevel
mparse_readmem(struct mparse * curp,const void * buf,size_t len,const char * file)68995c635efSGarrett D'Amore mparse_readmem(struct mparse *curp, const void *buf, size_t len,
69095c635efSGarrett D'Amore const char *file)
69195c635efSGarrett D'Amore {
69295c635efSGarrett D'Amore struct buf blk;
69395c635efSGarrett D'Amore
69495c635efSGarrett D'Amore blk.buf = UNCONST(buf);
69595c635efSGarrett D'Amore blk.sz = len;
69695c635efSGarrett D'Amore
697*698f87a4SGarrett D'Amore mparse_parse_buffer(curp, blk, file);
69895c635efSGarrett D'Amore return(curp->file_status);
69995c635efSGarrett D'Amore }
70095c635efSGarrett D'Amore
701*698f87a4SGarrett D'Amore enum mandoclevel
mparse_readfd(struct mparse * curp,int fd,const char * file)702*698f87a4SGarrett D'Amore mparse_readfd(struct mparse *curp, int fd, const char *file)
70395c635efSGarrett D'Amore {
70495c635efSGarrett D'Amore struct buf blk;
70595c635efSGarrett D'Amore int with_mmap;
70695c635efSGarrett D'Amore
70795c635efSGarrett D'Amore if (-1 == fd)
70895c635efSGarrett D'Amore if (-1 == (fd = open(file, O_RDONLY, 0))) {
70995c635efSGarrett D'Amore perror(file);
71095c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_SYSERR;
711*698f87a4SGarrett D'Amore goto out;
71295c635efSGarrett D'Amore }
71395c635efSGarrett D'Amore /*
71495c635efSGarrett D'Amore * Run for each opened file; may be called more than once for
71595c635efSGarrett D'Amore * each full parse sequence if the opened file is nested (i.e.,
71695c635efSGarrett D'Amore * from `so'). Simply sucks in the whole file and moves into
71795c635efSGarrett D'Amore * the parse phase for the file.
71895c635efSGarrett D'Amore */
71995c635efSGarrett D'Amore
72095c635efSGarrett D'Amore if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
72195c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_SYSERR;
722*698f87a4SGarrett D'Amore goto out;
72395c635efSGarrett D'Amore }
72495c635efSGarrett D'Amore
725*698f87a4SGarrett D'Amore mparse_parse_buffer(curp, blk, file);
72695c635efSGarrett D'Amore
72795c635efSGarrett D'Amore #ifdef HAVE_MMAP
72895c635efSGarrett D'Amore if (with_mmap)
72995c635efSGarrett D'Amore munmap(blk.buf, blk.sz);
73095c635efSGarrett D'Amore else
73195c635efSGarrett D'Amore #endif
73295c635efSGarrett D'Amore free(blk.buf);
73395c635efSGarrett D'Amore
73495c635efSGarrett D'Amore if (STDIN_FILENO != fd && -1 == close(fd))
73595c635efSGarrett D'Amore perror(file);
736*698f87a4SGarrett D'Amore out:
73795c635efSGarrett D'Amore return(curp->file_status);
73895c635efSGarrett D'Amore }
73995c635efSGarrett D'Amore
74095c635efSGarrett D'Amore struct mparse *
mparse_alloc(enum mparset inttype,enum mandoclevel wlevel,mandocmsg mmsg,void * arg,char * defos)741*698f87a4SGarrett D'Amore mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
742*698f87a4SGarrett D'Amore mandocmsg mmsg, void *arg, char *defos)
74395c635efSGarrett D'Amore {
74495c635efSGarrett D'Amore struct mparse *curp;
74595c635efSGarrett D'Amore
74695c635efSGarrett D'Amore assert(wlevel <= MANDOCLEVEL_FATAL);
74795c635efSGarrett D'Amore
74895c635efSGarrett D'Amore curp = mandoc_calloc(1, sizeof(struct mparse));
74995c635efSGarrett D'Amore
75095c635efSGarrett D'Amore curp->wlevel = wlevel;
75195c635efSGarrett D'Amore curp->mmsg = mmsg;
75295c635efSGarrett D'Amore curp->arg = arg;
75395c635efSGarrett D'Amore curp->inttype = inttype;
754*698f87a4SGarrett D'Amore curp->defos = defos;
75595c635efSGarrett D'Amore
756*698f87a4SGarrett D'Amore curp->roff = roff_alloc(inttype, curp);
75795c635efSGarrett D'Amore return(curp);
75895c635efSGarrett D'Amore }
75995c635efSGarrett D'Amore
76095c635efSGarrett D'Amore void
mparse_reset(struct mparse * curp)76195c635efSGarrett D'Amore mparse_reset(struct mparse *curp)
76295c635efSGarrett D'Amore {
76395c635efSGarrett D'Amore
76495c635efSGarrett D'Amore roff_reset(curp->roff);
76595c635efSGarrett D'Amore
76695c635efSGarrett D'Amore if (curp->mdoc)
76795c635efSGarrett D'Amore mdoc_reset(curp->mdoc);
76895c635efSGarrett D'Amore if (curp->man)
76995c635efSGarrett D'Amore man_reset(curp->man);
77095c635efSGarrett D'Amore if (curp->secondary)
77195c635efSGarrett D'Amore curp->secondary->sz = 0;
77295c635efSGarrett D'Amore
77395c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_OK;
77495c635efSGarrett D'Amore curp->mdoc = NULL;
77595c635efSGarrett D'Amore curp->man = NULL;
77695c635efSGarrett D'Amore }
77795c635efSGarrett D'Amore
77895c635efSGarrett D'Amore void
mparse_free(struct mparse * curp)77995c635efSGarrett D'Amore mparse_free(struct mparse *curp)
78095c635efSGarrett D'Amore {
78195c635efSGarrett D'Amore
78295c635efSGarrett D'Amore if (curp->pmdoc)
78395c635efSGarrett D'Amore mdoc_free(curp->pmdoc);
78495c635efSGarrett D'Amore if (curp->pman)
78595c635efSGarrett D'Amore man_free(curp->pman);
78695c635efSGarrett D'Amore if (curp->roff)
78795c635efSGarrett D'Amore roff_free(curp->roff);
78895c635efSGarrett D'Amore if (curp->secondary)
78995c635efSGarrett D'Amore free(curp->secondary->buf);
79095c635efSGarrett D'Amore
79195c635efSGarrett D'Amore free(curp->secondary);
79295c635efSGarrett D'Amore free(curp);
79395c635efSGarrett D'Amore }
79495c635efSGarrett D'Amore
79595c635efSGarrett D'Amore void
mparse_result(struct mparse * curp,struct mdoc ** mdoc,struct man ** man)79695c635efSGarrett D'Amore mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
79795c635efSGarrett D'Amore {
79895c635efSGarrett D'Amore
79995c635efSGarrett D'Amore if (mdoc)
80095c635efSGarrett D'Amore *mdoc = curp->mdoc;
80195c635efSGarrett D'Amore if (man)
80295c635efSGarrett D'Amore *man = curp->man;
80395c635efSGarrett D'Amore }
80495c635efSGarrett D'Amore
80595c635efSGarrett D'Amore void
mandoc_vmsg(enum mandocerr t,struct mparse * m,int ln,int pos,const char * fmt,...)80695c635efSGarrett D'Amore mandoc_vmsg(enum mandocerr t, struct mparse *m,
80795c635efSGarrett D'Amore int ln, int pos, const char *fmt, ...)
80895c635efSGarrett D'Amore {
80995c635efSGarrett D'Amore char buf[256];
81095c635efSGarrett D'Amore va_list ap;
81195c635efSGarrett D'Amore
81295c635efSGarrett D'Amore va_start(ap, fmt);
81395c635efSGarrett D'Amore vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
81495c635efSGarrett D'Amore va_end(ap);
81595c635efSGarrett D'Amore
81695c635efSGarrett D'Amore mandoc_msg(t, m, ln, pos, buf);
81795c635efSGarrett D'Amore }
81895c635efSGarrett D'Amore
81995c635efSGarrett D'Amore void
mandoc_msg(enum mandocerr er,struct mparse * m,int ln,int col,const char * msg)82095c635efSGarrett D'Amore mandoc_msg(enum mandocerr er, struct mparse *m,
82195c635efSGarrett D'Amore int ln, int col, const char *msg)
82295c635efSGarrett D'Amore {
82395c635efSGarrett D'Amore enum mandoclevel level;
82495c635efSGarrett D'Amore
82595c635efSGarrett D'Amore level = MANDOCLEVEL_FATAL;
82695c635efSGarrett D'Amore while (er < mandoclimits[level])
82795c635efSGarrett D'Amore level--;
82895c635efSGarrett D'Amore
82995c635efSGarrett D'Amore if (level < m->wlevel)
83095c635efSGarrett D'Amore return;
83195c635efSGarrett D'Amore
83295c635efSGarrett D'Amore if (m->mmsg)
83395c635efSGarrett D'Amore (*m->mmsg)(er, level, m->file, ln, col, msg);
83495c635efSGarrett D'Amore
83595c635efSGarrett D'Amore if (m->file_status < level)
83695c635efSGarrett D'Amore m->file_status = level;
83795c635efSGarrett D'Amore }
83895c635efSGarrett D'Amore
83995c635efSGarrett D'Amore const char *
mparse_strerror(enum mandocerr er)84095c635efSGarrett D'Amore mparse_strerror(enum mandocerr er)
84195c635efSGarrett D'Amore {
84295c635efSGarrett D'Amore
84395c635efSGarrett D'Amore return(mandocerrs[er]);
84495c635efSGarrett D'Amore }
84595c635efSGarrett D'Amore
84695c635efSGarrett D'Amore const char *
mparse_strlevel(enum mandoclevel lvl)84795c635efSGarrett D'Amore mparse_strlevel(enum mandoclevel lvl)
84895c635efSGarrett D'Amore {
84995c635efSGarrett D'Amore return(mandoclevels[lvl]);
85095c635efSGarrett D'Amore }
85195c635efSGarrett D'Amore
85295c635efSGarrett D'Amore void
mparse_keep(struct mparse * p)85395c635efSGarrett D'Amore mparse_keep(struct mparse *p)
85495c635efSGarrett D'Amore {
85595c635efSGarrett D'Amore
85695c635efSGarrett D'Amore assert(NULL == p->secondary);
85795c635efSGarrett D'Amore p->secondary = mandoc_calloc(1, sizeof(struct buf));
85895c635efSGarrett D'Amore }
85995c635efSGarrett D'Amore
86095c635efSGarrett D'Amore const char *
mparse_getkeep(const struct mparse * p)86195c635efSGarrett D'Amore mparse_getkeep(const struct mparse *p)
86295c635efSGarrett D'Amore {
86395c635efSGarrett D'Amore
86495c635efSGarrett D'Amore assert(p->secondary);
86595c635efSGarrett D'Amore return(p->secondary->sz ? p->secondary->buf : NULL);
86695c635efSGarrett D'Amore }
867