[BACK]Return to html.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/html.c between version 1.264 and 1.269

version 1.264, 2020/03/13 15:32:28 version 1.269, 2020/04/19 15:16:56
Line 112  static const struct htmldata htmltags[TAG_MAX] = {
Line 112  static const struct htmldata htmltags[TAG_MAX] = {
 };  };
   
 /* Avoid duplicate HTML id= attributes. */  /* 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  struct ohash     id_unique;
   
 static  void     html_reset_internal(struct html *);  static  void     html_reset_internal(struct html *);
Line 146  html_alloc(const struct manoutput *outopts)
Line 151  html_alloc(const struct manoutput *outopts)
         if (outopts->toc)          if (outopts->toc)
                 h->oflags |= HTML_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;          return h;
 }  }
Line 155  static void
Line 160  static void
 html_reset_internal(struct html *h)  html_reset_internal(struct html *h)
 {  {
         struct tag      *tag;          struct tag      *tag;
         char            *cp;          struct id_entry *entry;
         unsigned int     slot;          unsigned int     slot;
   
         while ((tag = h->tag) != NULL) {          while ((tag = h->tag) != NULL) {
                 h->tag = tag->next;                  h->tag = tag->next;
                 free(tag);                  free(tag);
         }          }
         cp = ohash_first(&id_unique, &slot);          entry = ohash_first(&id_unique, &slot);
         while (cp != NULL) {          while (entry != NULL) {
                 free(cp);                  free(entry);
                 cp = ohash_next(&id_unique, &slot);                  entry = ohash_next(&id_unique, &slot);
         }          }
         ohash_delete(&id_unique);          ohash_delete(&id_unique);
 }  }
Line 174  void
Line 179  void
 html_reset(void *p)  html_reset(void *p)
 {  {
         html_reset_internal(p);          html_reset_internal(p);
         mandoc_ohash_init(&id_unique, 4, 0);          mandoc_ohash_init(&id_unique, 4, offsetof(struct id_entry, id));
 }  }
   
 void  void
Line 329  html_fillmode(struct html *h, enum roff_tok want)
Line 334  html_fillmode(struct html *h, enum roff_tok want)
  * element and/or as a segment identifier for a URI in an <a> element.   * element and/or as a segment identifier for a URI in an <a> element.
  * The function may fail and return NULL if the node lacks text data   * The function may fail and return NULL if the node lacks text data
  * to create the attribute from.   * to create the attribute from.
  * If the "unique" argument is 0, the caller is responsible for   * The caller is responsible for free(3)ing the returned string.
  * free(3)ing the returned string after using it.   *
  * If the "unique" argument is non-zero, the "id_unique" ohash table   * If the "unique" argument is non-zero, the "id_unique" ohash table
  * is used for de-duplication and owns the returned string, so the   * is used for de-duplication.  If the "unique" argument is 1,
  * caller must not free(3) it.  In this case, it will be freed   * it is the first time the function is called for this tag and
  * automatically by html_reset() or html_free().   * 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 *  char *
 html_make_id(const struct roff_node *n, int unique)  html_make_id(const struct roff_node *n, int unique)
 {  {
         const struct roff_node  *nch;          const struct roff_node  *nch;
         char                    *buf, *bufs, *cp;          struct id_entry         *entry;
           char                    *buf, *cp;
           size_t                   len;
         unsigned int             slot;          unsigned int             slot;
         int                      suffix;  
   
         if (n->string != NULL)          if (n->tag != NULL)
                 buf = mandoc_strdup(n->string);                  buf = mandoc_strdup(n->tag);
         else {          else {
                 switch (n->tok) {                  switch (n->tok) {
                 case MDOC_Sh:                  case MDOC_Sh:
Line 362  html_make_id(const struct roff_node *n, int unique)
Line 371  html_make_id(const struct roff_node *n, int unique)
                                 return NULL;                                  return NULL;
                         break;                          break;
                 default:                  default:
                         if (n->child->type != ROFFT_TEXT)                          if (n->child == NULL || n->child->type != ROFFT_TEXT)
                                 return NULL;                                  return NULL;
                         buf = mandoc_strdup(n->child->string);                          buf = mandoc_strdup(n->child->string);
                         break;                          break;
Line 386  html_make_id(const struct roff_node *n, int unique)
Line 395  html_make_id(const struct roff_node *n, int unique)
   
         /* Avoid duplicate HTML id= attributes. */          /* Avoid duplicate HTML id= attributes. */
   
         bufs = NULL;  
         suffix = 1;  
         slot = ohash_qlookup(&id_unique, buf);          slot = ohash_qlookup(&id_unique, buf);
         cp = ohash_find(&id_unique, slot);          if ((entry = ohash_find(&id_unique, slot)) == NULL) {
         if (cp != NULL) {                  len = strlen(buf) + 1;
                 while (cp != NULL) {                  entry = mandoc_malloc(sizeof(*entry) + len);
                         free(bufs);                  entry->ord = 1;
                         if (++suffix > 127) {                  memcpy(entry->id, buf, len);
                                 free(buf);                  ohash_insert(&id_unique, slot, entry);
                                 return NULL;          } else if (unique == 1)
                         }                  entry->ord++;
                         mandoc_asprintf(&bufs, "%s_%d", buf, suffix);  
                         slot = ohash_qlookup(&id_unique, bufs);          if (entry->ord > 1) {
                         cp = ohash_find(&id_unique, slot);                  cp = buf;
                 }                  mandoc_asprintf(&buf, "%s_%d", cp, entry->ord);
                 free(buf);                  free(cp);
                 buf = bufs;  
         }          }
         ohash_insert(&id_unique, slot, buf);  
         return buf;          return buf;
 }  }
   
Line 769  print_otag(struct html *h, enum htmltag tag, const cha
Line 774  print_otag(struct html *h, enum htmltag tag, const cha
   
 /*  /*
  * Print an element with an optional "id=" attribute.   * Print an element with an optional "id=" attribute.
  * If there is an "id=" attribute, also add a permalink:   * If the element has phrasing content and an "id=" attribute,
  * outside if it's a phrasing element, or inside otherwise.   * also add a permalink: outside if it can be in phrasing context,
    * inside otherwise.
  */   */
 struct tag *  struct tag *
 print_otag_id(struct html *h, enum htmltag elemtype, const char *cattr,  print_otag_id(struct html *h, enum htmltag elemtype, const char *cattr,
     struct roff_node *n)      struct roff_node *n)
 {  {
           struct roff_node *nch;
         struct tag      *ret, *t;          struct tag      *ret, *t;
         const char      *id;          char            *id, *href;
   
         ret = NULL;          ret = NULL;
         id = NULL;          id = href = NULL;
         if (n->flags & NODE_ID)          if (n->flags & NODE_ID)
                 id = html_make_id(n, 1);                  id = html_make_id(n, 1);
         if (id != NULL && htmltags[elemtype].flags & HTML_INPHRASE)          if (n->flags & NODE_HREF)
                 ret = print_otag(h, TAG_A, "chR", "permalink", 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);          t = print_otag(h, elemtype, "ci", cattr, id);
         if (ret == NULL) {          if (ret == NULL) {
                 ret = t;                  ret = t;
                 if (id != NULL)                  if (href != NULL && (nch = n->child) != NULL) {
                         print_otag(h, TAG_A, "chR", "permalink", id);                          /* man(7) is safe, it tags phrasing content only. */
                           if (n->tok > MDOC_MAX ||
                               htmltags[elemtype].flags & HTML_TOPHRASE)
                                   nch = NULL;
                           else  /* For mdoc(7), beware of nested blocks. */
                                   while (nch != NULL && nch->type == ROFFT_TEXT)
                                           nch = nch->next;
                           if (nch == NULL)
                                   print_otag(h, TAG_A, "chR", "permalink", href);
                   }
         }          }
           free(id);
           if (id == NULL)
                   free(href);
         return ret;          return ret;
 }  }
   
Line 863  print_gen_comment(struct html *h, struct roff_node *n)
Line 884  print_gen_comment(struct html *h, struct roff_node *n)
 void  void
 print_text(struct html *h, const char *word)  print_text(struct html *h, const char *word)
 {  {
           print_tagged_text(h, word, NULL);
   }
   
   void
   print_tagged_text(struct html *h, const char *word, struct roff_node *n)
   {
           struct tag      *t;
           char            *href;
   
         /*          /*
          * Always wrap text in a paragraph unless already contained in           * Always wrap text in a paragraph unless already contained in
          * some flow container; never put it directly into a section.           * some flow container; never put it directly into a section.
Line 883  print_text(struct html *h, const char *word)
Line 913  print_text(struct html *h, const char *word)
         }          }
   
         /*          /*
          * Print the text, optionally surrounded by HTML whitespace,           * Optionally switch fonts, optionally write a permalink, then
          * optionally manually switching fonts before and after.           * print the text, optionally surrounded by HTML whitespace.
          */           */
   
         assert(h->metaf == NULL);          assert(h->metaf == NULL);
         print_metaf(h);          print_metaf(h);
         print_indent(h);          print_indent(h);
   
           if (n != NULL && (href = html_make_id(n, 2)) != NULL) {
                   t = print_otag(h, TAG_A, "chR", "permalink", href);
                   free(href);
           } else
                   t = NULL;
   
         if ( ! print_encode(h, word, NULL, 0)) {          if ( ! print_encode(h, word, NULL, 0)) {
                 if ( ! (h->flags & HTML_NONOSPACE))                  if ( ! (h->flags & HTML_NONOSPACE))
                         h->flags &= ~HTML_NOSPACE;                          h->flags &= ~HTML_NOSPACE;
Line 900  print_text(struct html *h, const char *word)
Line 937  print_text(struct html *h, const char *word)
         if (h->metaf != NULL) {          if (h->metaf != NULL) {
                 print_tagq(h, h->metaf);                  print_tagq(h, h->metaf);
                 h->metaf = NULL;                  h->metaf = NULL;
         }          } else if (t != NULL)
                   print_tagq(h, t);
   
         h->flags &= ~HTML_IGNDELIM;          h->flags &= ~HTML_IGNDELIM;
 }  }

Legend:
Removed from v.1.264  
changed lines
  Added in v.1.269

CVSweb