]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_term.c
libmdoc accepts whitespace following control character.
[mandoc.git] / mdoc_term.c
index 0b324ccdd1fb7f55ed5f98d98a1a61ac949ea0da..52d770b8e147d386241bb3bcf327089347ccc12a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_term.c,v 1.58 2009/07/23 08:36:32 kristaps Exp $ */
+/*     $Id: mdoc_term.c,v 1.66 2009/08/10 10:09:51 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -26,6 +26,9 @@
 #include "term.h"
 #include "mdoc.h"
 
+#define        INDENT            5
+#define        HALFINDENT        3
+
 /* FIXME: macro arguments can be escaped. */
 
 #define        TTYPE_PROG        0
@@ -98,6 +101,7 @@ struct       termact {
 };
 
 static void      termp____post(DECL_ARGS);
+static void      termp_an_post(DECL_ARGS);
 static void      termp_aq_post(DECL_ARGS);
 static void      termp_bd_post(DECL_ARGS);
 static void      termp_bl_post(DECL_ARGS);
@@ -124,6 +128,7 @@ static      void      termp_vt_post(DECL_ARGS);
 
 static int       termp__j_pre(DECL_ARGS);
 static int       termp__t_pre(DECL_ARGS);
+static int       termp_an_pre(DECL_ARGS);
 static int       termp_ap_pre(DECL_ARGS);
 static int       termp_aq_pre(DECL_ARGS);
 static int       termp_ar_pre(DECL_ARGS);
@@ -191,7 +196,7 @@ static const struct termact termacts[MDOC_MAX] = {
        { NULL, NULL }, /* El */
        { termp_it_pre, termp_it_post }, /* It */
        { NULL, NULL }, /* Ad */ 
-       { NULL, NULL }, /* An */
+       { termp_an_pre, termp_an_post }, /* An */
        { termp_ar_pre, NULL }, /* Ar */
        { termp_cd_pre, NULL }, /* Cd */
        { termp_cm_pre, NULL }, /* Cm */
@@ -670,8 +675,9 @@ fmt_block_vspace(struct termp *p,
 
        term_newln(p);
 
-       if (arg_hasattr(MDOC_Compact, bl))
+       if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Compact, bl))
                return;
+       assert(node);
 
        /*
         * Search through our prior nodes.  If we follow a `Ss' or `Sh',
@@ -695,7 +701,7 @@ fmt_block_vspace(struct termp *p,
         * within the list.
         */
 
-       if (arg_hasattr(MDOC_Column, bl))
+       if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Column, bl))
                if (node->prev && MDOC_It == node->prev->tok)
                        return;
 
@@ -703,7 +709,7 @@ fmt_block_vspace(struct termp *p,
         * XXX - not documented: a `-diag' without a body does not
         * assert a vspace prior to the next element. 
         */
-       if (arg_hasattr(MDOC_Diag, bl)) 
+       if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Diag, bl)) 
                if (node->prev && MDOC_It == node->prev->tok) {
                        assert(node->prev->body);
                        if (NULL == node->prev->body->child)
@@ -856,7 +862,8 @@ termp_it_pre(DECL_ARGS)
 
        switch (type) {
        case (MDOC_Diag):
-               term_word(p, "\\ \\ ");
+               if (MDOC_BODY == node->type)
+                       term_word(p, "\\ \\ ");
                break;
        case (MDOC_Inset):
                if (MDOC_BODY == node->type) 
@@ -908,7 +915,21 @@ termp_it_pre(DECL_ARGS)
                else
                        p->flags |= TERMP_NOLPAD;
 
-               if (MDOC_HEAD == node->type)
+               if (MDOC_HEAD != node->type)
+                       break;
+
+               /*
+                * This is ugly.  If `-hang' is specified and the body
+                * is a `Bl' or `Bd', then we want basically to nullify
+                * the "overstep" effect in term_flushln() and treat
+                * this as a `-ohang' list instead.
+                */
+               if (node->next->child && 
+                               (MDOC_Bl == node->next->child->tok ||
+                                MDOC_Bd == node->next->child->tok)) {
+                       p->flags &= ~TERMP_NOBREAK;
+                       p->flags &= ~TERMP_NOLPAD;
+               } else
                        p->flags |= TERMP_HANG;
                break;
        case (MDOC_Tag):
@@ -950,6 +971,17 @@ termp_it_pre(DECL_ARGS)
        p->offset += offset;
 
        switch (type) {
+       case (MDOC_Hang):
+               /*
+                * Same stipulation as above, regarding `-hang'.  We
+                * don't want to recalculate rmargin and offsets when
+                * using `Bd' or `Bl' within `-hang' overstep lists.
+                */
+               if (MDOC_HEAD == node->type && node->next->child &&
+                               (MDOC_Bl == node->next->child->tok || 
+                                MDOC_Bd == node->next->child->tok))
+                       break;
+               /* FALLTHROUGH */
        case (MDOC_Bullet):
                /* FALLTHROUGH */
        case (MDOC_Dash):
@@ -958,8 +990,6 @@ termp_it_pre(DECL_ARGS)
                /* FALLTHROUGH */
        case (MDOC_Hyphen):
                /* FALLTHROUGH */
-       case (MDOC_Hang):
-               /* FALLTHROUGH */
        case (MDOC_Tag):
                assert(width);
                if (MDOC_HEAD == node->type)
@@ -1105,6 +1135,65 @@ termp_fl_pre(DECL_ARGS)
 }
 
 
+/* ARGSUSED */
+static int
+termp_an_pre(DECL_ARGS)
+{
+
+       if (NULL == node->child)
+               return(1);
+
+       /*
+        * XXX: this is poorly documented.  If not in the AUTHORS
+        * section, `An -split' will cause newlines to occur before the
+        * author name.  If in the AUTHORS section, by default, the
+        * first `An' invocation is nosplit, then all subsequent ones,
+        * regardless of whether interspersed with other macros/text,
+        * are split.  -split, in this case, will override the condition
+        * of the implied first -nosplit.
+        */
+       
+       if (node->sec == SEC_AUTHORS) {
+               if ( ! (TERMP_ANPREC & p->flags)) {
+                       if (TERMP_SPLIT & p->flags)
+                               term_newln(p);
+                       return(1);
+               }
+               if (TERMP_NOSPLIT & p->flags)
+                       return(1);
+               term_newln(p);
+               return(1);
+       }
+
+       if (TERMP_SPLIT & p->flags)
+               term_newln(p);
+
+       return(1);
+}
+
+
+/* ARGSUSED */
+static void
+termp_an_post(DECL_ARGS)
+{
+
+       if (node->child) {
+               if (SEC_AUTHORS == node->sec)
+                       p->flags |= TERMP_ANPREC;
+               return;
+       }
+
+       if (arg_getattr(MDOC_Split, node) > -1) {
+               p->flags &= ~TERMP_NOSPLIT;
+               p->flags |= TERMP_SPLIT;
+       } else {
+               p->flags &= ~TERMP_SPLIT;
+               p->flags |= TERMP_NOSPLIT;
+       }
+
+}
+
+
 /* ARGSUSED */
 static int
 termp_ar_pre(DECL_ARGS)
@@ -1312,10 +1401,18 @@ termp_fd_post(DECL_ARGS)
 static int
 termp_sh_pre(DECL_ARGS)
 {
-
+       /* 
+        * XXX: undocumented: using two `Sh' macros in sequence has no
+        * vspace between calls, only a newline.
+        */
        switch (node->type) {
-       case (MDOC_HEAD):
+       case (MDOC_BLOCK):
+               if (node->prev && MDOC_Sh == node->prev->tok)
+                       if (NULL == node->prev->body->child)
+                               break;
                term_vspace(p);
+               break;
+       case (MDOC_HEAD):
                pair->flag |= ttypes[TTYPE_SECTION];
                break;
        case (MDOC_BODY):
@@ -1559,7 +1656,7 @@ termp_va_pre(DECL_ARGS)
 static int
 termp_bd_pre(DECL_ARGS)
 {
-       int              i, type, ln;
+       int              i, type;
 
        /*
         * This is fairly tricky due primarily to crappy documentation.
@@ -1578,12 +1675,9 @@ termp_bd_pre(DECL_ARGS)
        } else if (MDOC_BODY != node->type)
                return(1);
 
-       /* FIXME: display type should be mandated by parser. */
+       assert(node->parent->args);
 
-       if (NULL == node->parent->args)
-               errx(1, "missing display type");
-
-       for (type = -1, i = 0; 
+       for (type = -1, i = 0; -1 == type && 
                        i < (int)node->parent->args->argc; i++) {
                switch (node->parent->args->argv[i].arg) {
                case (MDOC_Ragged):
@@ -1594,22 +1688,17 @@ termp_bd_pre(DECL_ARGS)
                        /* FALLTHROUGH */
                case (MDOC_Literal):
                        type = node->parent->args->argv[i].arg;
-                       i = (int)node->parent->args->argc;
                        break;
                default:
                        break;
                }
        }
-
-       if (NULL == node->parent->args)
-               errx(1, "missing display type");
+       
+       assert(type > -1);
 
        i = arg_getattr(MDOC_Offset, node->parent);
-       if (-1 != i) {
-               if (1 != node->parent->args->argv[i].sz)
-                       errx(1, "expected single value");
+       if (-1 != i)
                p->offset += arg_offset(&node->parent->args->argv[i]);
-       }
 
        switch (type) {
        case (MDOC_Literal):
@@ -1620,21 +1709,11 @@ termp_bd_pre(DECL_ARGS)
                return(1);
        }
 
-       /*
-        * Tricky.  Iterate through all children.  If we're on a
-        * different parse line, append a newline and then the contents.
-        * Ew.
-        */
-
-       ln = node->child ? node->child->line : 0;
-
        for (node = node->child; node; node = node->next) {
-               if (ln < node->line) {
-                       term_flushln(p);
-                       p->flags |= TERMP_NOSPACE;
-               }
-               ln = node->line;
+               p->flags |= TERMP_NOSPACE;
                print_node(p, pair, meta, node);
+               if (node->next)
+                       term_flushln(p);
        }
 
        return(0);
@@ -1648,6 +1727,7 @@ termp_bd_post(DECL_ARGS)
 
        if (MDOC_BODY != node->type) 
                return;
+       p->flags |= TERMP_NOSPACE;
        term_flushln(p);
 }