=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.215 retrieving revision 1.231 diff -u -p -r1.215 -r1.231 --- mandoc/html.c 2017/06/23 02:32:12 1.215 +++ mandoc/html.c 2018/05/29 02:10:10 1.231 @@ -1,7 +1,7 @@ -/* $Id: html.c,v 1.215 2017/06/23 02:32:12 schwarze Exp $ */ +/* $Id: html.c,v 1.231 2018/05/29 02:10:10 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons - * Copyright (c) 2011-2015, 2017 Ingo Schwarze + * Copyright (c) 2011-2015, 2017, 2018 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include "mandoc_aux.h" +#include "mandoc_ohash.h" #include "mandoc.h" #include "roff.h" #include "out.h" @@ -59,6 +61,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, {"title", HTML_NLAROUND}, {"div", HTML_NLAROUND}, + {"div", 0}, {"h1", HTML_NLAROUND}, {"h2", HTML_NLAROUND}, {"span", 0}, @@ -116,6 +119,9 @@ static const char *const roffscales[SCALE_MAX] = { "ex", /* SCALE_FS */ }; +/* Avoid duplicate HTML id= attributes. */ +static struct ohash id_unique; + static void a2width(const char *, struct roffsu *); static void print_byte(struct html *, char); static void print_endword(struct html *); @@ -143,6 +149,8 @@ html_alloc(const struct manoutput *outopts) if (outopts->fragment) h->oflags |= HTML_FRAGMENT; + mandoc_ohash_init(&id_unique, 4, 0); + return h; } @@ -151,15 +159,22 @@ html_free(void *p) { struct tag *tag; struct html *h; + char *cp; + unsigned int slot; h = (struct html *)p; - while ((tag = h->tag) != NULL) { h->tag = tag->next; free(tag); } - free(h); + + cp = ohash_first(&id_unique, &slot); + while (cp != NULL) { + free(cp); + cp = ohash_next(&id_unique, &slot); + } + ohash_delete(&id_unique); } void @@ -168,9 +183,14 @@ print_gen_head(struct html *h) struct tag *t; print_otag(h, TAG_META, "?", "charset", "utf-8"); + if (h->style != NULL) { + print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", + h->style, "type", "text/css", "media", "all"); + return; + } /* - * Print a default style-sheet. + * Print a minimal embedded style sheet. */ t = print_otag(h, TAG_STYLE, ""); @@ -181,11 +201,23 @@ print_gen_head(struct html *h) print_text(h, "td.head-vol { text-align: center; }"); print_endline(h); print_text(h, "div.Pp { margin: 1ex 0ex; }"); + print_endline(h); + print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }"); + print_endline(h); + print_text(h, "span.Pa, span.Ad { font-style: italic; }"); + print_endline(h); + print_text(h, "span.Ms { font-weight: bold; }"); + print_endline(h); + print_text(h, "dl.Bl-diag "); + print_byte(h, '>'); + print_text(h, " dt { font-weight: bold; }"); + print_endline(h); + print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, " + "code.In, code.Fd, code.Fn,"); + print_endline(h); + print_text(h, "code.Cd { font-weight: bold; " + "font-family: inherit; }"); print_tagq(h, t); - - if (h->style) - print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", - h->style, "type", "text/css", "media", "all"); } static void @@ -239,10 +271,12 @@ print_metaf(struct html *h, enum mandoc_esc deco) } char * -html_make_id(const struct roff_node *n) +html_make_id(const struct roff_node *n, int unique) { const struct roff_node *nch; - char *buf, *cp; + char *buf, *bufs, *cp; + unsigned int slot; + int suffix; for (nch = n->child; nch != NULL; nch = nch->next) if (nch->type != ROFFT_TEXT) @@ -250,13 +284,45 @@ html_make_id(const struct roff_node *n) buf = NULL; deroff(&buf, n); + if (buf == NULL) + return NULL; - /* http://www.w3.org/TR/html5/dom.html#the-id-attribute */ + /* + * In ID attributes, only use ASCII characters that are + * permitted in URL-fragment strings according to the + * explicit list at: + * https://url.spec.whatwg.org/#url-fragment-string + */ for (cp = buf; *cp != '\0'; cp++) - if (*cp == ' ') + if (isalnum((unsigned char)*cp) == 0 && + strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL) *cp = '_'; + if (unique == 0) + return buf; + + /* Avoid duplicate HTML id= attributes. */ + + bufs = NULL; + suffix = 1; + slot = ohash_qlookup(&id_unique, buf); + cp = ohash_find(&id_unique, slot); + if (cp != NULL) { + while (cp != NULL) { + free(bufs); + if (++suffix > 127) { + free(buf); + return NULL; + } + mandoc_asprintf(&bufs, "%s_%d", buf, suffix); + slot = ohash_qlookup(&id_unique, bufs); + cp = ohash_find(&id_unique, slot); + } + free(buf); + buf = bufs; + } + ohash_insert(&id_unique, slot, buf); return buf; } @@ -453,7 +519,7 @@ print_encode(struct html *h, const char *p, const char (c > 0x7E && c < 0xA0)) c = 0xFFFD; if (c > 0x7E) { - (void)snprintf(numbuf, sizeof(numbuf), "&#%d;", c); + (void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c); print_word(h, numbuf); } else if (print_escape(h, c) == 0) print_byte(h, c); @@ -516,7 +582,7 @@ print_otag(struct html *h, enum htmltag tag, const cha print_indent(h); else if ((h->flags & HTML_NOSPACE) == 0) { if (h->flags & HTML_KEEP) - print_word(h, " "); + print_word(h, " "); else { if (h->flags & HTML_PREKEEP) h->flags |= HTML_KEEP; @@ -623,27 +689,20 @@ print_otag(struct html *h, enum htmltag tag, const cha case 'u': su = va_arg(ap, struct roffsu *); break; - case 'v': - i = va_arg(ap, int); - su = &mysu; - SCALE_VS_INIT(su, i); - break; case 'w': - if ((arg2 = va_arg(ap, char *)) == NULL) - break; - su = &mysu; - a2width(arg2, su); + if ((arg2 = va_arg(ap, char *)) != NULL) { + su = &mysu; + a2width(arg2, su); + } if (*fmt == '+') { - /* Increase to make even bold text fit. */ - su->scale *= 1.2; - /* Add padding. */ - su->scale += 3.0; + if (su != NULL) { + /* Make even bold text fit. */ + su->scale *= 1.2; + /* Add padding. */ + su->scale += 3.0; + } fmt++; } - if (*fmt == '-') { - su->scale *= -1.0; - fmt++; - } break; default: abort(); @@ -652,9 +711,6 @@ print_otag(struct html *h, enum htmltag tag, const cha /* Second letter: style name. */ switch (*fmt++) { - case 'b': - attr = "margin-bottom"; - break; case 'h': attr = "height"; break; @@ -664,9 +720,6 @@ print_otag(struct html *h, enum htmltag tag, const cha case 'l': attr = "margin-left"; break; - case 't': - attr = "margin-top"; - break; case 'w': attr = "width"; break; @@ -771,6 +824,32 @@ print_gen_decls(struct html *h) } void +print_gen_comment(struct html *h, struct roff_node *n) +{ + int wantblank; + + print_word(h, "") == NULL && + (wantblank || *n->string != '\0')) { + print_endline(h); + print_indent(h); + print_word(h, n->string); + wantblank = *n->string != '\0'; + } + n = n->next; + } + if (wantblank) + print_endline(h); + print_word(h, " -->"); + print_endline(h); + h->indent = 0; +} + +void print_text(struct html *h, const char *word) { if (h->col && (h->flags & HTML_NOSPACE) == 0) { @@ -779,7 +858,7 @@ print_text(struct html *h, const char *word) h->flags |= HTML_KEEP; print_endword(h); } else - print_word(h, " "); + print_word(h, " "); } assert(NULL == h->metaf);