]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_term.c
Fixed `Bd' prior vertical space (was ignoring -compact).
[mandoc.git] / mdoc_term.c
index d1ed5135f1548124109a4e51b0b4945aee806233..4c0c8af632c1e5e734d98b431daec8dc31f0d193 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_term.c,v 1.69 2009/09/15 08:16:20 kristaps Exp $ */
+/*     $Id: mdoc_term.c,v 1.85 2009/09/26 17:35:49 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
 #include "term.h"
 #include "mdoc.h"
 
+/* FIXME: check HANG lists: they seem to be broken... :
+ * .Bl -hang -width Ds
+ * .It a
+ * b
+ * .It Fl f Ns Ar option...
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * .
+ * .It a sasd fasd as afsd sfad sfds sadfs sd sfd ssfad asfd
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * Override default compiler behaviour.  See
+ * .Sx Compiler Options
+ * for details.
+ * .El
+ *
+ */
+
 #define        INDENT            5
 #define        HALFINDENT        3
 
@@ -71,6 +106,7 @@ static       void      termp_sq_post(DECL_ARGS);
 static void      termp_ss_post(DECL_ARGS);
 static void      termp_vt_post(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);
@@ -78,7 +114,6 @@ static       int       termp_bd_pre(DECL_ARGS);
 static int       termp_bf_pre(DECL_ARGS);
 static int       termp_bold_pre(DECL_ARGS);
 static int       termp_bq_pre(DECL_ARGS);
-static int       termp_br_pre(DECL_ARGS);
 static int       termp_brq_pre(DECL_ARGS);
 static int       termp_bt_pre(DECL_ARGS);
 static int       termp_cd_pre(DECL_ARGS);
@@ -98,7 +133,6 @@ static       int       termp_nm_pre(DECL_ARGS);
 static int       termp_ns_pre(DECL_ARGS);
 static int       termp_op_pre(DECL_ARGS);
 static int       termp_pf_pre(DECL_ARGS);
-static int       termp_pp_pre(DECL_ARGS);
 static int       termp_pq_pre(DECL_ARGS);
 static int       termp_qq_pre(DECL_ARGS);
 static int       termp_rs_pre(DECL_ARGS);
@@ -113,14 +147,14 @@ static    int       termp_ud_pre(DECL_ARGS);
 static int       termp_xr_pre(DECL_ARGS);
 static int       termp_xx_pre(DECL_ARGS);
 
-static const struct termact termacts[MDOC_MAX] = {
+static const struct termact termacts[MDOC_MAX] = {
        { termp_ap_pre, NULL }, /* Ap */
        { NULL, NULL }, /* Dd */
        { NULL, NULL }, /* Dt */
        { NULL, NULL }, /* Os */
        { termp_sh_pre, termp_sh_post }, /* Sh */
        { termp_ss_pre, termp_ss_post }, /* Ss */ 
-       { termp_pp_pre, NULL }, /* Pp */ 
+       { termp_sp_pre, NULL }, /* Pp */ 
        { termp_d1_pre, termp_d1_post }, /* D1 */
        { termp_d1_pre, termp_d1_post }, /* Dl */
        { termp_bd_pre, termp_bd_post }, /* Bd */
@@ -153,18 +187,18 @@ static const struct termact termacts[MDOC_MAX] = {
        { termp_rv_pre, NULL }, /* Rv */
        { NULL, NULL }, /* St */ 
        { termp_under_pre, NULL }, /* Va */
-       { termp_under_pre, termp_vt_post }, /* Vt */  /* FIXME: type name */
+       { termp_under_pre, termp_vt_post }, /* Vt */
        { termp_xr_pre, NULL }, /* Xr */
        { NULL, termp____post }, /* %A */
-       { NULL, termp____post }, /* %B */
+       { termp_under_pre, termp____post }, /* %B */
        { NULL, termp____post }, /* %D */
-       { NULL, termp____post }, /* %I */
+       { termp_under_pre, termp____post }, /* %I */
        { termp_under_pre, termp____post }, /* %J */
        { NULL, termp____post }, /* %N */
        { NULL, termp____post }, /* %O */
        { NULL, termp____post }, /* %P */
        { NULL, termp____post }, /* %R */
-       { termp_under_pre, termp____post }, /* %T */
+       { termp__t_pre, termp____post }, /* %T */
        { NULL, termp____post }, /* %V */
        { NULL, NULL }, /* Ac */
        { termp_aq_pre, termp_aq_post }, /* Ao */
@@ -185,7 +219,7 @@ static const struct termact termacts[MDOC_MAX] = {
        { termp_under_pre, NULL }, /* Em */ 
        { NULL, NULL }, /* Eo */
        { termp_xx_pre, NULL }, /* Fx */
-       { termp_bold_pre, NULL }, /* Ms */
+       { termp_bold_pre, NULL }, /* Ms */ /* FIXME: convert to symbol? */
        { NULL, NULL }, /* No */
        { termp_ns_pre, NULL }, /* Ns */
        { termp_xx_pre, NULL }, /* Nx */
@@ -221,18 +255,18 @@ static const struct termact termacts[MDOC_MAX] = {
        { NULL, NULL }, /* Fr */
        { termp_ud_pre, NULL }, /* Ud */
        { NULL, termp_lb_post }, /* Lb */
-       { termp_pp_pre, NULL }, /* Lp */ 
+       { termp_sp_pre, NULL }, /* Lp */ 
        { termp_lk_pre, NULL }, /* Lk */ 
        { termp_under_pre, NULL }, /* Mt */ 
        { termp_brq_pre, termp_brq_post }, /* Brq */ 
        { termp_brq_pre, termp_brq_post }, /* Bro */ 
        { NULL, NULL }, /* Brc */ 
-       { NULL, NULL }, /* %C */ 
-       { NULL, NULL }, /* Es */ 
-       { NULL, NULL }, /* En */ 
+       { NULL, termp____post }, /* %C */ 
+       { NULL, NULL }, /* Es */ /* TODO */
+       { NULL, NULL }, /* En */ /* TODO */
        { termp_xx_pre, NULL }, /* Dx */ 
-       { NULL, NULL }, /* %Q */ 
-       { termp_br_pre, NULL }, /* br */
+       { NULL, termp____post }, /* %Q */ 
+       { termp_sp_pre, NULL }, /* br */
        { termp_sp_pre, NULL }, /* sp */ 
 };
 
@@ -252,27 +286,24 @@ static    void      fmt_block_vspace(struct termp *,
                        const struct mdoc_node *,
                        const struct mdoc_node *);
 static void      print_node(DECL_ARGS);
-static void      print_head(struct termp *, 
-                       const struct mdoc_meta *);
+static void      print_head(DECL_ARGS);
 static void      print_body(DECL_ARGS);
-static void      print_foot(struct termp *, 
-                       const struct mdoc_meta *);
+static void      print_foot(DECL_ARGS);
 
 
-int
-mdoc_run(struct termp *p, const struct mdoc *m)
+void
+mdoc_run(struct termp *p, const struct mdoc *mdoc)
 {
-       /*
-        * Main output function.  When this is called, assume that the
-        * tree is properly formed.
-        */
-       print_head(p, mdoc_meta(m));
-       assert(mdoc_node(m));
-       assert(MDOC_ROOT == mdoc_node(m)->type);
-       if (mdoc_node(m)->child)
-               print_body(p, NULL, mdoc_meta(m), mdoc_node(m)->child);
-       print_foot(p, mdoc_meta(m));
-       return(1);
+       const struct mdoc_node  *n;
+       const struct mdoc_meta  *m;
+
+       n = mdoc_node(mdoc);
+       m = mdoc_meta(mdoc);
+
+       print_head(p, NULL, m, n);
+       if (n->child)
+               print_body(p, NULL, m, n->child);
+       print_foot(p, NULL, m, n);
 }
 
 
@@ -281,64 +312,60 @@ print_body(DECL_ARGS)
 {
 
        print_node(p, pair, meta, node);
-       if ( ! node->next)
-               return;
-       print_body(p, pair, meta, node->next);
+       if (node->next)
+               print_body(p, pair, meta, node->next);
 }
 
 
+/* ARGSUSED */
 static void
 print_node(DECL_ARGS)
 {
-       int              dochild, bold, under;
+       int              chld, bold, under;
        struct termpair  npair;
        size_t           offset, rmargin;
 
-       dochild = 1;
+       chld = 1;
        offset = p->offset;
        rmargin = p->rmargin;
        bold = p->bold;
        under = p->under;
 
+       bzero(&npair, sizeof(struct termpair));
        npair.ppair = pair;
-       npair.flag = 0;
-       npair.count = 0;
-
-       /*
-        * Note on termpair.  This allows a pre function to set a termp
-        * flag that is automatically unset after the body, but before
-        * the post function.  Thus, if a pre uses a termpair flag, it
-        * must be reapplied in the post for use.
-        */
 
        if (MDOC_TEXT != node->type) {
                if (termacts[node->tok].pre)
-                       if ( ! (*termacts[node->tok].pre)(p, &npair, meta, node))
-                               dochild = 0;
-       } else /* MDOC_TEXT == node->type */
+                       chld = (*termacts[node->tok].pre)
+                               (p, &npair, meta, node);
+       } else 
                term_word(p, node->string);
 
-       /* Children. */
-
-       if (dochild && node->child)
+       if (chld && node->child)
                print_body(p, &npair, meta, node->child);
 
+       /*
+        * XXX - if bold/under were to span scopes, this wouldn't be
+        * possible, but because decoration is always in-scope, we can
+        * get away with this.
+        */
+
        p->bold = bold;
        p->under = under;
 
-       /* Post-processing. */
-
        if (MDOC_TEXT != node->type)
                if (termacts[node->tok].post)
-                       (*termacts[node->tok].post)(p, &npair, meta, node);
+                       (*termacts[node->tok].post)
+                               (p, &npair, meta, node);
 
        p->offset = offset;
        p->rmargin = rmargin;
 }
 
 
+/* ARGSUSED */
 static void
-print_foot(struct termp *p, const struct mdoc_meta *meta)
+print_foot(DECL_ARGS)
 {
        struct tm       *tm;
        char            *buf, *os;
@@ -352,14 +379,14 @@ print_foot(struct termp *p, const struct mdoc_meta *meta)
         */
 
        if (NULL == (buf = malloc(p->rmargin)))
-               err(1, "malloc");
+               err(EXIT_FAILURE, "malloc");
        if (NULL == (os = malloc(p->rmargin)))
-               err(1, "malloc");
+               err(EXIT_FAILURE, "malloc");
 
        tm = localtime(&meta->date);
 
        if (0 == strftime(buf, p->rmargin, "%B %e, %Y", tm))
-               err(1, "strftime");
+               err(EXIT_FAILURE, "strftime");
 
        (void)strlcpy(os, meta->os, p->rmargin);
 
@@ -396,8 +423,10 @@ print_foot(struct termp *p, const struct mdoc_meta *meta)
 }
 
 
+/* FIXME: put in utility library. */
+/* ARGSUSED */
 static void
-print_head(struct termp *p, const struct mdoc_meta *meta)
+print_head(DECL_ARGS)
 {
        char            *buf, *title;
 
@@ -405,9 +434,9 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
        p->offset = 0;
 
        if (NULL == (buf = malloc(p->rmargin)))
-               err(1, "malloc");
+               err(EXIT_FAILURE, "malloc");
        if (NULL == (title = malloc(p->rmargin)))
-               err(1, "malloc");
+               err(EXIT_FAILURE, "malloc");
 
        /*
         * The header is strange.  It has three components, which are
@@ -431,8 +460,7 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
                (void)strlcat(buf, ")", p->rmargin);
        }
 
-       (void)snprintf(title, p->rmargin, "%s(%d)", 
-                       meta->title, meta->msec);
+       snprintf(title, p->rmargin, "%s(%d)", meta->title, meta->msec);
 
        p->offset = 0;
        p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
@@ -465,6 +493,7 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
 }
 
 
+/* FIXME: put in utility file for front-ends. */
 static size_t
 arg_width(const struct mdoc_argv *arg, int pos)
 {
@@ -491,6 +520,7 @@ arg_width(const struct mdoc_argv *arg, int pos)
 }
 
 
+/* FIXME: put in utility file for front-ends. */
 static int
 arg_listtype(const struct mdoc_node *n)
 {
@@ -532,6 +562,7 @@ arg_listtype(const struct mdoc_node *n)
 }
 
 
+/* FIXME: put in utility file for front-ends. */
 static size_t
 arg_offset(const struct mdoc_argv *arg)
 {
@@ -608,15 +639,10 @@ fmt_block_vspace(struct termp *p,
        const struct mdoc_node *n;
 
        term_newln(p);
-
-       if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Compact, bl))
+       if (arg_hasattr(MDOC_Compact, bl))
                return;
-       assert(node);
 
-       /*
-        * Search through our prior nodes.  If we follow a `Ss' or `Sh',
-        * then don't vspace.
-        */
+       /* Do not vspace directly after Ss/Sh. */
 
        for (n = node; n; n = n->parent) {
                if (MDOC_BLOCK != n->type)
@@ -630,19 +656,14 @@ fmt_block_vspace(struct termp *p,
                break;
        }
 
-       /* 
-        * XXX - not documented: a `-column' does not ever assert vspace
-        * within the list.
-        */
+       /* A `-column' does not assert vspace within the list. */
 
        if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Column, bl))
                if (node->prev && MDOC_It == node->prev->tok)
                        return;
 
-       /*
-        * XXX - not documented: a `-diag' without a body does not
-        * assert a vspace prior to the next element. 
-        */
+       /* A `-diag' without body does not vspace. */
+
        if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Diag, bl)) 
                if (node->prev && MDOC_It == node->prev->tok) {
                        assert(node->prev->body);
@@ -731,14 +752,14 @@ termp_it_pre(DECL_ARGS)
                 * the 0 will be adjusted to default 10 or, if in the
                 * last column case, set to stretch to the margin).
                 */
-               for (i = 0, n = node->prev; n && n && 
-                               i < (int)bl->args[vals[2]].argv->sz; 
+               for (i = 0, n = node->prev; n && 
+                               i < (int)bl->args->argv[vals[2]].sz; 
                                n = n->prev, i++)
                        offset += arg_width 
                                (&bl->args->argv[vals[2]], i);
 
                /* Whether exceeds maximum column. */
-               if (i < (int)bl->args[vals[2]].argv->sz)
+               if (i < (int)bl->args->argv[vals[2]].sz)
                        width = arg_width(&bl->args->argv[vals[2]], i);
                else
                        width = 0;
@@ -1069,13 +1090,12 @@ termp_an_pre(DECL_ARGS)
                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 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) {
@@ -1129,21 +1149,13 @@ termp_ns_pre(DECL_ARGS)
 }
 
 
-/* ARGSUSED */
-static int
-termp_pp_pre(DECL_ARGS)
-{
-
-       term_vspace(p);
-       return(1);
-}
-
-
 /* ARGSUSED */
 static int
 termp_rs_pre(DECL_ARGS)
 {
 
+       if (SEC_SEE_ALSO != node->sec)
+               return(1);
        if (MDOC_BLOCK == node->type && node->prev)
                term_vspace(p);
        return(1);
@@ -1329,10 +1341,9 @@ 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.
-        */
+
+       /* No vspace between consecutive `Sh' calls. */
+
        switch (node->type) {
        case (MDOC_BLOCK):
                if (node->prev && MDOC_Sh == node->prev->tok)
@@ -1395,7 +1406,7 @@ termp_bt_pre(DECL_ARGS)
 {
 
        term_word(p, "is currently in beta test.");
-       return(1);
+       return(0);
 }
 
 
@@ -1404,7 +1415,8 @@ static void
 termp_lb_post(DECL_ARGS)
 {
 
-       term_newln(p);
+       if (SEC_LIBRARY == node->sec)
+               term_newln(p);
 }
 
 
@@ -1496,10 +1508,6 @@ termp_fn_pre(DECL_ARGS)
 {
        const struct mdoc_node *n;
 
-       assert(node->child && MDOC_TEXT == node->child->type);
-
-       /* FIXME: can be "type funcname" "type varname"... */
-
        p->bold++;
        term_word(p, node->child->string);
        p->bold--;
@@ -1564,18 +1572,8 @@ termp_fa_pre(DECL_ARGS)
 static int
 termp_bd_pre(DECL_ARGS)
 {
-       int              i, type;
-
-       /*
-        * This is fairly tricky due primarily to crappy documentation.
-        * If -ragged or -filled are specified, the block does nothing
-        * but change the indentation.
-        *
-        * If, on the other hand, -unfilled or -literal are specified,
-        * then the game changes.  Text is printed exactly as entered in
-        * the display: if a macro line, a newline is appended to the
-        * line.  Blank lines are allowed.
-        */
+       int                      i, type;
+       const struct mdoc_node  *nn;
 
        if (MDOC_BLOCK == node->type) {
                fmt_block_vspace(p, node, node);
@@ -1583,11 +1581,10 @@ termp_bd_pre(DECL_ARGS)
        } else if (MDOC_BODY != node->type)
                return(1);
 
-       assert(node->parent->args);
+       nn = node->parent;
 
-       for (type = -1, i = 0; -1 == type && 
-                       i < (int)node->parent->args->argc; i++) {
-               switch (node->parent->args->argv[i].arg) {
+       for (type = -1, i = 0; i < (int)nn->args->argc; i++) {
+               switch (nn->args->argv[i].arg) {
                case (MDOC_Ragged):
                        /* FALLTHROUGH */
                case (MDOC_Filled):
@@ -1595,32 +1592,33 @@ termp_bd_pre(DECL_ARGS)
                case (MDOC_Unfilled):
                        /* FALLTHROUGH */
                case (MDOC_Literal):
-                       type = node->parent->args->argv[i].arg;
+                       type = nn->args->argv[i].arg;
+                       break;
+               case (MDOC_Offset):
+                       p->offset += arg_offset(&nn->args->argv[i]);
                        break;
                default:
                        break;
                }
        }
+
+       /*
+        * If -ragged or -filled are specified, the block does nothing
+        * but change the indentation.  If -unfilled or -literal are
+        * specified, text is printed exactly as entered in the display:
+        * for macro lines, a newline is appended to the line.  Blank
+        * lines are allowed.
+        */
        
        assert(type > -1);
-
-       i = arg_getattr(MDOC_Offset, node->parent);
-       if (-1 != i)
-               p->offset += arg_offset(&node->parent->args->argv[i]);
-
-       switch (type) {
-       case (MDOC_Literal):
-               /* FALLTHROUGH */
-       case (MDOC_Unfilled):
-               break;
-       default:
+       if (MDOC_Literal != type && MDOC_Unfilled != type)
                return(1);
-       }
 
-       for (node = node->child; node; node = node->next) {
-               p->flags |= TERMP_NOSPACE;
-               print_node(p, pair, meta, node);
-               if (node->next)
+       for (nn = node->child; nn; nn = nn->next) {
+               print_node(p, pair, meta, nn);
+               if (NULL == nn->next)
+                       continue;
+               if (nn->prev && nn->prev->line < nn->line)
                        term_flushln(p);
        }
 
@@ -1822,6 +1820,7 @@ termp_in_post(DECL_ARGS)
 {
 
        p->bold++;
+       p->flags |= TERMP_NOSPACE;
        term_word(p, ">");
        p->bold--;
 
@@ -1846,12 +1845,18 @@ termp_sp_pre(DECL_ARGS)
 {
        int              i, len;
 
-       if (NULL == node->child) {
-               term_vspace(p);
-               return(0);
+       switch (node->tok) {
+       case (MDOC_sp):
+               len = node->child ? atoi(node->child->string) : 1;
+               break;
+       case (MDOC_br):
+               len = 0;
+               break;
+       default:
+               len = 1;
+               break;
        }
 
-       len = atoi(node->child->string);
        if (0 == len)
                term_newln(p);
        for (i = 0; i < len; i++)
@@ -1861,16 +1866,6 @@ termp_sp_pre(DECL_ARGS)
 }
 
 
-/* ARGSUSED */
-static int
-termp_br_pre(DECL_ARGS)
-{
-
-       term_newln(p);
-       return(1);
-}
-
-
 /* ARGSUSED */
 static int
 termp_brq_pre(DECL_ARGS)
@@ -2049,6 +2044,14 @@ termp____post(DECL_ARGS)
 {
 
        p->flags |= TERMP_NOSPACE;
+       switch (node->tok) {
+       case (MDOC__T):
+               term_word(p, "\\(rq");
+               p->flags |= TERMP_NOSPACE;
+               break;
+       default:
+               break;
+       }
        term_word(p, node->next ? "," : ".");
 }
 
@@ -2090,3 +2093,14 @@ termp_under_pre(DECL_ARGS)
        p->under++;
        return(1);
 }
+
+
+/* ARGSUSED */
+static int
+termp__t_pre(DECL_ARGS)
+{
+
+       term_word(p, "\\(lq");
+       p->flags |= TERMP_NOSPACE;
+       return(1);
+}