1*6d38604fSBaptiste Daroussin /* $Id: read.c,v 1.220 2021/06/27 17:57:54 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
3*6d38604fSBaptiste 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.
18*6d38604fSBaptiste Daroussin *
19*6d38604fSBaptiste Daroussin * Top-level functions of the mandoc(3) parser:
20*6d38604fSBaptiste Daroussin * Parser and input encoding selection, decompression,
21*6d38604fSBaptiste Daroussin * handling of input bytes, characters, lines, and files,
22*6d38604fSBaptiste Daroussin * handling of roff(7) loops and file inclusion,
23*6d38604fSBaptiste 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"
50*6d38604fSBaptiste 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 */
157*6d38604fSBaptiste 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 }
184*6d38604fSBaptiste 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
2647295610fSBaptiste Daroussin /* XXX Ugly hack to mark the end of the input. */
2657295610fSBaptiste Daroussin
2667295610fSBaptiste Daroussin if (i == blk.sz || blk.buf[i] == '\0') {
26745a5aec3SBaptiste Daroussin if (pos + 2 > ln.sz)
26845a5aec3SBaptiste Daroussin resize_buf(&ln, 256);
26961d06d6bSBaptiste Daroussin ln.buf[pos++] = '\n';
27061d06d6bSBaptiste Daroussin ln.buf[pos] = '\0';
2717295610fSBaptiste Daroussin }
27261d06d6bSBaptiste Daroussin
27361d06d6bSBaptiste Daroussin /*
27461d06d6bSBaptiste Daroussin * A significant amount of complexity is contained by
27561d06d6bSBaptiste Daroussin * the roff preprocessor. It's line-oriented but can be
27661d06d6bSBaptiste Daroussin * expressed on one line, so we need at times to
27761d06d6bSBaptiste Daroussin * readjust our starting point and re-run it. The roff
27861d06d6bSBaptiste Daroussin * preprocessor can also readjust the buffers with new
27961d06d6bSBaptiste Daroussin * data, so we pass them in wholesale.
28061d06d6bSBaptiste Daroussin */
28161d06d6bSBaptiste Daroussin
28261d06d6bSBaptiste Daroussin of = 0;
28361d06d6bSBaptiste Daroussin rerun:
284*6d38604fSBaptiste Daroussin line_result = roff_parseln(curp->roff, curp->line,
285*6d38604fSBaptiste Daroussin &ln, &of, start && spos == 0 ? pos : 0);
28661d06d6bSBaptiste Daroussin
2877295610fSBaptiste Daroussin /* Process options. */
2887295610fSBaptiste Daroussin
2897295610fSBaptiste Daroussin if (line_result & ROFF_APPEND)
2907295610fSBaptiste Daroussin assert(line_result == (ROFF_IGN | ROFF_APPEND));
2917295610fSBaptiste Daroussin
2927295610fSBaptiste Daroussin if (line_result & ROFF_USERCALL)
2937295610fSBaptiste Daroussin assert((line_result & ROFF_MASK) == ROFF_REPARSE);
2947295610fSBaptiste Daroussin
2957295610fSBaptiste Daroussin if (line_result & ROFF_USERRET) {
2967295610fSBaptiste Daroussin assert(line_result == (ROFF_IGN | ROFF_USERRET));
2977295610fSBaptiste Daroussin if (start == 0) {
2987295610fSBaptiste Daroussin /* Return from the current macro. */
2997295610fSBaptiste Daroussin result = ROFF_USERRET;
3007295610fSBaptiste Daroussin goto out;
30161d06d6bSBaptiste Daroussin }
3027295610fSBaptiste Daroussin }
3037295610fSBaptiste Daroussin
3047295610fSBaptiste Daroussin switch (line_result & ROFF_LOOPMASK) {
3057295610fSBaptiste Daroussin case ROFF_IGN:
3067295610fSBaptiste Daroussin break;
3077295610fSBaptiste Daroussin case ROFF_WHILE:
3087295610fSBaptiste Daroussin if (curp->loop != NULL) {
3097295610fSBaptiste Daroussin if (loop == curp->loop)
3107295610fSBaptiste Daroussin break;
3117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_NEST,
3127295610fSBaptiste Daroussin curp->line, pos, NULL);
3137295610fSBaptiste Daroussin }
3147295610fSBaptiste Daroussin curp->loop = thisln;
3157295610fSBaptiste Daroussin loop = NULL;
3167295610fSBaptiste Daroussin inloop = 1;
3177295610fSBaptiste Daroussin break;
3187295610fSBaptiste Daroussin case ROFF_LOOPCONT:
3197295610fSBaptiste Daroussin case ROFF_LOOPEXIT:
3207295610fSBaptiste Daroussin if (curp->loop == NULL) {
3217295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_FAIL,
3227295610fSBaptiste Daroussin curp->line, pos, NULL);
3237295610fSBaptiste Daroussin break;
3247295610fSBaptiste Daroussin }
3257295610fSBaptiste Daroussin if (inloop == 0) {
3267295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_INTO,
3277295610fSBaptiste Daroussin curp->line, pos, NULL);
3287295610fSBaptiste Daroussin curp->loop = loop = NULL;
3297295610fSBaptiste Daroussin break;
3307295610fSBaptiste Daroussin }
3317295610fSBaptiste Daroussin if (line_result & ROFF_LOOPCONT)
3327295610fSBaptiste Daroussin loop = curp->loop;
3337295610fSBaptiste Daroussin else {
3347295610fSBaptiste Daroussin curp->loop = loop = NULL;
3357295610fSBaptiste Daroussin inloop = 0;
3367295610fSBaptiste Daroussin }
3377295610fSBaptiste Daroussin break;
3387295610fSBaptiste Daroussin default:
3397295610fSBaptiste Daroussin abort();
3407295610fSBaptiste Daroussin }
3417295610fSBaptiste Daroussin
3427295610fSBaptiste Daroussin /* Process the main instruction from the roff parser. */
3437295610fSBaptiste Daroussin
3447295610fSBaptiste Daroussin switch (line_result & ROFF_MASK) {
3457295610fSBaptiste Daroussin case ROFF_IGN:
3467295610fSBaptiste Daroussin break;
3477295610fSBaptiste Daroussin case ROFF_CONT:
3487295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_NONE)
3497295610fSBaptiste Daroussin choose_parser(curp);
3507295610fSBaptiste Daroussin if ((curp->man->meta.macroset == MACROSET_MDOC ?
3517295610fSBaptiste Daroussin mdoc_parseln(curp->man, curp->line, ln.buf, of) :
3527295610fSBaptiste Daroussin man_parseln(curp->man, curp->line, ln.buf, of)
3537295610fSBaptiste Daroussin ) == 2)
3547295610fSBaptiste Daroussin goto out;
3557295610fSBaptiste Daroussin break;
35661d06d6bSBaptiste Daroussin case ROFF_RERUN:
35761d06d6bSBaptiste Daroussin goto rerun;
3587295610fSBaptiste Daroussin case ROFF_REPARSE:
3597295610fSBaptiste Daroussin if (++curp->reparse_count > REPARSE_LIMIT) {
3607295610fSBaptiste Daroussin /* Abort and return to the top level. */
3617295610fSBaptiste Daroussin result = ROFF_IGN;
3627295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP,
3637295610fSBaptiste Daroussin curp->line, pos, NULL);
3647295610fSBaptiste Daroussin goto out;
3657295610fSBaptiste Daroussin }
3667295610fSBaptiste Daroussin result = mparse_buf_r(curp, ln, of, 0);
3677295610fSBaptiste Daroussin if (line_result & ROFF_USERCALL) {
3687295610fSBaptiste Daroussin roff_userret(curp->roff);
3697295610fSBaptiste Daroussin /* Continue normally. */
3707295610fSBaptiste Daroussin if (result & ROFF_USERRET)
3717295610fSBaptiste Daroussin result = ROFF_CONT;
3727295610fSBaptiste Daroussin }
3737295610fSBaptiste Daroussin if (start == 0 && result != ROFF_CONT)
3747295610fSBaptiste Daroussin goto out;
3757295610fSBaptiste Daroussin break;
37661d06d6bSBaptiste Daroussin case ROFF_SO:
37761d06d6bSBaptiste Daroussin if ( ! (curp->options & MPARSE_SO) &&
37861d06d6bSBaptiste Daroussin (i >= blk.sz || blk.buf[i] == '\0')) {
3797295610fSBaptiste Daroussin curp->man->meta.sodest =
3807295610fSBaptiste Daroussin mandoc_strdup(ln.buf + of);
3817295610fSBaptiste Daroussin goto out;
38261d06d6bSBaptiste Daroussin }
38361d06d6bSBaptiste Daroussin if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
38461d06d6bSBaptiste Daroussin mparse_readfd(curp, fd, ln.buf + of);
38561d06d6bSBaptiste Daroussin close(fd);
38661d06d6bSBaptiste Daroussin } else {
3877295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SO_FAIL,
3887295610fSBaptiste Daroussin curp->line, of, ".so %s: %s",
3897295610fSBaptiste Daroussin ln.buf + of, strerror(errno));
39061d06d6bSBaptiste Daroussin ln.sz = mandoc_asprintf(&cp,
39161d06d6bSBaptiste Daroussin ".sp\nSee the file %s.\n.sp",
39261d06d6bSBaptiste Daroussin ln.buf + of);
39361d06d6bSBaptiste Daroussin free(ln.buf);
39461d06d6bSBaptiste Daroussin ln.buf = cp;
39561d06d6bSBaptiste Daroussin of = 0;
39661d06d6bSBaptiste Daroussin mparse_buf_r(curp, ln, of, 0);
39761d06d6bSBaptiste Daroussin }
3987295610fSBaptiste Daroussin break;
39961d06d6bSBaptiste Daroussin default:
4007295610fSBaptiste Daroussin abort();
40161d06d6bSBaptiste Daroussin }
40261d06d6bSBaptiste Daroussin
40361d06d6bSBaptiste Daroussin /* Start the next input line. */
40461d06d6bSBaptiste Daroussin
4057295610fSBaptiste Daroussin if (loop != NULL &&
4067295610fSBaptiste Daroussin (line_result & ROFF_LOOPMASK) == ROFF_IGN)
4077295610fSBaptiste Daroussin loop = loop->next;
4087295610fSBaptiste Daroussin
4097295610fSBaptiste Daroussin if (loop != NULL) {
4107295610fSBaptiste Daroussin if ((line_result & ROFF_APPEND) == 0)
4117295610fSBaptiste Daroussin *ln.buf = '\0';
4127295610fSBaptiste Daroussin if (ln.sz < loop->sz)
4137295610fSBaptiste Daroussin resize_buf(&ln, loop->sz);
4147295610fSBaptiste Daroussin (void)strlcat(ln.buf, loop->buf, ln.sz);
4157295610fSBaptiste Daroussin of = 0;
4167295610fSBaptiste Daroussin goto rerun;
41761d06d6bSBaptiste Daroussin }
41861d06d6bSBaptiste Daroussin
4197295610fSBaptiste Daroussin pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0;
4207295610fSBaptiste Daroussin }
4217295610fSBaptiste Daroussin out:
4227295610fSBaptiste Daroussin if (inloop) {
4237295610fSBaptiste Daroussin if (result != ROFF_USERRET)
4247295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_WHILE_OUTOF,
4257295610fSBaptiste Daroussin curp->line, pos, NULL);
4267295610fSBaptiste Daroussin curp->loop = NULL;
4277295610fSBaptiste Daroussin }
42861d06d6bSBaptiste Daroussin free(ln.buf);
4297295610fSBaptiste Daroussin if (firstln != curp->secondary)
4307295610fSBaptiste Daroussin free_buf_list(firstln);
4317295610fSBaptiste Daroussin return result;
43261d06d6bSBaptiste Daroussin }
43361d06d6bSBaptiste Daroussin
43461d06d6bSBaptiste Daroussin static int
read_whole_file(struct mparse * curp,int fd,struct buf * fb,int * with_mmap)4357295610fSBaptiste Daroussin read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap)
43661d06d6bSBaptiste Daroussin {
43761d06d6bSBaptiste Daroussin struct stat st;
43861d06d6bSBaptiste Daroussin gzFile gz;
43961d06d6bSBaptiste Daroussin size_t off;
44061d06d6bSBaptiste Daroussin ssize_t ssz;
44161d06d6bSBaptiste Daroussin int gzerrnum, retval;
44261d06d6bSBaptiste Daroussin
44361d06d6bSBaptiste Daroussin if (fstat(fd, &st) == -1) {
44445a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_FSTAT, 0, 0, "%s", strerror(errno));
44545a5aec3SBaptiste Daroussin return -1;
44661d06d6bSBaptiste Daroussin }
44761d06d6bSBaptiste Daroussin
44861d06d6bSBaptiste Daroussin /*
44961d06d6bSBaptiste Daroussin * If we're a regular file, try just reading in the whole entry
45061d06d6bSBaptiste Daroussin * via mmap(). This is faster than reading it into blocks, and
45161d06d6bSBaptiste Daroussin * since each file is only a few bytes to begin with, I'm not
45261d06d6bSBaptiste Daroussin * concerned that this is going to tank any machines.
45361d06d6bSBaptiste Daroussin */
45461d06d6bSBaptiste Daroussin
45561d06d6bSBaptiste Daroussin if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
45661d06d6bSBaptiste Daroussin if (st.st_size > 0x7fffffff) {
4577295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
45845a5aec3SBaptiste Daroussin return -1;
45961d06d6bSBaptiste Daroussin }
46061d06d6bSBaptiste Daroussin *with_mmap = 1;
46161d06d6bSBaptiste Daroussin fb->sz = (size_t)st.st_size;
46261d06d6bSBaptiste Daroussin fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
46361d06d6bSBaptiste Daroussin if (fb->buf != MAP_FAILED)
46445a5aec3SBaptiste Daroussin return 0;
46561d06d6bSBaptiste Daroussin }
46661d06d6bSBaptiste Daroussin
46761d06d6bSBaptiste Daroussin if (curp->gzip) {
46861d06d6bSBaptiste Daroussin /*
46961d06d6bSBaptiste Daroussin * Duplicating the file descriptor is required
47061d06d6bSBaptiste Daroussin * because we will have to call gzclose(3)
47161d06d6bSBaptiste Daroussin * to free memory used internally by zlib,
47261d06d6bSBaptiste Daroussin * but that will also close the file descriptor,
47361d06d6bSBaptiste Daroussin * which this function must not do.
47461d06d6bSBaptiste Daroussin */
47561d06d6bSBaptiste Daroussin if ((fd = dup(fd)) == -1) {
47645a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_DUP, 0, 0,
47745a5aec3SBaptiste Daroussin "%s", strerror(errno));
47845a5aec3SBaptiste Daroussin return -1;
47961d06d6bSBaptiste Daroussin }
48061d06d6bSBaptiste Daroussin if ((gz = gzdopen(fd, "rb")) == NULL) {
48145a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_GZDOPEN, 0, 0,
48245a5aec3SBaptiste Daroussin "%s", strerror(errno));
48361d06d6bSBaptiste Daroussin close(fd);
48445a5aec3SBaptiste Daroussin return -1;
48561d06d6bSBaptiste Daroussin }
48661d06d6bSBaptiste Daroussin } else
48761d06d6bSBaptiste Daroussin gz = NULL;
48861d06d6bSBaptiste Daroussin
48961d06d6bSBaptiste Daroussin /*
49061d06d6bSBaptiste Daroussin * If this isn't a regular file (like, say, stdin), then we must
49161d06d6bSBaptiste Daroussin * go the old way and just read things in bit by bit.
49261d06d6bSBaptiste Daroussin */
49361d06d6bSBaptiste Daroussin
49461d06d6bSBaptiste Daroussin *with_mmap = 0;
49561d06d6bSBaptiste Daroussin off = 0;
49645a5aec3SBaptiste Daroussin retval = -1;
49761d06d6bSBaptiste Daroussin fb->sz = 0;
49861d06d6bSBaptiste Daroussin fb->buf = NULL;
49961d06d6bSBaptiste Daroussin for (;;) {
50061d06d6bSBaptiste Daroussin if (off == fb->sz) {
50161d06d6bSBaptiste Daroussin if (fb->sz == (1U << 31)) {
5027295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
50361d06d6bSBaptiste Daroussin break;
50461d06d6bSBaptiste Daroussin }
50561d06d6bSBaptiste Daroussin resize_buf(fb, 65536);
50661d06d6bSBaptiste Daroussin }
50761d06d6bSBaptiste Daroussin ssz = curp->gzip ?
50861d06d6bSBaptiste Daroussin gzread(gz, fb->buf + (int)off, fb->sz - off) :
50961d06d6bSBaptiste Daroussin read(fd, fb->buf + (int)off, fb->sz - off);
51061d06d6bSBaptiste Daroussin if (ssz == 0) {
51161d06d6bSBaptiste Daroussin fb->sz = off;
51245a5aec3SBaptiste Daroussin retval = 0;
51361d06d6bSBaptiste Daroussin break;
51461d06d6bSBaptiste Daroussin }
51561d06d6bSBaptiste Daroussin if (ssz == -1) {
51661d06d6bSBaptiste Daroussin if (curp->gzip)
51761d06d6bSBaptiste Daroussin (void)gzerror(gz, &gzerrnum);
51845a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_READ, 0, 0, "%s",
51961d06d6bSBaptiste Daroussin curp->gzip && gzerrnum != Z_ERRNO ?
52061d06d6bSBaptiste Daroussin zError(gzerrnum) : strerror(errno));
52161d06d6bSBaptiste Daroussin break;
52261d06d6bSBaptiste Daroussin }
52361d06d6bSBaptiste Daroussin off += (size_t)ssz;
52461d06d6bSBaptiste Daroussin }
52561d06d6bSBaptiste Daroussin
52661d06d6bSBaptiste Daroussin if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK)
52745a5aec3SBaptiste Daroussin mandoc_msg(MANDOCERR_GZCLOSE, 0, 0, "%s",
52861d06d6bSBaptiste Daroussin gzerrnum == Z_ERRNO ? strerror(errno) :
52961d06d6bSBaptiste Daroussin zError(gzerrnum));
53045a5aec3SBaptiste Daroussin if (retval == -1) {
53161d06d6bSBaptiste Daroussin free(fb->buf);
53261d06d6bSBaptiste Daroussin fb->buf = NULL;
53361d06d6bSBaptiste Daroussin }
53461d06d6bSBaptiste Daroussin return retval;
53561d06d6bSBaptiste Daroussin }
53661d06d6bSBaptiste Daroussin
53761d06d6bSBaptiste Daroussin static void
mparse_end(struct mparse * curp)53861d06d6bSBaptiste Daroussin mparse_end(struct mparse *curp)
53961d06d6bSBaptiste Daroussin {
5407295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_NONE)
5417295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MAN;
5427295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_MDOC)
54361d06d6bSBaptiste Daroussin mdoc_endparse(curp->man);
54461d06d6bSBaptiste Daroussin else
54561d06d6bSBaptiste Daroussin man_endparse(curp->man);
54661d06d6bSBaptiste Daroussin roff_endparse(curp->roff);
54761d06d6bSBaptiste Daroussin }
54861d06d6bSBaptiste Daroussin
5497295610fSBaptiste Daroussin /*
5507295610fSBaptiste Daroussin * Read the whole file into memory and call the parsers.
5517295610fSBaptiste Daroussin * Called recursively when an .so request is encountered.
5527295610fSBaptiste Daroussin */
5537295610fSBaptiste Daroussin void
mparse_readfd(struct mparse * curp,int fd,const char * filename)5547295610fSBaptiste Daroussin mparse_readfd(struct mparse *curp, int fd, const char *filename)
55561d06d6bSBaptiste Daroussin {
55661d06d6bSBaptiste Daroussin static int recursion_depth;
55761d06d6bSBaptiste Daroussin
5587295610fSBaptiste Daroussin struct buf blk;
5597295610fSBaptiste Daroussin struct buf *save_primary;
560*6d38604fSBaptiste Daroussin const char *save_filename, *cp;
5617295610fSBaptiste Daroussin size_t offset;
5627295610fSBaptiste Daroussin int save_filenc, save_lineno;
5637295610fSBaptiste Daroussin int with_mmap;
5647295610fSBaptiste Daroussin
5657295610fSBaptiste Daroussin if (recursion_depth > 64) {
5667295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL);
56761d06d6bSBaptiste Daroussin return;
568*6d38604fSBaptiste Daroussin } else if (recursion_depth == 0 &&
569*6d38604fSBaptiste Daroussin (cp = strrchr(filename, '.')) != NULL &&
570*6d38604fSBaptiste Daroussin cp[1] >= '1' && cp[1] <= '9')
571*6d38604fSBaptiste Daroussin curp->man->filesec = cp[1];
572*6d38604fSBaptiste Daroussin else
573*6d38604fSBaptiste Daroussin curp->man->filesec = '\0';
574*6d38604fSBaptiste Daroussin
57545a5aec3SBaptiste Daroussin if (read_whole_file(curp, fd, &blk, &with_mmap) == -1)
5767295610fSBaptiste Daroussin return;
57761d06d6bSBaptiste Daroussin
5787295610fSBaptiste Daroussin /*
5797295610fSBaptiste Daroussin * Save some properties of the parent file.
5807295610fSBaptiste Daroussin */
5817295610fSBaptiste Daroussin
5827295610fSBaptiste Daroussin save_primary = curp->primary;
5837295610fSBaptiste Daroussin save_filenc = curp->filenc;
5847295610fSBaptiste Daroussin save_lineno = curp->line;
5857295610fSBaptiste Daroussin save_filename = mandoc_msg_getinfilename();
5867295610fSBaptiste Daroussin
58761d06d6bSBaptiste Daroussin curp->primary = &blk;
5887295610fSBaptiste Daroussin curp->filenc = curp->options & (MPARSE_UTF8 | MPARSE_LATIN1);
58961d06d6bSBaptiste Daroussin curp->line = 1;
5907295610fSBaptiste Daroussin mandoc_msg_setinfilename(filename);
59161d06d6bSBaptiste Daroussin
59261d06d6bSBaptiste Daroussin /* Skip an UTF-8 byte order mark. */
59361d06d6bSBaptiste Daroussin if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
59461d06d6bSBaptiste Daroussin (unsigned char)blk.buf[0] == 0xef &&
59561d06d6bSBaptiste Daroussin (unsigned char)blk.buf[1] == 0xbb &&
59661d06d6bSBaptiste Daroussin (unsigned char)blk.buf[2] == 0xbf) {
59761d06d6bSBaptiste Daroussin offset = 3;
59861d06d6bSBaptiste Daroussin curp->filenc &= ~MPARSE_LATIN1;
59961d06d6bSBaptiste Daroussin } else
60061d06d6bSBaptiste Daroussin offset = 0;
60161d06d6bSBaptiste Daroussin
6027295610fSBaptiste Daroussin recursion_depth++;
60361d06d6bSBaptiste Daroussin mparse_buf_r(curp, blk, offset, 1);
60461d06d6bSBaptiste Daroussin if (--recursion_depth == 0)
60561d06d6bSBaptiste Daroussin mparse_end(curp);
60661d06d6bSBaptiste Daroussin
60761d06d6bSBaptiste Daroussin /*
6087295610fSBaptiste Daroussin * Clean up and restore saved parent properties.
60961d06d6bSBaptiste Daroussin */
61061d06d6bSBaptiste Daroussin
61161d06d6bSBaptiste Daroussin if (with_mmap)
61261d06d6bSBaptiste Daroussin munmap(blk.buf, blk.sz);
61361d06d6bSBaptiste Daroussin else
61461d06d6bSBaptiste Daroussin free(blk.buf);
6157295610fSBaptiste Daroussin
6167295610fSBaptiste Daroussin curp->primary = save_primary;
6177295610fSBaptiste Daroussin curp->filenc = save_filenc;
6187295610fSBaptiste Daroussin curp->line = save_lineno;
6197295610fSBaptiste Daroussin if (save_filename != NULL)
6207295610fSBaptiste Daroussin mandoc_msg_setinfilename(save_filename);
62161d06d6bSBaptiste Daroussin }
62261d06d6bSBaptiste Daroussin
62361d06d6bSBaptiste Daroussin int
mparse_open(struct mparse * curp,const char * file)62461d06d6bSBaptiste Daroussin mparse_open(struct mparse *curp, const char *file)
62561d06d6bSBaptiste Daroussin {
62661d06d6bSBaptiste Daroussin char *cp;
6277295610fSBaptiste Daroussin int fd, save_errno;
62861d06d6bSBaptiste Daroussin
62961d06d6bSBaptiste Daroussin cp = strrchr(file, '.');
63061d06d6bSBaptiste Daroussin curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
63161d06d6bSBaptiste Daroussin
63261d06d6bSBaptiste Daroussin /* First try to use the filename as it is. */
63361d06d6bSBaptiste Daroussin
63461d06d6bSBaptiste Daroussin if ((fd = open(file, O_RDONLY)) != -1)
63561d06d6bSBaptiste Daroussin return fd;
63661d06d6bSBaptiste Daroussin
63761d06d6bSBaptiste Daroussin /*
63861d06d6bSBaptiste Daroussin * If that doesn't work and the filename doesn't
63961d06d6bSBaptiste Daroussin * already end in .gz, try appending .gz.
64061d06d6bSBaptiste Daroussin */
64161d06d6bSBaptiste Daroussin
64261d06d6bSBaptiste Daroussin if ( ! curp->gzip) {
6437295610fSBaptiste Daroussin save_errno = errno;
64461d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "%s.gz", file);
64561d06d6bSBaptiste Daroussin fd = open(cp, O_RDONLY);
64661d06d6bSBaptiste Daroussin free(cp);
6477295610fSBaptiste Daroussin errno = save_errno;
64861d06d6bSBaptiste Daroussin if (fd != -1) {
64961d06d6bSBaptiste Daroussin curp->gzip = 1;
65061d06d6bSBaptiste Daroussin return fd;
65161d06d6bSBaptiste Daroussin }
65261d06d6bSBaptiste Daroussin }
65361d06d6bSBaptiste Daroussin
65461d06d6bSBaptiste Daroussin /* Neither worked, give up. */
65561d06d6bSBaptiste Daroussin
65661d06d6bSBaptiste Daroussin return -1;
65761d06d6bSBaptiste Daroussin }
65861d06d6bSBaptiste Daroussin
65961d06d6bSBaptiste Daroussin struct mparse *
mparse_alloc(int options,enum mandoc_os os_e,const char * os_s)6607295610fSBaptiste Daroussin mparse_alloc(int options, enum mandoc_os os_e, const char *os_s)
66161d06d6bSBaptiste Daroussin {
66261d06d6bSBaptiste Daroussin struct mparse *curp;
66361d06d6bSBaptiste Daroussin
66461d06d6bSBaptiste Daroussin curp = mandoc_calloc(1, sizeof(struct mparse));
66561d06d6bSBaptiste Daroussin
66661d06d6bSBaptiste Daroussin curp->options = options;
66761d06d6bSBaptiste Daroussin curp->os_s = os_s;
66861d06d6bSBaptiste Daroussin
6697295610fSBaptiste Daroussin curp->roff = roff_alloc(options);
6707295610fSBaptiste Daroussin curp->man = roff_man_alloc(curp->roff, curp->os_s,
67161d06d6bSBaptiste Daroussin curp->options & MPARSE_QUICK ? 1 : 0);
67261d06d6bSBaptiste Daroussin if (curp->options & MPARSE_MDOC) {
6737295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MDOC;
67461d06d6bSBaptiste Daroussin if (curp->man->mdocmac == NULL)
67561d06d6bSBaptiste Daroussin curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
67661d06d6bSBaptiste Daroussin } else if (curp->options & MPARSE_MAN) {
6777295610fSBaptiste Daroussin curp->man->meta.macroset = MACROSET_MAN;
67861d06d6bSBaptiste Daroussin if (curp->man->manmac == NULL)
67961d06d6bSBaptiste Daroussin curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
68061d06d6bSBaptiste Daroussin }
6817295610fSBaptiste Daroussin curp->man->meta.first->tok = TOKEN_NONE;
68261d06d6bSBaptiste Daroussin curp->man->meta.os_e = os_e;
683*6d38604fSBaptiste Daroussin tag_alloc();
68461d06d6bSBaptiste Daroussin return curp;
68561d06d6bSBaptiste Daroussin }
68661d06d6bSBaptiste Daroussin
68761d06d6bSBaptiste Daroussin void
mparse_reset(struct mparse * curp)68861d06d6bSBaptiste Daroussin mparse_reset(struct mparse *curp)
68961d06d6bSBaptiste Daroussin {
690*6d38604fSBaptiste Daroussin tag_free();
69161d06d6bSBaptiste Daroussin roff_reset(curp->roff);
69261d06d6bSBaptiste Daroussin roff_man_reset(curp->man);
6937295610fSBaptiste Daroussin free_buf_list(curp->secondary);
6947295610fSBaptiste Daroussin curp->secondary = NULL;
69561d06d6bSBaptiste Daroussin curp->gzip = 0;
696*6d38604fSBaptiste Daroussin tag_alloc();
69761d06d6bSBaptiste Daroussin }
69861d06d6bSBaptiste Daroussin
69961d06d6bSBaptiste Daroussin void
mparse_free(struct mparse * curp)70061d06d6bSBaptiste Daroussin mparse_free(struct mparse *curp)
70161d06d6bSBaptiste Daroussin {
702*6d38604fSBaptiste Daroussin tag_free();
70361d06d6bSBaptiste Daroussin roffhash_free(curp->man->mdocmac);
70461d06d6bSBaptiste Daroussin roffhash_free(curp->man->manmac);
70561d06d6bSBaptiste Daroussin roff_man_free(curp->man);
70661d06d6bSBaptiste Daroussin roff_free(curp->roff);
7077295610fSBaptiste Daroussin free_buf_list(curp->secondary);
70861d06d6bSBaptiste Daroussin free(curp);
70961d06d6bSBaptiste Daroussin }
71061d06d6bSBaptiste Daroussin
7117295610fSBaptiste Daroussin struct roff_meta *
mparse_result(struct mparse * curp)7127295610fSBaptiste Daroussin mparse_result(struct mparse *curp)
71361d06d6bSBaptiste Daroussin {
7147295610fSBaptiste Daroussin roff_state_reset(curp->man);
7157295610fSBaptiste Daroussin if (curp->options & MPARSE_VALIDATE) {
7167295610fSBaptiste Daroussin if (curp->man->meta.macroset == MACROSET_MDOC)
7177295610fSBaptiste Daroussin mdoc_validate(curp->man);
7187295610fSBaptiste Daroussin else
7197295610fSBaptiste Daroussin man_validate(curp->man);
720*6d38604fSBaptiste Daroussin tag_postprocess(curp->man, curp->man->meta.first);
72161d06d6bSBaptiste Daroussin }
7227295610fSBaptiste Daroussin return &curp->man->meta;
72361d06d6bSBaptiste Daroussin }
72461d06d6bSBaptiste Daroussin
72561d06d6bSBaptiste Daroussin void
mparse_copy(const struct mparse * p)7267295610fSBaptiste Daroussin mparse_copy(const struct mparse *p)
72761d06d6bSBaptiste Daroussin {
7287295610fSBaptiste Daroussin struct buf *buf;
72961d06d6bSBaptiste Daroussin
7307295610fSBaptiste Daroussin for (buf = p->secondary; buf != NULL; buf = buf->next)
7317295610fSBaptiste Daroussin puts(buf->buf);
73261d06d6bSBaptiste Daroussin }
733