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