From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=SUBJ_OBFU_PUNCT_FEW, UNPARSEABLE_RELAY autolearn=no autolearn_force=no version=3.4.2 Received: (qmail 14422 invoked from network); 19 Apr 2020 15:17:30 -0000 Received: from bsd.lv (HELO mandoc.bsd.lv) (66.111.2.12) by inbox.vuxu.org with UTF8ESMTPZ; 19 Apr 2020 15:17:30 -0000 Received: from fantadrom.bsd.lv (localhost [127.0.0.1]) by mandoc.bsd.lv (OpenSMTPD) with ESMTP id e0610d0d for ; Sun, 19 Apr 2020 10:17:27 -0500 (EST) Received: from localhost (mandoc.bsd.lv [local]) by mandoc.bsd.lv (OpenSMTPD) with ESMTPA id ac95e868 for ; Sun, 19 Apr 2020 10:17:27 -0500 (EST) Date: Sun, 19 Apr 2020 10:17:27 -0500 (EST) X-Mailinglist: mandoc-source Reply-To: source@mandoc.bsd.lv MIME-Version: 1.0 From: schwarze@mandoc.bsd.lv To: source@mandoc.bsd.lv Subject: mandoc: Correctly handle non-unique tags even when NODE_ID and NODE_HREF X-Mailer: activitymail 1.26, http://search.cpan.org/dist/activitymail/ Content-Type: text/plain; charset=utf-8 Message-ID: <8a57be14be74a5bc@mandoc.bsd.lv> Log Message: ----------- Correctly handle non-unique tags even when NODE_ID and NODE_HREF fall apart, NODE_ID occurring earlier than NODE_HREF. Modified Files: -------------- mandoc: html.c mdoc_html.c mandoc_html.3 Revision Data ------------- Index: html.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/html.c,v retrieving revision 1.268 retrieving revision 1.269 diff -Lhtml.c -Lhtml.c -u -p -r1.268 -r1.269 --- html.c +++ html.c @@ -112,6 +112,11 @@ static const struct htmldata htmltags[TA }; /* Avoid duplicate HTML id= attributes. */ + +struct id_entry { + int ord; /* Ordinal number of the latest occurrence. */ + char id[]; /* The id= attribute without any ordinal suffix. */ +}; static struct ohash id_unique; static void html_reset_internal(struct html *); @@ -146,7 +151,7 @@ html_alloc(const struct manoutput *outop if (outopts->toc) h->oflags |= HTML_TOC; - mandoc_ohash_init(&id_unique, 4, 0); + mandoc_ohash_init(&id_unique, 4, offsetof(struct id_entry, id)); return h; } @@ -155,17 +160,17 @@ static void html_reset_internal(struct html *h) { struct tag *tag; - char *cp; + struct id_entry *entry; unsigned int slot; while ((tag = h->tag) != NULL) { h->tag = tag->next; free(tag); } - cp = ohash_first(&id_unique, &slot); - while (cp != NULL) { - free(cp); - cp = ohash_next(&id_unique, &slot); + entry = ohash_first(&id_unique, &slot); + while (entry != NULL) { + free(entry); + entry = ohash_next(&id_unique, &slot); } ohash_delete(&id_unique); } @@ -174,7 +179,7 @@ void html_reset(void *p) { html_reset_internal(p); - mandoc_ohash_init(&id_unique, 4, 0); + mandoc_ohash_init(&id_unique, 4, offsetof(struct id_entry, id)); } void @@ -329,20 +334,24 @@ html_fillmode(struct html *h, enum roff_ * 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. + * The caller is responsible for free(3)ing the returned string. + * * 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(). + * is used for de-duplication. If the "unique" argument is 1, + * it is the first time the function is called for this tag and + * location, so if an ordinal suffix is needed, it is incremented. + * If the "unique" argument is 2, it is the second time the function + * is called for this tag and location, so the ordinal suffix + * remains unchanged. */ char * html_make_id(const struct roff_node *n, int unique) { const struct roff_node *nch; - char *buf, *bufs, *cp; + struct id_entry *entry; + char *buf, *cp; + size_t len; unsigned int slot; - int suffix; if (n->tag != NULL) buf = mandoc_strdup(n->tag); @@ -386,25 +395,21 @@ html_make_id(const struct roff_node *n, /* 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; + if ((entry = ohash_find(&id_unique, slot)) == NULL) { + len = strlen(buf) + 1; + entry = mandoc_malloc(sizeof(*entry) + len); + entry->ord = 1; + memcpy(entry->id, buf, len); + ohash_insert(&id_unique, slot, entry); + } else if (unique == 1) + entry->ord++; + + if (entry->ord > 1) { + cp = buf; + mandoc_asprintf(&buf, "%s_%d", cp, entry->ord); + free(cp); } - ohash_insert(&id_unique, slot, buf); return buf; } @@ -786,7 +791,7 @@ print_otag_id(struct html *h, enum htmlt if (n->flags & NODE_ID) id = html_make_id(n, 1); if (n->flags & NODE_HREF) - href = id == NULL ? html_make_id(n, 0) : id; + href = id == NULL ? html_make_id(n, 2) : id; if (href != NULL && htmltags[elemtype].flags & HTML_INPHRASE) ret = print_otag(h, TAG_A, "chR", "permalink", href); t = print_otag(h, elemtype, "ci", cattr, id); @@ -804,6 +809,7 @@ print_otag_id(struct html *h, enum htmlt print_otag(h, TAG_A, "chR", "permalink", href); } } + free(id); if (id == NULL) free(href); return ret; @@ -915,7 +921,7 @@ print_tagged_text(struct html *h, const print_metaf(h); print_indent(h); - if (n != NULL && (href = html_make_id(n, 0)) != NULL) { + if (n != NULL && (href = html_make_id(n, 2)) != NULL) { t = print_otag(h, TAG_A, "chR", "permalink", href); free(href); } else Index: mandoc_html.3 =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandoc_html.3,v retrieving revision 1.21 retrieving revision 1.22 diff -Lmandoc_html.3 -Lmandoc_html.3 -u -p -r1.21 -r1.22 --- mandoc_html.3 +++ mandoc_html.3 @@ -366,6 +366,18 @@ If the .Fa unique argument is non-zero, deduplication is performed by appending an underscore and a decimal integer, if necessary. +If the +.Fa unique +argument is 1, this is assumed to be the first call for this tag +at this location, typically for use by +.Dv NODE_ID , +so the integer is incremented before use. +If the +.Fa unique +argument is 2, this is ssumed to be the second call for this tag +at this location, typically for use by +.Dv NODE_HREF , +so the existing integer, if any, is used without incrementing it. .Pp The function .Fn print_otag_id @@ -400,9 +412,9 @@ This function is a wrapper around .Fn html_make_id and .Fn print_otag , -fixing the +automatically chosing the .Fa unique -argument to 1 and the +argument appropriately and setting the .Fa fmt arguments to .Qq chR @@ -457,20 +469,9 @@ returns a newly allocated string or if .Fa n lacks text data to create the attribute from. -If the -.Fa unique -argument is 0, the caller is responsible for +The caller is responsible for .Xr free 3 Ns ing the returned string after using it. -If the -.Fa unique -argument is non-zero, the -.Va id_unique -ohash table is used for de-duplication and owns the returned string. -In this case, it will be freed automatically by -.Fn html_reset -or -.Fn html_free . .Pp In case of .Xr malloc 3 Index: mdoc_html.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mdoc_html.c,v retrieving revision 1.339 retrieving revision 1.340 diff -Lmdoc_html.c -Lmdoc_html.c -u -p -r1.339 -r1.340 --- mdoc_html.c +++ mdoc_html.c @@ -695,8 +695,10 @@ mdoc_tg_pre(MDOC_ARGS) { char *id; - if ((id = html_make_id(n, 1)) != NULL) + if ((id = html_make_id(n, 1)) != NULL) { print_tagq(h, print_otag(h, TAG_MARK, "i", id)); + free(id); + } return 0; } @@ -1211,6 +1213,8 @@ mdoc_skip_pre(MDOC_ARGS) static int mdoc_pp_pre(MDOC_ARGS) { + char *id; + if (n->flags & NODE_NOFILL) { print_endline(h); if (n->flags & NODE_ID) @@ -1221,8 +1225,9 @@ mdoc_pp_pre(MDOC_ARGS) } } else { html_close_paragraph(h); - print_otag(h, TAG_P, "ci", "Pp", - n->flags & NODE_ID ? html_make_id(n, 1) : NULL); + id = n->flags & NODE_ID ? html_make_id(n, 1) : NULL; + print_otag(h, TAG_P, "ci", "Pp", id); + free(id); } return 0; } -- To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv