]> git.cameronkatri.com Git - mandoc.git/blobdiff - read.c
On a new RS nesting level, the saved width starts from the default
[mandoc.git] / read.c
diff --git a/read.c b/read.c
index 821ca89e1ef814c700c76d6f46f3c983b96332f8..8adad316e96db488059fc1e0575d98ec19346b53 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/*     $Id: read.c,v 1.109 2015/01/14 22:58:16 schwarze Exp $ */
+/*     $Id: read.c,v 1.133 2015/04/02 21:36:50 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -8,9 +8,9 @@
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@@ -29,6 +29,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "mandoc.h"
 #include "mandoc_aux.h"
-#include "libmandoc.h"
+#include "mandoc.h"
+#include "roff.h"
 #include "mdoc.h"
 #include "man.h"
+#include "libmandoc.h"
 
 #define        REPARSE_LIMIT   1000
 
@@ -80,7 +82,7 @@ static        const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
        MANDOCERR_WARNING,
        MANDOCERR_WARNING,
        MANDOCERR_ERROR,
-       MANDOCERR_FATAL,
+       MANDOCERR_UNSUPP,
        MANDOCERR_MAX,
        MANDOCERR_MAX
 };
@@ -109,7 +111,11 @@ static     const char * const      mandocerrs[MANDOCERR_MAX] = {
        "no document body",
        "content before first section header",
        "first section is not \"NAME\"",
-       "bad NAME section contents",
+       "NAME section without name",
+       "NAME section without description",
+       "description not at the end of NAME",
+       "bad NAME section content",
+       "missing description line, using \"\"",
        "sections out of conventional order",
        "duplicate section title",
        "unexpected section",
@@ -135,18 +141,22 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "skipping empty request",
        "conditional request controls empty scope",
        "skipping empty macro",
+       "empty block",
        "empty argument, using 0n",
-       "argument count wrong",
        "missing display type, using -ragged",
        "list type is not the first argument",
        "missing -width in -tag list, using 8n",
        "missing utility name, using \"\"",
+       "missing function name, using \"\"",
        "empty head in list item",
        "empty list item",
        "missing font type, using \\fR",
        "unknown font type, using \\fR",
        "nothing follows prefix",
+       "empty reference block",
        "missing -std argument, adding it",
+       "missing option string, using \"\"",
+       "missing resource identifier, using \"\"",
        "missing eqn box, using \"\"",
 
        /* related to bad macro arguments */
@@ -156,12 +166,14 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "skipping duplicate display type",
        "skipping duplicate list type",
        "skipping -width argument",
+       "wrong number of cells",
        "unknown AT&T UNIX version",
        "comma in function argument",
        "parenthesis in function name",
        "invalid content in Rs block",
        "invalid Boolean argument",
        "unknown font, skipping request",
+       "odd number of characters in request",
 
        /* related to plain text */
        "blank line in fill mode, using .sp",
@@ -171,39 +183,41 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "invalid escape sequence",
        "undefined string, using \"\"",
 
-       "generic error",
+       /* related to tables */
+       "tbl line starts with span",
+       "tbl column starts with span",
+       "skipping vertical bar in tbl layout",
 
-       /* related to equations */
-       "unexpected equation scope closure",
-       "equation scope open on exit",
-       "overlapping equation scopes",
-       "unexpected end of equation",
+       "generic error",
 
        /* related to tables */
-       "bad table syntax",
-       "bad table option",
-       "bad table layout",
-       "no table layout cells specified",
-       "no table data cells specified",
-       "ignore data in cell",
-       "data block still open",
-       "ignoring extra data cells",
-       "ignoring macro in table",
+       "non-alphabetic character in tbl options",
+       "skipping unknown tbl option",
+       "missing tbl option argument",
+       "wrong tbl option argument size",
+       "empty tbl layout",
+       "invalid character in tbl layout",
+       "unmatched parenthesis in tbl layout",
+       "tbl without any data cells",
+       "ignoring data in spanned tbl cell",
+       "ignoring extra tbl data cells",
+       "data block open at end of tbl",
 
        /* related to document structure and macros */
        NULL,
        "input stack limit exceeded, infinite loop?",
        "skipping bad character",
        "skipping unknown macro",
+       "skipping insecure request",
        "skipping item outside list",
        "skipping column outside column list",
        "skipping end of block that is not open",
+       "fewer RS blocks open, skipping",
        "inserting missing end of block",
        "appending missing end of block",
 
        /* related to request and macro arguments */
        "escaped character not allowed in a name",
-       "argument count wrong",
        "NOT IMPLEMENTED: Bd -file",
        "missing list type, using -item",
        "missing manual name, using \"\"",
@@ -211,14 +225,18 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "unknown standard specifier",
        "skipping request without numeric argument",
        "NOT IMPLEMENTED: .so with absolute path or \"..\"",
+       ".so request failed",
        "skipping all arguments",
        "skipping excess arguments",
        "divide by zero",
 
-       "generic fatal error",
-
+       "unsupported feature",
        "input too large",
-       ".so request failed",
+       "unsupported control character",
+       "unsupported roff request",
+       "eqn delim option in tbl",
+       "unsupported tbl layout modifier",
+       "ignoring macro in table",
 };
 
 static const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
@@ -226,7 +244,7 @@ static      const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
        "RESERVED",
        "WARNING",
        "ERROR",
-       "FATAL",
+       "UNSUPP",
        "BADARG",
        "SYSERR"
 };
@@ -306,10 +324,14 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
 {
        const struct tbl_span   *span;
        struct buf       ln;
+       const char      *save_file;
+       char            *cp;
        size_t           pos; /* byte number in the ln buffer */
        enum rofferr     rr;
        int              of;
        int              lnn; /* line number in the real file */
+       int              fd;
+       pid_t            save_child;
        unsigned char    c;
 
        memset(&ln, 0, sizeof(ln));
@@ -364,9 +386,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
                        if (c & 0x80) {
                                if ( ! (curp->filenc && preconv_encode(
                                    &blk, &i, &ln, &pos, &curp->filenc))) {
-                                       mandoc_vmsg(MANDOCERR_BADCHAR,
-                                           curp, curp->line, pos,
-                                           "0x%x", c);
+                                       mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
+                                           curp->line, pos, "0x%x", c);
                                        ln.buf[pos++] = '?';
                                        i++;
                                }
@@ -378,10 +399,13 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
                         */
 
                        if (c == 0x7f || (c < 0x20 && c != 0x09)) {
-                               mandoc_vmsg(MANDOCERR_BADCHAR, curp,
-                                   curp->line, pos, "0x%x", c);
+                               mandoc_vmsg(c == 0x00 || c == 0x04 ||
+                                   c > 0x0a ? MANDOCERR_CHAR_BAD :
+                                   MANDOCERR_CHAR_UNSUPP,
+                                   curp, curp->line, pos, "0x%x", c);
                                i++;
-                               ln.buf[pos++] = '?';
+                               if (c != '\r')
+                                       ln.buf[pos++] = '?';
                                continue;
                        }
 
@@ -435,7 +459,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
 
                        if ( ! (isascii(c) &&
                            (isgraph(c) || isblank(c)))) {
-                               mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+                               mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
                                    curp->line, pos, "0x%x", c);
                                i += 2;
                                ln.buf[pos++] = '?';
@@ -518,27 +542,32 @@ rerun:
                         */
                        if (curp->secondary)
                                curp->secondary->sz -= pos + 1;
-                       mparse_readfd(curp, -1, ln.buf + of);
-                       if (MANDOCLEVEL_FATAL <= curp->file_status) {
+                       save_file = curp->file;
+                       save_child = curp->child;
+                       if (mparse_open(curp, &fd, ln.buf + of) ==
+                           MANDOCLEVEL_OK) {
+                               mparse_readfd(curp, fd, ln.buf + of);
+                               curp->file = save_file;
+                       } else {
+                               curp->file = save_file;
                                mandoc_vmsg(MANDOCERR_SO_FAIL,
                                    curp, curp->line, pos,
                                    ".so %s", ln.buf + of);
-                               break;
+                               ln.sz = mandoc_asprintf(&cp,
+                                   ".sp\nSee the file %s.\n.sp",
+                                   ln.buf + of);
+                               free(ln.buf);
+                               ln.buf = cp;
+                               of = 0;
+                               mparse_buf_r(curp, ln, of, 0);
                        }
+                       curp->child = save_child;
                        pos = 0;
                        continue;
                default:
                        break;
                }
 
-               /*
-                * If we encounter errors in the recursive parse, make
-                * sure we don't continue parsing.
-                */
-
-               if (MANDOCLEVEL_FATAL <= curp->file_status)
-                       break;
-
                /*
                 * If input parsers have not been allocated, do so now.
                 * We keep these instanced between parsers, but set them
@@ -609,11 +638,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
         */
 
        if (S_ISREG(st.st_mode)) {
-               if (st.st_size >= (1U << 31)) {
-                       curp->file_status = MANDOCLEVEL_FATAL;
-                       if (curp->mmsg)
-                               (*curp->mmsg)(MANDOCERR_TOOLARGE,
-                                   curp->file_status, file, 0, 0, NULL);
+               if (st.st_size > 0x7fffffff) {
+                       mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
                        return(0);
                }
                *with_mmap = 1;
@@ -636,11 +662,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
        for (;;) {
                if (off == fb->sz) {
                        if (fb->sz == (1U << 31)) {
-                               curp->file_status = MANDOCLEVEL_FATAL;
-                               if (curp->mmsg)
-                                       (*curp->mmsg)(MANDOCERR_TOOLARGE,
-                                           curp->file_status,
-                                           file, 0, 0, NULL);
+                               mandoc_msg(MANDOCERR_TOOLARGE, curp,
+                                   0, 0, NULL);
                                break;
                        }
                        resize_buf(fb, 65536);
@@ -666,9 +689,6 @@ static void
 mparse_end(struct mparse *curp)
 {
 
-       if (MANDOCLEVEL_FATAL <= curp->file_status)
-               return;
-
        if (curp->mdoc == NULL &&
            curp->man == NULL &&
            curp->sodest == NULL) {
@@ -682,17 +702,10 @@ mparse_end(struct mparse *curp)
                        curp->man = curp->pman;
                }
        }
-
-       if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
-               assert(MANDOCLEVEL_FATAL <= curp->file_status);
-               return;
-       }
-
-       if (curp->man && ! man_endparse(curp->man)) {
-               assert(MANDOCLEVEL_FATAL <= curp->file_status);
-               return;
-       }
-
+       if (curp->mdoc)
+               mdoc_endparse(curp->mdoc);
+       if (curp->man)
+               man_endparse(curp->man);
        roff_endparse(curp->roff);
 }
 
@@ -729,7 +742,7 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
 
        mparse_buf_r(curp, blk, offset, 1);
 
-       if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
+       if (--recursion_depth == 0)
                mparse_end(curp);
 
        curp->primary = svprimary;
@@ -750,8 +763,6 @@ mparse_readmem(struct mparse *curp, void *buf, size_t len,
 }
 
 /*
- * If a file descriptor is given, use it and assume it points
- * to the named file.  Otherwise, open the named file.
  * Read the whole file into memory and call the parsers.
  * Called recursively when an .so request is encountered.
  */
@@ -761,13 +772,6 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
        struct buf       blk;
        int              with_mmap;
        int              save_filenc;
-       pid_t            save_child;
-
-       save_child = curp->child;
-       if (fd != -1)
-               curp->child = 0;
-       else if (mparse_open(curp, &fd, file) != MANDOCLEVEL_OK)
-               goto out;
 
        if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
                save_filenc = curp->filenc;
@@ -787,8 +791,6 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
                perror(file);
 
        mparse_wait(curp);
-out:
-       curp->child = save_child;
        return(curp->file_status);
 }
 
@@ -846,6 +848,7 @@ mparse_open(struct mparse *curp, int *fd, const char *file)
                        perror("dup");
                        exit((int)MANDOCLEVEL_SYSERR);
                }
+               signal(SIGPIPE, SIG_DFL);
                execlp("gunzip", "gunzip", "-c", file, NULL);
                perror("exec");
                exit((int)MANDOCLEVEL_SYSERR);
@@ -868,6 +871,7 @@ mparse_wait(struct mparse *curp)
                perror("wait");
                exit((int)MANDOCLEVEL_SYSERR);
        }
+       curp->child = 0;
        if (WIFSIGNALED(status)) {
                mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
                    "gunzip died from signal %d", WTERMSIG(status));
@@ -887,8 +891,6 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
 {
        struct mparse   *curp;
 
-       assert(wlevel <= MANDOCLEVEL_FATAL);
-
        curp = mandoc_calloc(1, sizeof(struct mparse));
 
        curp->options = options;
@@ -985,7 +987,7 @@ mandoc_msg(enum mandocerr er, struct mparse *m,
 {
        enum mandoclevel level;
 
-       level = MANDOCLEVEL_FATAL;
+       level = MANDOCLEVEL_UNSUPP;
        while (er < mandoclimits[level])
                level--;