]> git.cameronkatri.com Git - mandoc.git/blobdiff - read.c
Move main format autodetection from the parser dispatcher to the
[mandoc.git] / read.c
diff --git a/read.c b/read.c
index 3b9ce545377620e1c6e88aa25cdf69de3e35702d..26cd6288df190ae1891dcaea13bb1756b30edd96 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/*     $Id: read.c,v 1.82 2014/09/03 23:21:47 schwarze Exp $ */
+/*     $Id: read.c,v 1.83 2014/09/06 22:39:36 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -51,21 +51,22 @@ struct      buf {
 };
 
 struct mparse {
-       enum mandoclevel  file_status; /* status of current parse */
-       enum mandoclevel  wlevel; /* ignore messages below this */
-       int               line; /* line number in the file */
-       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) */
        char             *sodest; /* filename pointed to by .so */
-       int               reparse_count; /* finite interp. stack */
-       mandocmsg         mmsg; /* warning/error message handler */
-       const char       *file;
-       struct buf       *secondary;
+       const char       *file; /* filename of current input file */
+       struct buf       *primary; /* buffer currently being parsed */
+       struct buf       *secondary; /* preprocessed copy of input */
        const char       *defos; /* default operating system */
+       mandocmsg         mmsg; /* warning/error message handler */
+       enum mandoclevel  file_status; /* status of current parse */
+       enum mandoclevel  wlevel; /* ignore messages below this */
+       int               options; /* parser options */
+       int               reparse_count; /* finite interp. stack */
+       int               line; /* line number in the file */
 };
 
 static void      resize_buf(struct buf *, size_t);
@@ -248,19 +249,10 @@ resize_buf(struct buf *buf, size_t initial)
 static void
 pset(const char *buf, int pos, struct mparse *curp)
 {
+       char            *cp, *ep;
+       int              format;
        int              i;
 
-       /*
-        * Try to intuit which kind of manual parser should be used.  If
-        * passed in by command-line (-man, -mdoc), then use that
-        * explicitly.  If passed as -mandoc, then try to guess from the
-        * line: either skip dot-lines, use -mdoc when finding `.Dt', or
-        * default to -man, which is more lenient.
-        *
-        * Separate out pmdoc/pman from mdoc/man: the first persists
-        * through all parsers, while the latter is used per-parse.
-        */
-
        if ('.' == buf[0] || '\'' == buf[0]) {
                for (i = 1; buf[i]; i++)
                        if (' ' != buf[i] && '\t' != buf[i])
@@ -269,15 +261,35 @@ pset(const char *buf, int pos, struct mparse *curp)
                        return;
        }
 
-       if (MPARSE_MDOC & curp->options) {
-               curp->mdoc = curp->pmdoc;
-               return;
-       } else if (MPARSE_MAN & curp->options) {
-               curp->man = curp->pman;
-               return;
+       /*
+        * If neither command line arguments -mdoc or -man select
+        * a parser nor the roff parser found a .Dd or .TH macro
+        * yet, look ahead in the main input buffer.
+        */
+
+       if ((format = roff_getformat(curp->roff)) == 0) {
+               cp = curp->primary->buf;
+               ep = cp + curp->primary->sz;
+               while (cp < ep) {
+                       if (*cp == '.' || *cp != '\'') {
+                               cp++;
+                               if (cp[0] == 'D' && cp[1] == 'd') {
+                                       format = MPARSE_MDOC;
+                                       break;
+                               }
+                               if (cp[0] == 'T' && cp[1] == 'H') {
+                                       format = MPARSE_MAN;
+                                       break;
+                               }
+                       }
+                       cp = memchr(cp, '\n', ep - cp);
+                       if (cp == NULL)
+                               break;
+                       cp++;
+               }
        }
 
-       if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
+       if (format == MPARSE_MDOC) {
                if (NULL == curp->pmdoc)
                        curp->pmdoc = mdoc_alloc(
                            curp->roff, curp, curp->defos,
@@ -287,6 +299,8 @@ pset(const char *buf, int pos, struct mparse *curp)
                return;
        }
 
+       /* Fall back to man(7) as a last resort. */
+
        if (NULL == curp->pman)
                curp->pman = man_alloc(curp->roff, curp,
                    MPARSE_QUICK & curp->options ? 1 : 0);
@@ -720,6 +734,7 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
        /* Line number is per-file. */
        svfile = curp->file;
        curp->file = file;
+       curp->primary = &blk;
        curp->line = 1;
        recursion_depth++;