=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.257 retrieving revision 1.264 diff -u -p -r1.257 -r1.264 --- mandoc/html.c 2019/08/29 17:57:29 1.257 +++ mandoc/html.c 2020/03/13 15:32:28 1.264 @@ -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 * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons - * Copyright (c) 2011-2015, 2017-2019 Ingo Schwarze * * 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 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,15 +344,31 @@ 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; + 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; + } + } - buf = NULL; - deroff(&buf, n); - if (buf == NULL) - return NULL; - /* * In ID attributes, only use ASCII characters that are * permitted in URL-fragment strings according to the @@ -594,8 +622,16 @@ print_otag(struct html *h, enum htmltag tag, const cha 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. */ if ((tflags & HTML_NOSTACK) == 0) { @@ -731,6 +767,33 @@ print_otag(struct html *h, enum htmltag tag, const cha 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, " "); } + /* + * 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(' '); } /*