1*95c635efSGarrett D'Amore /* $Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #ifdef HAVE_MMAP 23*95c635efSGarrett D'Amore # include <sys/stat.h> 24*95c635efSGarrett D'Amore # include <sys/mman.h> 25*95c635efSGarrett D'Amore #endif 26*95c635efSGarrett D'Amore 27*95c635efSGarrett D'Amore #include <assert.h> 28*95c635efSGarrett D'Amore #include <ctype.h> 29*95c635efSGarrett D'Amore #include <fcntl.h> 30*95c635efSGarrett D'Amore #include <stdarg.h> 31*95c635efSGarrett D'Amore #include <stdint.h> 32*95c635efSGarrett D'Amore #include <stdio.h> 33*95c635efSGarrett D'Amore #include <stdlib.h> 34*95c635efSGarrett D'Amore #include <string.h> 35*95c635efSGarrett D'Amore #include <unistd.h> 36*95c635efSGarrett D'Amore 37*95c635efSGarrett D'Amore #include "mandoc.h" 38*95c635efSGarrett D'Amore #include "libmandoc.h" 39*95c635efSGarrett D'Amore #include "mdoc.h" 40*95c635efSGarrett D'Amore #include "man.h" 41*95c635efSGarrett D'Amore #include "main.h" 42*95c635efSGarrett D'Amore 43*95c635efSGarrett D'Amore #ifndef MAP_FILE 44*95c635efSGarrett D'Amore #define MAP_FILE 0 45*95c635efSGarrett D'Amore #endif 46*95c635efSGarrett D'Amore 47*95c635efSGarrett D'Amore #define REPARSE_LIMIT 1000 48*95c635efSGarrett D'Amore 49*95c635efSGarrett D'Amore struct buf { 50*95c635efSGarrett D'Amore char *buf; /* binary input buffer */ 51*95c635efSGarrett D'Amore size_t sz; /* size of binary buffer */ 52*95c635efSGarrett D'Amore }; 53*95c635efSGarrett D'Amore 54*95c635efSGarrett D'Amore struct mparse { 55*95c635efSGarrett D'Amore enum mandoclevel file_status; /* status of current parse */ 56*95c635efSGarrett D'Amore enum mandoclevel wlevel; /* ignore messages below this */ 57*95c635efSGarrett D'Amore int line; /* line number in the file */ 58*95c635efSGarrett D'Amore enum mparset inttype; /* which parser to use */ 59*95c635efSGarrett D'Amore struct man *pman; /* persistent man parser */ 60*95c635efSGarrett D'Amore struct mdoc *pmdoc; /* persistent mdoc parser */ 61*95c635efSGarrett D'Amore struct man *man; /* man parser */ 62*95c635efSGarrett D'Amore struct mdoc *mdoc; /* mdoc parser */ 63*95c635efSGarrett D'Amore struct roff *roff; /* roff parser (!NULL) */ 64*95c635efSGarrett D'Amore int reparse_count; /* finite interp. stack */ 65*95c635efSGarrett D'Amore mandocmsg mmsg; /* warning/error message handler */ 66*95c635efSGarrett D'Amore void *arg; /* argument to mmsg */ 67*95c635efSGarrett D'Amore const char *file; 68*95c635efSGarrett D'Amore struct buf *secondary; 69*95c635efSGarrett D'Amore }; 70*95c635efSGarrett D'Amore 71*95c635efSGarrett D'Amore static void resize_buf(struct buf *, size_t); 72*95c635efSGarrett D'Amore static void mparse_buf_r(struct mparse *, struct buf, int); 73*95c635efSGarrett D'Amore static void mparse_readfd_r(struct mparse *, int, const char *, int); 74*95c635efSGarrett D'Amore static void pset(const char *, int, struct mparse *); 75*95c635efSGarrett D'Amore static int read_whole_file(const char *, int, struct buf *, int *); 76*95c635efSGarrett D'Amore static void mparse_end(struct mparse *); 77*95c635efSGarrett D'Amore 78*95c635efSGarrett D'Amore static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { 79*95c635efSGarrett D'Amore MANDOCERR_OK, 80*95c635efSGarrett D'Amore MANDOCERR_WARNING, 81*95c635efSGarrett D'Amore MANDOCERR_WARNING, 82*95c635efSGarrett D'Amore MANDOCERR_ERROR, 83*95c635efSGarrett D'Amore MANDOCERR_FATAL, 84*95c635efSGarrett D'Amore MANDOCERR_MAX, 85*95c635efSGarrett D'Amore MANDOCERR_MAX 86*95c635efSGarrett D'Amore }; 87*95c635efSGarrett D'Amore 88*95c635efSGarrett D'Amore static const char * const mandocerrs[MANDOCERR_MAX] = { 89*95c635efSGarrett D'Amore "ok", 90*95c635efSGarrett D'Amore 91*95c635efSGarrett D'Amore "generic warning", 92*95c635efSGarrett D'Amore 93*95c635efSGarrett D'Amore /* related to the prologue */ 94*95c635efSGarrett D'Amore "no title in document", 95*95c635efSGarrett D'Amore "document title should be all caps", 96*95c635efSGarrett D'Amore "unknown manual section", 97*95c635efSGarrett D'Amore "date missing, using today's date", 98*95c635efSGarrett D'Amore "cannot parse date, using it verbatim", 99*95c635efSGarrett D'Amore "prologue macros out of order", 100*95c635efSGarrett D'Amore "duplicate prologue macro", 101*95c635efSGarrett D'Amore "macro not allowed in prologue", 102*95c635efSGarrett D'Amore "macro not allowed in body", 103*95c635efSGarrett D'Amore 104*95c635efSGarrett D'Amore /* related to document structure */ 105*95c635efSGarrett D'Amore ".so is fragile, better use ln(1)", 106*95c635efSGarrett D'Amore "NAME section must come first", 107*95c635efSGarrett D'Amore "bad NAME section contents", 108*95c635efSGarrett D'Amore "manual name not yet set", 109*95c635efSGarrett D'Amore "sections out of conventional order", 110*95c635efSGarrett D'Amore "duplicate section name", 111*95c635efSGarrett D'Amore "section not in conventional manual section", 112*95c635efSGarrett D'Amore 113*95c635efSGarrett D'Amore /* related to macros and nesting */ 114*95c635efSGarrett D'Amore "skipping obsolete macro", 115*95c635efSGarrett D'Amore "skipping paragraph macro", 116*95c635efSGarrett D'Amore "skipping no-space macro", 117*95c635efSGarrett D'Amore "blocks badly nested", 118*95c635efSGarrett D'Amore "child violates parent syntax", 119*95c635efSGarrett D'Amore "nested displays are not portable", 120*95c635efSGarrett D'Amore "already in literal mode", 121*95c635efSGarrett D'Amore "line scope broken", 122*95c635efSGarrett D'Amore 123*95c635efSGarrett D'Amore /* related to missing macro arguments */ 124*95c635efSGarrett D'Amore "skipping empty macro", 125*95c635efSGarrett D'Amore "argument count wrong", 126*95c635efSGarrett D'Amore "missing display type", 127*95c635efSGarrett D'Amore "list type must come first", 128*95c635efSGarrett D'Amore "tag lists require a width argument", 129*95c635efSGarrett D'Amore "missing font type", 130*95c635efSGarrett D'Amore "skipping end of block that is not open", 131*95c635efSGarrett D'Amore 132*95c635efSGarrett D'Amore /* related to bad macro arguments */ 133*95c635efSGarrett D'Amore "skipping argument", 134*95c635efSGarrett D'Amore "duplicate argument", 135*95c635efSGarrett D'Amore "duplicate display type", 136*95c635efSGarrett D'Amore "duplicate list type", 137*95c635efSGarrett D'Amore "unknown AT&T UNIX version", 138*95c635efSGarrett D'Amore "bad Boolean value", 139*95c635efSGarrett D'Amore "unknown font", 140*95c635efSGarrett D'Amore "unknown standard specifier", 141*95c635efSGarrett D'Amore "bad width argument", 142*95c635efSGarrett D'Amore 143*95c635efSGarrett D'Amore /* related to plain text */ 144*95c635efSGarrett D'Amore "blank line in non-literal context", 145*95c635efSGarrett D'Amore "tab in non-literal context", 146*95c635efSGarrett D'Amore "end of line whitespace", 147*95c635efSGarrett D'Amore "bad comment style", 148*95c635efSGarrett D'Amore "bad escape sequence", 149*95c635efSGarrett D'Amore "unterminated quoted string", 150*95c635efSGarrett D'Amore 151*95c635efSGarrett D'Amore /* related to equations */ 152*95c635efSGarrett D'Amore "unexpected literal in equation", 153*95c635efSGarrett D'Amore 154*95c635efSGarrett D'Amore "generic error", 155*95c635efSGarrett D'Amore 156*95c635efSGarrett D'Amore /* related to equations */ 157*95c635efSGarrett D'Amore "unexpected equation scope closure", 158*95c635efSGarrett D'Amore "equation scope open on exit", 159*95c635efSGarrett D'Amore "overlapping equation scopes", 160*95c635efSGarrett D'Amore "unexpected end of equation", 161*95c635efSGarrett D'Amore "equation syntax error", 162*95c635efSGarrett D'Amore 163*95c635efSGarrett D'Amore /* related to tables */ 164*95c635efSGarrett D'Amore "bad table syntax", 165*95c635efSGarrett D'Amore "bad table option", 166*95c635efSGarrett D'Amore "bad table layout", 167*95c635efSGarrett D'Amore "no table layout cells specified", 168*95c635efSGarrett D'Amore "no table data cells specified", 169*95c635efSGarrett D'Amore "ignore data in cell", 170*95c635efSGarrett D'Amore "data block still open", 171*95c635efSGarrett D'Amore "ignoring extra data cells", 172*95c635efSGarrett D'Amore 173*95c635efSGarrett D'Amore "input stack limit exceeded, infinite loop?", 174*95c635efSGarrett D'Amore "skipping bad character", 175*95c635efSGarrett D'Amore "escaped character not allowed in a name", 176*95c635efSGarrett D'Amore "skipping text before the first section header", 177*95c635efSGarrett D'Amore "skipping unknown macro", 178*95c635efSGarrett D'Amore "NOT IMPLEMENTED, please use groff: skipping request", 179*95c635efSGarrett D'Amore "argument count wrong", 180*95c635efSGarrett D'Amore "skipping end of block that is not open", 181*95c635efSGarrett D'Amore "missing end of block", 182*95c635efSGarrett D'Amore "scope open on exit", 183*95c635efSGarrett D'Amore "uname(3) system call failed", 184*95c635efSGarrett D'Amore "macro requires line argument(s)", 185*95c635efSGarrett D'Amore "macro requires body argument(s)", 186*95c635efSGarrett D'Amore "macro requires argument(s)", 187*95c635efSGarrett D'Amore "missing list type", 188*95c635efSGarrett D'Amore "line argument(s) will be lost", 189*95c635efSGarrett D'Amore "body argument(s) will be lost", 190*95c635efSGarrett D'Amore 191*95c635efSGarrett D'Amore "generic fatal error", 192*95c635efSGarrett D'Amore 193*95c635efSGarrett D'Amore "not a manual", 194*95c635efSGarrett D'Amore "column syntax is inconsistent", 195*95c635efSGarrett D'Amore "NOT IMPLEMENTED: .Bd -file", 196*95c635efSGarrett D'Amore "argument count wrong, violates syntax", 197*95c635efSGarrett D'Amore "child violates parent syntax", 198*95c635efSGarrett D'Amore "argument count wrong, violates syntax", 199*95c635efSGarrett D'Amore "NOT IMPLEMENTED: .so with absolute path or \"..\"", 200*95c635efSGarrett D'Amore "no document body", 201*95c635efSGarrett D'Amore "no document prologue", 202*95c635efSGarrett D'Amore "static buffer exhausted", 203*95c635efSGarrett D'Amore }; 204*95c635efSGarrett D'Amore 205*95c635efSGarrett D'Amore static const char * const mandoclevels[MANDOCLEVEL_MAX] = { 206*95c635efSGarrett D'Amore "SUCCESS", 207*95c635efSGarrett D'Amore "RESERVED", 208*95c635efSGarrett D'Amore "WARNING", 209*95c635efSGarrett D'Amore "ERROR", 210*95c635efSGarrett D'Amore "FATAL", 211*95c635efSGarrett D'Amore "BADARG", 212*95c635efSGarrett D'Amore "SYSERR" 213*95c635efSGarrett D'Amore }; 214*95c635efSGarrett D'Amore 215*95c635efSGarrett D'Amore static void 216*95c635efSGarrett D'Amore resize_buf(struct buf *buf, size_t initial) 217*95c635efSGarrett D'Amore { 218*95c635efSGarrett D'Amore 219*95c635efSGarrett D'Amore buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; 220*95c635efSGarrett D'Amore buf->buf = mandoc_realloc(buf->buf, buf->sz); 221*95c635efSGarrett D'Amore } 222*95c635efSGarrett D'Amore 223*95c635efSGarrett D'Amore static void 224*95c635efSGarrett D'Amore pset(const char *buf, int pos, struct mparse *curp) 225*95c635efSGarrett D'Amore { 226*95c635efSGarrett D'Amore int i; 227*95c635efSGarrett D'Amore 228*95c635efSGarrett D'Amore /* 229*95c635efSGarrett D'Amore * Try to intuit which kind of manual parser should be used. If 230*95c635efSGarrett D'Amore * passed in by command-line (-man, -mdoc), then use that 231*95c635efSGarrett D'Amore * explicitly. If passed as -mandoc, then try to guess from the 232*95c635efSGarrett D'Amore * line: either skip dot-lines, use -mdoc when finding `.Dt', or 233*95c635efSGarrett D'Amore * default to -man, which is more lenient. 234*95c635efSGarrett D'Amore * 235*95c635efSGarrett D'Amore * Separate out pmdoc/pman from mdoc/man: the first persists 236*95c635efSGarrett D'Amore * through all parsers, while the latter is used per-parse. 237*95c635efSGarrett D'Amore */ 238*95c635efSGarrett D'Amore 239*95c635efSGarrett D'Amore if ('.' == buf[0] || '\'' == buf[0]) { 240*95c635efSGarrett D'Amore for (i = 1; buf[i]; i++) 241*95c635efSGarrett D'Amore if (' ' != buf[i] && '\t' != buf[i]) 242*95c635efSGarrett D'Amore break; 243*95c635efSGarrett D'Amore if ('\0' == buf[i]) 244*95c635efSGarrett D'Amore return; 245*95c635efSGarrett D'Amore } 246*95c635efSGarrett D'Amore 247*95c635efSGarrett D'Amore switch (curp->inttype) { 248*95c635efSGarrett D'Amore case (MPARSE_MDOC): 249*95c635efSGarrett D'Amore if (NULL == curp->pmdoc) 250*95c635efSGarrett D'Amore curp->pmdoc = mdoc_alloc(curp->roff, curp); 251*95c635efSGarrett D'Amore assert(curp->pmdoc); 252*95c635efSGarrett D'Amore curp->mdoc = curp->pmdoc; 253*95c635efSGarrett D'Amore return; 254*95c635efSGarrett D'Amore case (MPARSE_MAN): 255*95c635efSGarrett D'Amore if (NULL == curp->pman) 256*95c635efSGarrett D'Amore curp->pman = man_alloc(curp->roff, curp); 257*95c635efSGarrett D'Amore assert(curp->pman); 258*95c635efSGarrett D'Amore curp->man = curp->pman; 259*95c635efSGarrett D'Amore return; 260*95c635efSGarrett D'Amore default: 261*95c635efSGarrett D'Amore break; 262*95c635efSGarrett D'Amore } 263*95c635efSGarrett D'Amore 264*95c635efSGarrett D'Amore if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { 265*95c635efSGarrett D'Amore if (NULL == curp->pmdoc) 266*95c635efSGarrett D'Amore curp->pmdoc = mdoc_alloc(curp->roff, curp); 267*95c635efSGarrett D'Amore assert(curp->pmdoc); 268*95c635efSGarrett D'Amore curp->mdoc = curp->pmdoc; 269*95c635efSGarrett D'Amore return; 270*95c635efSGarrett D'Amore } 271*95c635efSGarrett D'Amore 272*95c635efSGarrett D'Amore if (NULL == curp->pman) 273*95c635efSGarrett D'Amore curp->pman = man_alloc(curp->roff, curp); 274*95c635efSGarrett D'Amore assert(curp->pman); 275*95c635efSGarrett D'Amore curp->man = curp->pman; 276*95c635efSGarrett D'Amore } 277*95c635efSGarrett D'Amore 278*95c635efSGarrett D'Amore /* 279*95c635efSGarrett D'Amore * Main parse routine for an opened file. This is called for each 280*95c635efSGarrett D'Amore * opened file and simply loops around the full input file, possibly 281*95c635efSGarrett D'Amore * nesting (i.e., with `so'). 282*95c635efSGarrett D'Amore */ 283*95c635efSGarrett D'Amore static void 284*95c635efSGarrett D'Amore mparse_buf_r(struct mparse *curp, struct buf blk, int start) 285*95c635efSGarrett D'Amore { 286*95c635efSGarrett D'Amore const struct tbl_span *span; 287*95c635efSGarrett D'Amore struct buf ln; 288*95c635efSGarrett D'Amore enum rofferr rr; 289*95c635efSGarrett D'Amore int i, of, rc; 290*95c635efSGarrett D'Amore int pos; /* byte number in the ln buffer */ 291*95c635efSGarrett D'Amore int lnn; /* line number in the real file */ 292*95c635efSGarrett D'Amore unsigned char c; 293*95c635efSGarrett D'Amore 294*95c635efSGarrett D'Amore memset(&ln, 0, sizeof(struct buf)); 295*95c635efSGarrett D'Amore 296*95c635efSGarrett D'Amore lnn = curp->line; 297*95c635efSGarrett D'Amore pos = 0; 298*95c635efSGarrett D'Amore 299*95c635efSGarrett D'Amore for (i = 0; i < (int)blk.sz; ) { 300*95c635efSGarrett D'Amore if (0 == pos && '\0' == blk.buf[i]) 301*95c635efSGarrett D'Amore break; 302*95c635efSGarrett D'Amore 303*95c635efSGarrett D'Amore if (start) { 304*95c635efSGarrett D'Amore curp->line = lnn; 305*95c635efSGarrett D'Amore curp->reparse_count = 0; 306*95c635efSGarrett D'Amore } 307*95c635efSGarrett D'Amore 308*95c635efSGarrett D'Amore while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { 309*95c635efSGarrett D'Amore 310*95c635efSGarrett D'Amore /* 311*95c635efSGarrett D'Amore * When finding an unescaped newline character, 312*95c635efSGarrett D'Amore * leave the character loop to process the line. 313*95c635efSGarrett D'Amore * Skip a preceding carriage return, if any. 314*95c635efSGarrett D'Amore */ 315*95c635efSGarrett D'Amore 316*95c635efSGarrett D'Amore if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz && 317*95c635efSGarrett D'Amore '\n' == blk.buf[i + 1]) 318*95c635efSGarrett D'Amore ++i; 319*95c635efSGarrett D'Amore if ('\n' == blk.buf[i]) { 320*95c635efSGarrett D'Amore ++i; 321*95c635efSGarrett D'Amore ++lnn; 322*95c635efSGarrett D'Amore break; 323*95c635efSGarrett D'Amore } 324*95c635efSGarrett D'Amore 325*95c635efSGarrett D'Amore /* 326*95c635efSGarrett D'Amore * Warn about bogus characters. If you're using 327*95c635efSGarrett D'Amore * non-ASCII encoding, you're screwing your 328*95c635efSGarrett D'Amore * readers. Since I'd rather this not happen, 329*95c635efSGarrett D'Amore * I'll be helpful and replace these characters 330*95c635efSGarrett D'Amore * with "?", so we don't display gibberish. 331*95c635efSGarrett D'Amore * Note to manual writers: use special characters. 332*95c635efSGarrett D'Amore */ 333*95c635efSGarrett D'Amore 334*95c635efSGarrett D'Amore c = (unsigned char) blk.buf[i]; 335*95c635efSGarrett D'Amore 336*95c635efSGarrett D'Amore if ( ! (isascii(c) && 337*95c635efSGarrett D'Amore (isgraph(c) || isblank(c)))) { 338*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_BADCHAR, curp, 339*95c635efSGarrett D'Amore curp->line, pos, NULL); 340*95c635efSGarrett D'Amore i++; 341*95c635efSGarrett D'Amore if (pos >= (int)ln.sz) 342*95c635efSGarrett D'Amore resize_buf(&ln, 256); 343*95c635efSGarrett D'Amore ln.buf[pos++] = '?'; 344*95c635efSGarrett D'Amore continue; 345*95c635efSGarrett D'Amore } 346*95c635efSGarrett D'Amore 347*95c635efSGarrett D'Amore /* Trailing backslash = a plain char. */ 348*95c635efSGarrett D'Amore 349*95c635efSGarrett D'Amore if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) { 350*95c635efSGarrett D'Amore if (pos >= (int)ln.sz) 351*95c635efSGarrett D'Amore resize_buf(&ln, 256); 352*95c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++]; 353*95c635efSGarrett D'Amore continue; 354*95c635efSGarrett D'Amore } 355*95c635efSGarrett D'Amore 356*95c635efSGarrett D'Amore /* 357*95c635efSGarrett D'Amore * Found escape and at least one other character. 358*95c635efSGarrett D'Amore * When it's a newline character, skip it. 359*95c635efSGarrett D'Amore * When there is a carriage return in between, 360*95c635efSGarrett D'Amore * skip that one as well. 361*95c635efSGarrett D'Amore */ 362*95c635efSGarrett D'Amore 363*95c635efSGarrett D'Amore if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz && 364*95c635efSGarrett D'Amore '\n' == blk.buf[i + 2]) 365*95c635efSGarrett D'Amore ++i; 366*95c635efSGarrett D'Amore if ('\n' == blk.buf[i + 1]) { 367*95c635efSGarrett D'Amore i += 2; 368*95c635efSGarrett D'Amore ++lnn; 369*95c635efSGarrett D'Amore continue; 370*95c635efSGarrett D'Amore } 371*95c635efSGarrett D'Amore 372*95c635efSGarrett D'Amore if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) { 373*95c635efSGarrett D'Amore i += 2; 374*95c635efSGarrett D'Amore /* Comment, skip to end of line */ 375*95c635efSGarrett D'Amore for (; i < (int)blk.sz; ++i) { 376*95c635efSGarrett D'Amore if ('\n' == blk.buf[i]) { 377*95c635efSGarrett D'Amore ++i; 378*95c635efSGarrett D'Amore ++lnn; 379*95c635efSGarrett D'Amore break; 380*95c635efSGarrett D'Amore } 381*95c635efSGarrett D'Amore } 382*95c635efSGarrett D'Amore 383*95c635efSGarrett D'Amore /* Backout trailing whitespaces */ 384*95c635efSGarrett D'Amore for (; pos > 0; --pos) { 385*95c635efSGarrett D'Amore if (ln.buf[pos - 1] != ' ') 386*95c635efSGarrett D'Amore break; 387*95c635efSGarrett D'Amore if (pos > 2 && ln.buf[pos - 2] == '\\') 388*95c635efSGarrett D'Amore break; 389*95c635efSGarrett D'Amore } 390*95c635efSGarrett D'Amore break; 391*95c635efSGarrett D'Amore } 392*95c635efSGarrett D'Amore 393*95c635efSGarrett D'Amore /* Some other escape sequence, copy & cont. */ 394*95c635efSGarrett D'Amore 395*95c635efSGarrett D'Amore if (pos + 1 >= (int)ln.sz) 396*95c635efSGarrett D'Amore resize_buf(&ln, 256); 397*95c635efSGarrett D'Amore 398*95c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++]; 399*95c635efSGarrett D'Amore ln.buf[pos++] = blk.buf[i++]; 400*95c635efSGarrett D'Amore } 401*95c635efSGarrett D'Amore 402*95c635efSGarrett D'Amore if (pos >= (int)ln.sz) 403*95c635efSGarrett D'Amore resize_buf(&ln, 256); 404*95c635efSGarrett D'Amore 405*95c635efSGarrett D'Amore ln.buf[pos] = '\0'; 406*95c635efSGarrett D'Amore 407*95c635efSGarrett D'Amore /* 408*95c635efSGarrett D'Amore * A significant amount of complexity is contained by 409*95c635efSGarrett D'Amore * the roff preprocessor. It's line-oriented but can be 410*95c635efSGarrett D'Amore * expressed on one line, so we need at times to 411*95c635efSGarrett D'Amore * readjust our starting point and re-run it. The roff 412*95c635efSGarrett D'Amore * preprocessor can also readjust the buffers with new 413*95c635efSGarrett D'Amore * data, so we pass them in wholesale. 414*95c635efSGarrett D'Amore */ 415*95c635efSGarrett D'Amore 416*95c635efSGarrett D'Amore of = 0; 417*95c635efSGarrett D'Amore 418*95c635efSGarrett D'Amore /* 419*95c635efSGarrett D'Amore * Maintain a lookaside buffer of all parsed lines. We 420*95c635efSGarrett D'Amore * only do this if mparse_keep() has been invoked (the 421*95c635efSGarrett D'Amore * buffer may be accessed with mparse_getkeep()). 422*95c635efSGarrett D'Amore */ 423*95c635efSGarrett D'Amore 424*95c635efSGarrett D'Amore if (curp->secondary) { 425*95c635efSGarrett D'Amore curp->secondary->buf = 426*95c635efSGarrett D'Amore mandoc_realloc 427*95c635efSGarrett D'Amore (curp->secondary->buf, 428*95c635efSGarrett D'Amore curp->secondary->sz + pos + 2); 429*95c635efSGarrett D'Amore memcpy(curp->secondary->buf + 430*95c635efSGarrett D'Amore curp->secondary->sz, 431*95c635efSGarrett D'Amore ln.buf, pos); 432*95c635efSGarrett D'Amore curp->secondary->sz += pos; 433*95c635efSGarrett D'Amore curp->secondary->buf 434*95c635efSGarrett D'Amore [curp->secondary->sz] = '\n'; 435*95c635efSGarrett D'Amore curp->secondary->sz++; 436*95c635efSGarrett D'Amore curp->secondary->buf 437*95c635efSGarrett D'Amore [curp->secondary->sz] = '\0'; 438*95c635efSGarrett D'Amore } 439*95c635efSGarrett D'Amore rerun: 440*95c635efSGarrett D'Amore rr = roff_parseln 441*95c635efSGarrett D'Amore (curp->roff, curp->line, 442*95c635efSGarrett D'Amore &ln.buf, &ln.sz, of, &of); 443*95c635efSGarrett D'Amore 444*95c635efSGarrett D'Amore switch (rr) { 445*95c635efSGarrett D'Amore case (ROFF_REPARSE): 446*95c635efSGarrett D'Amore if (REPARSE_LIMIT >= ++curp->reparse_count) 447*95c635efSGarrett D'Amore mparse_buf_r(curp, ln, 0); 448*95c635efSGarrett D'Amore else 449*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ROFFLOOP, curp, 450*95c635efSGarrett D'Amore curp->line, pos, NULL); 451*95c635efSGarrett D'Amore pos = 0; 452*95c635efSGarrett D'Amore continue; 453*95c635efSGarrett D'Amore case (ROFF_APPEND): 454*95c635efSGarrett D'Amore pos = (int)strlen(ln.buf); 455*95c635efSGarrett D'Amore continue; 456*95c635efSGarrett D'Amore case (ROFF_RERUN): 457*95c635efSGarrett D'Amore goto rerun; 458*95c635efSGarrett D'Amore case (ROFF_IGN): 459*95c635efSGarrett D'Amore pos = 0; 460*95c635efSGarrett D'Amore continue; 461*95c635efSGarrett D'Amore case (ROFF_ERR): 462*95c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status); 463*95c635efSGarrett D'Amore break; 464*95c635efSGarrett D'Amore case (ROFF_SO): 465*95c635efSGarrett D'Amore /* 466*95c635efSGarrett D'Amore * We remove `so' clauses from our lookaside 467*95c635efSGarrett D'Amore * buffer because we're going to descend into 468*95c635efSGarrett D'Amore * the file recursively. 469*95c635efSGarrett D'Amore */ 470*95c635efSGarrett D'Amore if (curp->secondary) 471*95c635efSGarrett D'Amore curp->secondary->sz -= pos + 1; 472*95c635efSGarrett D'Amore mparse_readfd_r(curp, -1, ln.buf + of, 1); 473*95c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status) 474*95c635efSGarrett D'Amore break; 475*95c635efSGarrett D'Amore pos = 0; 476*95c635efSGarrett D'Amore continue; 477*95c635efSGarrett D'Amore default: 478*95c635efSGarrett D'Amore break; 479*95c635efSGarrett D'Amore } 480*95c635efSGarrett D'Amore 481*95c635efSGarrett D'Amore /* 482*95c635efSGarrett D'Amore * If we encounter errors in the recursive parse, make 483*95c635efSGarrett D'Amore * sure we don't continue parsing. 484*95c635efSGarrett D'Amore */ 485*95c635efSGarrett D'Amore 486*95c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status) 487*95c635efSGarrett D'Amore break; 488*95c635efSGarrett D'Amore 489*95c635efSGarrett D'Amore /* 490*95c635efSGarrett D'Amore * If input parsers have not been allocated, do so now. 491*95c635efSGarrett D'Amore * We keep these instanced between parsers, but set them 492*95c635efSGarrett D'Amore * locally per parse routine since we can use different 493*95c635efSGarrett D'Amore * parsers with each one. 494*95c635efSGarrett D'Amore */ 495*95c635efSGarrett D'Amore 496*95c635efSGarrett D'Amore if ( ! (curp->man || curp->mdoc)) 497*95c635efSGarrett D'Amore pset(ln.buf + of, pos - of, curp); 498*95c635efSGarrett D'Amore 499*95c635efSGarrett D'Amore /* 500*95c635efSGarrett D'Amore * Lastly, push down into the parsers themselves. One 501*95c635efSGarrett D'Amore * of these will have already been set in the pset() 502*95c635efSGarrett D'Amore * routine. 503*95c635efSGarrett D'Amore * If libroff returns ROFF_TBL, then add it to the 504*95c635efSGarrett D'Amore * currently open parse. Since we only get here if 505*95c635efSGarrett D'Amore * there does exist data (see tbl_data.c), we're 506*95c635efSGarrett D'Amore * guaranteed that something's been allocated. 507*95c635efSGarrett D'Amore * Do the same for ROFF_EQN. 508*95c635efSGarrett D'Amore */ 509*95c635efSGarrett D'Amore 510*95c635efSGarrett D'Amore rc = -1; 511*95c635efSGarrett D'Amore 512*95c635efSGarrett D'Amore if (ROFF_TBL == rr) 513*95c635efSGarrett D'Amore while (NULL != (span = roff_span(curp->roff))) { 514*95c635efSGarrett D'Amore rc = curp->man ? 515*95c635efSGarrett D'Amore man_addspan(curp->man, span) : 516*95c635efSGarrett D'Amore mdoc_addspan(curp->mdoc, span); 517*95c635efSGarrett D'Amore if (0 == rc) 518*95c635efSGarrett D'Amore break; 519*95c635efSGarrett D'Amore } 520*95c635efSGarrett D'Amore else if (ROFF_EQN == rr) 521*95c635efSGarrett D'Amore rc = curp->mdoc ? 522*95c635efSGarrett D'Amore mdoc_addeqn(curp->mdoc, 523*95c635efSGarrett D'Amore roff_eqn(curp->roff)) : 524*95c635efSGarrett D'Amore man_addeqn(curp->man, 525*95c635efSGarrett D'Amore roff_eqn(curp->roff)); 526*95c635efSGarrett D'Amore else if (curp->man || curp->mdoc) 527*95c635efSGarrett D'Amore rc = curp->man ? 528*95c635efSGarrett D'Amore man_parseln(curp->man, 529*95c635efSGarrett D'Amore curp->line, ln.buf, of) : 530*95c635efSGarrett D'Amore mdoc_parseln(curp->mdoc, 531*95c635efSGarrett D'Amore curp->line, ln.buf, of); 532*95c635efSGarrett D'Amore 533*95c635efSGarrett D'Amore if (0 == rc) { 534*95c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status); 535*95c635efSGarrett D'Amore break; 536*95c635efSGarrett D'Amore } 537*95c635efSGarrett D'Amore 538*95c635efSGarrett D'Amore /* Temporary buffers typically are not full. */ 539*95c635efSGarrett D'Amore 540*95c635efSGarrett D'Amore if (0 == start && '\0' == blk.buf[i]) 541*95c635efSGarrett D'Amore break; 542*95c635efSGarrett D'Amore 543*95c635efSGarrett D'Amore /* Start the next input line. */ 544*95c635efSGarrett D'Amore 545*95c635efSGarrett D'Amore pos = 0; 546*95c635efSGarrett D'Amore } 547*95c635efSGarrett D'Amore 548*95c635efSGarrett D'Amore free(ln.buf); 549*95c635efSGarrett D'Amore } 550*95c635efSGarrett D'Amore 551*95c635efSGarrett D'Amore static int 552*95c635efSGarrett D'Amore read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap) 553*95c635efSGarrett D'Amore { 554*95c635efSGarrett D'Amore size_t off; 555*95c635efSGarrett D'Amore ssize_t ssz; 556*95c635efSGarrett D'Amore 557*95c635efSGarrett D'Amore #ifdef HAVE_MMAP 558*95c635efSGarrett D'Amore struct stat st; 559*95c635efSGarrett D'Amore if (-1 == fstat(fd, &st)) { 560*95c635efSGarrett D'Amore perror(file); 561*95c635efSGarrett D'Amore return(0); 562*95c635efSGarrett D'Amore } 563*95c635efSGarrett D'Amore 564*95c635efSGarrett D'Amore /* 565*95c635efSGarrett D'Amore * If we're a regular file, try just reading in the whole entry 566*95c635efSGarrett D'Amore * via mmap(). This is faster than reading it into blocks, and 567*95c635efSGarrett D'Amore * since each file is only a few bytes to begin with, I'm not 568*95c635efSGarrett D'Amore * concerned that this is going to tank any machines. 569*95c635efSGarrett D'Amore */ 570*95c635efSGarrett D'Amore 571*95c635efSGarrett D'Amore if (S_ISREG(st.st_mode)) { 572*95c635efSGarrett D'Amore if (st.st_size >= (1U << 31)) { 573*95c635efSGarrett D'Amore fprintf(stderr, "%s: input too large\n", file); 574*95c635efSGarrett D'Amore return(0); 575*95c635efSGarrett D'Amore } 576*95c635efSGarrett D'Amore *with_mmap = 1; 577*95c635efSGarrett D'Amore fb->sz = (size_t)st.st_size; 578*95c635efSGarrett D'Amore fb->buf = mmap(NULL, fb->sz, PROT_READ, 579*95c635efSGarrett D'Amore MAP_FILE|MAP_SHARED, fd, 0); 580*95c635efSGarrett D'Amore if (fb->buf != MAP_FAILED) 581*95c635efSGarrett D'Amore return(1); 582*95c635efSGarrett D'Amore } 583*95c635efSGarrett D'Amore #endif 584*95c635efSGarrett D'Amore 585*95c635efSGarrett D'Amore /* 586*95c635efSGarrett D'Amore * If this isn't a regular file (like, say, stdin), then we must 587*95c635efSGarrett D'Amore * go the old way and just read things in bit by bit. 588*95c635efSGarrett D'Amore */ 589*95c635efSGarrett D'Amore 590*95c635efSGarrett D'Amore *with_mmap = 0; 591*95c635efSGarrett D'Amore off = 0; 592*95c635efSGarrett D'Amore fb->sz = 0; 593*95c635efSGarrett D'Amore fb->buf = NULL; 594*95c635efSGarrett D'Amore for (;;) { 595*95c635efSGarrett D'Amore if (off == fb->sz) { 596*95c635efSGarrett D'Amore if (fb->sz == (1U << 31)) { 597*95c635efSGarrett D'Amore fprintf(stderr, "%s: input too large\n", file); 598*95c635efSGarrett D'Amore break; 599*95c635efSGarrett D'Amore } 600*95c635efSGarrett D'Amore resize_buf(fb, 65536); 601*95c635efSGarrett D'Amore } 602*95c635efSGarrett D'Amore ssz = read(fd, fb->buf + (int)off, fb->sz - off); 603*95c635efSGarrett D'Amore if (ssz == 0) { 604*95c635efSGarrett D'Amore fb->sz = off; 605*95c635efSGarrett D'Amore return(1); 606*95c635efSGarrett D'Amore } 607*95c635efSGarrett D'Amore if (ssz == -1) { 608*95c635efSGarrett D'Amore perror(file); 609*95c635efSGarrett D'Amore break; 610*95c635efSGarrett D'Amore } 611*95c635efSGarrett D'Amore off += (size_t)ssz; 612*95c635efSGarrett D'Amore } 613*95c635efSGarrett D'Amore 614*95c635efSGarrett D'Amore free(fb->buf); 615*95c635efSGarrett D'Amore fb->buf = NULL; 616*95c635efSGarrett D'Amore return(0); 617*95c635efSGarrett D'Amore } 618*95c635efSGarrett D'Amore 619*95c635efSGarrett D'Amore static void 620*95c635efSGarrett D'Amore mparse_end(struct mparse *curp) 621*95c635efSGarrett D'Amore { 622*95c635efSGarrett D'Amore 623*95c635efSGarrett D'Amore if (MANDOCLEVEL_FATAL <= curp->file_status) 624*95c635efSGarrett D'Amore return; 625*95c635efSGarrett D'Amore 626*95c635efSGarrett D'Amore if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { 627*95c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status); 628*95c635efSGarrett D'Amore return; 629*95c635efSGarrett D'Amore } 630*95c635efSGarrett D'Amore 631*95c635efSGarrett D'Amore if (curp->man && ! man_endparse(curp->man)) { 632*95c635efSGarrett D'Amore assert(MANDOCLEVEL_FATAL <= curp->file_status); 633*95c635efSGarrett D'Amore return; 634*95c635efSGarrett D'Amore } 635*95c635efSGarrett D'Amore 636*95c635efSGarrett D'Amore if ( ! (curp->man || curp->mdoc)) { 637*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL); 638*95c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_FATAL; 639*95c635efSGarrett D'Amore return; 640*95c635efSGarrett D'Amore } 641*95c635efSGarrett D'Amore 642*95c635efSGarrett D'Amore roff_endparse(curp->roff); 643*95c635efSGarrett D'Amore } 644*95c635efSGarrett D'Amore 645*95c635efSGarrett D'Amore static void 646*95c635efSGarrett D'Amore mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file, 647*95c635efSGarrett D'Amore int re) 648*95c635efSGarrett D'Amore { 649*95c635efSGarrett D'Amore const char *svfile; 650*95c635efSGarrett D'Amore 651*95c635efSGarrett D'Amore /* Line number is per-file. */ 652*95c635efSGarrett D'Amore svfile = curp->file; 653*95c635efSGarrett D'Amore curp->file = file; 654*95c635efSGarrett D'Amore curp->line = 1; 655*95c635efSGarrett D'Amore 656*95c635efSGarrett D'Amore mparse_buf_r(curp, blk, 1); 657*95c635efSGarrett D'Amore 658*95c635efSGarrett D'Amore if (0 == re && MANDOCLEVEL_FATAL > curp->file_status) 659*95c635efSGarrett D'Amore mparse_end(curp); 660*95c635efSGarrett D'Amore 661*95c635efSGarrett D'Amore curp->file = svfile; 662*95c635efSGarrett D'Amore } 663*95c635efSGarrett D'Amore 664*95c635efSGarrett D'Amore enum mandoclevel 665*95c635efSGarrett D'Amore mparse_readmem(struct mparse *curp, const void *buf, size_t len, 666*95c635efSGarrett D'Amore const char *file) 667*95c635efSGarrett D'Amore { 668*95c635efSGarrett D'Amore struct buf blk; 669*95c635efSGarrett D'Amore 670*95c635efSGarrett D'Amore blk.buf = UNCONST(buf); 671*95c635efSGarrett D'Amore blk.sz = len; 672*95c635efSGarrett D'Amore 673*95c635efSGarrett D'Amore mparse_parse_buffer(curp, blk, file, 0); 674*95c635efSGarrett D'Amore return(curp->file_status); 675*95c635efSGarrett D'Amore } 676*95c635efSGarrett D'Amore 677*95c635efSGarrett D'Amore static void 678*95c635efSGarrett D'Amore mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) 679*95c635efSGarrett D'Amore { 680*95c635efSGarrett D'Amore struct buf blk; 681*95c635efSGarrett D'Amore int with_mmap; 682*95c635efSGarrett D'Amore 683*95c635efSGarrett D'Amore if (-1 == fd) 684*95c635efSGarrett D'Amore if (-1 == (fd = open(file, O_RDONLY, 0))) { 685*95c635efSGarrett D'Amore perror(file); 686*95c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_SYSERR; 687*95c635efSGarrett D'Amore return; 688*95c635efSGarrett D'Amore } 689*95c635efSGarrett D'Amore /* 690*95c635efSGarrett D'Amore * Run for each opened file; may be called more than once for 691*95c635efSGarrett D'Amore * each full parse sequence if the opened file is nested (i.e., 692*95c635efSGarrett D'Amore * from `so'). Simply sucks in the whole file and moves into 693*95c635efSGarrett D'Amore * the parse phase for the file. 694*95c635efSGarrett D'Amore */ 695*95c635efSGarrett D'Amore 696*95c635efSGarrett D'Amore if ( ! read_whole_file(file, fd, &blk, &with_mmap)) { 697*95c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_SYSERR; 698*95c635efSGarrett D'Amore return; 699*95c635efSGarrett D'Amore } 700*95c635efSGarrett D'Amore 701*95c635efSGarrett D'Amore mparse_parse_buffer(curp, blk, file, re); 702*95c635efSGarrett D'Amore 703*95c635efSGarrett D'Amore #ifdef HAVE_MMAP 704*95c635efSGarrett D'Amore if (with_mmap) 705*95c635efSGarrett D'Amore munmap(blk.buf, blk.sz); 706*95c635efSGarrett D'Amore else 707*95c635efSGarrett D'Amore #endif 708*95c635efSGarrett D'Amore free(blk.buf); 709*95c635efSGarrett D'Amore 710*95c635efSGarrett D'Amore if (STDIN_FILENO != fd && -1 == close(fd)) 711*95c635efSGarrett D'Amore perror(file); 712*95c635efSGarrett D'Amore } 713*95c635efSGarrett D'Amore 714*95c635efSGarrett D'Amore enum mandoclevel 715*95c635efSGarrett D'Amore mparse_readfd(struct mparse *curp, int fd, const char *file) 716*95c635efSGarrett D'Amore { 717*95c635efSGarrett D'Amore 718*95c635efSGarrett D'Amore mparse_readfd_r(curp, fd, file, 0); 719*95c635efSGarrett D'Amore return(curp->file_status); 720*95c635efSGarrett D'Amore } 721*95c635efSGarrett D'Amore 722*95c635efSGarrett D'Amore struct mparse * 723*95c635efSGarrett D'Amore mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg) 724*95c635efSGarrett D'Amore { 725*95c635efSGarrett D'Amore struct mparse *curp; 726*95c635efSGarrett D'Amore 727*95c635efSGarrett D'Amore assert(wlevel <= MANDOCLEVEL_FATAL); 728*95c635efSGarrett D'Amore 729*95c635efSGarrett D'Amore curp = mandoc_calloc(1, sizeof(struct mparse)); 730*95c635efSGarrett D'Amore 731*95c635efSGarrett D'Amore curp->wlevel = wlevel; 732*95c635efSGarrett D'Amore curp->mmsg = mmsg; 733*95c635efSGarrett D'Amore curp->arg = arg; 734*95c635efSGarrett D'Amore curp->inttype = inttype; 735*95c635efSGarrett D'Amore 736*95c635efSGarrett D'Amore curp->roff = roff_alloc(curp); 737*95c635efSGarrett D'Amore return(curp); 738*95c635efSGarrett D'Amore } 739*95c635efSGarrett D'Amore 740*95c635efSGarrett D'Amore void 741*95c635efSGarrett D'Amore mparse_reset(struct mparse *curp) 742*95c635efSGarrett D'Amore { 743*95c635efSGarrett D'Amore 744*95c635efSGarrett D'Amore roff_reset(curp->roff); 745*95c635efSGarrett D'Amore 746*95c635efSGarrett D'Amore if (curp->mdoc) 747*95c635efSGarrett D'Amore mdoc_reset(curp->mdoc); 748*95c635efSGarrett D'Amore if (curp->man) 749*95c635efSGarrett D'Amore man_reset(curp->man); 750*95c635efSGarrett D'Amore if (curp->secondary) 751*95c635efSGarrett D'Amore curp->secondary->sz = 0; 752*95c635efSGarrett D'Amore 753*95c635efSGarrett D'Amore curp->file_status = MANDOCLEVEL_OK; 754*95c635efSGarrett D'Amore curp->mdoc = NULL; 755*95c635efSGarrett D'Amore curp->man = NULL; 756*95c635efSGarrett D'Amore } 757*95c635efSGarrett D'Amore 758*95c635efSGarrett D'Amore void 759*95c635efSGarrett D'Amore mparse_free(struct mparse *curp) 760*95c635efSGarrett D'Amore { 761*95c635efSGarrett D'Amore 762*95c635efSGarrett D'Amore if (curp->pmdoc) 763*95c635efSGarrett D'Amore mdoc_free(curp->pmdoc); 764*95c635efSGarrett D'Amore if (curp->pman) 765*95c635efSGarrett D'Amore man_free(curp->pman); 766*95c635efSGarrett D'Amore if (curp->roff) 767*95c635efSGarrett D'Amore roff_free(curp->roff); 768*95c635efSGarrett D'Amore if (curp->secondary) 769*95c635efSGarrett D'Amore free(curp->secondary->buf); 770*95c635efSGarrett D'Amore 771*95c635efSGarrett D'Amore free(curp->secondary); 772*95c635efSGarrett D'Amore free(curp); 773*95c635efSGarrett D'Amore } 774*95c635efSGarrett D'Amore 775*95c635efSGarrett D'Amore void 776*95c635efSGarrett D'Amore mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man) 777*95c635efSGarrett D'Amore { 778*95c635efSGarrett D'Amore 779*95c635efSGarrett D'Amore if (mdoc) 780*95c635efSGarrett D'Amore *mdoc = curp->mdoc; 781*95c635efSGarrett D'Amore if (man) 782*95c635efSGarrett D'Amore *man = curp->man; 783*95c635efSGarrett D'Amore } 784*95c635efSGarrett D'Amore 785*95c635efSGarrett D'Amore void 786*95c635efSGarrett D'Amore mandoc_vmsg(enum mandocerr t, struct mparse *m, 787*95c635efSGarrett D'Amore int ln, int pos, const char *fmt, ...) 788*95c635efSGarrett D'Amore { 789*95c635efSGarrett D'Amore char buf[256]; 790*95c635efSGarrett D'Amore va_list ap; 791*95c635efSGarrett D'Amore 792*95c635efSGarrett D'Amore va_start(ap, fmt); 793*95c635efSGarrett D'Amore vsnprintf(buf, sizeof(buf) - 1, fmt, ap); 794*95c635efSGarrett D'Amore va_end(ap); 795*95c635efSGarrett D'Amore 796*95c635efSGarrett D'Amore mandoc_msg(t, m, ln, pos, buf); 797*95c635efSGarrett D'Amore } 798*95c635efSGarrett D'Amore 799*95c635efSGarrett D'Amore void 800*95c635efSGarrett D'Amore mandoc_msg(enum mandocerr er, struct mparse *m, 801*95c635efSGarrett D'Amore int ln, int col, const char *msg) 802*95c635efSGarrett D'Amore { 803*95c635efSGarrett D'Amore enum mandoclevel level; 804*95c635efSGarrett D'Amore 805*95c635efSGarrett D'Amore level = MANDOCLEVEL_FATAL; 806*95c635efSGarrett D'Amore while (er < mandoclimits[level]) 807*95c635efSGarrett D'Amore level--; 808*95c635efSGarrett D'Amore 809*95c635efSGarrett D'Amore if (level < m->wlevel) 810*95c635efSGarrett D'Amore return; 811*95c635efSGarrett D'Amore 812*95c635efSGarrett D'Amore if (m->mmsg) 813*95c635efSGarrett D'Amore (*m->mmsg)(er, level, m->file, ln, col, msg); 814*95c635efSGarrett D'Amore 815*95c635efSGarrett D'Amore if (m->file_status < level) 816*95c635efSGarrett D'Amore m->file_status = level; 817*95c635efSGarrett D'Amore } 818*95c635efSGarrett D'Amore 819*95c635efSGarrett D'Amore const char * 820*95c635efSGarrett D'Amore mparse_strerror(enum mandocerr er) 821*95c635efSGarrett D'Amore { 822*95c635efSGarrett D'Amore 823*95c635efSGarrett D'Amore return(mandocerrs[er]); 824*95c635efSGarrett D'Amore } 825*95c635efSGarrett D'Amore 826*95c635efSGarrett D'Amore const char * 827*95c635efSGarrett D'Amore mparse_strlevel(enum mandoclevel lvl) 828*95c635efSGarrett D'Amore { 829*95c635efSGarrett D'Amore return(mandoclevels[lvl]); 830*95c635efSGarrett D'Amore } 831*95c635efSGarrett D'Amore 832*95c635efSGarrett D'Amore void 833*95c635efSGarrett D'Amore mparse_keep(struct mparse *p) 834*95c635efSGarrett D'Amore { 835*95c635efSGarrett D'Amore 836*95c635efSGarrett D'Amore assert(NULL == p->secondary); 837*95c635efSGarrett D'Amore p->secondary = mandoc_calloc(1, sizeof(struct buf)); 838*95c635efSGarrett D'Amore } 839*95c635efSGarrett D'Amore 840*95c635efSGarrett D'Amore const char * 841*95c635efSGarrett D'Amore mparse_getkeep(const struct mparse *p) 842*95c635efSGarrett D'Amore { 843*95c635efSGarrett D'Amore 844*95c635efSGarrett D'Amore assert(p->secondary); 845*95c635efSGarrett D'Amore return(p->secondary->sz ? p->secondary->buf : NULL); 846*95c635efSGarrett D'Amore } 847