In order to become able to generate syntax tree nodes on the roff(7)
authorschwarze <schwarze@openbsd.org>
Tue, 20 Oct 2015 02:00:49 +0000 (02:00 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 20 Oct 2015 02:00:49 +0000 (02:00 +0000)
level, validation must be separated from parsing and rewinding.
This first big step moves calling of the mdoc(7) post_*() functions
out of the parser loop into their own mdoc_validate() pass, while
using a new mdoc_state() module to make syntax tree state handling
available to both the parser loop and the validation pass.

12 files changed:
usr.bin/mandoc/Makefile
usr.bin/mandoc/cgi.c
usr.bin/mandoc/libmdoc.h
usr.bin/mandoc/main.c
usr.bin/mandoc/mandocdb.c
usr.bin/mandoc/mdoc.c
usr.bin/mandoc/mdoc.h
usr.bin/mandoc/mdoc_macro.c
usr.bin/mandoc/mdoc_state.c [new file with mode: 0644]
usr.bin/mandoc/mdoc_validate.c
usr.bin/mandoc/roff.c
usr.bin/mandoc/roff_int.h

index d2e41d6..021fe34 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.98 2015/10/13 15:50:15 schwarze Exp $
+#      $OpenBSD: Makefile,v 1.99 2015/10/20 02:00:49 schwarze Exp $
 
 .include <bsd.own.mk>
 
@@ -9,7 +9,7 @@ LDADD   += -lsqlite3 -lutil -lz
 SRCS=  mandoc.c mandoc_aux.c mandoc_ohash.c preconv.c read.c \
        roff.c tbl.c tbl_opts.c tbl_layout.c tbl_data.c eqn.c
 SRCS+= mdoc_macro.c mdoc.c mdoc_hash.c \
-       mdoc_argv.c mdoc_validate.c att.c msec.c st.c
+       mdoc_argv.c mdoc_state.c mdoc_validate.c att.c msec.c st.c
 SRCS+= man_macro.c man.c man_hash.c man_validate.c
 SRCS+= main.c mdoc_term.c tag.c chars.c term.c tree.c man_term.c eqn_term.c
 SRCS+= mdoc_man.c
@@ -41,8 +41,8 @@ CLEANFILES += man.cgi cgi.o
 # To install, run:     sudo make installcgi
 # After that, read:    man man.cgi.8
 
-LIBMDOC_OBJS = mdoc_argv.o mdoc_hash.o mdoc_macro.o mdoc_validate.o \
-               mdoc.o att.o st.o
+LIBMDOC_OBJS = mdoc_argv.o mdoc_hash.o mdoc_macro.o mdoc_state.o \
+               mdoc_validate.o mdoc.o att.o st.o
 LIBMAN_OBJS =  man.o man_hash.o man_macro.o man_validate.o
 LIBROFF_OBJS = roff.o eqn.o tbl.o tbl_data.o tbl_layout.o tbl_opts.o
 LIBMANDOC_OBJS = ${LIBMDOC_OBJS} ${LIBMAN_OBJS} ${LIBROFF_OBJS} \
@@ -52,7 +52,8 @@ HTML_OBJS =   html.o mdoc_html.o man_html.o tbl_html.o eqn_html.o out.o
 CGI_OBJS =     ${LIBMANDOC_OBJS} ${HTML_OBJS} \
                mansearch.o mansearch_const.o cgi.o
 
-cgi.o: main.h mandoc.h mandoc_aux.h mandoc_ohash.h manconf.h mansearch.h cgi.h
+cgi.o: cgi.h main.h manconf.h mandoc.h mandoc_aux.h mansearch.h \
+       mdoc.h roff.h
 
 man.cgi: ${CGI_OBJS}
        ${CC} ${LDFLAGS} ${STATIC} -o ${.TARGET} ${CGI_OBJS} ${LDADD}
index b2fc30c..f1e65e1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cgi.c,v 1.49 2015/10/13 22:57:49 schwarze Exp $ */
+/*     $OpenBSD: cgi.c,v 1.50 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@usta.de>
@@ -31,6 +31,7 @@
 #include "mandoc_aux.h"
 #include "mandoc.h"
 #include "roff.h"
+#include "mdoc.h"
 #include "main.h"
 #include "manconf.h"
 #include "mansearch.h"
@@ -854,9 +855,10 @@ format(const struct req *req, const char *file)
 
        vp = html_alloc(&conf);
 
-       if (man->macroset == MACROSET_MDOC)
+       if (man->macroset == MACROSET_MDOC) {
+               mdoc_validate(man);
                html_mdoc(vp, man);
-       else
+       else
                html_man(vp, man);
 
        html_free(vp);
index ef3f17b..99b3360 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: libmdoc.h,v 1.77 2015/10/17 00:19:58 schwarze Exp $ */
+/*     $OpenBSD: libmdoc.h,v 1.78 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -73,10 +73,14 @@ void                  mdoc_tail_alloc(struct roff_man *, int, int, int);
 struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, int,
                        struct roff_node *, enum mdoc_endbody);
 void             mdoc_node_relink(struct roff_man *, struct roff_node *);
+void             mdoc_node_validate(struct roff_man *);
+void             mdoc_state(struct roff_man *, struct roff_node *);
+void             mdoc_state_reset(struct roff_man *);
 int              mdoc_hash_find(const char *);
+const char      *mdoc_a2arch(const char *);
 const char      *mdoc_a2att(const char *);
+enum roff_sec    mdoc_a2sec(const char *);
 const char      *mdoc_a2st(const char *);
-const char      *mdoc_a2arch(const char *);
 void             mdoc_argv(struct roff_man *, int, int,
                        struct mdoc_arg **, int *, char *);
 enum margserr    mdoc_args(struct roff_man *, int,
index 413c27c..493fb8e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.158 2015/10/19 19:51:06 schwarze Exp $ */
+/*     $OpenBSD: main.c,v 1.159 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -672,6 +672,7 @@ parse(struct curparse *curp, int fd, const char *file)
        if (man == NULL)
                return;
        if (man->macroset == MACROSET_MDOC) {
+               mdoc_validate(man);
                switch (curp->outtype) {
                case OUTT_HTML:
                        html_mdoc(curp->outdata, man);
index eae173b..4762811 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mandocdb.c,v 1.158 2015/10/16 13:37:44 millert Exp $ */
+/*     $OpenBSD: mandocdb.c,v 1.159 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -1168,6 +1168,7 @@ mpages_merge(struct mparse *mp)
                        }
                        goto nextpage;
                } else if (man != NULL && man->macroset == MACROSET_MDOC) {
+                       mdoc_validate(man);
                        mpage->form = FORM_SRC;
                        mpage->sec = man->meta.msec;
                        mpage->sec = mandoc_strdup(
index 90255f0..0a84263 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc.c,v 1.143 2015/10/12 00:07:27 schwarze Exp $ */
+/*     $OpenBSD: mdoc.c,v 1.144 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -119,24 +119,6 @@ mdoc_macro(MACRO_PROT_ARGS)
 {
        assert(tok > TOKEN_NONE && tok < MDOC_MAX);
 
-       if (mdoc->flags & MDOC_PBODY) {
-               if (tok == MDOC_Dt) {
-                       mandoc_vmsg(MANDOCERR_DT_LATE,
-                           mdoc->parse, line, ppos,
-                           "Dt %s", buf + *pos);
-                       return;
-               }
-       } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
-               if (mdoc->meta.title == NULL) {
-                       mandoc_vmsg(MANDOCERR_DT_NOTITLE,
-                           mdoc->parse, line, ppos, "%s %s",
-                           mdoc_macronames[tok], buf + *pos);
-                       mdoc->meta.title = mandoc_strdup("UNTITLED");
-               }
-               if (NULL == mdoc->meta.vol)
-                       mdoc->meta.vol = mandoc_strdup("LOCAL");
-               mdoc->flags |= MDOC_PBODY;
-       }
        (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
 }
 
@@ -317,8 +299,8 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
                 * behaviour that we want to work around it.
                 */
                roff_elem_alloc(mdoc, line, offs, MDOC_sp);
+               mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
                mdoc->next = ROFF_NEXT_SIBLING;
-               mdoc_valid_post(mdoc);
                return 1;
        }
 
@@ -493,3 +475,12 @@ mdoc_isdelim(const char *p)
 
        return DELIM_NONE;
 }
+
+void
+mdoc_validate(struct roff_man *mdoc)
+{
+
+       mdoc->last = mdoc->first;
+       mdoc_node_validate(mdoc);
+       mdoc_state_reset(mdoc);
+}
index 28669f4..a920314 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc.h,v 1.67 2015/04/23 16:17:04 schwarze Exp $ */
+/*     $OpenBSD: mdoc.h,v 1.68 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -279,3 +279,9 @@ extern      const char *const *mdoc_macronames;
 
 /* Names of macro args.  Index is enum mdocargt. */
 extern const char *const *mdoc_argnames;
+
+__BEGIN_DECLS
+
+void            mdoc_validate(struct roff_man *);
+
+__END_DECLS
index 1de61e7..2d76e1e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc_macro.c,v 1.161 2015/10/17 00:19:58 schwarze Exp $ */
+/*     $OpenBSD: mdoc_macro.c,v 1.162 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -226,6 +226,7 @@ mdoc_endparse(struct roff_man *mdoc)
        /* Rewind to the first. */
 
        rew_last(mdoc, mdoc->first);
+       mdoc_state_reset(mdoc);
 }
 
 /*
@@ -260,25 +261,18 @@ lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
 static void
 rew_last(struct roff_man *mdoc, const struct roff_node *to)
 {
-       struct roff_node        *np;
 
        if (to->flags & MDOC_VALID)
                return;
 
        while (mdoc->last != to) {
-               /*
-                * Save the parent here, because we may delete the
-                * mdoc->last node in the post-validation phase and reset
-                * it to mdoc->last->parent, causing a step in the closing
-                * out to be lost.
-                */
-               np = mdoc->last->parent;
-               mdoc_valid_post(mdoc);
-               mdoc->last = np;
-               assert(mdoc->last);
+               mdoc_state(mdoc, mdoc->last);
+               mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
+               mdoc->last = mdoc->last->parent;
        }
+       mdoc_state(mdoc, mdoc->last);
+       mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
        mdoc->next = ROFF_NEXT_SIBLING;
-       mdoc_valid_post(mdoc);
 }
 
 /*
diff --git a/usr.bin/mandoc/mdoc_state.c b/usr.bin/mandoc/mdoc_state.c
new file mode 100644 (file)
index 0000000..3e04279
--- /dev/null
@@ -0,0 +1,269 @@
+/*     $OpenBSD: mdoc_state.c,v 1.1 2015/10/20 02:00:49 schwarze Exp $ */
+/*
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mandoc.h"
+#include "roff.h"
+#include "mdoc.h"
+#include "libmandoc.h"
+#include "libmdoc.h"
+
+#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
+
+typedef        void    (*state_handler)(STATE_ARGS);
+
+static void     state_bd(STATE_ARGS);
+static void     state_dl(STATE_ARGS);
+static void     state_sh(STATE_ARGS);
+static void     state_sm(STATE_ARGS);
+
+static const state_handler state_handlers[MDOC_MAX] = {
+       NULL,           /* Ap */
+       NULL,           /* Dd */
+       NULL,           /* Dt */
+       NULL,           /* Os */
+       state_sh,       /* Sh */
+       NULL,           /* Ss */
+       NULL,           /* Pp */
+       NULL,           /* D1 */
+       state_dl,       /* Dl */
+       state_bd,       /* Bd */
+       NULL,           /* Ed */
+       NULL,           /* Bl */
+       NULL,           /* El */
+       NULL,           /* It */
+       NULL,           /* Ad */
+       NULL,           /* An */
+       NULL,           /* Ar */
+       NULL,           /* Cd */
+       NULL,           /* Cm */
+       NULL,           /* Dv */
+       NULL,           /* Er */
+       NULL,           /* Ev */
+       NULL,           /* Ex */
+       NULL,           /* Fa */
+       NULL,           /* Fd */
+       NULL,           /* Fl */
+       NULL,           /* Fn */
+       NULL,           /* Ft */
+       NULL,           /* Ic */
+       NULL,           /* In */
+       NULL,           /* Li */
+       NULL,           /* Nd */
+       NULL,           /* Nm */
+       NULL,           /* Op */
+       NULL,           /* Ot */
+       NULL,           /* Pa */
+       NULL,           /* Rv */
+       NULL,           /* St */
+       NULL,           /* Va */
+       NULL,           /* Vt */
+       NULL,           /* Xr */
+       NULL,           /* %A */
+       NULL,           /* %B */
+       NULL,           /* %D */
+       NULL,           /* %I */
+       NULL,           /* %J */
+       NULL,           /* %N */
+       NULL,           /* %O */
+       NULL,           /* %P */
+       NULL,           /* %R */
+       NULL,           /* %T */
+       NULL,           /* %V */
+       NULL,           /* Ac */
+       NULL,           /* Ao */
+       NULL,           /* Aq */
+       NULL,           /* At */
+       NULL,           /* Bc */
+       NULL,           /* Bf */
+       NULL,           /* Bo */
+       NULL,           /* Bq */
+       NULL,           /* Bsx */
+       NULL,           /* Bx */
+       NULL,           /* Db */
+       NULL,           /* Dc */
+       NULL,           /* Do */
+       NULL,           /* Dq */
+       NULL,           /* Ec */
+       NULL,           /* Ef */
+       NULL,           /* Em */
+       NULL,           /* Eo */
+       NULL,           /* Fx */
+       NULL,           /* Ms */
+       NULL,           /* No */
+       NULL,           /* Ns */
+       NULL,           /* Nx */
+       NULL,           /* Ox */
+       NULL,           /* Pc */
+       NULL,           /* Pf */
+       NULL,           /* Po */
+       NULL,           /* Pq */
+       NULL,           /* Qc */
+       NULL,           /* Ql */
+       NULL,           /* Qo */
+       NULL,           /* Qq */
+       NULL,           /* Re */
+       NULL,           /* Rs */
+       NULL,           /* Sc */
+       NULL,           /* So */
+       NULL,           /* Sq */
+       state_sm,       /* Sm */
+       NULL,           /* Sx */
+       NULL,           /* Sy */
+       NULL,           /* Tn */
+       NULL,           /* Ux */
+       NULL,           /* Xc */
+       NULL,           /* Xo */
+       NULL,           /* Fo */
+       NULL,           /* Fc */
+       NULL,           /* Oo */
+       NULL,           /* Oc */
+       NULL,           /* Bk */
+       NULL,           /* Ek */
+       NULL,           /* Bt */
+       NULL,           /* Hf */
+       NULL,           /* Fr */
+       NULL,           /* Ud */
+       NULL,           /* Lb */
+       NULL,           /* Lp */
+       NULL,           /* Lk */
+       NULL,           /* Mt */
+       NULL,           /* Brq */
+       NULL,           /* Bro */
+       NULL,           /* Brc */
+       NULL,           /* %C */
+       NULL,           /* Es */
+       NULL,           /* En */
+       NULL,           /* Dx */
+       NULL,           /* %Q */
+       NULL,           /* br */
+       NULL,           /* sp */
+       NULL,           /* %U */
+       NULL,           /* Ta */
+       NULL,           /* ll */
+};
+
+
+void
+mdoc_state(struct roff_man *mdoc, struct roff_node *n)
+{
+       state_handler handler;
+
+       if (n->tok == TOKEN_NONE)
+               return;
+
+       if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
+               mdoc->flags |= MDOC_PBODY;
+
+       handler = state_handlers[n->tok];
+       if (*handler)
+               (*handler)(mdoc, n);
+}
+
+void
+mdoc_state_reset(struct roff_man *mdoc)
+{
+
+       roff_setreg(mdoc->roff, "nS", 0, '=');
+       mdoc->flags = 0;
+}
+
+static void
+state_bd(STATE_ARGS)
+{
+       enum mdocargt arg;
+
+       if (n->type != ROFFT_HEAD &&
+           (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
+               return;
+
+       arg = n->parent->args->argv[0].arg;
+       if (arg != MDOC_Literal && arg != MDOC_Unfilled)
+               return;
+
+       state_dl(mdoc, n);
+}
+
+static void
+state_dl(STATE_ARGS)
+{
+
+       switch (n->type) {
+       case ROFFT_HEAD:
+               mdoc->flags |= MDOC_LITERAL;
+               break;
+       case ROFFT_BODY:
+               mdoc->flags &= ~MDOC_LITERAL;
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+state_sh(STATE_ARGS)
+{
+       struct roff_node *nch;
+       char             *secname;
+
+       if (n->type != ROFFT_HEAD)
+               return;
+
+       if ( ! (n->flags & MDOC_VALID)) {
+               secname = NULL;
+               deroff(&secname, n);
+
+               /*
+                * Set the section attribute for the BLOCK, HEAD,
+                * and HEAD children; the latter can only be TEXT
+                * nodes, so no recursion is needed.  For other
+                * nodes, including the .Sh BODY, this is done
+                * when allocating the node data structures, but
+                * for .Sh BLOCK and HEAD, the section is still
+                * unknown at that time.
+                */
+
+               n->sec = n->parent->sec = secname == NULL ?
+                   SEC_CUSTOM : mdoc_a2sec(secname);
+               for (nch = n->child; nch != NULL; nch = nch->next)
+                       nch->sec = n->sec;
+               free(secname);
+       }
+
+       if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
+               roff_setreg(mdoc->roff, "nS", 1, '=');
+               mdoc->flags |= MDOC_SYNOPSIS;
+       } else {
+               roff_setreg(mdoc->roff, "nS", 0, '=');
+               mdoc->flags &= ~MDOC_SYNOPSIS;
+       }
+}
+
+static void
+state_sm(STATE_ARGS)
+{
+
+       if (n->child == NULL)
+               mdoc->flags ^= MDOC_SMOFF;
+       else if ( ! strcmp(n->child->string, "on"))
+               mdoc->flags &= ~MDOC_SMOFF;
+       else if ( ! strcmp(n->child->string, "off"))
+               mdoc->flags |= MDOC_SMOFF;
+}
index f03e09d..43a1fd0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc_validate.c,v 1.213 2015/10/19 20:03:57 schwarze Exp $ */
+/*     $OpenBSD: mdoc_validate.c,v 1.214 2015/10/20 02:00:49 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -61,7 +61,6 @@ static        void     check_argv(struct roff_man *,
                        struct roff_node *, struct mdoc_argv *);
 static void     check_args(struct roff_man *, struct roff_node *);
 static int      child_an(const struct roff_node *);
-static enum roff_sec   a2sec(const char *);
 static size_t          macro2len(int);
 static void     rewrite_macro2len(char **);
 
@@ -109,25 +108,21 @@ static    void     post_st(POST_ARGS);
 static void     pre_an(PRE_ARGS);
 static void     pre_bd(PRE_ARGS);
 static void     pre_bl(PRE_ARGS);
-static void     pre_dd(PRE_ARGS);
 static void     pre_display(PRE_ARGS);
-static void     pre_dt(PRE_ARGS);
-static void     pre_literal(PRE_ARGS);
 static void     pre_obsolete(PRE_ARGS);
-static void     pre_os(PRE_ARGS);
 static void     pre_par(PRE_ARGS);
 static void     pre_std(PRE_ARGS);
 
 static const struct valids mdoc_valids[MDOC_MAX] = {
        { NULL, NULL },                         /* Ap */
-       { pre_dd, post_dd },                    /* Dd */
-       { pre_dt, post_dt },                    /* Dt */
-       { pre_os, post_os },                    /* Os */
+       { NULL, post_dd },                      /* Dd */
+       { NULL, post_dt },                      /* Dt */
+       { NULL, post_os },                      /* Os */
        { NULL, post_sh },                      /* Sh */
        { NULL, post_ignpar },                  /* Ss */
        { pre_par, post_par },                  /* Pp */
        { pre_display, post_d1 },               /* D1 */
-       { pre_literal, post_literal },          /* Dl */
+       { pre_display, post_literal },          /* Dl */
        { pre_bd, post_literal },               /* Bd */
        { NULL, NULL },                         /* Ed */
        { pre_bl, post_bl },                    /* Bl */
@@ -315,16 +310,23 @@ mdoc_valid_pre(struct roff_man *mdoc, struct roff_node *n)
 }
 
 void
-mdoc_valid_post(struct roff_man *mdoc)
+mdoc_node_validate(struct roff_man *mdoc)
 {
        struct roff_node *n;
        v_post p;
 
        n = mdoc->last;
-       if (n->flags & MDOC_VALID)
-               return;
-       n->flags |= MDOC_VALID | MDOC_ENDED;
+       mdoc->last = mdoc->last->child;
+       while (mdoc->last != NULL) {
+               mdoc_node_validate(mdoc);
+               if (mdoc->last == n)
+                       mdoc->last = mdoc->last->child;
+               else
+                       mdoc->last = mdoc->last->next;
+       }
 
+       mdoc->last = n;
+       mdoc->next = ROFF_NEXT_SIBLING;
        switch (n->type) {
        case ROFFT_TEXT:
        case ROFFT_EQN:
@@ -351,6 +353,8 @@ mdoc_valid_post(struct roff_man *mdoc)
                p = mdoc_valids[n->tok].post;
                if (*p)
                        (*p)(mdoc);
+               if (mdoc->last == n)
+                       mdoc_state(mdoc, n);
                break;
        }
 }
@@ -592,7 +596,7 @@ pre_bd(PRE_ARGS)
        int               i;
        enum mdoc_disp    dt;
 
-       pre_literal(mdoc, n);
+       pre_display(mdoc, n);
 
        if (n->type != ROFFT_BLOCK)
                return;
@@ -711,48 +715,6 @@ pre_obsolete(PRE_ARGS)
                    n->line, n->pos, mdoc_macronames[n->tok]);
 }
 
-static void
-pre_dt(PRE_ARGS)
-{
-
-       if (mdoc->meta.title != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
-                   n->line, n->pos, "Dt");
-       else if (mdoc->meta.os != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
-                   n->line, n->pos, "Dt after Os");
-}
-
-static void
-pre_os(PRE_ARGS)
-{
-
-       if (mdoc->meta.os != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
-                   n->line, n->pos, "Os");
-       else if (mdoc->flags & MDOC_PBODY)
-               mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
-                   n->line, n->pos, "Os");
-}
-
-static void
-pre_dd(PRE_ARGS)
-{
-
-       if (mdoc->meta.date != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
-                   n->line, n->pos, "Dd");
-       else if (mdoc->flags & MDOC_PBODY)
-               mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
-                   n->line, n->pos, "Dd");
-       else if (mdoc->meta.title != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
-                   n->line, n->pos, "Dd after Dt");
-       else if (mdoc->meta.os != NULL)
-               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
-                   n->line, n->pos, "Dd after Os");
-}
-
 static void
 post_bf(POST_ARGS)
 {
@@ -977,19 +939,12 @@ post_literal(POST_ARGS)
 
        n = mdoc->last;
 
-       if (n->type != ROFFT_BODY)
+       if (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)
                return;
 
        if (n->child == NULL)
                mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
                    n->line, n->pos, mdoc_macronames[n->tok]);
-
-       if (n->tok == MDOC_Bd &&
-           n->norm->Bd.type != DISP_literal &&
-           n->norm->Bd.type != DISP_unfilled)
-               return;
-
-       mdoc->flags &= ~MDOC_LITERAL;
 }
 
 static void
@@ -1007,15 +962,16 @@ post_defaults(POST_ARGS)
                return;
 
        nn = mdoc->last;
-       mdoc->next = ROFF_NEXT_CHILD;
 
        switch (nn->tok) {
        case MDOC_Ar:
+               mdoc->next = ROFF_NEXT_CHILD;
                roff_word_alloc(mdoc, nn->line, nn->pos, "file");
                roff_word_alloc(mdoc, nn->line, nn->pos, "...");
                break;
        case MDOC_Pa:
        case MDOC_Mt:
+               mdoc->next = ROFF_NEXT_CHILD;
                roff_word_alloc(mdoc, nn->line, nn->pos, "~");
                break;
        default:
@@ -1375,6 +1331,8 @@ post_bl(POST_ARGS)
        default:
                return;
        }
+       if (nbody->end != ENDBODY_NOT)
+               return;
 
        nchild = nbody->child;
        if (nchild == NULL) {
@@ -1819,9 +1777,7 @@ post_sh_authors(POST_ARGS)
 static void
 post_sh_head(POST_ARGS)
 {
-       struct roff_node *n;
        const char      *goodsec;
-       char            *secname;
        enum roff_sec    sec;
 
        /*
@@ -1831,20 +1787,18 @@ post_sh_head(POST_ARGS)
         * manual sections.
         */
 
-       secname = NULL;
-       deroff(&secname, mdoc->last);
-       sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
+       sec = mdoc->last->sec;
 
        /* The NAME should be first. */
 
        if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
                mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
                    mdoc->last->line, mdoc->last->pos,
-                   "Sh %s", secname);
+                   "Sh %s", secnames[sec]);
 
        /* The SYNOPSIS gets special attention in other areas. */
 
-       if (SEC_SYNOPSIS == sec) {
+       if (sec == SEC_SYNOPSIS) {
                roff_setreg(mdoc->roff, "nS", 1, '=');
                mdoc->flags |= MDOC_SYNOPSIS;
        } else {
@@ -1856,26 +1810,10 @@ post_sh_head(POST_ARGS)
 
        mdoc->lastsec = sec;
 
-       /*
-        * Set the section attribute for the current HEAD, for its
-        * parent BLOCK, and for the HEAD children; the latter can
-        * only be TEXT nodes, so no recursion is needed.
-        * For other blocks and elements, including .Sh BODY, this is
-        * done when allocating the node data structures, but for .Sh
-        * BLOCK and HEAD, the section is still unknown at that time.
-        */
-
-       mdoc->last->parent->sec = sec;
-       mdoc->last->sec = sec;
-       for (n = mdoc->last->child; n != NULL; n = n->next)
-               n->sec = sec;
-
        /* We don't care about custom sections after this. */
 
-       if (SEC_CUSTOM == sec) {
-               free(secname);
+       if (sec == SEC_CUSTOM)
                return;
-       }
 
        /*
         * Check whether our non-custom section is being repeated or is
@@ -1885,12 +1823,12 @@ post_sh_head(POST_ARGS)
        if (sec == mdoc->lastnamed)
                mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
                    mdoc->last->line, mdoc->last->pos,
-                   "Sh %s", secname);
+                   "Sh %s", secnames[sec]);
 
        if (sec < mdoc->lastnamed)
                mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
                    mdoc->last->line, mdoc->last->pos,
-                   "Sh %s", secname);
+                   "Sh %s", secnames[sec]);
 
        /* Mark the last named section. */
 
@@ -1898,10 +1836,8 @@ post_sh_head(POST_ARGS)
 
        /* Check particular section/manual conventions. */
 
-       if (mdoc->meta.msec == NULL) {
-               free(secname);
+       if (mdoc->meta.msec == NULL)
                return;
-       }
 
        goodsec = NULL;
        switch (sec) {
@@ -1926,12 +1862,11 @@ post_sh_head(POST_ARGS)
                        goodsec = "9";
                mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
                    mdoc->last->line, mdoc->last->pos,
-                   "Sh %s for %s only", secname, goodsec);
+                   "Sh %s for %s only", secnames[sec], goodsec);
                break;
        default:
                break;
        }
-       free(secname);
 }
 
 static void
@@ -2033,45 +1968,27 @@ post_par(POST_ARGS)
        roff_node_delete(mdoc, mdoc->last);
 }
 
-static void
-pre_literal(PRE_ARGS)
-{
-
-       pre_display(mdoc, n);
-
-       if (n->type != ROFFT_BODY)
-               return;
-
-       /*
-        * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
-        * -unfilled' macros set MDOC_LITERAL on entrance to the body.
-        */
-
-       switch (n->tok) {
-       case MDOC_Dl:
-               mdoc->flags |= MDOC_LITERAL;
-               break;
-       case MDOC_Bd:
-               if (DISP_literal == n->norm->Bd.type)
-                       mdoc->flags |= MDOC_LITERAL;
-               if (DISP_unfilled == n->norm->Bd.type)
-                       mdoc->flags |= MDOC_LITERAL;
-               break;
-       default:
-               abort();
-       }
-}
-
 static void
 post_dd(POST_ARGS)
 {
        struct roff_node *n;
        char             *datestr;
 
-       if (mdoc->meta.date)
+       n = mdoc->last;
+       if (mdoc->meta.date != NULL) {
+               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+                   n->line, n->pos, "Dd");
                free(mdoc->meta.date);
+       } else if (mdoc->flags & MDOC_PBODY)
+               mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+                   n->line, n->pos, "Dd");
+       else if (mdoc->meta.title != NULL)
+               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+                   n->line, n->pos, "Dd after Dt");
+       else if (mdoc->meta.os != NULL)
+               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+                   n->line, n->pos, "Dd after Os");
 
-       n = mdoc->last;
        if (n->child == NULL || n->child->string[0] == '\0') {
                mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
                    mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
@@ -2099,6 +2016,18 @@ post_dt(POST_ARGS)
        char             *p;
 
        n = mdoc->last;
+       if (mdoc->flags & MDOC_PBODY) {
+               mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse,
+                   n->line, n->pos, "Dt");
+               goto out;
+       }
+
+       if (mdoc->meta.title != NULL)
+               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+                   n->line, n->pos, "Dt");
+       else if (mdoc->meta.os != NULL)
+               mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+                   n->line, n->pos, "Dt after Os");
 
        free(mdoc->meta.title);
        free(mdoc->meta.msec);
@@ -2201,6 +2130,12 @@ post_os(POST_ARGS)
        struct roff_node *n;
 
        n = mdoc->last;
+       if (mdoc->meta.os != NULL)
+               mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+                   n->line, n->pos, "Os");
+       else if (mdoc->flags & MDOC_PBODY)
+               mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+                   n->line, n->pos, "Os");
 
        /*
         * Set the operating system by way of the `Os' macro.
@@ -2266,8 +2201,8 @@ post_ex(POST_ARGS)
        mdoc->last = n;
 }
 
-static enum roff_sec
-a2sec(const char *p)
+enum roff_sec
+mdoc_a2sec(const char *p)
 {
        int              i;
 
index ffd1892..2e041b7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.152 2015/10/15 23:35:38 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.153 2015/10/20 02:00:50 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -1005,6 +1005,11 @@ roff_node_append(struct roff_man *man, struct roff_node *n)
 
        switch (man->next) {
        case ROFF_NEXT_SIBLING:
+               if (man->last->next != NULL) {
+                       n->next = man->last->next;
+                       man->last->next->prev = n;
+               } else
+                       man->last->parent->last = n;
                man->last->next = n;
                n->prev = man->last;
                n->parent = man->last->parent;
@@ -1012,12 +1017,12 @@ roff_node_append(struct roff_man *man, struct roff_node *n)
        case ROFF_NEXT_CHILD:
                man->last->child = n;
                n->parent = man->last;
+               n->parent->last = n;
                break;
        default:
                abort();
        }
        n->parent->nchild++;
-       n->parent->last = n;
 
        /*
         * Copy over the normalised-data pointer of our parent.  Not
@@ -1070,7 +1075,7 @@ roff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
        n->string = roff_strdup(man->roff, word);
        roff_node_append(man, n);
        if (man->macroset == MACROSET_MDOC)
-               mdoc_valid_post(man);
+               n->flags |= MDOC_VALID | MDOC_ENDED;
        else
                man_valid_post(man);
        man->next = ROFF_NEXT_SIBLING;
@@ -1158,7 +1163,7 @@ roff_addtbl(struct roff_man *man, const struct tbl_span *tbl)
        n->span = tbl;
        roff_node_append(man, n);
        if (man->macroset == MACROSET_MDOC)
-               mdoc_valid_post(man);
+               n->flags |= MDOC_VALID | MDOC_ENDED;
        else
                man_valid_post(man);
        man->next = ROFF_NEXT_SIBLING;
index ab9a8b3..a1ed91d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff_int.h,v 1.3 2015/04/19 14:57:16 schwarze Exp $   */
+/*     $OpenBSD: roff_int.h,v 1.4 2015/10/20 02:00:50 schwarze Exp $   */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -43,7 +43,6 @@ void            man_breakscope(struct roff_man *, int);
 void             man_valid_post(struct roff_man *);
 
 void             mdoc_valid_pre(struct roff_man *, struct roff_node *);
-void             mdoc_valid_post(struct roff_man *);
 void             mdoc_argv_free(struct mdoc_arg *);
 
 __END_DECLS