1*c1c95addSBrooks Davis /* $Id: read.c,v 1.221 2022/05/19 14:48:56 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
36d38604fSBaptiste Daroussin * Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
561d06d6bSBaptiste Daroussin * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
661d06d6bSBaptiste Daroussin *
761d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any
861d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above
961d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies.
1061d06d6bSBaptiste Daroussin *
1161d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1261d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1361d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1461d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1561d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1661d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1761d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
186d38604fSBaptiste Daroussin *
196d38604fSBaptiste Daroussin * Top-level functions of the mandoc(3) parser:
206d38604fSBaptiste Daroussin * Parser and input encoding selection, decompression,
216d38604fSBaptiste Daroussin * handling of input bytes, characters, lines, and files,
226d38604fSBaptiste Daroussin * handling of roff(7) loops and file inclusion,
236d38604fSBaptiste Daroussin * and steering of the various parsers.
2461d06d6bSBaptiste Daroussin */
2561d06d6bSBaptiste Daroussin #include "config.h"
2661d06d6bSBaptiste Daroussin
2761d06d6bSBaptiste Daroussin #include <sys/types.h>
2861d06d6bSBaptiste Daroussin #include <sys/mman.h>
2961d06d6bSBaptiste Daroussin #include <sys/stat.h>
3061d06d6bSBaptiste Daroussin
3161d06d6bSBaptiste Daroussin #include <assert.h>
3261d06d6bSBaptiste Daroussin #include <ctype.h>
3361d06d6bSBaptiste Daroussin #include <errno.h>
3461d06d6bSBaptiste Daroussin #include <fcntl.h>
3561d06d6bSBaptiste Daroussin #include <stdarg.h>
3661d06d6bSBaptiste Daroussin #include <stdio.h>
3761d06d6bSBaptiste Daroussin #include <stdlib.h>
3861d06d6bSBaptiste Daroussin #include <string.h>
3961d06d6bSBaptiste Daroussin #include <unistd.h>
4061d06d6bSBaptiste Daroussin #include <zlib.h>
4161d06d6bSBaptiste Daroussin
4261d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
4361d06d6bSBaptiste Daroussin #include "mandoc.h"
4461d06d6bSBaptiste Daroussin #include "roff.h"
4561d06d6bSBaptiste Daroussin #include "mdoc.h"
4661d06d6bSBaptiste Daroussin #include "man.h"
477295610fSBaptiste Daroussin #include "mandoc_parse.h"
4861d06d6bSBaptiste Daroussin #include "libmandoc.h"
497295610fSBaptiste Daroussin #include "roff_int.h"
506d38604fSBaptiste Daroussin #include "tag.h"
5161d06d6bSBaptiste Daroussin
5261d06d6bSBaptiste Daroussin #define REPARSE_LIMIT 1000
5361d06d6bSBaptiste Daroussin
5461d06d6bSBaptiste Daroussin struct mparse {
5561d06d6bSBaptiste Daroussin struct roff *roff; /* roff parser (!NULL) */
5661d06d6bSBaptiste Daroussin struct roff_man *man; /* man parser */
5761d06d6bSBaptiste Daroussin struct buf *primary; /* buffer currently being parsed */
587295610fSBaptiste Daroussin struct buf *secondary; /* copy of top level input */
597295610fSBaptiste Daroussin struct buf *loop; /* open .while request line */
6061d06d6bSBaptiste Daroussin const char *os_s; /* default operating system */
6161d06d6bSBaptiste Daroussin int options; /* parser options */
6261d06d6bSBaptiste Daroussin int gzip; /* current input file is gzipped */
6361d06d6bSBaptiste Daroussin int filenc; /* encoding of the current file */
6461d06d6bSBaptiste Daroussin int reparse_count; /* finite interp. stack */
6561d06d6bSBaptiste Daroussin int line; /* line number in the file */
6661d06d6bSBaptiste Daroussin };
6761d06d6bSBaptiste Daroussin
6861d06d6bSBaptiste Daroussin static void choose_parser(struct mparse *);
697295610fSBaptiste Daroussin static void free_buf_list(struct buf *);
7061d06d6bSBaptiste Daroussin static void resize_buf(struct buf *, size_t);
7161d06d6bSBaptiste Daroussin static int mparse_buf_r(struct mparse *, struct buf, size_t, int);
727295610fSBaptiste Daroussin static int read_whole_file(struct mparse *, int, struct buf *, int *);
7361d06d6bSBaptiste Daroussin static void mparse_end(struct mparse *);
7461d06d6bSBaptiste Daroussin
7561d06d6bSBaptiste Daroussin
7661d06d6bSBaptiste Daroussin static void
resize_buf(struct buf * buf,size_t initial)7761d06d6bSBaptiste Daroussin resize_buf(struct buf *buf, size_t initial)
7861d06d6bSBaptiste Daroussin {
7961d06d6bSBaptiste Daroussin
8061d06d6bSBaptiste Daroussin buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
8161d06d6bSBaptiste Daroussin buf->buf = mandoc_realloc(buf->buf, buf->sz);
8261d06d6bSBaptiste Daroussin }
8361d06d6bSBaptiste Daroussin
8461d06d6bSBaptiste Daroussin static void
free_buf_list(struct buf * buf)857295610fSBaptiste Daroussin free_buf_list(struct buf *buf)
867295610fSBaptiste Daroussin {
877295610fSBaptiste Daroussin struct buf *tmp;
887295610fSBaptiste Daroussin
897295610fSBaptiste Daroussin while (buf != NULL) {
907295610fSBaptiste Daroussin tmp = buf;
917295610fSBaptiste Daroussin buf = tmp->next;
927295610fSBaptiste Daroussin free(tmp->buf);
937295610fSBaptiste Daroussin free(tmp);
947295610fSBaptiste Daroussin }
957295610fSBaptiste Daroussin }
967295610fSBaptiste Daroussin
977295610fSBaptiste Daroussin static void
choose_parser(struct mparse * curp)9861d06d6bSBaptiste Daroussin choose_parser(struct mparse *curp)
9961d06d6bSBaptiste Daroussin {
10061d06d6bSBaptiste Daroussin char *cp, *ep;
10161d06d6bSBaptiste Daroussin int format;
10261d06d6bSBaptiste Daroussin
10361d06d6bSBaptiste Daroussin /*
10461d06d6bSBaptiste Daroussin * If neither command line arguments -mdoc or -man select
10561d06d6bSBaptiste Daroussin * a parser nor the roff parser found a .Dd or .TH macro
10661d06d6bSBaptiste Daroussin * yet, look ahead in the main input buffer.
10761d06d6bSBaptiste Daroussin */
10861d06d6bSBaptiste Daroussin
10961d06d6bSBaptiste Daroussin if ((format = roff_getformat(curp->roff)) == 0) {
11061d06d6bSBaptiste Daroussin cp = curp->primary->buf;
11161d06d6bSBaptiste Daroussin ep = cp + curp->primary->sz;
11261d06d6bSBaptiste Daroussin while (cp < ep) {
11361d06d6bSBaptiste Daroussin if (*cp == '.' || *cp == '\'') {
11461d06d6bSBaptiste Daroussin cp++;
11561d06d6bSBaptiste Daroussin if (cp[0] == 'D' && cp[1] == 'd') {
11661d06d6bSBaptiste Daroussin format = MPARSE_MDOC;
11761d06d6bSBaptiste Daroussin break;
11861d06d6bSBaptiste Daroussin }
11961d06d6bSBaptiste Daroussin if (cp[0] == 'T' && cp[1] == 'H') {
12061d06d6bSBaptiste Daroussin format = MPARSE_MAN;
12161d06d6bSBaptiste Daroussin break;
12261d06d6bSBaptiste Daroussin }
12361d06d6bSBaptiste Daroussin }
12461d06d6bSBaptiste Daroussin cp = memchr(cp, '\n', ep - cp);
12561d06d6bSBaptiste Daroussin if (cp == NULL)
12661d06d6bSBaptiste Daroussin break;
12761d06d6bSBaptiste Daroussin cp++;
12861d06d6bSBaptiste Daroussin }
12961d06d6bSBaptiste Daroussin }
13061d06d6bSBaptiste Daroussin
13161d06d6bSBaptiste Daroussin if (format == MPARSE_MDOC) {
1327295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MDOC;
13361d06d6bSBaptiste Daroussin if (curp->man->mdocmac == NULL)
13461d06d6bSBaptiste Daroussin curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
13561d06d6bSBaptiste Daroussin } else {
1367295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MAN;
13761d06d6bSBaptiste Daroussin if (curp->man->manmac == NULL)
13861d06d6bSBaptiste Daroussin curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
13961d06d6bSBaptiste Daroussin }
1407295610fSBaptiste Daroussin curp->man->meta.first->tok = TOKEN_NONE;
14161d06d6bSBaptiste Daroussin }
14261d06d6bSBaptiste Daroussin
14361d06d6bSBaptiste Daroussin /*
14461d06d6bSBaptiste Daroussin * Main parse routine for a buffer.
14561d06d6bSBaptiste Daroussin * It assumes encoding and line numbering are already set up.
14661d06d6bSBaptiste Daroussin * It can recurse directly (for invocations of user-defined
14761d06d6bSBaptiste Daroussin * macros, inline equations, and input line traps)
14861d06d6bSBaptiste Daroussin * and indirectly (for .so file inclusion).
14961d06d6bSBaptiste Daroussin */
15061d06d6bSBaptiste Daroussin static int
mparse_buf_r(struct mparse * curp,struct buf blk,size_t i,int start)15161d06d6bSBaptiste Daroussin mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
15261d06d6bSBaptiste Daroussin {
15361d06d6bSBaptiste Daroussin struct buf ln;
1547295610fSBaptiste Daroussin struct buf *firstln, *lastln, *thisln, *loop;
15561d06d6bSBaptiste Daroussin char *cp;
15661d06d6bSBaptiste Daroussin size_t pos; /* byte number in the ln buffer */
1576d38604fSBaptiste Daroussin size_t spos; /* at the start of the current line parse */
1587295610fSBaptiste Daroussin int line_result, result;
15961d06d6bSBaptiste Daroussin int of;
16061d06d6bSBaptiste Daroussin int lnn; /* line number in the real file */
16161d06d6bSBaptiste Daroussin int fd;
1627295610fSBaptiste Daroussin int inloop; /* Saw .while on this level. */
16361d06d6bSBaptiste Daroussin unsigned char c;
16461d06d6bSBaptiste Daroussin
1657295610fSBaptiste Daroussin ln.sz = 256;
1667295610fSBaptiste Daroussin ln.buf = mandoc_malloc(ln.sz);
1677295610fSBaptiste Daroussin ln.next = NULL;
16845a5aec3SBaptiste Daroussin firstln = lastln = loop = NULL;
16961d06d6bSBaptiste Daroussin lnn = curp->line;
17061d06d6bSBaptiste Daroussin pos = 0;
1717295610fSBaptiste Daroussin inloop = 0;
1727295610fSBaptiste Daroussin result = ROFF_CONT;
17361d06d6bSBaptiste Daroussin
1747295610fSBaptiste Daroussin while (i < blk.sz && (blk.buf[i] != '\0' || pos != 0)) {
17561d06d6bSBaptiste Daroussin if (start) {
17661d06d6bSBaptiste Daroussin curp->line = lnn;
17761d06d6bSBaptiste Daroussin curp->reparse_count = 0;
17861d06d6bSBaptiste Daroussin
17961d06d6bSBaptiste Daroussin if (lnn < 3 &&
18061d06d6bSBaptiste Daroussin curp->filenc & MPARSE_UTF8 &&
18161d06d6bSBaptiste Daroussin curp->filenc & MPARSE_LATIN1)
18261d06d6bSBaptiste Daroussin curp->filenc = preconv_cue(&blk, i);
18361d06d6bSBaptiste Daroussin }
1846d38604fSBaptiste Daroussin spos = pos;
18561d06d6bSBaptiste Daroussin
18661d06d6bSBaptiste Daroussin while (i < blk.sz && (start || blk.buf[i] != '\0')) {
18761d06d6bSBaptiste Daroussin
18861d06d6bSBaptiste Daroussin /*
18961d06d6bSBaptiste Daroussin * When finding an unescaped newline character,
19061d06d6bSBaptiste Daroussin * leave the character loop to process the line.
19161d06d6bSBaptiste Daroussin * Skip a preceding carriage return, if any.
19261d06d6bSBaptiste Daroussin */
19361d06d6bSBaptiste Daroussin
19461d06d6bSBaptiste Daroussin if ('\r' == blk.buf[i] && i + 1 < blk.sz &&
19561d06d6bSBaptiste Daroussin '\n' == blk.buf[i + 1])
19661d06d6bSBaptiste Daroussin ++i;
19761d06d6bSBaptiste Daroussin if ('\n' == blk.buf[i]) {
19861d06d6bSBaptiste Daroussin ++i;
19961d06d6bSBaptiste Daroussin ++lnn;
20061d06d6bSBaptiste Daroussin break;
20161d06d6bSBaptiste Daroussin }
20261d06d6bSBaptiste Daroussin
20361d06d6bSBaptiste Daroussin /*
20461d06d6bSBaptiste Daroussin * Make sure we have space for the worst
2057295610fSBaptiste Daroussin * case of 12 bytes: "\\[u10ffff]\n\0"
20661d06d6bSBaptiste Daroussin */
20761d06d6bSBaptiste Daroussin
2087295610fSBaptiste Daroussin if (pos + 12 > ln.sz)
20961d06d6bSBaptiste Daroussin resize_buf(&ln, 256);
21061d06d6bSBaptiste Daroussin
21161d06d6bSBaptiste Daroussin /*
21261d06d6bSBaptiste Daroussin * Encode 8-bit input.
21361d06d6bSBaptiste Daroussin */
21461d06d6bSBaptiste Daroussin
21561d06d6bSBaptiste Daroussin c = blk.buf[i];
21661d06d6bSBaptiste Daroussin if (c & 0x80) {
21761d06d6bSBaptiste Daroussin if ( ! (curp->filenc && preconv_encode(
21861d06d6bSBaptiste Daroussin &blk, &i, &ln, &pos, &curp->filenc))) {
2197295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_CHAR_BAD,
22061d06d6bSBaptiste Daroussin curp->line, pos, "0x%x", c);
22161d06d6bSBaptiste Daroussin ln.buf[pos++] = '?';
22261d06d6bSBaptiste Daroussin i++;
22361d06d6bSBaptiste Daroussin }
22461d06d6bSBaptiste Daroussin continue;
22561d06d6bSBaptiste Daroussin }
22661d06d6bSBaptiste Daroussin
22761d06d6bSBaptiste Daroussin /*
22861d06d6bSBaptiste Daroussin * Exclude control characters.
22961d06d6bSBaptiste Daroussin */
23061d06d6bSBaptiste Daroussin
23161d06d6bSBaptiste Daroussin if (c == 0x7f || (c < 0x20 && c != 0x09)) {
2327295610fSBaptiste Daroussin mandoc_msg(c == 0x00 || c == 0x04 ||
23361d06d6bSBaptiste Daroussin c > 0x0a ? MANDOCERR_CHAR_BAD :
23461d06d6bSBaptiste Daroussin MANDOCERR_CHAR_UNSUPP,
2357295610fSBaptiste Daroussin curp->line, pos, "0x%x", c);
23661d06d6bSBaptiste Daroussin i++;
23761d06d6bSBaptiste Daroussin if (c != '\r')
23861d06d6bSBaptiste Daroussin ln.buf[pos++] = '?';
23961d06d6bSBaptiste Daroussin continue;
24061d06d6bSBaptiste Daroussin }
24161d06d6bSBaptiste Daroussin
24261d06d6bSBaptiste Daroussin ln.buf[pos++] = blk.buf[i++];
24361d06d6bSBaptiste Daroussin }
2447295610fSBaptiste Daroussin ln.buf[pos] = '\0';
24561d06d6bSBaptiste Daroussin
2467295610fSBaptiste Daroussin /*
2477295610fSBaptiste Daroussin * Maintain a lookaside buffer of all lines.
2487295610fSBaptiste Daroussin * parsed from this input source.
2497295610fSBaptiste Daroussin */
25061d06d6bSBaptiste Daroussin
2517295610fSBaptiste Daroussin thisln = mandoc_malloc(sizeof(*thisln));
2527295610fSBaptiste Daroussin thisln->buf = mandoc_strdup(ln.buf);
2537295610fSBaptiste Daroussin thisln->sz = strlen(ln.buf) + 1;
2547295610fSBaptiste Daroussin thisln->next = NULL;
2557295610fSBaptiste Daroussin if (firstln == NULL) {
2567295610fSBaptiste Daroussin firstln = lastln = thisln;
2577295610fSBaptiste Daroussin if (curp->secondary == NULL)
2587295610fSBaptiste Daroussin curp->secondary = firstln;
2597295610fSBaptiste Daroussin } else {
2607295610fSBaptiste Daroussin lastln->next = thisln;
2617295610fSBaptiste Daroussin lastln = thisln;
2627295610fSBaptiste Daroussin }
2637295610fSBaptiste Daroussin
264*c1c95addSBrooks Davis /*
265*c1c95addSBrooks Davis * XXX Ugly hack to mark the end of the input,
266*c1c95addSBrooks Davis * such that the function roff_parse_comment()
267*c1c95addSBrooks Davis * doesn't attempt to append another line if the
268*c1c95addSBrooks Davis * last input line ends with an escape character.
269*c1c95addSBrooks Davis */
2707295610fSBaptiste Daroussin
2717295610fSBaptiste Daroussin if (i == blk.sz || blk.buf[i] == '\0') {
27245a5aec3SBaptiste Daroussin if (pos + 2 > ln.sz)
27345a5aec3SBaptiste Daroussin resize_buf(&ln, 256);
27461d06d6bSBaptiste Daroussin ln.buf[pos++] = '\n';
27561d06d6bSBaptiste Daroussin ln.buf[pos] = '\0';
2767295610fSBaptiste Daroussin }
27761d06d6bSBaptiste Daroussin
27861d06d6bSBaptiste Daroussin /*
27961d06d6bSBaptiste Daroussin * A significant amount of complexity is contained by
28061d06d6bSBaptiste Daroussin * the roff preprocessor. It's line-oriented but can be
28161d06d6bSBaptiste Daroussin * expressed on one line, so we need at times to
28261d06d6bSBaptiste Daroussin * readjust our starting point and re-run it. The roff
28361d06d6bSBaptiste Daroussin * preprocessor can also readjust the buffers with new
28461d06d6bSBaptiste Daroussin * data, so we pass them in wholesale.
28561d06d6bSBaptiste Daroussin */
28661d06d6bSBaptiste Daroussin
28761d06d6bSBaptiste Daroussin of = 0;
28861d06d6bSBaptiste Daroussin rerun:
2896d38604fSBaptiste Daroussin line_result = roff_parseln(curp->roff, curp->line,
2906d38604fSBaptiste Daroussin &ln, &of, start && spos == 0 ? pos : 0);
29161d06d6bSBaptiste Daroussin
2927295610fSBaptiste Daroussin /* Process options. */
2937295610fSBaptiste Daroussin
2947295610fSBaptiste Daroussin if (line_result & ROFF_APPEND)
2957295610fSBaptiste Daroussin assert(line_result == (ROFF_IGN | ROFF_APPEND));
2967295610fSBaptiste Daroussin
2977295610fSBaptiste Daroussin if (line_result & ROFF_USERCALL)
2987295610fSBaptiste Daroussin assert((line_result & ROFF_MASK) == ROFF_REPARSE);
2997295610fSBaptiste Daroussin
3007295610fSBaptiste Daroussin if (line_result & ROFF_USERRET) {
3017295610fSBaptiste Daroussin assert(line_result == (ROFF_IGN | ROFF_USERRET));
3027295610fSBaptiste Daroussin if (start == 0) {
3037295610fSBaptiste Daroussin /* Return from the current macro. */
3047295610fSBaptiste Daroussin result = ROFF_USERRET;
3057295610fSBaptiste Daroussin goto out;
30661d06d6bSBaptiste Daroussin }
3077295610fSBaptiste Daroussin }
3087295610fSBaptiste Daroussin
3097295610fSBaptiste Daroussin switch (line_result & ROFF_LOOPMASK) {
3107295610fSBaptiste Daroussin case ROFF_IGN:
3117295610fSBaptiste Daroussin break;
3127295610fSBaptiste Daroussin case ROFF_WHILE:
3137295610fSBaptiste Daroussin if (curp->loop != NULL) {
3147295610fSBaptiste Daroussin if (loop == curp->loop)
3157295610fSBaptiste Daroussin break;
3167295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_NEST,
3177295610fSBaptiste Daroussin curp->line, pos, NULL);
3187295610fSBaptiste Daroussin }
3197295610fSBaptiste Daroussin curp->loop = thisln;
3207295610fSBaptiste Daroussin loop = NULL;
3217295610fSBaptiste Daroussin inloop = 1;
3227295610fSBaptiste Daroussin break;
3237295610fSBaptiste Daroussin case ROFF_LOOPCONT:
3247295610fSBaptiste Daroussin case ROFF_LOOPEXIT:
3257295610fSBaptiste Daroussin if (curp->loop == NULL) {
3267295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_FAIL,
3277295610fSBaptiste Daroussin curp->line, pos, NULL);
3287295610fSBaptiste Daroussin break;
3297295610fSBaptiste Daroussin }
3307295610fSBaptiste Daroussin if (inloop == 0) {
3317295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_INTO,
3327295610fSBaptiste Daroussin curp->line, pos, NULL);
3337295610fSBaptiste Daroussin curp->loop = loop = NULL;
3347295610fSBaptiste Daroussin break;
3357295610fSBaptiste Daroussin }
3367295610fSBaptiste Daroussin if (line_result & ROFF_LOOPCONT)
3377295610fSBaptiste Daroussin loop = curp->loop;
3387295610fSBaptiste Daroussin else {
3397295610fSBaptiste Daroussin curp->loop = loop = NULL;
3407295610fSBaptiste Daroussin inloop = 0;
3417295610fSBaptiste Daroussin }
3427295610fSBaptiste Daroussin break;
3437295610fSBaptiste Daroussin default:
3447295610fSBaptiste Daroussin abort();
3457295610fSBaptiste Daroussin }
3467295610fSBaptiste Daroussin
3477295610fSBaptiste Daroussin /* Process the main instruction from the roff parser. */
3487295610fSBaptiste Daroussin
3497295610fSBaptiste Daroussin switch (line_result & ROFF_MASK) {
3507295610fSBaptiste Daroussin case ROFF_IGN:
3517295610fSBaptiste Daroussin break;
3527295610fSBaptiste Daroussin case ROFF_CONT:
3537295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_NONE)
3547295610fSBaptiste Daroussin choose_parser(curp);
3557295610fSBaptiste Daroussin if ((curp->man->meta.macroset == MACROSET_MDOC ?
3567295610fSBaptiste Daroussin mdoc_parseln(curp->man, curp->line, ln.buf, of) :
3577295610fSBaptiste Daroussin man_parseln(curp->man, curp->line, ln.buf, of)
3587295610fSBaptiste Daroussin ) == 2)
3597295610fSBaptiste Daroussin goto out;
3607295610fSBaptiste Daroussin break;
36161d06d6bSBaptiste Daroussin case ROFF_RERUN:
36261d06d6bSBaptiste Daroussin goto rerun;
3637295610fSBaptiste Daroussin case ROFF_REPARSE:
3647295610fSBaptiste Daroussin if (++curp->reparse_count > REPARSE_LIMIT) {
3657295610fSBaptiste Daroussin /* Abort and return to the top level. */
3667295610fSBaptiste Daroussin result = ROFF_IGN;
3677295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP,
3687295610fSBaptiste Daroussin curp->line, pos, NULL);
3697295610fSBaptiste Daroussin goto out;
3707295610fSBaptiste Daroussin }
3717295610fSBaptiste Daroussin result = mparse_buf_r(curp, ln, of, 0);
3727295610fSBaptiste Daroussin if (line_result & ROFF_USERCALL) {
3737295610fSBaptiste Daroussin roff_userret(curp->roff);
3747295610fSBaptiste Daroussin /* Continue normally. */
3757295610fSBaptiste Daroussin if (result & ROFF_USERRET)
3767295610fSBaptiste Daroussin result = ROFF_CONT;
3777295610fSBaptiste Daroussin }
3787295610fSBaptiste Daroussin if (start == 0 && result != ROFF_CONT)
3797295610fSBaptiste Daroussin goto out;
3807295610fSBaptiste Daroussin break;
38161d06d6bSBaptiste Daroussin case ROFF_SO:
38261d06d6bSBaptiste Daroussin if ( ! (curp->options & MPARSE_SO) &&
38361d06d6bSBaptiste Daroussin (i >= blk.sz || blk.buf[i] == '\0')) {
3847295610fSBaptiste Daroussin curp->man->meta.sodest =
3857295610fSBaptiste Daroussin mandoc_strdup(ln.buf + of);
3867295610fSBaptiste Daroussin goto out;
38761d06d6bSBaptiste Daroussin }
38861d06d6bSBaptiste Daroussin if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
38961d06d6bSBaptiste Daroussin mparse_readfd(curp, fd, ln.buf + of);
39061d06d6bSBaptiste Daroussin close(fd);
39161d06d6bSBaptiste Daroussin } else {
3927295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SO_FAIL,
3937295610fSBaptiste Daroussin curp->line, of, ".so %s: %s",
3947295610fSBaptiste Daroussin ln.buf + of, strerror(errno));
39561d06d6bSBaptiste Daroussin ln.sz = mandoc_asprintf(&cp,
39661d06d6bSBaptiste Daroussin ".sp\nSee the file %s.\n.sp",
39761d06d6bSBaptiste Daroussin ln.buf + of);
39861d06d6bSBaptiste Daroussin free(ln.buf);
39961d06d6bSBaptiste Daroussin ln.buf = cp;
40061d06d6bSBaptiste Daroussin of = 0;
40161d06d6bSBaptiste Daroussin mparse_buf_r(curp, ln, of, 0);
40261d06d6bSBaptiste Daroussin }
4037295610fSBaptiste Daroussin break;
40461d06d6bSBaptiste Daroussin default:
4057295610fSBaptiste Daroussin abort();
40661d06d6bSBaptiste Daroussin }
40761d06d6bSBaptiste Daroussin
40861d06d6bSBaptiste Daroussin /* Start the next input line. */
40961d06d6bSBaptiste Daroussin
4107295610fSBaptiste Daroussin if (loop != NULL &&
4117295610fSBaptiste Daroussin (line_result & ROFF_LOOPMASK) == ROFF_IGN)
4127295610fSBaptiste Daroussin loop = loop->next;
4137295610fSBaptiste Daroussin
4147295610fSBaptiste Daroussin if (loop != NULL) {
4157295610fSBaptiste Daroussin if ((line_result & ROFF_APPEND) == 0)
4167295610fSBaptiste Daroussin *ln.buf = '\0';
4177295610fSBaptiste Daroussin if (ln.sz < loop->sz)
4187295610fSBaptiste Daroussin resize_buf(&ln, loop->sz);
4197295610fSBaptiste Daroussin (void)strlcat(ln.buf, loop->buf, ln.sz);
4207295610fSBaptiste Daroussin of = 0;
4217295610fSBaptiste Daroussin goto rerun;
42261d06d6bSBaptiste Daroussin }
42361d06d6bSBaptiste Daroussin
4247295610fSBaptiste Daroussin pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0;
4257295610fSBaptiste Daroussin }
4267295610fSBaptiste Daroussin out:
4277295610fSBaptiste Daroussin if (inloop) {
4287295610fSBaptiste Daroussin if (result != ROFF_USERRET)
4297295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_OUTOF,
4307295610fSBaptiste Daroussin curp->line, pos, NULL);
4317295610fSBaptiste Daroussin curp->loop = NULL;
4327295610fSBaptiste Daroussin }
43361d06d6bSBaptiste Daroussin free(ln.buf);
4347295610fSBaptiste Daroussin if (firstln != curp->secondary)
4357295610fSBaptiste Daroussin free_buf_list(firstln);
4367295610fSBaptiste Daroussin return result;
43761d06d6bSBaptiste Daroussin }
43861d06d6bSBaptiste Daroussin
43961d06d6bSBaptiste Daroussin static int
read_whole_file(struct mparse * curp,int fd,struct buf * fb,int * with_mmap)4407295610fSBaptiste Daroussin read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap)
44161d06d6bSBaptiste Daroussin {
44261d06d6bSBaptiste Daroussin struct stat st;
44361d06d6bSBaptiste Daroussin gzFile gz;
44461d06d6bSBaptiste Daroussin size_t off;
44561d06d6bSBaptiste Daroussin ssize_t ssz;
44661d06d6bSBaptiste Daroussin int gzerrnum, retval;
44761d06d6bSBaptiste Daroussin
44861d06d6bSBaptiste Daroussin if (fstat(fd, &st) == -1) {
44945a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_FSTAT, 0, 0, "%s", strerror(errno));
45045a5aec3SBaptiste Daroussin return -1;
45161d06d6bSBaptiste Daroussin }
45261d06d6bSBaptiste Daroussin
45361d06d6bSBaptiste Daroussin /*
45461d06d6bSBaptiste Daroussin * If we're a regular file, try just reading in the whole entry
45561d06d6bSBaptiste Daroussin * via mmap(). This is faster than reading it into blocks, and
45661d06d6bSBaptiste Daroussin * since each file is only a few bytes to begin with, I'm not
45761d06d6bSBaptiste Daroussin * concerned that this is going to tank any machines.
45861d06d6bSBaptiste Daroussin */
45961d06d6bSBaptiste Daroussin
46061d06d6bSBaptiste Daroussin if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
46161d06d6bSBaptiste Daroussin if (st.st_size > 0x7fffffff) {
4627295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
46345a5aec3SBaptiste Daroussin return -1;
46461d06d6bSBaptiste Daroussin }
46561d06d6bSBaptiste Daroussin *with_mmap = 1;
46661d06d6bSBaptiste Daroussin fb->sz = (size_t)st.st_size;
46761d06d6bSBaptiste Daroussin fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
46861d06d6bSBaptiste Daroussin if (fb->buf != MAP_FAILED)
46945a5aec3SBaptiste Daroussin return 0;
47061d06d6bSBaptiste Daroussin }
47161d06d6bSBaptiste Daroussin
47261d06d6bSBaptiste Daroussin if (curp->gzip) {
47361d06d6bSBaptiste Daroussin /*
47461d06d6bSBaptiste Daroussin * Duplicating the file descriptor is required
47561d06d6bSBaptiste Daroussin * because we will have to call gzclose(3)
47661d06d6bSBaptiste Daroussin * to free memory used internally by zlib,
47761d06d6bSBaptiste Daroussin * but that will also close the file descriptor,
47861d06d6bSBaptiste Daroussin * which this function must not do.
47961d06d6bSBaptiste Daroussin */
48061d06d6bSBaptiste Daroussin if ((fd = dup(fd)) == -1) {
48145a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_DUP, 0, 0,
48245a5aec3SBaptiste Daroussin "%s", strerror(errno));
48345a5aec3SBaptiste Daroussin return -1;
48461d06d6bSBaptiste Daroussin }
48561d06d6bSBaptiste Daroussin if ((gz = gzdopen(fd, "rb")) == NULL) {
48645a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_GZDOPEN, 0, 0,
48745a5aec3SBaptiste Daroussin "%s", strerror(errno));
48861d06d6bSBaptiste Daroussin close(fd);
48945a5aec3SBaptiste Daroussin return -1;
49061d06d6bSBaptiste Daroussin }
49161d06d6bSBaptiste Daroussin } else
49261d06d6bSBaptiste Daroussin gz = NULL;
49361d06d6bSBaptiste Daroussin
49461d06d6bSBaptiste Daroussin /*
49561d06d6bSBaptiste Daroussin * If this isn't a regular file (like, say, stdin), then we must
49661d06d6bSBaptiste Daroussin * go the old way and just read things in bit by bit.
49761d06d6bSBaptiste Daroussin */
49861d06d6bSBaptiste Daroussin
49961d06d6bSBaptiste Daroussin *with_mmap = 0;
50061d06d6bSBaptiste Daroussin off = 0;
50145a5aec3SBaptiste Daroussin retval = -1;
50261d06d6bSBaptiste Daroussin fb->sz = 0;
50361d06d6bSBaptiste Daroussin fb->buf = NULL;
50461d06d6bSBaptiste Daroussin for (;;) {
50561d06d6bSBaptiste Daroussin if (off == fb->sz) {
50661d06d6bSBaptiste Daroussin if (fb->sz == (1U << 31)) {
5077295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
50861d06d6bSBaptiste Daroussin break;
50961d06d6bSBaptiste Daroussin }
51061d06d6bSBaptiste Daroussin resize_buf(fb, 65536);
51161d06d6bSBaptiste Daroussin }
51261d06d6bSBaptiste Daroussin ssz = curp->gzip ?
51361d06d6bSBaptiste Daroussin gzread(gz, fb->buf + (int)off, fb->sz - off) :
51461d06d6bSBaptiste Daroussin read(fd, fb->buf + (int)off, fb->sz - off);
51561d06d6bSBaptiste Daroussin if (ssz == 0) {
51661d06d6bSBaptiste Daroussin fb->sz = off;
51745a5aec3SBaptiste Daroussin retval = 0;
51861d06d6bSBaptiste Daroussin break;
51961d06d6bSBaptiste Daroussin }
52061d06d6bSBaptiste Daroussin if (ssz == -1) {
52161d06d6bSBaptiste Daroussin if (curp->gzip)
52261d06d6bSBaptiste Daroussin (void)gzerror(gz, &gzerrnum);
52345a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_READ, 0, 0, "%s",
52461d06d6bSBaptiste Daroussin curp->gzip && gzerrnum != Z_ERRNO ?
52561d06d6bSBaptiste Daroussin zError(gzerrnum) : strerror(errno));
52661d06d6bSBaptiste Daroussin break;
52761d06d6bSBaptiste Daroussin }
52861d06d6bSBaptiste Daroussin off += (size_t)ssz;
52961d06d6bSBaptiste Daroussin }
53061d06d6bSBaptiste Daroussin
53161d06d6bSBaptiste Daroussin if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK)
53245a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_GZCLOSE, 0, 0, "%s",
53361d06d6bSBaptiste Daroussin gzerrnum == Z_ERRNO ? strerror(errno) :
53461d06d6bSBaptiste Daroussin zError(gzerrnum));
53545a5aec3SBaptiste Daroussin if (retval == -1) {
53661d06d6bSBaptiste Daroussin free(fb->buf);
53761d06d6bSBaptiste Daroussin fb->buf = NULL;
53861d06d6bSBaptiste Daroussin }
53961d06d6bSBaptiste Daroussin return retval;
54061d06d6bSBaptiste Daroussin }
54161d06d6bSBaptiste Daroussin
54261d06d6bSBaptiste Daroussin static void
mparse_end(struct mparse * curp)54361d06d6bSBaptiste Daroussin mparse_end(struct mparse *curp)
54461d06d6bSBaptiste Daroussin {
5457295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_NONE)
5467295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MAN;
5477295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_MDOC)
54861d06d6bSBaptiste Daroussin mdoc_endparse(curp->man);
54961d06d6bSBaptiste Daroussin else
55061d06d6bSBaptiste Daroussin man_endparse(curp->man);
55161d06d6bSBaptiste Daroussin roff_endparse(curp->roff);
55261d06d6bSBaptiste Daroussin }
55361d06d6bSBaptiste Daroussin
5547295610fSBaptiste Daroussin /*
5557295610fSBaptiste Daroussin * Read the whole file into memory and call the parsers.
5567295610fSBaptiste Daroussin * Called recursively when an .so request is encountered.
5577295610fSBaptiste Daroussin */
5587295610fSBaptiste Daroussin void
mparse_readfd(struct mparse * curp,int fd,const char * filename)5597295610fSBaptiste Daroussin mparse_readfd(struct mparse *curp, int fd, const char *filename)
56061d06d6bSBaptiste Daroussin {
56161d06d6bSBaptiste Daroussin static int recursion_depth;
56261d06d6bSBaptiste Daroussin
5637295610fSBaptiste Daroussin struct buf blk;
5647295610fSBaptiste Daroussin struct buf *save_primary;
5656d38604fSBaptiste Daroussin const char *save_filename, *cp;
5667295610fSBaptiste Daroussin size_t offset;
5677295610fSBaptiste Daroussin int save_filenc, save_lineno;
5687295610fSBaptiste Daroussin int with_mmap;
5697295610fSBaptiste Daroussin
5707295610fSBaptiste Daroussin if (recursion_depth > 64) {
5717295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL);
57261d06d6bSBaptiste Daroussin return;
5736d38604fSBaptiste Daroussin } else if (recursion_depth == 0 &&
5746d38604fSBaptiste Daroussin (cp = strrchr(filename, '.')) != NULL &&
5756d38604fSBaptiste Daroussin cp[1] >= '1' && cp[1] <= '9')
5766d38604fSBaptiste Daroussin curp->man->filesec = cp[1];
5776d38604fSBaptiste Daroussin else
5786d38604fSBaptiste Daroussin curp->man->filesec = '\0';
5796d38604fSBaptiste Daroussin
58045a5aec3SBaptiste Daroussin if (read_whole_file(curp, fd, &blk, &with_mmap) == -1)
5817295610fSBaptiste Daroussin return;
58261d06d6bSBaptiste Daroussin
5837295610fSBaptiste Daroussin /*
5847295610fSBaptiste Daroussin * Save some properties of the parent file.
5857295610fSBaptiste Daroussin */
5867295610fSBaptiste Daroussin
5877295610fSBaptiste Daroussin save_primary = curp->primary;
5887295610fSBaptiste Daroussin save_filenc = curp->filenc;
5897295610fSBaptiste Daroussin save_lineno = curp->line;
5907295610fSBaptiste Daroussin save_filename = mandoc_msg_getinfilename();
5917295610fSBaptiste Daroussin
59261d06d6bSBaptiste Daroussin curp->primary = &blk;
5937295610fSBaptiste Daroussin curp->filenc = curp->options & (MPARSE_UTF8 | MPARSE_LATIN1);
59461d06d6bSBaptiste Daroussin curp->line = 1;
5957295610fSBaptiste Daroussin mandoc_msg_setinfilename(filename);
59661d06d6bSBaptiste Daroussin
59761d06d6bSBaptiste Daroussin /* Skip an UTF-8 byte order mark. */
59861d06d6bSBaptiste Daroussin if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
59961d06d6bSBaptiste Daroussin (unsigned char)blk.buf[0] == 0xef &&
60061d06d6bSBaptiste Daroussin (unsigned char)blk.buf[1] == 0xbb &&
60161d06d6bSBaptiste Daroussin (unsigned char)blk.buf[2] == 0xbf) {
60261d06d6bSBaptiste Daroussin offset = 3;
60361d06d6bSBaptiste Daroussin curp->filenc &= ~MPARSE_LATIN1;
60461d06d6bSBaptiste Daroussin } else
60561d06d6bSBaptiste Daroussin offset = 0;
60661d06d6bSBaptiste Daroussin
6077295610fSBaptiste Daroussin recursion_depth++;
60861d06d6bSBaptiste Daroussin mparse_buf_r(curp, blk, offset, 1);
60961d06d6bSBaptiste Daroussin if (--recursion_depth == 0)
61061d06d6bSBaptiste Daroussin mparse_end(curp);
61161d06d6bSBaptiste Daroussin
61261d06d6bSBaptiste Daroussin /*
6137295610fSBaptiste Daroussin * Clean up and restore saved parent properties.
61461d06d6bSBaptiste Daroussin */
61561d06d6bSBaptiste Daroussin
61661d06d6bSBaptiste Daroussin if (with_mmap)
61761d06d6bSBaptiste Daroussin munmap(blk.buf, blk.sz);
61861d06d6bSBaptiste Daroussin else
61961d06d6bSBaptiste Daroussin free(blk.buf);
6207295610fSBaptiste Daroussin
6217295610fSBaptiste Daroussin curp->primary = save_primary;
6227295610fSBaptiste Daroussin curp->filenc = save_filenc;
6237295610fSBaptiste Daroussin curp->line = save_lineno;
6247295610fSBaptiste Daroussin if (save_filename != NULL)
6257295610fSBaptiste Daroussin mandoc_msg_setinfilename(save_filename);
62661d06d6bSBaptiste Daroussin }
62761d06d6bSBaptiste Daroussin
62861d06d6bSBaptiste Daroussin int
mparse_open(struct mparse * curp,const char * file)62961d06d6bSBaptiste Daroussin mparse_open(struct mparse *curp, const char *file)
63061d06d6bSBaptiste Daroussin {
63161d06d6bSBaptiste Daroussin char *cp;
6327295610fSBaptiste Daroussin int fd, save_errno;
63361d06d6bSBaptiste Daroussin
63461d06d6bSBaptiste Daroussin cp = strrchr(file, '.');
63561d06d6bSBaptiste Daroussin curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
63661d06d6bSBaptiste Daroussin
63761d06d6bSBaptiste Daroussin /* First try to use the filename as it is. */
63861d06d6bSBaptiste Daroussin
63961d06d6bSBaptiste Daroussin if ((fd = open(file, O_RDONLY)) != -1)
64061d06d6bSBaptiste Daroussin return fd;
64161d06d6bSBaptiste Daroussin
64261d06d6bSBaptiste Daroussin /*
64361d06d6bSBaptiste Daroussin * If that doesn't work and the filename doesn't
64461d06d6bSBaptiste Daroussin * already end in .gz, try appending .gz.
64561d06d6bSBaptiste Daroussin */
64661d06d6bSBaptiste Daroussin
64761d06d6bSBaptiste Daroussin if ( ! curp->gzip) {
6487295610fSBaptiste Daroussin save_errno = errno;
64961d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "%s.gz", file);
65061d06d6bSBaptiste Daroussin fd = open(cp, O_RDONLY);
65161d06d6bSBaptiste Daroussin free(cp);
6527295610fSBaptiste Daroussin errno = save_errno;
65361d06d6bSBaptiste Daroussin if (fd != -1) {
65461d06d6bSBaptiste Daroussin curp->gzip = 1;
65561d06d6bSBaptiste Daroussin return fd;
65661d06d6bSBaptiste Daroussin }
65761d06d6bSBaptiste Daroussin }
65861d06d6bSBaptiste Daroussin
65961d06d6bSBaptiste Daroussin /* Neither worked, give up. */
66061d06d6bSBaptiste Daroussin
66161d06d6bSBaptiste Daroussin return -1;
66261d06d6bSBaptiste Daroussin }
66361d06d6bSBaptiste Daroussin
66461d06d6bSBaptiste Daroussin struct mparse *
mparse_alloc(int options,enum mandoc_os os_e,const char * os_s)6657295610fSBaptiste Daroussin mparse_alloc(int options, enum mandoc_os os_e, const char *os_s)
66661d06d6bSBaptiste Daroussin {
66761d06d6bSBaptiste Daroussin struct mparse *curp;
66861d06d6bSBaptiste Daroussin
66961d06d6bSBaptiste Daroussin curp = mandoc_calloc(1, sizeof(struct mparse));
67061d06d6bSBaptiste Daroussin
67161d06d6bSBaptiste Daroussin curp->options = options;
67261d06d6bSBaptiste Daroussin curp->os_s = os_s;
67361d06d6bSBaptiste Daroussin
6747295610fSBaptiste Daroussin curp->roff = roff_alloc(options);
6757295610fSBaptiste Daroussin curp->man = roff_man_alloc(curp->roff, curp->os_s,
67661d06d6bSBaptiste Daroussin curp->options & MPARSE_QUICK ? 1 : 0);
67761d06d6bSBaptiste Daroussin if (curp->options & MPARSE_MDOC) {
6787295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MDOC;
67961d06d6bSBaptiste Daroussin if (curp->man->mdocmac == NULL)
68061d06d6bSBaptiste Daroussin curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
68161d06d6bSBaptiste Daroussin } else if (curp->options & MPARSE_MAN) {
6827295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MAN;
68361d06d6bSBaptiste Daroussin if (curp->man->manmac == NULL)
68461d06d6bSBaptiste Daroussin curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
68561d06d6bSBaptiste Daroussin }
6867295610fSBaptiste Daroussin curp->man->meta.first->tok = TOKEN_NONE;
68761d06d6bSBaptiste Daroussin curp->man->meta.os_e = os_e;
6886d38604fSBaptiste Daroussin tag_alloc();
68961d06d6bSBaptiste Daroussin return curp;
69061d06d6bSBaptiste Daroussin }
69161d06d6bSBaptiste Daroussin
69261d06d6bSBaptiste Daroussin void
mparse_reset(struct mparse * curp)69361d06d6bSBaptiste Daroussin mparse_reset(struct mparse *curp)
69461d06d6bSBaptiste Daroussin {
6956d38604fSBaptiste Daroussin tag_free();
69661d06d6bSBaptiste Daroussin roff_reset(curp->roff);
69761d06d6bSBaptiste Daroussin roff_man_reset(curp->man);
6987295610fSBaptiste Daroussin free_buf_list(curp->secondary);
6997295610fSBaptiste Daroussin curp->secondary = NULL;
70061d06d6bSBaptiste Daroussin curp->gzip = 0;
7016d38604fSBaptiste Daroussin tag_alloc();
70261d06d6bSBaptiste Daroussin }
70361d06d6bSBaptiste Daroussin
70461d06d6bSBaptiste Daroussin void
mparse_free(struct mparse * curp)70561d06d6bSBaptiste Daroussin mparse_free(struct mparse *curp)
70661d06d6bSBaptiste Daroussin {
7076d38604fSBaptiste Daroussin tag_free();
70861d06d6bSBaptiste Daroussin roffhash_free(curp->man->mdocmac);
70961d06d6bSBaptiste Daroussin roffhash_free(curp->man->manmac);
71061d06d6bSBaptiste Daroussin roff_man_free(curp->man);
71161d06d6bSBaptiste Daroussin roff_free(curp->roff);
7127295610fSBaptiste Daroussin free_buf_list(curp->secondary);
71361d06d6bSBaptiste Daroussin free(curp);
71461d06d6bSBaptiste Daroussin }
71561d06d6bSBaptiste Daroussin
7167295610fSBaptiste Daroussin struct roff_meta *
mparse_result(struct mparse * curp)7177295610fSBaptiste Daroussin mparse_result(struct mparse *curp)
71861d06d6bSBaptiste Daroussin {
7197295610fSBaptiste Daroussin roff_state_reset(curp->man);
7207295610fSBaptiste Daroussin if (curp->options & MPARSE_VALIDATE) {
7217295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_MDOC)
7227295610fSBaptiste Daroussin mdoc_validate(curp->man);
7237295610fSBaptiste Daroussin else
7247295610fSBaptiste Daroussin man_validate(curp->man);
7256d38604fSBaptiste Daroussin tag_postprocess(curp->man, curp->man->meta.first);
72661d06d6bSBaptiste Daroussin }
7277295610fSBaptiste Daroussin return &curp->man->meta;
72861d06d6bSBaptiste Daroussin }
72961d06d6bSBaptiste Daroussin
73061d06d6bSBaptiste Daroussin void
mparse_copy(const struct mparse * p)7317295610fSBaptiste Daroussin mparse_copy(const struct mparse *p)
73261d06d6bSBaptiste Daroussin {
7337295610fSBaptiste Daroussin struct buf *buf;
73461d06d6bSBaptiste Daroussin
7357295610fSBaptiste Daroussin for (buf = p->secondary; buf != NULL; buf = buf->next)
7367295610fSBaptiste Daroussin puts(buf->buf);
73761d06d6bSBaptiste Daroussin }
738