371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: read.c,v 1.149 2016/07/10 13:34:30 schwarze Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct roff *roff; /* roff parser (!NULL) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *file; /* filename of current input file */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct buf *primary; /* buffer currently being parsed */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct buf *secondary; /* preprocessed copy of input */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *defos; /* default operating system */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore mandocmsg mmsg; /* warning/error message handler */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov enum mandoclevel file_status; /* status of current parse */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov enum mandoclevel wlevel; /* ignore messages below this */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void resize_buf(struct buf *, size_t);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void mparse_buf_r(struct mparse *, struct buf, size_t, int);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int read_whole_file(struct mparse *, const char *, int,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct buf *, int *);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amorestatic void mparse_parse_buffer(struct mparse *, struct buf,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore const char *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const char * const mandocerrs[MANDOCERR_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "generic warning",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to the prologue */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing manual title, using UNTITLED",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing manual title, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "lower case character in document title",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing manual section, using \"\"",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "unknown manual section",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing date, using today's date",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "cannot parse date, using it verbatim",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing Os macro, using \"\"",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "duplicate prologue macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "late prologue macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping late title macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "prologue macros out of order",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to document structure */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ".so is fragile, better use ln(1)",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "no document body",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "content before first section header",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "first section is not \"NAME\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "NAME section without name",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "NAME section without description",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "description not at the end of NAME",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "bad NAME section content",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing description line, using \"\"",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "sections out of conventional order",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "duplicate section title",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unexpected section",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unusual Xr order",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unusual Xr punctuation",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "AUTHORS section without An macro",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to macros and nesting */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "obsolete macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "macro neither callable nor escaped",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping paragraph macro",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "moving paragraph macro out of list",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping no-space macro",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "blocks badly nested",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "nested displays are not portable",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "moving content out of list",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "fill mode already enabled, skipping",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "fill mode already disabled, skipping",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "line scope broken",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to missing macro arguments */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping empty request",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "conditional request controls empty scope",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping empty macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty block",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty argument, using 0n",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing display type, using -ragged",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "list type is not the first argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing -width in -tag list, using 8n",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing utility name, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing function name, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty head in list item",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty list item",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing font type, using \\fR",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unknown font type, using \\fR",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "nothing follows prefix",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty reference block",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing -std argument, adding it",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing option string, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing resource identifier, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing eqn box, using \"\"",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to bad macro arguments */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unterminated quoted argument",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "duplicate argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping duplicate argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping duplicate display type",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping duplicate list type",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping -width argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "wrong number of cells",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "unknown AT&T UNIX version",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "comma in function argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "parenthesis in function name",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "invalid content in Rs block",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "invalid Boolean argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unknown font, skipping request",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "odd number of characters in request",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to plain text */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "blank line in fill mode, using .sp",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "tab in filled text",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "whitespace at end of input line",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "bad comment style",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "invalid escape sequence",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "undefined string, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* related to tables */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "tbl line starts with span",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "tbl column starts with span",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping vertical bar in tbl layout",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "generic error",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* related to tables */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "non-alphabetic character in tbl options",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping unknown tbl option",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing tbl option argument",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "wrong tbl option argument size",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "empty tbl layout",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "invalid character in tbl layout",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unmatched parenthesis in tbl layout",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "tbl without any data cells",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "ignoring data in spanned tbl cell",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "ignoring extra tbl data cells",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "data block open at end of tbl",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* related to document structure and macros */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "input stack limit exceeded, infinite loop?",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping bad character",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping unknown macro",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping insecure request",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping item outside list",
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore "skipping column outside column list",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "skipping end of block that is not open",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "fewer RS blocks open, skipping",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "inserting missing end of block",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "appending missing end of block",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* related to request and macro arguments */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "escaped character not allowed in a name",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "NOT IMPLEMENTED: Bd -file",
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov "skipping display without arguments",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing list type, using -item",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "missing manual name, using \"\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "uname(3) system call failed, using UNKNOWN",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unknown standard specifier",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping request without numeric argument",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore "NOT IMPLEMENTED: .so with absolute path or \"..\"",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".so request failed",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping all arguments",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "skipping excess arguments",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "divide by zero",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unsupported feature",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "input too large",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unsupported control character",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unsupported roff request",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "eqn delim option in tbl",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "unsupported tbl layout modifier",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "ignoring macro in table",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const char * const mandoclevels[MANDOCLEVEL_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore buf->buf = mandoc_realloc(buf->buf, buf->sz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If neither command line arguments -mdoc or -man select
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * a parser nor the roff parser found a .Dd or .TH macro
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * yet, look ahead in the main input buffer.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((format = roff_getformat(curp->roff)) == 0) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Main parse routine for a buffer.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * It assumes encoding and line numbering are already set up.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * It can recurse directly (for invocations of user-defined
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * macros, inline equations, and input line traps)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and indirectly (for .so file inclusion).
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovmparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore unsigned char c;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (i < blk.sz && (start || blk.buf[i] != '\0')) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * When finding an unescaped newline character,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * leave the character loop to process the line.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Skip a preceding carriage return, if any.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Make sure we have space for the worst
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * case of 11 bytes: "\\[u10ffff]\0"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Encode 8-bit input.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (c & 0x80) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Exclude control characters.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (c != '\r')
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Trailing backslash = a plain char. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Found escape and at least one other character.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * When it's a newline character, skip it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * When there is a carriage return in between,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * skip that one as well.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Comment, skip to end of line */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Backout trailing whitespaces */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Catch escaped bogus characters. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (isascii(c) &&
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Some other escape sequence, copy & cont. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A significant amount of complexity is contained by
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the roff preprocessor. It's line-oriented but can be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * expressed on one line, so we need at times to
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * readjust our starting point and re-run it. The roff
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * preprocessor can also readjust the buffers with new
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * data, so we pass them in wholesale.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Maintain a lookaside buffer of all parsed lines. We
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * only do this if mparse_keep() has been invoked (the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * buffer may be accessed with mparse_getkeep()).
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov rr = roff_parseln(curp->roff, curp->line, &ln, &of);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * We remove `so' clauses from our lookaside
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * buffer because we're going to descend into
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the file recursively.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ".sp\nSee the file %s.\n.sp",
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If input parsers have not been allocated, do so now.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * We keep these instanced between parsers, but set them
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * locally per parse routine since we can use different
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * parsers with each one.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Lastly, push down into the parsers themselves.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If libroff returns ROFF_TBL, then add it to the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * currently open parse. Since we only get here if
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * there does exist data (see tbl_data.c), we're
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * guaranteed that something's been allocated.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Do the same for ROFF_EQN.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else if ((curp->man->macroset == MACROSET_MDOC ?
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mdoc_parseln(curp->man, curp->line, ln.buf, of) :
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Temporary buffers typically are not full. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Start the next input line. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovread_whole_file(struct mparse *curp, const char *file, int fd,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're a regular file, try just reading in the whole entry
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * via mmap(). This is faster than reading it into blocks, and
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * since each file is only a few bytes to begin with, I'm not
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * concerned that this is going to tank any machines.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If this isn't a regular file (like, say, stdin), then we must
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * go the old way and just read things in bit by bit.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoremparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Line number is per-file. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Skip an UTF-8 byte order mark. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovmparse_readmem(struct mparse *curp, void *buf, size_t len,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Read the whole file into memory and call the parsers.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Called recursively when an .so request is encountered.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amoremparse_readfd(struct mparse *curp, int fd, const char *file)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovmparse_open(struct mparse *curp, const char *file)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* First try to use the filename as it is. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * If that doesn't work and the filename doesn't
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * already end in .gz, try appending .gz.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Neither worked, give up. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovmparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *defos)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp = mandoc_calloc(1, sizeof(struct mparse));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->man = roff_man_alloc( curp->roff, curp, curp->defos,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovmparse_result(struct mparse *curp, struct roff_man **man,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (sodest && NULL != (*sodest = curp->sodest)) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoremandoc_vmsg(enum mandocerr t, struct mparse *m,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore (*m->mmsg)(er, level, m->file, ln, col, msg);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->secondary = mandoc_calloc(1, sizeof(struct buf));
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return p->secondary->sz ? p->secondary->buf : NULL;