From e23a77096fcef5d491ce207daaa9ce6f57384647 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Fri, 25 May 2018 20:23:51 +0000 Subject: Do not write duplicate id= attributes, they violate HTML syntax. Append suffixes for disambiguation. Issue first reported by Jakub Klinkovsky (Arch Linux). --- TODO | 11 ++++------- html.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- html.h | 4 ++-- man_html.c | 8 +++----- mdoc_html.c | 23 ++++++----------------- 5 files changed, 60 insertions(+), 36 deletions(-) diff --git a/TODO b/TODO index 24981679..b17d14c5 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ ************************************************************************ * Official mandoc TODO. -* $Id: TODO,v 1.253 2018/05/08 21:42:34 schwarze Exp $ +* $Id: TODO,v 1.254 2018/05/25 20:23:51 schwarze Exp $ ************************************************************************ Many issues are annotated for difficulty as follows: @@ -379,12 +379,9 @@ are mere guesses, and some may be wrong. --- HTML issues -------------------------------------------------------- -- duplicate names generate duplicate href="#..." anchor attributes - possibly use "#..._" suffixes? - Jakub Klinkovsky 3 Oct 2017 21:23:36 +0200 - see also the thread: gre(4): Rename duplicate sections - up to 20 Apr 2018 15:27:33 +0200 - loc * exist * algo * size * imp *** +- @media queries to reduce indentation on low-res displays + some mails in the Viewport for man.openbsd.org thread + e.g. Adam Thompson 24 May 2018 15:09:00 -0500 - wrap Sh and Ss content into
Laura Morales 21 Apr 2018 18:10:48 +0200 diff --git a/html.c b/html.c index 60e88371..9ad83e8e 100644 --- a/html.c +++ b/html.c @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.228 2018/05/21 01:11:31 schwarze Exp $ */ +/* $Id: html.c,v 1.229 2018/05/25 20:23:51 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 @@ -257,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) @@ -277,6 +293,30 @@ html_make_id(const struct roff_node *n) if (*cp == ' ') *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; } diff --git a/html.h b/html.h index fc722694..1ded39e0 100644 --- a/html.h +++ b/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.89 2018/05/09 00:46:10 schwarze Exp $ */ +/* $Id: html.h,v 1.90 2018/05/25 20:23:51 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2017, 2018 Ingo Schwarze @@ -133,5 +133,5 @@ void print_eqn(struct html *, const struct eqn_box *); void print_paragraph(struct html *); void print_endline(struct html *); -char *html_make_id(const struct roff_node *); +char *html_make_id(const struct roff_node *, int); int html_strlen(const char *); diff --git a/man_html.c b/man_html.c index e8b4138c..90f45528 100644 --- a/man_html.c +++ b/man_html.c @@ -1,4 +1,4 @@ -/* $Id: man_html.c,v 1.149 2018/05/08 21:42:34 schwarze Exp $ */ +/* $Id: man_html.c,v 1.150 2018/05/25 20:23:51 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze @@ -428,11 +428,10 @@ man_SH_pre(MAN_ARGS) char *id; if (n->type == ROFFT_HEAD) { - id = html_make_id(n); + id = html_make_id(n, 1); print_otag(h, TAG_H1, "cTi", "Sh", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - free(id); } return 1; } @@ -498,11 +497,10 @@ man_SS_pre(MAN_ARGS) char *id; if (n->type == ROFFT_HEAD) { - id = html_make_id(n); + id = html_make_id(n, 1); print_otag(h, TAG_H2, "cTi", "Ss", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - free(id); } return 1; } diff --git a/mdoc_html.c b/mdoc_html.c index 58eb71b6..9bdcd426 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.303 2018/05/21 01:11:31 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.304 2018/05/25 20:23:51 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze @@ -502,7 +502,7 @@ cond_id(const struct roff_node *n) (n->parent->tok == MDOC_Xo && n->parent->parent->prev == NULL && n->parent->parent->parent->tok == MDOC_It))) - return html_make_id(n); + return html_make_id(n, 1); return NULL; } @@ -513,11 +513,10 @@ mdoc_sh_pre(MDOC_ARGS) switch (n->type) { case ROFFT_HEAD: - id = html_make_id(n); + id = html_make_id(n, 1); print_otag(h, TAG_H1, "cTi", "Sh", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - free(id); break; case ROFFT_BODY: if (n->sec == SEC_AUTHORS) @@ -537,11 +536,10 @@ mdoc_ss_pre(MDOC_ARGS) if (n->type != ROFFT_HEAD) return 1; - id = html_make_id(n); + id = html_make_id(n, 1); print_otag(h, TAG_H2, "cTi", "Ss", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - free(id); return 1; } @@ -553,7 +551,6 @@ mdoc_fl_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Fl", id); - free(id); print_text(h, "\\-"); if (!(n->child == NULL && @@ -573,7 +570,6 @@ mdoc_cm_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Cm", id); - free(id); return 1; } @@ -882,7 +878,7 @@ mdoc_sx_pre(MDOC_ARGS) { char *id; - id = html_make_id(n); + id = html_make_id(n, 0); print_otag(h, TAG_A, "cThR", "Sx", id); free(id); return 1; @@ -1030,7 +1026,6 @@ mdoc_dv_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Dv", id); - free(id); return 1; } @@ -1042,7 +1037,6 @@ mdoc_ev_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Ev", id); - free(id); return 1; } @@ -1055,12 +1049,11 @@ mdoc_er_pre(MDOC_ARGS) (n->parent->tok == MDOC_It || (n->parent->tok == MDOC_Bq && n->parent->parent->parent->tok == MDOC_It)) ? - html_make_id(n) : NULL; + html_make_id(n, 1) : NULL; if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Er", id); - free(id); return 1; } @@ -1411,7 +1404,6 @@ mdoc_ic_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "cTi", "Ic", id); - free(id); return 1; } @@ -1464,7 +1456,6 @@ mdoc_ms_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_SPAN, "cTi", "Ms", id); - free(id); return 1; } @@ -1505,7 +1496,6 @@ mdoc_no_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_SPAN, "ci", "No", id); - free(id); return 1; } @@ -1517,7 +1507,6 @@ mdoc_li_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); print_otag(h, TAG_CODE, "ci", "Li", id); - free(id); return 1; } -- cgit v1.2.3-56-ge451