]> git.cameronkatri.com Git - mandoc.git/blobdiff - read.c
Next speed optimization step for the new apropos(1).
[mandoc.git] / read.c
diff --git a/read.c b/read.c
index c91079315159e322237f40f9e2cceabb6f57cdea..d78a0b0d6dee2f406767662659abb47ad4cf9a31 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,7 +1,8 @@
-/*     $Id: read.c,v 1.35 2013/05/30 03:52:59 schwarze Exp $ */
+/*     $Id: read.c,v 1.46 2014/03/23 11:25:26 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -26,6 +27,7 @@
 
 #include <assert.h>
 #include <ctype.h>
 
 #include <assert.h>
 #include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <unistd.h>
 
 #include "mandoc.h"
 #include <unistd.h>
 
 #include "mandoc.h"
+#include "mandoc_aux.h"
 #include "libmandoc.h"
 #include "mdoc.h"
 #include "man.h"
 #include "main.h"
 
 #include "libmandoc.h"
 #include "mdoc.h"
 #include "man.h"
 #include "main.h"
 
-#ifndef MAP_FILE
-#define        MAP_FILE        0
-#endif
-
 #define        REPARSE_LIMIT   1000
 
 struct buf {
 #define        REPARSE_LIMIT   1000
 
 struct buf {
@@ -55,15 +54,15 @@ struct      mparse {
        enum mandoclevel  file_status; /* status of current parse */
        enum mandoclevel  wlevel; /* ignore messages below this */
        int               line; /* line number in the file */
        enum mandoclevel  file_status; /* status of current parse */
        enum mandoclevel  wlevel; /* ignore messages below this */
        int               line; /* line number in the file */
-       enum mparset      inttype; /* which parser to use */
+       int               options; /* parser options */
        struct man       *pman; /* persistent man parser */
        struct mdoc      *pmdoc; /* persistent mdoc parser */
        struct man       *man; /* man parser */
        struct mdoc      *mdoc; /* mdoc parser */
        struct roff      *roff; /* roff parser (!NULL) */
        struct man       *pman; /* persistent man parser */
        struct mdoc      *pmdoc; /* persistent mdoc parser */
        struct man       *man; /* man parser */
        struct mdoc      *mdoc; /* mdoc parser */
        struct roff      *roff; /* roff parser (!NULL) */
+       char             *sodest; /* filename pointed to by .so */
        int               reparse_count; /* finite interp. stack */
        mandocmsg         mmsg; /* warning/error message handler */
        int               reparse_count; /* finite interp. stack */
        mandocmsg         mmsg; /* warning/error message handler */
-       void             *arg; /* argument to mmsg */
        const char       *file; 
        struct buf       *secondary;
        char             *defos; /* default operating system */
        const char       *file; 
        struct buf       *secondary;
        char             *defos; /* default operating system */
@@ -71,10 +70,12 @@ struct      mparse {
 
 static void      resize_buf(struct buf *, size_t);
 static void      mparse_buf_r(struct mparse *, struct buf, int);
 
 static void      resize_buf(struct buf *, size_t);
 static void      mparse_buf_r(struct mparse *, struct buf, int);
-static void      mparse_readfd_r(struct mparse *, int, const char *, int);
 static void      pset(const char *, int, struct mparse *);
 static void      pset(const char *, int, struct mparse *);
-static int       read_whole_file(const char *, int, struct buf *, int *);
+static int       read_whole_file(struct mparse *, const char *, int,
+                               struct buf *, int *);
 static void      mparse_end(struct mparse *);
 static void      mparse_end(struct mparse *);
+static void      mparse_parse_buffer(struct mparse *, struct buf,
+                       const char *);
 
 static const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
        MANDOCERR_OK,
 
 static const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
        MANDOCERR_OK,
@@ -109,7 +110,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "bad NAME section contents",
        "sections out of conventional order",
        "duplicate section name",
        "bad NAME section contents",
        "sections out of conventional order",
        "duplicate section name",
-       "section not in conventional manual section",
+       "section header suited to sections 2, 3, and 9 only",
 
        /* related to macros and nesting */
        "skipping obsolete macro",
 
        /* related to macros and nesting */
        "skipping obsolete macro",
@@ -188,12 +189,14 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "macro requires line argument(s)",
        "macro requires body argument(s)",
        "macro requires argument(s)",
        "macro requires line argument(s)",
        "macro requires body argument(s)",
        "macro requires argument(s)",
+       "request requires a numeric argument",
        "missing list type",
        "line argument(s) will be lost",
        "body argument(s) will be lost",
 
        "generic fatal error",
 
        "missing list type",
        "line argument(s) will be lost",
        "body argument(s) will be lost",
 
        "generic fatal error",
 
+       "input too large",
        "not a manual",
        "column syntax is inconsistent",
        "NOT IMPLEMENTED: .Bd -file",
        "not a manual",
        "column syntax is inconsistent",
        "NOT IMPLEMENTED: .Bd -file",
@@ -204,6 +207,11 @@ static     const char * const      mandocerrs[MANDOCERR_MAX] = {
        "no document body",
        "no document prologue",
        "static buffer exhausted",
        "no document body",
        "no document prologue",
        "static buffer exhausted",
+
+       /* system errors */
+       "cannot open file",
+       "cannot stat file",
+       "cannot read file",
 };
 
 static const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
 };
 
 static const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
@@ -248,35 +256,36 @@ pset(const char *buf, int pos, struct mparse *curp)
                        return;
        }
 
                        return;
        }
 
-       switch (curp->inttype) {
-       case (MPARSE_MDOC):
+       if (MPARSE_MDOC & curp->options) {
                if (NULL == curp->pmdoc) 
                if (NULL == curp->pmdoc) 
-                       curp->pmdoc = mdoc_alloc(curp->roff, curp,
-                                       curp->defos);
+                       curp->pmdoc = mdoc_alloc(
+                           curp->roff, curp, curp->defos,
+                           MPARSE_QUICK & curp->options ? 1 : 0);
                assert(curp->pmdoc);
                curp->mdoc = curp->pmdoc;
                return;
                assert(curp->pmdoc);
                curp->mdoc = curp->pmdoc;
                return;
-       case (MPARSE_MAN):
+       } else if (MPARSE_MAN & curp->options) {
                if (NULL == curp->pman) 
                if (NULL == curp->pman) 
-                       curp->pman = man_alloc(curp->roff, curp);
+                       curp->pman = man_alloc(curp->roff, curp,
+                           MPARSE_QUICK & curp->options ? 1 : 0);
                assert(curp->pman);
                curp->man = curp->pman;
                return;
                assert(curp->pman);
                curp->man = curp->pman;
                return;
-       default:
-               break;
        }
 
        if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
                if (NULL == curp->pmdoc) 
        }
 
        if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
                if (NULL == curp->pmdoc) 
-                       curp->pmdoc = mdoc_alloc(curp->roff, curp,
-                                       curp->defos);
+                       curp->pmdoc = mdoc_alloc(
+                           curp->roff, curp, curp->defos,
+                           MPARSE_QUICK & curp->options ? 1 : 0);
                assert(curp->pmdoc);
                curp->mdoc = curp->pmdoc;
                return;
        } 
 
        if (NULL == curp->pman) 
                assert(curp->pmdoc);
                curp->mdoc = curp->pmdoc;
                return;
        } 
 
        if (NULL == curp->pman) 
-               curp->pman = man_alloc(curp->roff, curp);
+               curp->pman = man_alloc(curp->roff, curp,
+                   MPARSE_QUICK & curp->options ? 1 : 0);
        assert(curp->pman);
        curp->man = curp->pman;
 }
        assert(curp->pman);
        curp->man = curp->pman;
 }
@@ -483,6 +492,12 @@ rerun:
                        assert(MANDOCLEVEL_FATAL <= curp->file_status);
                        break;
                case (ROFF_SO):
                        assert(MANDOCLEVEL_FATAL <= curp->file_status);
                        break;
                case (ROFF_SO):
+                       if (0 == (MPARSE_SO & curp->options) &&
+                           (i >= (int)blk.sz || '\0' == blk.buf[i])) {
+                               curp->sodest = mandoc_strdup(ln.buf + of);
+                               free(ln.buf);
+                               return;
+                       }
                        /*
                         * We remove `so' clauses from our lookaside
                         * buffer because we're going to descend into
                        /*
                         * We remove `so' clauses from our lookaside
                         * buffer because we're going to descend into
@@ -490,7 +505,7 @@ rerun:
                         */
                        if (curp->secondary) 
                                curp->secondary->sz -= pos + 1;
                         */
                        if (curp->secondary) 
                                curp->secondary->sz -= pos + 1;
-                       mparse_readfd_r(curp, -1, ln.buf + of, 1);
+                       mparse_readfd(curp, -1, ln.buf + of);
                        if (MANDOCLEVEL_FATAL <= curp->file_status)
                                break;
                        pos = 0;
                        if (MANDOCLEVEL_FATAL <= curp->file_status)
                                break;
                        pos = 0;
@@ -554,7 +569,8 @@ rerun:
                if (0 == rc) {
                        assert(MANDOCLEVEL_FATAL <= curp->file_status);
                        break;
                if (0 == rc) {
                        assert(MANDOCLEVEL_FATAL <= curp->file_status);
                        break;
-               }
+               } else if (2 == rc)
+                       break;
 
                /* Temporary buffers typically are not full. */
 
 
                /* Temporary buffers typically are not full. */
 
@@ -570,7 +586,8 @@ rerun:
 }
 
 static int
 }
 
 static int
-read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, const char *file, int fd,
+               struct buf *fb, int *with_mmap)
 {
        size_t           off;
        ssize_t          ssz;
 {
        size_t           off;
        ssize_t          ssz;
@@ -578,7 +595,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
 #ifdef HAVE_MMAP
        struct stat      st;
        if (-1 == fstat(fd, &st)) {
 #ifdef HAVE_MMAP
        struct stat      st;
        if (-1 == fstat(fd, &st)) {
-               perror(file);
+               curp->file_status = MANDOCLEVEL_SYSERR;
+               if (curp->mmsg)
+                       (*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
+                           file, 0, 0, strerror(errno));
                return(0);
        }
 
                return(0);
        }
 
@@ -591,13 +611,15 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
 
        if (S_ISREG(st.st_mode)) {
                if (st.st_size >= (1U << 31)) {
 
        if (S_ISREG(st.st_mode)) {
                if (st.st_size >= (1U << 31)) {
-                       fprintf(stderr, "%s: input too large\n", file);
+                       curp->file_status = MANDOCLEVEL_FATAL;
+                       if (curp->mmsg)
+                               (*curp->mmsg)(MANDOCERR_TOOLARGE,
+                                   curp->file_status, file, 0, 0, NULL);
                        return(0);
                }
                *with_mmap = 1;
                fb->sz = (size_t)st.st_size;
                        return(0);
                }
                *with_mmap = 1;
                fb->sz = (size_t)st.st_size;
-               fb->buf = mmap(NULL, fb->sz, PROT_READ, 
-                               MAP_FILE|MAP_SHARED, fd, 0);
+               fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
                if (fb->buf != MAP_FAILED)
                        return(1);
        }
                if (fb->buf != MAP_FAILED)
                        return(1);
        }
@@ -615,7 +637,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
        for (;;) {
                if (off == fb->sz) {
                        if (fb->sz == (1U << 31)) {
        for (;;) {
                if (off == fb->sz) {
                        if (fb->sz == (1U << 31)) {
-                               fprintf(stderr, "%s: input too large\n", file);
+                               curp->file_status = MANDOCLEVEL_FATAL;
+                               if (curp->mmsg)
+                                       (*curp->mmsg)(MANDOCERR_TOOLARGE,
+                                           curp->file_status,
+                                           file, 0, 0, NULL);
                                break;
                        }
                        resize_buf(fb, 65536);
                                break;
                        }
                        resize_buf(fb, 65536);
@@ -626,7 +652,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
                        return(1);
                }
                if (ssz == -1) {
                        return(1);
                }
                if (ssz == -1) {
-                       perror(file);
+                       curp->file_status = MANDOCLEVEL_SYSERR;
+                       if (curp->mmsg)
+                               (*curp->mmsg)(MANDOCERR_SYSREAD,
+                                   curp->file_status, file, 0, 0,
+                                   strerror(errno));
                        break;
                }
                off += (size_t)ssz;
                        break;
                }
                off += (size_t)ssz;
@@ -654,7 +684,7 @@ mparse_end(struct mparse *curp)
                return;
        }
 
                return;
        }
 
-       if ( ! (curp->man || curp->mdoc)) {
+       if ( ! (curp->mdoc || curp->man || curp->sodest)) {
                mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
                curp->file_status = MANDOCLEVEL_FATAL;
                return;
                mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
                curp->file_status = MANDOCLEVEL_FATAL;
                return;
@@ -664,19 +694,25 @@ mparse_end(struct mparse *curp)
 }
 
 static void
 }
 
 static void
-mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file,
-               int re)
+mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
 {
        const char      *svfile;
 {
        const char      *svfile;
+       static int       recursion_depth;
+
+       if (64 < recursion_depth) {
+               mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
+               return;
+       }
 
        /* Line number is per-file. */
        svfile = curp->file;
        curp->file = file;
        curp->line = 1;
 
        /* Line number is per-file. */
        svfile = curp->file;
        curp->file = file;
        curp->line = 1;
+       recursion_depth++;
 
        mparse_buf_r(curp, blk, 1);
 
 
        mparse_buf_r(curp, blk, 1);
 
-       if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
+       if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
                mparse_end(curp);
 
        curp->file = svfile;
                mparse_end(curp);
 
        curp->file = svfile;
@@ -691,22 +727,25 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len,
        blk.buf = UNCONST(buf);
        blk.sz = len;
 
        blk.buf = UNCONST(buf);
        blk.sz = len;
 
-       mparse_parse_buffer(curp, blk, file, 0);
+       mparse_parse_buffer(curp, blk, file);
        return(curp->file_status);
 }
 
        return(curp->file_status);
 }
 
-static void
-mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
+enum mandoclevel
+mparse_readfd(struct mparse *curp, int fd, const char *file)
 {
        struct buf       blk;
        int              with_mmap;
 
 {
        struct buf       blk;
        int              with_mmap;
 
-       if (-1 == fd)
-               if (-1 == (fd = open(file, O_RDONLY, 0))) {
-                       perror(file);
-                       curp->file_status = MANDOCLEVEL_SYSERR;
-                       return;
-               }
+       if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
+               curp->file_status = MANDOCLEVEL_SYSERR;
+               if (curp->mmsg)
+                       (*curp->mmsg)(MANDOCERR_SYSOPEN,
+                           curp->file_status,
+                           file, 0, 0, strerror(errno));
+               goto out;
+       }
+
        /*
         * Run for each opened file; may be called more than once for
         * each full parse sequence if the opened file is nested (i.e.,
        /*
         * Run for each opened file; may be called more than once for
         * each full parse sequence if the opened file is nested (i.e.,
@@ -714,12 +753,10 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
         * the parse phase for the file.
         */
 
         * the parse phase for the file.
         */
 
-       if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
-               curp->file_status = MANDOCLEVEL_SYSERR;
-               return;
-       }
+       if ( ! read_whole_file(curp, file, fd, &blk, &with_mmap))
+               goto out;
 
 
-       mparse_parse_buffer(curp, blk, file, re);
+       mparse_parse_buffer(curp, blk, file);
 
 #ifdef HAVE_MMAP
        if (with_mmap)
 
 #ifdef HAVE_MMAP
        if (with_mmap)
@@ -730,19 +767,13 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
 
        if (STDIN_FILENO != fd && -1 == close(fd))
                perror(file);
 
        if (STDIN_FILENO != fd && -1 == close(fd))
                perror(file);
-}
-
-enum mandoclevel
-mparse_readfd(struct mparse *curp, int fd, const char *file)
-{
-
-       mparse_readfd_r(curp, fd, file, 0);
+out:
        return(curp->file_status);
 }
 
 struct mparse *
        return(curp->file_status);
 }
 
 struct mparse *
-mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
-               mandocmsg mmsg, void *arg, char *defos)
+mparse_alloc(int options, enum mandoclevel wlevel,
+               mandocmsg mmsg, char *defos)
 {
        struct mparse   *curp;
 
 {
        struct mparse   *curp;
 
@@ -750,13 +781,12 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
 
        curp = mandoc_calloc(1, sizeof(struct mparse));
 
 
        curp = mandoc_calloc(1, sizeof(struct mparse));
 
+       curp->options = options;
        curp->wlevel = wlevel;
        curp->mmsg = mmsg;
        curp->wlevel = wlevel;
        curp->mmsg = mmsg;
-       curp->arg = arg;
-       curp->inttype = inttype;
        curp->defos = defos;
 
        curp->defos = defos;
 
-       curp->roff = roff_alloc(inttype, curp);
+       curp->roff = roff_alloc(curp, options);
        return(curp);
 }
 
        return(curp);
 }
 
@@ -776,6 +806,9 @@ mparse_reset(struct mparse *curp)
        curp->file_status = MANDOCLEVEL_OK;
        curp->mdoc = NULL;
        curp->man = NULL;
        curp->file_status = MANDOCLEVEL_OK;
        curp->mdoc = NULL;
        curp->man = NULL;
+
+       free(curp->sodest);
+       curp->sodest = NULL;
 }
 
 void
 }
 
 void
@@ -792,13 +825,20 @@ mparse_free(struct mparse *curp)
                free(curp->secondary->buf);
 
        free(curp->secondary);
                free(curp->secondary->buf);
 
        free(curp->secondary);
+       free(curp->sodest);
        free(curp);
 }
 
 void
        free(curp);
 }
 
 void
-mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
+mparse_result(struct mparse *curp,
+       struct mdoc **mdoc, struct man **man, char **sodest)
 {
 
 {
 
+       if (sodest && NULL != (*sodest = curp->sodest)) {
+               *mdoc = NULL;
+               *man = NULL;
+               return;
+       }
        if (mdoc)
                *mdoc = curp->mdoc;
        if (man)
        if (mdoc)
                *mdoc = curp->mdoc;
        if (man)