mandoc(1): Update to 1.9.20.
authorSascha Wildner <saw@online.de>
Tue, 30 Mar 2010 13:31:19 +0000 (15:31 +0200)
committerSascha Wildner <saw@online.de>
Tue, 30 Mar 2010 13:31:19 +0000 (15:31 +0200)
For a full list of changes, see <http://mdocml.bsd.lv/ChangeLog.html>.

Thanks-to: Kristaps Dzonsons

usr.bin/mandoc/Makefile
usr.bin/mandoc/libman.h
usr.bin/mandoc/man.c
usr.bin/mandoc/man_macro.c
usr.bin/mandoc/man_validate.c
usr.bin/mandoc/mandoc.1
usr.bin/mandoc/mdoc_argv.c
usr.bin/mandoc/mdoc_html.c
usr.bin/mandoc/mdoc_macro.c
usr.bin/mandoc/mdoc_strings.c
usr.bin/mandoc/mdoc_term.c

index 2b22f52..973f6fa 100644 (file)
@@ -1,6 +1,6 @@
 #      $OpenBSD: Makefile,v 1.21 2009/10/27 21:40:07 schwarze Exp $
 
-VERSION=1.9.19
+VERSION=1.9.20
 CFLAGS+=-DVERSION=\"${VERSION}\"
 WARNS?=        3
 
index ecd7da6..748ee95 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: libman.h,v 1.28 2010/03/27 10:04:56 kristaps Exp $ */
+/*     $Id: libman.h,v 1.30 2010/03/29 10:10:35 kristaps Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -27,14 +27,17 @@ enum        man_next {
 struct man {
        void            *data;
        struct man_cb    cb;
-       int              pflags;
-       int              flags;
-#define        MAN_HALT        (1 << 0)
+       int              pflags; /* parse flags (see man.h) */
+       int              svflags; /* flags saved during roff blocks */
+       int              flags; /* parse flags */
+#define        MAN_HALT        (1 << 0) /* badness happened: die */
 #define        MAN_ELINE       (1 << 1)        /* Next-line element scope. */
 #define        MAN_BLINE       (1 << 2)        /* Next-line block scope. */
 #define        MAN_ILINE       (1 << 3) /* Ignored in next-line scope. */
 #define        MAN_LITERAL     (1 << 4) /* Literal input. */
+#define        MAN_BPLINE      (1 << 5)
        enum man_next    next;
+       enum man_next    svnext;
        struct man_node *last;
        struct man_node *first;
        struct man_meta  meta;
index 7b84ee5..2b2531f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man.c,v 1.57 2010/03/27 10:26:39 kristaps Exp $ */
+/*     $Id: man.c,v 1.59 2010/03/29 10:10:35 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -474,15 +474,13 @@ macrowarn(struct man *m, int ln, const char *buf)
 int
 man_pmacro(struct man *m, int ln, char *buf)
 {
-       int              i, j, ppos, fl;
+       int              i, j, ppos;
        enum mant        tok;
        char             mac[5];
        struct man_node *n;
 
        /* Comments and empties are quickly ignored. */
 
-       fl = m->flags;
-
        if ('\0' == buf[1])
                return(1);
 
@@ -550,6 +548,9 @@ man_pmacro(struct man *m, int ln, char *buf)
         * Remove prior ELINE macro, as it's being clobbering by a new
         * macro.  Note that NSCOPED macros do not close out ELINE
         * macros---they don't print text---so we let those slip by.
+        * NOTE: we don't allow roff blocks (NOCLOSE) to be embedded
+        * here because that would stipulate blocks as children of
+        * elements!
         */
 
        if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
@@ -581,10 +582,18 @@ man_pmacro(struct man *m, int ln, char *buf)
                m->flags &= ~MAN_ELINE;
        }
 
-       /* Begin recursive parse sequence. */
+       /*
+        * Save the fact that we're in the next-line for a block.  In
+        * this way, embedded roff instructions can "remember" state
+        * when they exit.
+        */
+
+       if (MAN_BLINE & m->flags)
+               m->flags |= MAN_BPLINE;
 
-       assert(man_macros[tok].fp);
+       /* Call to handler... */
 
+       assert(man_macros[tok].fp);
        if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &i, buf))
                goto err;
 
@@ -592,15 +601,13 @@ out:
        /*
         * We weren't in a block-line scope when entering the
         * above-parsed macro, so return.
-        *
-        * FIXME: this prohibits the nesting of blocks (e.g., `de' and
-        * family) within BLINE or ELINE systems.  This is annoying.
         */
 
-       if ( ! (MAN_BLINE & fl)) {
+       if ( ! (MAN_BPLINE & m->flags)) {
                m->flags &= ~MAN_ILINE;
                return(1);
        }
+       m->flags &= ~MAN_BPLINE;
 
        /*
         * If we're in a block scope, then allow this macro to slip by
index f8f892b..3049a68 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man_macro.c,v 1.40 2010/03/27 10:14:32 kristaps Exp $ */
+/*     $Id: man_macro.c,v 1.42 2010/03/29 10:10:35 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -311,19 +311,13 @@ blk_dotted(MACRO_PROT_ARGS)
                return(0);
 
        /*
-        * XXX: manually adjust our next-line status.  roff macros are,
-        * for the moment, ignored, so we don't want to close out bodies
-        * and so on.
+        * Restore flags set when we got here and also stipulate that we
+        * don't post-process the line when exiting the macro op
+        * function in man_pmacro().  See blk_exp().
         */
 
-       switch (m->last->type) {
-       case (MAN_BODY):
-               m->next = MAN_NEXT_CHILD;
-               break;
-       default:
-               break;
-       }
-
+       m->flags = m->svflags | MAN_ILINE;
+       m->next = m->svnext;
        return(1);
 }
 
@@ -381,6 +375,17 @@ blk_exp(MACRO_PROT_ARGS)
                        return(0);
                if ( ! rew_scope(MAN_BLOCK, m, tok))
                        return(0);
+       } else {
+               /*
+                * Save our state and next-scope indicator; we restore
+                * it when exiting from the roff instruction block.  See
+                * blk_dotted().
+                */
+               m->svflags = m->flags;
+               m->svnext = m->next;
+
+               /* Make sure we drop any line modes. */
+               m->flags = 0;
        }
 
        if ( ! man_block_alloc(m, line, ppos, tok))
index 416a73e..3f245bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man_validate.c,v 1.32 2010/03/27 10:04:56 kristaps Exp $ */
+/*     $Id: man_validate.c,v 1.33 2010/03/29 10:10:35 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -55,7 +55,7 @@ static        v_check   posts_part[] = { check_part, NULL };
 static v_check   posts_sec[] = { check_sec, NULL };
 static v_check   posts_le1[] = { check_le1, NULL };
 static v_check   pres_bline[] = { check_bline, NULL };
-static v_check   pres_roff[] = { check_bline, check_roff, NULL };
+static v_check   pres_roff[] = { check_roff, NULL };
 
 static const struct man_valid man_valids[MAN_MAX] = {
        { NULL, posts_eq0 }, /* br */
index eff7132..b2174b6 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $Id: mandoc.1,v 1.54 2010/03/27 10:10:10 kristaps Exp $
+.\"    $Id: mandoc.1,v 1.56 2010/03/29 10:10:35 kristaps Exp $
 .\"
 .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd March 27, 2010
+.Dd March 30, 2010
 .Dt MANDOC 1
 .Os
 .
@@ -220,7 +220,8 @@ and
 .Fl f Ns Ar no-ign-chars .
 .
 .It Fl f Ns Ar ign-errors
-Don't halt when encountering parse errors.  Useful with
+When parsing multiple files, don't halt when one errors out.  Useful
+with
 .Fl T Ns Ar lint
 over a large set of manuals passed on the command line.
 .El
index 846c55e..1dfaef3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_argv.c,v 1.33 2010/01/01 17:14:29 kristaps Exp $ */
+/*     $Id: mdoc_argv.c,v 1.34 2010/03/29 19:28:04 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -397,9 +397,9 @@ args(struct mdoc *m, int line, int *pos,
         * follows the pattern of [[::delim::][ ]+]+.
         */
 
-       if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
+       if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos]) > 1) {
                for (i = *pos; buf[i]; ) {
-                       if ( ! mdoc_iscdelim(buf[i]))
+                       if ( mdoc_iscdelim(buf[i]) < 2)
                                break;
                        i++;
                        if (0 == buf[i] || ' ' != buf[i])
index 3d862fe..c74be2b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_html.c,v 1.54 2010/01/30 08:42:20 kristaps Exp $ */
+/*     $Id: mdoc_html.c,v 1.55 2010/03/29 19:28:04 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -196,7 +196,7 @@ static      const struct htmlmdoc mdocs[MDOC_MAX] = {
        {NULL, NULL}, /* Dc */
        {mdoc_dq_pre, mdoc_dq_post}, /* Do */
        {mdoc_dq_pre, mdoc_dq_post}, /* Dq */
-       {NULL, NULL}, /* Ec */
+       {NULL, NULL}, /* Ec */ /* FIXME: no space */
        {NULL, NULL}, /* Ef */
        {mdoc_em_pre, NULL}, /* Em */
        {NULL, NULL}, /* Eo */
index 88383f5..7e17b52 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_macro.c,v 1.42 2010/02/17 19:28:11 kristaps Exp $ */
+/*     $Id: mdoc_macro.c,v 1.46 2010/03/30 08:24:01 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -710,6 +710,7 @@ in_line(MACRO_PROT_ARGS)
         * Whether we allow ignored elements (those without content,
         * usually because of reserved words) to squeak by.
         */
+
        switch (tok) {
        case (MDOC_An):
                /* FALLTHROUGH */
@@ -831,8 +832,8 @@ in_line(MACRO_PROT_ARGS)
         * If no elements have been collected and we're allowed to have
         * empties (nc), open a scope and close it out.  Otherwise,
         * raise a warning.
-        *
         */
+
        if (nc && 0 == cnt) {
                if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
                        return(0);
@@ -853,25 +854,12 @@ in_line(MACRO_PROT_ARGS)
 static int
 blk_full(MACRO_PROT_ARGS)
 {
-       int               c, lastarg, reopen, dohead;
+       int               c, la;
        struct mdoc_arg  *arg;
+       struct mdoc_node *head; /* save of head macro */
        char             *p;
 
-       /*
-        * Whether to process a block-head section.  If this is
-        * non-zero, then a head will be opened for all line arguments.
-        * If not, then the head will always be empty and only a body
-        * will be opened, which will stay open at the eoln.
-        */
-
-       switch (tok) {
-       case (MDOC_Nd):
-               dohead = 0;
-               break;
-       default:
-               dohead = 1;
-               break;
-       }
+       /* Close out prior implicit scope. */
 
        if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
                if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
@@ -880,12 +868,21 @@ blk_full(MACRO_PROT_ARGS)
                        return(0);
        }
 
+       /*
+        * This routine accomodates implicitly- and explicitly-scoped
+        * macro openings.  Implicit ones first close out prior scope
+        * (seen above).  Delay opening the head until necessary to
+        * allow leading punctuation to print.  Special consideration
+        * for `It -column', which has phrase-part syntax instead of
+        * regular child nodes.
+        */
+
        for (arg = NULL;; ) {
-               lastarg = *pos;
+               la = *pos;
                c = mdoc_argv(m, line, tok, &arg, pos, buf);
 
                if (ARGV_WORD == c) {
-                       *pos = lastarg;
+                       *pos = la;
                        break;
                }
 
@@ -901,72 +898,84 @@ blk_full(MACRO_PROT_ARGS)
        if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
                return(0);
 
-       if (0 == buf[*pos]) {
+       head = NULL;
+
+       /*
+        * The `Nd' macro has all arguments in its body: it's a hybrid
+        * of block partial-explicit and full-implicit.  Stupid.
+        */
+
+       if (MDOC_Nd == tok) {
                if ( ! mdoc_head_alloc(m, line, ppos, tok))
                        return(0);
+               head = m->last;
                if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                        return(0);
                if ( ! mdoc_body_alloc(m, line, ppos, tok))
                        return(0);
-               return(1);
        }
 
-       if ( ! mdoc_head_alloc(m, line, ppos, tok))
+       for (;;) {
+               la = *pos;
+               c = mdoc_args(m, line, pos, buf, tok, &p);
+
+               if (ARGS_ERROR == c)
                return(0);
+               if (ARGS_EOLN == c)
+                       break;
 
-       /* Immediately close out head and enter body, if applicable. */
+               /* Don't emit leading punct. for phrases. */
 
-       if (0 == dohead) {
-               if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-                       return(0);
-               if ( ! mdoc_body_alloc(m, line, ppos, tok))
-                       return(0);
+               if (NULL == head && ARGS_PHRASE != c &&
+                               1 == mdoc_isdelim(p)) {
+                       if ( ! mdoc_word_alloc(m, line, la, p))
+                               return(0);
+                       continue;
        }
 
-       for (reopen = 0;; ) {
-               lastarg = *pos;
-               c = mdoc_args(m, line, pos, buf, tok, &p);
+               /* Always re-open head for phrases. */
 
-               if (ARGS_ERROR == c)
-                       return(0);
-               if (ARGS_EOLN == c)
-                       break;
-               if (ARGS_PHRASE == c) {
-                       assert(dohead);
-                       if (reopen && ! mdoc_head_alloc(m, line, ppos, tok))
+               if (NULL == head || ARGS_PHRASE == c) {
+                       if ( ! mdoc_head_alloc(m, line, ppos, tok))
                                return(0);
-                       /*
-                        * Phrases are self-contained macro phrases used
-                        * in the columnar output of a macro. They need
-                        * special handling.
-                        */
-                       if ( ! phrase(m, line, lastarg, buf))
+                       head = m->last;
+               }
+
+               if (ARGS_PHRASE == c) {
+                       if ( ! phrase(m, line, la, buf))
                                return(0);
                        if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                                return(0);
-
-                       reopen = 1;
                        continue;
                }
 
-               if (MDOC_MAX == (c = lookup(tok, p))) {
-                       if ( ! mdoc_word_alloc(m, line, lastarg, p))
+               c = lookup(tok, p);
+               if (MDOC_MAX != c) {
+                       if ( ! mdoc_macro(m, c, line, la, pos, buf))
                                return(0);
-                       continue;
+                       break;
                }
+               if ( ! mdoc_word_alloc(m, line, la, p))
+                       return(0);
+
+       }
 
-               if ( ! mdoc_macro(m, c, line, lastarg, pos, buf))
+       if (NULL == head) {
+               if ( ! mdoc_head_alloc(m, line, ppos, tok))
                        return(0);
-               break;
+               head = m->last;
        }
 
        if (1 == ppos && ! append_delims(m, line, pos, buf))
                return(0);
 
-       /* If the body's already open, then just return. */
-       if (0 == dohead)
+       /* See notes on `Nd' hybrid, above. */
+
+       if (MDOC_Nd == tok)
                return(1);
 
+       /* Close out scopes to remain in a consistent state. */
+
        if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                return(0);
        if ( ! mdoc_body_alloc(m, line, ppos, tok))
@@ -981,59 +990,92 @@ blk_part_imp(MACRO_PROT_ARGS)
 {
        int               la, c;
        char             *p;
-       struct mdoc_node *blk, *body, *n;
+       struct mdoc_node *blk; /* saved block context */
+       struct mdoc_node *body; /* saved body context */
+       struct mdoc_node *n;
 
-       /* If applicable, close out prior scopes. */
+       /*
+        * A macro that spans to the end of the line.  This is generally
+        * (but not necessarily) called as the first macro.  The block
+        * has a head as the immediate child, which is always empty,
+        * followed by zero or more opening punctuation nodes, then the
+        * body (which may be empty, depending on the macro), then zero
+        * or more closing punctuation nodes.
+        */
 
        if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
                return(0);
-       /* Saved for later close-out. */
+
        blk = m->last;
+
        if ( ! mdoc_head_alloc(m, line, ppos, tok))
                return(0);
        if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                return(0);
-       if ( ! mdoc_body_alloc(m, line, ppos, tok))
-               return(0);
-       /* Saved for later close-out. */
-       body = m->last;
 
-       /* Body argument processing. */
+       /*
+        * Open the body scope "on-demand", that is, after we've
+        * processed all our the leading delimiters (open parenthesis,
+        * etc.).
+        */
 
-       for (;;) {
+       for (body = NULL; ; ) {
                la = *pos;
                c = mdoc_args(m, line, pos, buf, tok, &p);
+
                assert(ARGS_PHRASE != c);
 
                if (ARGS_ERROR == c)
                        return(0);
-               if (ARGS_PUNCT == c)
-                       break;
                if (ARGS_EOLN == c)
                        break;
+               if (ARGS_PUNCT == c)
+                       break;
 
-               if (MDOC_MAX == (c = lookup(tok, p))) {
+               if (NULL == body && 1 == mdoc_isdelim(p)) {
                        if ( ! mdoc_word_alloc(m, line, la, p))
                                return(0);
                        continue;
                }
 
-               if ( ! mdoc_macro(m, c, line, la, pos, buf))
+               if (NULL == body) {
+                      if ( ! mdoc_body_alloc(m, line, ppos, tok))
+                              return(0);
+                       body = m->last;
+               }
+
+               if (MDOC_MAX != (c = lookup(tok, p))) {
+                       if ( ! mdoc_macro(m, c, line, la, pos, buf))
+                               return(0);
+                       break;
+               }
+
+               if ( ! mdoc_word_alloc(m, line, la, p))
                        return(0);
-               break;
+       }
+
+       /* Clean-ups to leave in a consistent state. */
+
+       if (NULL == body) {
+               if ( ! mdoc_body_alloc(m, line, ppos, tok))
+                       return(0);
+               body = m->last;
        }
 
        /*
         * If we can't rewind to our body, then our scope has already
         * been closed by another macro (like `Oc' closing `Op').  This
         * is ugly behaviour nodding its head to OpenBSD's overwhelming
-        * crufty use of `Op' breakage--XXX, deprecate in time.
+        * crufty use of `Op' breakage.  XXX: DEPRECATE.
         */
+
        for (n = m->last; n; n = n->parent)
                if (body == n)
                        break;
+
        if (NULL == n && ! mdoc_nwarn(m, body, EIMPBRK))
                return(0);
+
        if (n && ! rew_last(m, body))
                return(0);
 
@@ -1054,59 +1096,23 @@ blk_part_imp(MACRO_PROT_ARGS)
 static int
 blk_part_exp(MACRO_PROT_ARGS)
 {
-       int               la, flushed, j, c, maxargs;
+       int               la, c;
+       struct mdoc_node *head; /* keep track of head */
+       struct mdoc_node *body; /* keep track of body */
        char             *p;
 
-       /* Number of head arguments.  Only `Eo' has these, */
-
-       switch (tok) {
-       case (MDOC_Eo):
-               maxargs = 1;
-               break;
-       default:
-               maxargs = 0;
-               break;
-       }
-
-       /* Begin the block scope. */
-
-       if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
-               return(0);
-
        /*
-        * If no head arguments, open and then close out a head, noting
-        * that we've flushed our terms.  `flushed' means that we've
-        * flushed out the head and the body is open.
+        * The opening of an explicit macro having zero or more leading
+        * punctuation nodes; a head with optional single element (the
+        * case of `Eo'); and a body that may be empty.
         */
 
-       if (0 == maxargs) {
-               if ( ! mdoc_head_alloc(m, line, ppos, tok))
-                       return(0);
-               if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-                       return(0);
-               if ( ! mdoc_body_alloc(m, line, ppos, tok))
-                       return(0);
-               flushed = 1;
-       } else {
-               if ( ! mdoc_head_alloc(m, line, ppos, tok))
-                       return(0);
-               flushed = 0;
-       }
-
-       /* Process the head/head+body line arguments. */
+       if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
+               return(0);
 
-       for (j = 0; ; j++) {
+       for (head = body = NULL; ; ) {
                la = *pos;
-               if (j == maxargs && ! flushed) {
-                       if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-                               return(0);
-                       flushed = 1;
-                       if ( ! mdoc_body_alloc(m, line, ppos, tok))
-                               return(0);
-               }
-
                c = mdoc_args(m, line, pos, buf, tok, &p);
-               assert(ARGS_PHRASE != c);
 
                if (ARGS_ERROR == c)
                        return(0);
@@ -1115,44 +1121,79 @@ blk_part_exp(MACRO_PROT_ARGS)
                if (ARGS_EOLN == c)
                        break;
 
-               if (MDOC_MAX != (c = lookup(tok, p))) {
-                       if ( ! flushed) {
-                               if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-                                       return(0);
-                               flushed = 1;
-                               if ( ! mdoc_body_alloc(m, line, ppos, tok))
-                                       return(0);
-                       }
-                       if ( ! mdoc_macro(m, c, line, la, pos, buf))
+               assert(ARGS_PHRASE != c);
+
+               /* Flush out leading punctuation. */
+
+               if (NULL == head && 1 == mdoc_isdelim(p)) {
+                       assert(NULL == body);
+                       if ( ! mdoc_word_alloc(m, line, la, p))
                                return(0);
-                       break;
+                       continue;
+               }
+
+               if (NULL == head) {
+                       assert(NULL == body);
+                       if ( ! mdoc_head_alloc(m, line, ppos, tok))
+                               return(0);
+                       head = m->last;
                }
 
-               if ( ! flushed && mdoc_isdelim(p)) {
+               /*
+                * `Eo' gobbles any data into the head, but most other
+                * macros just immediately close out and begin the body.
+                */
+
+               if (NULL == body) {
+                       assert(head);
+                       /* No check whether it's a macro! */
+                       if (MDOC_Eo == tok)
+                               if ( ! mdoc_word_alloc(m, line, la, p))
+                                       return(0);
+
                        if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                                return(0);
-                       flushed = 1;
                        if ( ! mdoc_body_alloc(m, line, ppos, tok))
                                return(0);
+                       body = m->last;
+
+                       if (MDOC_Eo == tok)
+                               continue;
+               }
+
+               assert(NULL != head && NULL != body);
+
+               if (MDOC_MAX != (c = lookup(tok, p))) {
+                       if ( ! mdoc_macro(m, c, line, la, pos, buf))
+                               return(0);
+                       break;
                }
 
                if ( ! mdoc_word_alloc(m, line, la, p))
                        return(0);
        }
 
-       /* Close the head and open the body, if applicable. */
+       /* Clean-up to leave in a consistent state. */
+
+       if (NULL == head) {
+               if ( ! mdoc_head_alloc(m, line, ppos, tok))
+                       return(0);
+               head = m->last;
+       }
 
-       if ( ! flushed) {
+       if (NULL == body) {
                if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
                        return(0);
                if ( ! mdoc_body_alloc(m, line, ppos, tok))
                        return(0);
+               body = m->last;
        }
 
        /* Standard appending of delimiters. */
 
        if (ppos > 1)
                return(1);
+
        return(append_delims(m, line, pos, buf));
 }
 
@@ -1164,7 +1205,13 @@ in_line_argn(MACRO_PROT_ARGS)
        struct mdoc_arg  *arg;
        char             *p;
 
-       /* Fixed maximum arguments per macro, if applicable. */
+       /*
+        * A line macro that has a fixed number of arguments (maxargs).
+        * Only open the scope once the first non-leading-punctuation is
+        * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
+        * keep it open until the maximum number of arguments are
+        * exhausted.
+        */
 
        switch (tok) {
        case (MDOC_Ap):
@@ -1184,8 +1231,6 @@ in_line_argn(MACRO_PROT_ARGS)
                break;
        }
 
-       /* Macro argument processing. */
-
        for (arg = NULL;; ) {
                la = *pos;
                c = mdoc_argv(m, line, tok, &arg, pos, buf);
@@ -1204,22 +1249,8 @@ in_line_argn(MACRO_PROT_ARGS)
                return(0);
        }
 
-       /* Open the element scope. */
-
-       if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
-               return(0);
-
-       /* Process element arguments. */
-
-       for (flushed = j = 0; ; j++) {
+       for (flushed = j = 0; ; ) {
                la = *pos;
-
-               if (j == maxargs && ! flushed) {
-                       if ( ! rew_elem(m, tok))
-                               return(0);
-                       flushed = 1;
-               }
-
                c = mdoc_args(m, line, pos, buf, tok, &p);
 
                if (ARGS_ERROR == c)
@@ -1229,12 +1260,28 @@ in_line_argn(MACRO_PROT_ARGS)
                if (ARGS_EOLN == c)
                        break;
 
+               if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
+                               0 == j && 1 == mdoc_isdelim(p)) {
+                       if ( ! mdoc_word_alloc(m, line, la, p))
+                               return(0);
+                       continue;
+               } else if (0 == j)
+                      if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
+                              return(0);
+
+               if (j == maxargs && ! flushed) {
+                       if ( ! rew_elem(m, tok))
+                               return(0);
+                       flushed = 1;
+               }
+
                if (MDOC_MAX != (c = lookup(tok, p))) {
                        if ( ! flushed && ! rew_elem(m, tok))
                                return(0);
                        flushed = 1;
                        if ( ! mdoc_macro(m, c, line, la, pos, buf))
                                return(0);
+                       j++;
                        break;
                }
 
@@ -1251,18 +1298,25 @@ in_line_argn(MACRO_PROT_ARGS)
                 * ideally be deprecated behaviour, but because this is
                 * code is no here, it's unlikely to be removed.
                 */
+
+#ifdef __OpenBSD__
                if (MDOC_Xr == tok && j == maxargs) {
-                       if ( ! mdoc_elem_alloc(m, line, ppos, MDOC_Ns, NULL))
+                       if ( ! mdoc_elem_alloc(m, line, la, MDOC_Ns, NULL))
                                return(0);
                        if ( ! rew_elem(m, MDOC_Ns))
                                return(0);
                }
+#endif
 
                if ( ! mdoc_word_alloc(m, line, la, p))
                        return(0);
+               j++;
        }
 
-       /* Close out and append delimiters. */
+       if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
+              return(0);
+
+       /* Close out in a consistent state. */
 
        if ( ! flushed && ! rew_elem(m, tok))
                return(0);
index 438433b..a137941 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_strings.c,v 1.14 2010/01/01 17:14:30 kristaps Exp $ */
+/*     $Id: mdoc_strings.c,v 1.15 2010/03/29 19:28:04 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -64,6 +64,12 @@ mdoc_iscdelim(char p)
        switch (p) {
        case('|'):
                /* FALLTHROUGH */
+       case('('):
+               /* FALLTHROUGH */
+       case('['):
+               /* FALLTHROUGH */
+       case('{'):
+               return(1);
        case('.'):
                /* FALLTHROUGH */
        case(','):
@@ -76,18 +82,12 @@ mdoc_iscdelim(char p)
                /* FALLTHROUGH */
        case('!'):
                /* FALLTHROUGH */
-       case('('):
-               /* FALLTHROUGH */
        case(')'):
                /* FALLTHROUGH */
-       case('['):
-               /* FALLTHROUGH */
        case(']'):
                /* FALLTHROUGH */
-       case('{'):
-               /* FALLTHROUGH */
        case('}'):
-               return(1);
+               return(2);
        default:
                break;
        }
index 4835fcd..b29b025 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_term.c,v 1.111 2010/03/23 12:42:22 kristaps Exp $ */
+/*     $Id: mdoc_term.c,v 1.112 2010/03/29 19:28:04 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -199,7 +199,7 @@ static      const struct termact termacts[MDOC_MAX] = {
        { NULL, NULL }, /* Dc */
        { termp_dq_pre, termp_dq_post }, /* Do */
        { termp_dq_pre, termp_dq_post }, /* Dq */
-       { NULL, NULL }, /* Ec */
+       { NULL, NULL }, /* Ec */ /* FIXME: no space */
        { NULL, NULL }, /* Ef */
        { termp_under_pre, NULL }, /* Em */
        { NULL, NULL }, /* Eo */