]> git.cameronkatri.com Git - mandoc.git/blobdiff - read.c
simple implementation of the roff(7) .als (macro alias) request,
[mandoc.git] / read.c
diff --git a/read.c b/read.c
index 6cbcd2df0079561885a78608a59210b32ddd4506..f86d57003a9726b9f4bea2adf1b974f498d5084d 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,7 +1,7 @@
-/*     $Id: read.c,v 1.149 2016/07/10 13:34:30 schwarze Exp $ */
+/*     $Id: read.c,v 1.176 2017/06/11 19:37:01 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2017 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
 #include "config.h"
 
 #include <sys/types.h>
-#if HAVE_MMAP
 #include <sys/mman.h>
 #include <sys/stat.h>
-#endif
 
 #include <assert.h>
 #include <ctype.h>
@@ -32,7 +30,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -50,8 +47,8 @@
 #define        REPARSE_LIMIT   1000
 
 struct mparse {
-       struct roff_man  *man; /* man parser */
        struct roff      *roff; /* roff parser (!NULL) */
+       struct roff_man  *man; /* man parser */
        char             *sodest; /* filename pointed to by .so */
        const char       *file; /* filename of current input file */
        struct buf       *primary; /* buffer currently being parsed */
@@ -69,7 +66,7 @@ struct        mparse {
 
 static void      choose_parser(struct mparse *);
 static void      resize_buf(struct buf *, size_t);
-static void      mparse_buf_r(struct mparse *, struct buf, size_t, int);
+static int       mparse_buf_r(struct mparse *, struct buf, size_t, int);
 static int       read_whole_file(struct mparse *, const char *, int,
                                struct buf *, int *);
 static void      mparse_end(struct mparse *);
@@ -78,7 +75,7 @@ static        void      mparse_parse_buffer(struct mparse *, struct buf,
 
 static const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
        MANDOCERR_OK,
-       MANDOCERR_WARNING,
+       MANDOCERR_STYLE,
        MANDOCERR_WARNING,
        MANDOCERR_ERROR,
        MANDOCERR_UNSUPP,
@@ -89,6 +86,19 @@ static       const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
 static const char * const      mandocerrs[MANDOCERR_MAX] = {
        "ok",
 
+       "generic style suggestion",
+
+       "Mdocdate found",
+       "Mdocdate missing",
+       "legacy man(7) date format",
+       "useless macro",
+       "consider using OS macro",
+       "errnos out of order",
+       "duplicate errno",
+       "description line ends with a full stop",
+       "no blank before trailing delimiter",
+       "function name without markup",
+
        "generic warning",
 
        /* related to the prologue */
@@ -110,11 +120,13 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "no document body",
        "content before first section header",
        "first section is not \"NAME\"",
-       "NAME section without name",
+       "NAME section without Nm before Nd",
        "NAME section without description",
        "description not at the end of NAME",
        "bad NAME section content",
+       "missing comma before name",
        "missing description line, using \"\"",
+       "description line outside NAME section",
        "sections out of conventional order",
        "duplicate section title",
        "unexpected section",
@@ -134,6 +146,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "fill mode already enabled, skipping",
        "fill mode already disabled, skipping",
        "line scope broken",
+       "skipping blank line in line scope",
 
        /* related to missing macro arguments */
        "skipping empty request",
@@ -143,7 +156,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "empty argument, using 0n",
        "missing display type, using -ragged",
        "list type is not the first argument",
-       "missing -width in -tag list, using 8n",
+       "missing -width in -tag list, using 6n",
        "missing utility name, using \"\"",
        "missing function name, using \"\"",
        "empty head in list item",
@@ -152,6 +165,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "unknown font type, using \\fR",
        "nothing follows prefix",
        "empty reference block",
+       "missing section argument",
        "missing -std argument, adding it",
        "missing option string, using \"\"",
        "missing resource identifier, using \"\"",
@@ -168,6 +182,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "unknown AT&T UNIX version",
        "comma in function argument",
        "parenthesis in function name",
+       "unknown library name",
        "invalid content in Rs block",
        "invalid Boolean argument",
        "unknown font, skipping request",
@@ -177,6 +192,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "blank line in fill mode, using .sp",
        "tab in filled text",
        "whitespace at end of input line",
+       "new sentence, new line",
        "bad comment style",
        "invalid escape sequence",
        "undefined string, using \"\"",
@@ -219,6 +235,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "NOT IMPLEMENTED: Bd -file",
        "skipping display without arguments",
        "missing list type, using -item",
+       "argument is not numeric, using 1",
        "missing manual name, using \"\"",
        "uname(3) system call failed, using UNKNOWN",
        "unknown standard specifier",
@@ -240,7 +257,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
 
 static const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
        "SUCCESS",
-       "RESERVED",
+       "STYLE",
        "WARNING",
        "ERROR",
        "UNSUPP",
@@ -291,22 +308,16 @@ choose_parser(struct mparse *curp)
                }
        }
 
-       if (curp->man == NULL) {
-               curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
-                   curp->options & MPARSE_QUICK ? 1 : 0);
-               curp->man->macroset = MACROSET_MAN;
-               curp->man->first->tok = TOKEN_NONE;
-       }
-
        if (format == MPARSE_MDOC) {
-               mdoc_hash_init();
                curp->man->macroset = MACROSET_MDOC;
-               curp->man->first->tok = TOKEN_NONE;
+               if (curp->man->mdocmac == NULL)
+                       curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
        } else {
-               man_hash_init();
                curp->man->macroset = MACROSET_MAN;
-               curp->man->first->tok = TOKEN_NONE;
+               if (curp->man->manmac == NULL)
+                       curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
        }
+       curp->man->first->tok = TOKEN_NONE;
 }
 
 /*
@@ -316,7 +327,7 @@ choose_parser(struct mparse *curp)
  * macros, inline equations, and input line traps)
  * and indirectly (for .so file inclusion).
  */
-static void
+static int
 mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
 {
        const struct tbl_span   *span;
@@ -405,72 +416,14 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
                                continue;
                        }
 
-                       /* Trailing backslash = a plain char. */
-
-                       if (blk.buf[i] != '\\' || i + 1 == blk.sz) {
-                               ln.buf[pos++] = blk.buf[i++];
-                               continue;
-                       }
-
-                       /*
-                        * Found escape and at least one other character.
-                        * When it's a newline character, skip it.
-                        * When there is a carriage return in between,
-                        * skip that one as well.
-                        */
-
-                       if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz &&
-                           '\n' == blk.buf[i + 2])
-                               ++i;
-                       if ('\n' == blk.buf[i + 1]) {
-                               i += 2;
-                               ++lnn;
-                               continue;
-                       }
-
-                       if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
-                               i += 2;
-                               /* Comment, skip to end of line */
-                               for (; i < blk.sz; ++i) {
-                                       if ('\n' == blk.buf[i]) {
-                                               ++i;
-                                               ++lnn;
-                                               break;
-                                       }
-                               }
-
-                               /* Backout trailing whitespaces */
-                               for (; pos > 0; --pos) {
-                                       if (ln.buf[pos - 1] != ' ')
-                                               break;
-                                       if (pos > 2 && ln.buf[pos - 2] == '\\')
-                                               break;
-                               }
-                               break;
-                       }
-
-                       /* Catch escaped bogus characters. */
-
-                       c = (unsigned char) blk.buf[i+1];
-
-                       if ( ! (isascii(c) &&
-                           (isgraph(c) || isblank(c)))) {
-                               mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
-                                   curp->line, pos, "0x%x", c);
-                               i += 2;
-                               ln.buf[pos++] = '?';
-                               continue;
-                       }
-
-                       /* Some other escape sequence, copy & cont. */
-
-                       ln.buf[pos++] = blk.buf[i++];
                        ln.buf[pos++] = blk.buf[i++];
                }
 
-               if (pos >= ln.sz)
+               if (pos + 1 >= ln.sz)
                        resize_buf(&ln, 256);
 
+               if (i == blk.sz || blk.buf[i] == '\0')
+                       ln.buf[pos++] = '\n';
                ln.buf[pos] = '\0';
 
                /*
@@ -509,13 +462,16 @@ rerun:
 
                switch (rr) {
                case ROFF_REPARSE:
-                       if (REPARSE_LIMIT >= ++curp->reparse_count)
-                               mparse_buf_r(curp, ln, of, 0);
-                       else
+                       if (++curp->reparse_count > REPARSE_LIMIT)
                                mandoc_msg(MANDOCERR_ROFFLOOP, curp,
                                    curp->line, pos, NULL);
-                       pos = 0;
-                       continue;
+                       else if (mparse_buf_r(curp, ln, of, 0) == 1 ||
+                           start == 1) {
+                               pos = 0;
+                               continue;
+                       }
+                       free(ln.buf);
+                       return 0;
                case ROFF_APPEND:
                        pos = strlen(ln.buf);
                        continue;
@@ -529,7 +485,7 @@ rerun:
                            (i >= blk.sz || blk.buf[i] == '\0')) {
                                curp->sodest = mandoc_strdup(ln.buf + of);
                                free(ln.buf);
-                               return;
+                               return 1;
                        }
                        /*
                         * We remove `so' clauses from our lookaside
@@ -562,15 +518,7 @@ rerun:
                        break;
                }
 
-               /*
-                * If input parsers have not been allocated, do so now.
-                * We keep these instanced between parsers, but set them
-                * locally per parse routine since we can use different
-                * parsers with each one.
-                */
-
-               if (curp->man == NULL ||
-                   curp->man->macroset == MACROSET_NONE)
+               if (curp->man->macroset == MACROSET_NONE)
                        choose_parser(curp);
 
                /*
@@ -603,19 +551,18 @@ rerun:
        }
 
        free(ln.buf);
+       return 1;
 }
 
 static int
 read_whole_file(struct mparse *curp, const char *file, int fd,
                struct buf *fb, int *with_mmap)
 {
+       struct stat      st;
        gzFile           gz;
        size_t           off;
        ssize_t          ssz;
 
-#if HAVE_MMAP
-       struct stat      st;
-
        if (fstat(fd, &st) == -1)
                err((int)MANDOCLEVEL_SYSERR, "%s", file);
 
@@ -637,7 +584,6 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
                if (fb->buf != MAP_FAILED)
                        return 1;
        }
-#endif
 
        if (curp->gzip) {
                if ((gz = gzdopen(fd, "rb")) == NULL)
@@ -683,10 +629,6 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
 static void
 mparse_end(struct mparse *curp)
 {
-
-       if (curp->man == NULL && curp->sodest == NULL)
-               curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
-                   curp->options & MPARSE_QUICK ? 1 : 0);
        if (curp->man->macroset == MACROSET_NONE)
                curp->man->macroset = MACROSET_MAN;
        if (curp->man->macroset == MACROSET_MDOC)
@@ -766,11 +708,9 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
                    (MPARSE_UTF8 | MPARSE_LATIN1);
                mparse_parse_buffer(curp, blk, file);
                curp->filenc = save_filenc;
-#if HAVE_MMAP
                if (with_mmap)
                        munmap(blk.buf, blk.sz);
                else
-#endif
                        free(blk.buf);
        }
        return curp->file_status;
@@ -829,11 +769,13 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
        curp->man = roff_man_alloc( curp->roff, curp, curp->defos,
                curp->options & MPARSE_QUICK ? 1 : 0);
        if (curp->options & MPARSE_MDOC) {
-               mdoc_hash_init();
                curp->man->macroset = MACROSET_MDOC;
+               if (curp->man->mdocmac == NULL)
+                       curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
        } else if (curp->options & MPARSE_MAN) {
-               man_hash_init();
                curp->man->macroset = MACROSET_MAN;
+               if (curp->man->manmac == NULL)
+                       curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
        }
        curp->man->first->tok = TOKEN_NONE;
        return curp;
@@ -842,27 +784,27 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
 void
 mparse_reset(struct mparse *curp)
 {
-
        roff_reset(curp->roff);
+       roff_man_reset(curp->man);
+
+       free(curp->sodest);
+       curp->sodest = NULL;
 
-       if (curp->man != NULL)
-               roff_man_reset(curp->man);
        if (curp->secondary)
                curp->secondary->sz = 0;
 
        curp->file_status = MANDOCLEVEL_OK;
-
-       free(curp->sodest);
-       curp->sodest = NULL;
+       curp->gzip = 0;
 }
 
 void
 mparse_free(struct mparse *curp)
 {
 
+       roffhash_free(curp->man->mdocmac);
+       roffhash_free(curp->man->manmac);
        roff_man_free(curp->man);
-       if (curp->roff)
-               roff_free(curp->roff);
+       roff_free(curp->roff);
        if (curp->secondary)
                free(curp->secondary->buf);
 
@@ -884,6 +826,13 @@ mparse_result(struct mparse *curp, struct roff_man **man,
                *man = curp->man;
 }
 
+void
+mparse_updaterc(struct mparse *curp, enum mandoclevel *rc)
+{
+       if (curp->file_status > *rc)
+               *rc = curp->file_status;
+}
+
 void
 mandoc_vmsg(enum mandocerr t, struct mparse *m,
                int ln, int pos, const char *fmt, ...)