]> git.cameronkatri.com Git - mandoc.git/blobdiff - html.c
Make the "make depend" maintainer target more convenient
[mandoc.git] / html.c
diff --git a/html.c b/html.c
index 4b9c08760cba4d671c544cfcbb552c08a2143e3c..769acce8d39bb3383afb082a066e3d9a849a83a9 100644 (file)
--- a/html.c
+++ b/html.c
@@ -1,7 +1,7 @@
-/*     $Id: html.c,v 1.257 2019/08/29 17:57:29 schwarze Exp $ */
+/* $Id: html.c,v 1.264 2020/03/13 15:32:28 schwarze Exp $ */
 /*
+ * Copyright (c) 2011-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017-2019 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
@@ -14,6 +14,9 @@
  * 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.
+ *
+ * Common functions for mandoc(1) HTML formatters.
+ * For use by individual formatters and by the main program.
  */
 #include "config.h"
 
@@ -65,7 +68,6 @@ static        const struct htmldata htmltags[TAG_MAX] = {
        {"title",       HTML_NLAROUND},
        {"body",        HTML_NLALL},
        {"div",         HTML_NLAROUND},
-       {"div",         0},
        {"section",     HTML_NLALL},
        {"table",       HTML_NLALL | HTML_INDENT},
        {"tr",          HTML_NLALL | HTML_INDENT},
@@ -89,6 +91,7 @@ static        const struct htmldata htmltags[TAG_MAX] = {
        {"span",        HTML_INPHRASE | HTML_TOPHRASE},
        {"var",         HTML_INPHRASE | HTML_TOPHRASE},
        {"br",          HTML_INPHRASE | HTML_NOSTACK | HTML_NLALL},
+       {"mark",        HTML_INPHRASE },
        {"math",        HTML_INPHRASE | HTML_NLALL | HTML_INDENT},
        {"mrow",        0},
        {"mi",          0},
@@ -272,21 +275,18 @@ print_metaf(struct html *h)
 void
 html_close_paragraph(struct html *h)
 {
-       struct tag      *t;
+       struct tag      *this, *next;
+       int              flags;
 
-       for (t = h->tag; t != NULL && t->closed == 0; t = t->next) {
-               switch(t->tag) {
-               case TAG_P:
-               case TAG_PRE:
-                       print_tagq(h, t);
+       this = h->tag;
+       for (;;) {
+               next = this->next;
+               flags = htmltags[this->tag].flags;
+               if (flags & (HTML_INPHRASE | HTML_TOPHRASE))
+                       print_ctag(h, this);
+               if ((flags & HTML_INPHRASE) == 0)
                        break;
-               case TAG_A:
-                       print_tagq(h, t);
-                       continue;
-               default:
-                       continue;
-               }
-               break;
+               this = next;
        }
 }
 
@@ -324,6 +324,18 @@ html_fillmode(struct html *h, enum roff_tok want)
        return had;
 }
 
+/*
+ * Allocate a string to be used for the "id=" attribute of an HTML
+ * element and/or as a segment identifier for a URI in an <a> element.
+ * The function may fail and return NULL if the node lacks text data
+ * to create the attribute from.
+ * If the "unique" argument is 0, the caller is responsible for
+ * free(3)ing the returned string after using it.
+ * If the "unique" argument is non-zero, the "id_unique" ohash table
+ * is used for de-duplication and owns the returned string, so the
+ * caller must not free(3) it.  In this case, it will be freed
+ * automatically by html_reset() or html_free().
+ */
 char *
 html_make_id(const struct roff_node *n, int unique)
 {
@@ -332,14 +344,30 @@ html_make_id(const struct roff_node *n, int unique)
        unsigned int             slot;
        int                      suffix;
 
-       for (nch = n->child; nch != NULL; nch = nch->next)
-               if (nch->type != ROFFT_TEXT)
-                       return NULL;
-
-       buf = NULL;
-       deroff(&buf, n);
-       if (buf == NULL)
-               return NULL;
+       if (n->string != NULL)
+               buf = mandoc_strdup(n->string);
+       else {
+               switch (n->tok) {
+               case MDOC_Sh:
+               case MDOC_Ss:
+               case MDOC_Sx:
+               case MAN_SH:
+               case MAN_SS:
+                       for (nch = n->child; nch != NULL; nch = nch->next)
+                               if (nch->type != ROFFT_TEXT)
+                                       return NULL;
+                       buf = NULL;
+                       deroff(&buf, n);
+                       if (buf == NULL)
+                               return NULL;
+                       break;
+               default:
+                       if (n->child->type != ROFFT_TEXT)
+                               return NULL;
+                       buf = mandoc_strdup(n->child->string);
+                       break;
+               }
+       }
 
        /*
         * In ID attributes, only use ASCII characters that are
@@ -594,7 +622,15 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
                        assert((htmltags[t->tag].flags & HTML_TOPHRASE) == 0);
                        break;
                }
-       }
+
+       /*
+        * Always wrap phrasing elements in a paragraph
+        * unless already contained in some flow container;
+        * never put them directly into a section.
+        */
+
+       } else if (tflags & HTML_TOPHRASE && h->tag->tag == TAG_SECTION)
+               print_otag(h, TAG_P, "c", "Pp");
 
        /* Push this tag onto the stack of open scopes. */
 
@@ -731,6 +767,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
        return t;
 }
 
+/*
+ * Print an element with an optional "id=" attribute.
+ * If there is an "id=" attribute, also add a permalink:
+ * outside if it's a phrasing element, or inside otherwise.
+ */
+struct tag *
+print_otag_id(struct html *h, enum htmltag elemtype, const char *cattr,
+    struct roff_node *n)
+{
+       struct tag      *ret, *t;
+       const char      *id;
+
+       ret = NULL;
+       id = NULL;
+       if (n->flags & NODE_ID)
+               id = html_make_id(n, 1);
+       if (id != NULL && htmltags[elemtype].flags & HTML_INPHRASE)
+               ret = print_otag(h, TAG_A, "chR", "permalink", id);
+       t = print_otag(h, elemtype, "ci", cattr, id);
+       if (ret == NULL) {
+               ret = t;
+               if (id != NULL)
+                       print_otag(h, TAG_A, "chR", "permalink", id);
+       }
+       return ret;
+}
+
 static void
 print_ctag(struct html *h, struct tag *tag)
 {
@@ -800,6 +863,16 @@ print_gen_comment(struct html *h, struct roff_node *n)
 void
 print_text(struct html *h, const char *word)
 {
+       /*
+        * Always wrap text in a paragraph unless already contained in
+        * some flow container; never put it directly into a section.
+        */
+
+       if (h->tag->tag == TAG_SECTION)
+               print_otag(h, TAG_P, "c", "Pp");
+
+       /* Output whitespace before this text? */
+
        if (h->col && (h->flags & HTML_NOSPACE) == 0) {
                if ( ! (HTML_KEEP & h->flags)) {
                        if (HTML_PREKEEP & h->flags)
@@ -809,6 +882,11 @@ print_text(struct html *h, const char *word)
                        print_word(h, "&#x00A0;");
        }
 
+       /*
+        * Print the text, optionally surrounded by HTML whitespace,
+        * optionally manually switching fonts before and after.
+        */
+
        assert(h->metaf == NULL);
        print_metaf(h);
        print_indent(h);
@@ -949,15 +1027,12 @@ print_indent(struct html *h)
 {
        size_t   i;
 
-       if (h->col)
+       if (h->col || h->noindent)
                return;
 
-       if (h->noindent == 0) {
-               h->col = h->indent * 2;
-               for (i = 0; i < h->col; i++)
-                       putchar(' ');
-       }
-       h->flags &= ~HTML_NOSPACE;
+       h->col = h->indent * 2;
+       for (i = 0; i < h->col; i++)
+               putchar(' ');
 }
 
 /*