=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.227 retrieving revision 1.231 diff -u -p -r1.227 -r1.231 --- mandoc/html.c 2018/05/21 00:30:23 1.227 +++ mandoc/html.c 2018/05/29 02:10:10 1.231 @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.227 2018/05/21 00:30:23 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, 2018 Ingo Schwarze @@ -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" @@ -117,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 *); @@ -144,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; } @@ -152,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 @@ -192,6 +206,8 @@ print_gen_head(struct html *h) 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; }"); @@ -255,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) @@ -269,12 +287,42 @@ html_make_id(const struct roff_node *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; } @@ -646,12 +694,6 @@ print_otag(struct html *h, enum htmltag tag, const cha su = &mysu; a2width(arg2, su); } - if (*fmt == '*') { - if (su != NULL && su->unit == SCALE_EN && - su->scale > 5.9 && su->scale < 6.1) - su = NULL; - fmt++; - } if (*fmt == '+') { if (su != NULL) { /* Make even bold text fit. */ @@ -659,11 +701,6 @@ print_otag(struct html *h, enum htmltag tag, const cha /* Add padding. */ su->scale += 3.0; } - fmt++; - } - if (*fmt == '-') { - if (su != NULL) - su->scale *= -1.0; fmt++; } break;