]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_term.c
Implement the traditional -h option for man(1): show the SYNOPSIS only.
[mandoc.git] / mdoc_term.c
index 8472b8f332e52caa46d9dcd701936700ddf9f514..21aa4a7c0b3431d508df6b315a3736212e072e2a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_term.c,v 1.265 2014/04/20 19:40:13 schwarze Exp $ */
+/*     $Id: mdoc_term.c,v 1.281 2014/09/03 05:22:45 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,9 +16,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 
@@ -30,6 +28,7 @@
 #include <string.h>
 
 #include "mandoc.h"
+#include "mandoc_aux.h"
 #include "out.h"
 #include "term.h"
 #include "mdoc.h"
@@ -94,6 +93,7 @@ static        int       termp_bt_pre(DECL_ARGS);
 static int       termp_bx_pre(DECL_ARGS);
 static int       termp_cd_pre(DECL_ARGS);
 static int       termp_d1_pre(DECL_ARGS);
+static int       termp_es_pre(DECL_ARGS);
 static int       termp_ex_pre(DECL_ARGS);
 static int       termp_fa_pre(DECL_ARGS);
 static int       termp_fd_pre(DECL_ARGS);
@@ -157,7 +157,7 @@ static      const struct termact termacts[MDOC_MAX] = {
        { termp_nd_pre, NULL }, /* Nd */
        { termp_nm_pre, termp_nm_post }, /* Nm */
        { termp_quote_pre, termp_quote_post }, /* Op */
-       { NULL, NULL }, /* Ot */
+       { termp_ft_pre, NULL }, /* Ot */
        { termp_under_pre, NULL }, /* Pa */
        { termp_rv_pre, NULL }, /* Rv */
        { NULL, NULL }, /* St */
@@ -227,7 +227,7 @@ static      const struct termact termacts[MDOC_MAX] = {
        { NULL, NULL }, /* Ek */
        { termp_bt_pre, NULL }, /* Bt */
        { NULL, NULL }, /* Hf */
-       { NULL, NULL }, /* Fr */
+       { termp_under_pre, NULL }, /* Fr */
        { termp_ud_pre, NULL }, /* Ud */
        { NULL, termp_lb_post }, /* Lb */
        { termp_sp_pre, NULL }, /* Lp */
@@ -237,8 +237,8 @@ static      const struct termact termacts[MDOC_MAX] = {
        { termp_quote_pre, termp_quote_post }, /* Bro */
        { NULL, NULL }, /* Brc */
        { NULL, termp____post }, /* %C */
-       { NULL, NULL }, /* Es */ /* TODO */
-       { NULL, NULL }, /* En */ /* TODO */
+       { termp_es_pre, NULL }, /* Es */
+       { termp_quote_pre, termp_quote_post }, /* En */
        { termp_xx_pre, NULL }, /* Dx */
        { NULL, termp____post }, /* %Q */
        { termp_sp_pre, NULL }, /* br */
@@ -252,31 +252,44 @@ static    const struct termact termacts[MDOC_MAX] = {
 void
 terminal_mdoc(void *arg, const struct mdoc *mdoc)
 {
-       const struct mdoc_node  *n;
        const struct mdoc_meta  *meta;
+       struct mdoc_node        *n;
        struct termp            *p;
 
        p = (struct termp *)arg;
 
-       if (0 == p->defindent)
-               p->defindent = 5;
-
        p->overstep = 0;
-       p->maxrmargin = p->defrmargin;
+       p->rmargin = p->maxrmargin = p->defrmargin;
        p->tabwidth = term_len(p, 5);
 
        if (NULL == p->symtab)
                p->symtab = mchars_alloc();
 
-       n = mdoc_node(mdoc);
+       n = mdoc_node(mdoc)->child;
        meta = mdoc_meta(mdoc);
 
-       term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
-
-       if (n->child)
-               print_mdoc_nodelist(p, NULL, meta, n->child);
-
-       term_end(p);
+       if (p->synopsisonly) {
+               while (n != NULL) {
+                       if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
+                               if (n->child->next->child != NULL)
+                                       print_mdoc_nodelist(p, NULL,
+                                           meta, n->child->next->child);
+                               term_newln(p);
+                               break;
+                       }
+                       n = n->next;
+               }
+       } else {
+               if (p->defindent == 0)
+                       p->defindent = 5;
+               term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
+               if (n != NULL) {
+                       if (n->tok != MDOC_Sh)
+                               term_vspace(p);
+                       print_mdoc_nodelist(p, NULL, meta, n);
+               }
+               term_end(p);
+       }
 }
 
 static void
@@ -441,9 +454,9 @@ print_mdoc_foot(struct termp *p, const void *arg)
 static void
 print_mdoc_head(struct termp *p, const void *arg)
 {
-       char            buf[BUFSIZ], title[BUFSIZ];
-       size_t          buflen, titlen;
-       const struct mdoc_meta *meta;
+       const struct mdoc_meta  *meta;
+       char                    *volume, *title;
+       size_t                   vollen, titlen;
 
        meta = (const struct mdoc_meta *)arg;
 
@@ -460,39 +473,37 @@ print_mdoc_head(struct termp *p, const void *arg)
         * switches on the manual section.
         */
 
-       p->offset = 0;
-       p->rmargin = p->maxrmargin;
-
        assert(meta->vol);
-       strlcpy(buf, meta->vol, BUFSIZ);
-       buflen = term_strlen(p, buf);
-
-       if (meta->arch) {
-               strlcat(buf, " (", BUFSIZ);
-               strlcat(buf, meta->arch, BUFSIZ);
-               strlcat(buf, ")", BUFSIZ);
-       }
+       if (NULL == meta->arch)
+               volume = mandoc_strdup(meta->vol);
+       else
+               mandoc_asprintf(&volume, "%s (%s)",
+                   meta->vol, meta->arch);
+       vollen = term_strlen(p, volume);
 
-       snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+       if (NULL == meta->msec)
+               title = mandoc_strdup(meta->title);
+       else
+               mandoc_asprintf(&title, "%s(%s)",
+                   meta->title, meta->msec);
        titlen = term_strlen(p, title);
 
        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
        p->trailspace = 1;
        p->offset = 0;
-       p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
-           (p->maxrmargin -
-            term_strlen(p, buf) + term_len(p, 1)) / 2 :
-           p->maxrmargin - buflen;
+       p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+           (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
+           p->maxrmargin - vollen;
 
        term_word(p, title);
        term_flushln(p);
 
        p->flags |= TERMP_NOSPACE;
        p->offset = p->rmargin;
-       p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
+       p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
            p->maxrmargin - titlen : p->maxrmargin;
 
-       term_word(p, buf);
+       term_word(p, volume);
        term_flushln(p);
 
        p->flags &= ~TERMP_NOBREAK;
@@ -508,6 +519,8 @@ print_mdoc_head(struct termp *p, const void *arg)
        p->flags &= ~TERMP_NOSPACE;
        p->offset = 0;
        p->rmargin = p->maxrmargin;
+       free(title);
+       free(volume);
 }
 
 static size_t
@@ -746,7 +759,7 @@ termp_it_pre(DECL_ARGS)
                        term_word(p, "\\ \\ ");
                break;
        case LIST_inset:
-               if (MDOC_BODY == n->type)
+               if (MDOC_BODY == n->type && n->parent->head->nchild)
                        term_word(p, "\\ ");
                break;
        default:
@@ -800,7 +813,8 @@ termp_it_pre(DECL_ARGS)
                 * the "overstep" effect in term_flushln() and treat
                 * this as a `-ohang' list instead.
                 */
-               if (n->next->child &&
+               if (NULL != n->next &&
+                   NULL != n->next->child &&
                    (MDOC_Bl == n->next->child->tok ||
                     MDOC_Bd == n->next->child->tok))
                        break;
@@ -856,7 +870,9 @@ termp_it_pre(DECL_ARGS)
                 * don't want to recalculate rmargin and offsets when
                 * using `Bd' or `Bl' within `-hang' overstep lists.
                 */
-               if (MDOC_HEAD == n->type && n->next->child &&
+               if (MDOC_HEAD == n->type &&
+                   NULL != n->next &&
+                   NULL != n->next->child &&
                    (MDOC_Bl == n->next->child->tok ||
                     MDOC_Bd == n->next->child->tok))
                        break;
@@ -1021,7 +1037,8 @@ termp_nm_pre(DECL_ARGS)
        if (MDOC_HEAD == n->type)
                synopsis_pre(p, n->parent);
 
-       if (MDOC_HEAD == n->type && n->next->child) {
+       if (MDOC_HEAD == n->type &&
+           NULL != n->next && NULL != n->next->child) {
                p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
                p->trailspace = 1;
                p->rmargin = p->offset + term_len(p, 1);
@@ -1049,7 +1066,8 @@ termp_nm_post(DECL_ARGS)
 
        if (MDOC_BLOCK == n->type) {
                p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
-       } else if (MDOC_HEAD == n->type && n->next->child) {
+       } else if (MDOC_HEAD == n->type &&
+           NULL != n->next && NULL != n->next->child) {
                term_flushln(p);
                p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
                p->trailspace = 0;
@@ -1064,9 +1082,10 @@ termp_fl_pre(DECL_ARGS)
        term_fontpush(p, TERMFONT_BOLD);
        term_word(p, "\\-");
 
-       if (n->child)
-               p->flags |= TERMP_NOSPACE;
-       else if (n->next && n->next->line == n->line)
+       if ( ! (n->nchild == 0 &&
+           (n->next == NULL ||
+            n->next->type == MDOC_TEXT ||
+            n->next->flags & MDOC_LINE)))
                p->flags |= TERMP_NOSPACE;
 
        return(1);
@@ -1163,33 +1182,42 @@ termp_rv_pre(DECL_ARGS)
        int              nchild;
 
        term_newln(p);
-       term_word(p, "The");
 
        nchild = n->nchild;
-       for (n = n->child; n; n = n->next) {
-               term_fontpush(p, TERMFONT_BOLD);
-               term_word(p, n->string);
-               term_fontpop(p);
+       if (nchild > 0) {
+               term_word(p, "The");
 
-               p->flags |= TERMP_NOSPACE;
-               term_word(p, "()");
+               for (n = n->child; n; n = n->next) {
+                       term_fontpush(p, TERMFONT_BOLD);
+                       term_word(p, n->string);
+                       term_fontpop(p);
 
-               if (nchild > 2 && n->next) {
                        p->flags |= TERMP_NOSPACE;
-                       term_word(p, ",");
+                       term_word(p, "()");
+
+                       if (n->next == NULL)
+                               continue;
+
+                       if (nchild > 2) {
+                               p->flags |= TERMP_NOSPACE;
+                               term_word(p, ",");
+                       }
+                       if (n->next->next == NULL)
+                               term_word(p, "and");
                }
 
-               if (n->next && NULL == n->next->next)
-                       term_word(p, "and");
-       }
+               if (nchild > 1)
+                       term_word(p, "functions return");
+               else
+                       term_word(p, "function returns");
 
-       if (nchild > 1)
-               term_word(p, "functions return");
-       else
-               term_word(p, "function returns");
+               term_word(p, "the value\\~0 if successful;");
+       } else
+               term_word(p, "Upon successful completion,"
+                   " the value\\~0 is returned;");
 
-       term_word(p, "the value 0 if successful; otherwise the "
-           "value -1 is returned and the global variable");
+       term_word(p, "otherwise the value\\~\\-1 is returned"
+           " and the global variable");
 
        term_fontpush(p, TERMFONT_UNDER);
        term_word(p, "errno");
@@ -1225,11 +1253,11 @@ termp_ex_pre(DECL_ARGS)
        }
 
        if (nchild > 1)
-               term_word(p, "utilities exit");
+               term_word(p, "utilities exit\\~0");
        else
-               term_word(p, "utility exits");
+               term_word(p, "utility exits\\~0");
 
-       term_word(p, "0 on success, and >0 if an error occurs.");
+       term_word(p, "on success, and\\~>0 if an error occurs.");
 
        p->flags |= TERMP_SENTENCE;
        return(0);
@@ -1567,7 +1595,7 @@ termp_fa_pre(DECL_ARGS)
 static int
 termp_bd_pre(DECL_ARGS)
 {
-       size_t                   tabwidth, rm, rmax;
+       size_t                   tabwidth, lm, len, rm, rmax;
        struct mdoc_node        *nn;
 
        if (MDOC_BLOCK == n->type) {
@@ -1588,18 +1616,29 @@ termp_bd_pre(DECL_ARGS)
         */
 
        if (DISP_literal != n->norm->Bd.type &&
-           DISP_unfilled != n->norm->Bd.type)
+           DISP_unfilled != n->norm->Bd.type &&
+           DISP_centered != n->norm->Bd.type)
                return(1);
 
        tabwidth = p->tabwidth;
        if (DISP_literal == n->norm->Bd.type)
                p->tabwidth = term_len(p, 8);
 
+       lm = p->offset;
        rm = p->rmargin;
        rmax = p->maxrmargin;
        p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
 
        for (nn = n->child; nn; nn = nn->next) {
+               if (DISP_centered == n->norm->Bd.type) {
+                       if (MDOC_TEXT == nn->type) {
+                               len = term_strlen(p, nn->string);
+                               p->offset = len >= rm ? 0 :
+                                   lm + len >= rm ? rm - len :
+                                   (lm + rm - len) / 2;
+                       } else
+                               p->offset = lm;
+               }
                print_mdoc_node(p, pair, meta, nn);
                /*
                 * If the printed node flushes its own line, then we
@@ -1746,6 +1785,9 @@ termp_ss_pre(DECL_ARGS)
                term_fontpush(p, TERMFONT_BOLD);
                p->offset = term_len(p, (p->defindent+1)/2);
                break;
+       case MDOC_BODY:
+               p->offset = term_len(p, p->defindent);
+               break;
        default:
                break;
        }
@@ -1757,7 +1799,7 @@ static void
 termp_ss_post(DECL_ARGS)
 {
 
-       if (MDOC_HEAD == n->type)
+       if (n->type == MDOC_HEAD || n->type == MDOC_BODY)
                term_newln(p);
 }
 
@@ -1828,6 +1870,13 @@ termp_sp_pre(DECL_ARGS)
        return(0);
 }
 
+static int
+termp_es_pre(DECL_ARGS)
+{
+
+       return(0);
+}
+
 static int
 termp_quote_pre(DECL_ARGS)
 {
@@ -1860,6 +1909,12 @@ termp_quote_pre(DECL_ARGS)
        case MDOC_Dq:
                term_word(p, "\\(lq");
                break;
+       case MDOC_En:
+               if (NULL == n->norm->Es ||
+                   NULL == n->norm->Es->child)
+                       return(1);
+               term_word(p, n->norm->Es->child->string);
+               break;
        case MDOC_Eo:
                break;
        case MDOC_Po:
@@ -1897,7 +1952,8 @@ termp_quote_post(DECL_ARGS)
        if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
                return;
 
-       p->flags |= TERMP_NOSPACE;
+       if (MDOC_En != n->tok)
+               p->flags |= TERMP_NOSPACE;
 
        switch (n->tok) {
        case MDOC_Ao:
@@ -1924,6 +1980,14 @@ termp_quote_post(DECL_ARGS)
        case MDOC_Dq:
                term_word(p, "\\(rq");
                break;
+       case MDOC_En:
+               if (NULL != n->norm->Es &&
+                   NULL != n->norm->Es->child &&
+                   NULL != n->norm->Es->child->next) {
+                       p->flags |= TERMP_NOSPACE;
+                       term_word(p, n->norm->Es->child->next->string);
+               }
+               break;
        case MDOC_Eo:
                break;
        case MDOC_Po:
@@ -2033,14 +2097,16 @@ static int
 termp_sm_pre(DECL_ARGS)
 {
 
-       assert(n->child && MDOC_TEXT == n->child->type);
-       if (0 == strcmp("on", n->child->string)) {
-               if (p->col)
-                       p->flags &= ~TERMP_NOSPACE;
+       if (NULL == n->child)
+               p->flags ^= TERMP_NONOSPACE;
+       else if (0 == strcmp("on", n->child->string))
                p->flags &= ~TERMP_NONOSPACE;
-       else
+       else
                p->flags |= TERMP_NONOSPACE;
 
+       if (p->col && ! (TERMP_NONOSPACE & p->flags))
+               p->flags &= ~TERMP_NOSPACE;
+
        return(0);
 }