=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.227 retrieving revision 1.236 diff -u -p -r1.227 -r1.236 --- mandoc/html.c 2018/05/21 00:30:23 1.227 +++ mandoc/html.c 2018/06/25 14:00:28 1.236 @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.227 2018/05/21 00:30:23 schwarze Exp $ */ +/* $Id: html.c,v 1.236 2018/06/25 14:00:28 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" @@ -67,8 +69,6 @@ static const struct htmldata htmltags[TAG_MAX] = { {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, {"a", 0}, {"table", HTML_NLALL | HTML_INDENT}, - {"colgroup", HTML_NLALL | HTML_INDENT}, - {"col", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, {"tr", HTML_NLALL | HTML_INDENT}, {"td", HTML_NLAROUND}, {"li", HTML_NLAROUND | HTML_INDENT}, @@ -117,7 +117,9 @@ static const char *const roffscales[SCALE_MAX] = { "ex", /* SCALE_FS */ }; -static void a2width(const char *, struct roffsu *); +/* Avoid duplicate HTML id= attributes. */ +static struct ohash id_unique; + static void print_byte(struct html *, char); static void print_endword(struct html *); static void print_indent(struct html *); @@ -144,6 +146,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 +156,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 +203,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 +268,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 +284,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; } @@ -641,32 +686,6 @@ print_otag(struct html *h, enum htmltag tag, const cha case 'u': su = va_arg(ap, struct roffsu *); break; - case 'w': - if ((arg2 = va_arg(ap, char *)) != NULL) { - 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. */ - su->scale *= 1.2; - /* Add padding. */ - su->scale += 3.0; - } - fmt++; - } - if (*fmt == '-') { - if (su != NULL) - su->scale *= -1.0; - fmt++; - } - break; default: abort(); } @@ -677,18 +696,9 @@ print_otag(struct html *h, enum htmltag tag, const cha case 'h': attr = "height"; break; - case 'i': - attr = "text-indent"; - break; case 'l': attr = "margin-left"; break; - case 'w': - attr = "width"; - break; - case 'W': - attr = "min-width"; - break; case '?': attr = arg1; arg1 = va_arg(ap, char *); @@ -1002,22 +1012,4 @@ print_word(struct html *h, const char *cp) { while (*cp != '\0') print_byte(h, *cp++); -} - -/* - * Calculate the scaling unit passed in a `-width' argument. This uses - * either a native scaling unit (e.g., 1i, 2m) or the string length of - * the value. - */ -static void -a2width(const char *p, struct roffsu *su) -{ - const char *end; - - end = a2roffsu(p, su, SCALE_MAX); - if (end == NULL || *end != '\0') { - su->unit = SCALE_EN; - su->scale = html_strlen(p); - } else if (su->scale < 0.0) - su->scale = 0.0; }