Print this page
9718 update mandoc to 1.14.4

@@ -1,9 +1,9 @@
-/*      $Id: mdoc_html.c,v 1.294 2017/07/15 17:57:51 schwarze Exp $ */
+/*      $Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *

@@ -32,12 +32,10 @@
 #include "mdoc.h"
 #include "out.h"
 #include "html.h"
 #include "main.h"
 
-#define INDENT           5
-
 #define MDOC_ARGS         const struct roff_meta *meta, \
                           struct roff_node *n, \
                           struct html *h
 
 #ifndef MIN

@@ -48,18 +46,21 @@
         int             (*pre)(MDOC_ARGS);
         void            (*post)(MDOC_ARGS);
 };
 
 static  char             *cond_id(const struct roff_node *);
-static  void              print_mdoc_head(MDOC_ARGS);
+static  void              print_mdoc_head(const struct roff_meta *,
+                                struct html *);
 static  void              print_mdoc_node(MDOC_ARGS);
 static  void              print_mdoc_nodelist(MDOC_ARGS);
 static  void              synopsis_pre(struct html *,
                                 const struct roff_node *);
 
-static  void              mdoc_root_post(MDOC_ARGS);
-static  int               mdoc_root_pre(MDOC_ARGS);
+static  void              mdoc_root_post(const struct roff_meta *,
+                                struct html *);
+static  int               mdoc_root_pre(const struct roff_meta *,
+                                struct html *);
 
 static  void              mdoc__x_post(MDOC_ARGS);
 static  int               mdoc__x_pre(MDOC_ARGS);
 static  int               mdoc_ad_pre(MDOC_ARGS);
 static  int               mdoc_an_pre(MDOC_ARGS);

@@ -283,33 +284,37 @@
 
 void
 html_mdoc(void *arg, const struct roff_man *mdoc)
 {
         struct html     *h;
+        struct roff_node        *n;
         struct tag      *t;
 
         h = (struct html *)arg;
+        n = mdoc->first->child;
 
         if ((h->oflags & HTML_FRAGMENT) == 0) {
                 print_gen_decls(h);
                 print_otag(h, TAG_HTML, "");
+                if (n->type == ROFFT_COMMENT)
+                        print_gen_comment(h, n);
                 t = print_otag(h, TAG_HEAD, "");
-                print_mdoc_head(&mdoc->meta, mdoc->first->child, h);
+                print_mdoc_head(&mdoc->meta, h);
                 print_tagq(h, t);
                 print_otag(h, TAG_BODY, "");
         }
 
-        mdoc_root_pre(&mdoc->meta, mdoc->first->child, h);
+        mdoc_root_pre(&mdoc->meta, h);
         t = print_otag(h, TAG_DIV, "c", "manual-text");
-        print_mdoc_nodelist(&mdoc->meta, mdoc->first->child, h);
+        print_mdoc_nodelist(&mdoc->meta, n, h);
         print_tagq(h, t);
-        mdoc_root_post(&mdoc->meta, mdoc->first->child, h);
+        mdoc_root_post(&mdoc->meta, h);
         print_tagq(h, NULL);
 }
 
 static void
-print_mdoc_head(MDOC_ARGS)
+print_mdoc_head(const struct roff_meta *meta, struct html *h)
 {
         char    *cp;
 
         print_gen_head(h);
 

@@ -342,11 +347,11 @@
 print_mdoc_node(MDOC_ARGS)
 {
         int              child;
         struct tag      *t;
 
-        if (n->flags & NODE_NOPRT)
+        if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
                 return;
 
         child = 1;
         t = h->tag;
         n->flags &= ~NODE_ENDED;

@@ -427,11 +432,11 @@
                 break;
         }
 }
 
 static void
-mdoc_root_post(MDOC_ARGS)
+mdoc_root_post(const struct roff_meta *meta, struct html *h)
 {
         struct tag      *t, *tt;
 
         t = print_otag(h, TAG_TABLE, "c", "foot");
         tt = print_otag(h, TAG_TR, "");

@@ -444,11 +449,11 @@
         print_text(h, meta->os);
         print_tagq(h, t);
 }
 
 static int
-mdoc_root_pre(MDOC_ARGS)
+mdoc_root_pre(const struct roff_meta *meta, struct html *h)
 {
         struct tag      *t, *tt;
         char            *volume, *title;
 
         if (NULL == meta->arch)

@@ -493,11 +498,11 @@
               strcmp(n->prev->string, "|") == 0)) &&
             (n->parent->tok == MDOC_It ||
              (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;
 }
 
 static int
 mdoc_sh_pre(MDOC_ARGS)

@@ -504,15 +509,14 @@
 {
         char    *id;
 
         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", "selflink", id);
-                free(id);
+                        print_otag(h, TAG_A, "chR", "permalink", id);
                 break;
         case ROFFT_BODY:
                 if (n->sec == SEC_AUTHORS)
                         h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
                 break;

@@ -528,27 +532,25 @@
         char    *id;
 
         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", "selflink", id);
-        free(id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         return 1;
 }
 
 static int
 mdoc_fl_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
-        print_otag(h, TAG_B, "cTi", "Fl", id);
-        free(id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
+        print_otag(h, TAG_CODE, "cTi", "Fl", id);
 
         print_text(h, "\\-");
         if (!(n->child == NULL &&
             (n->next == NULL ||
              n->next->type == ROFFT_TEXT ||

@@ -562,26 +564,24 @@
 mdoc_cm_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
-        print_otag(h, TAG_B, "cTi", "Cm", id);
-        free(id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
+        print_otag(h, TAG_CODE, "cTi", "Cm", id);
         return 1;
 }
 
 static int
 mdoc_nd_pre(MDOC_ARGS)
 {
         if (n->type != ROFFT_BODY)
                 return 1;
 
-        /* XXX: this tag in theory can contain block elements. */
-
         print_text(h, "\\(em");
-        print_otag(h, TAG_SPAN, "cT", "Nd");
+        /* Cannot use TAG_SPAN because it may contain blocks. */
+        print_otag(h, TAG_DIV, "cT", "Nd");
         return 1;
 }
 
 static int
 mdoc_nm_pre(MDOC_ARGS)

@@ -589,11 +589,11 @@
         switch (n->type) {
         case ROFFT_HEAD:
                 print_otag(h, TAG_TD, "");
                 /* FALLTHROUGH */
         case ROFFT_ELEM:
-                print_otag(h, TAG_B, "cT", "Nm");
+                print_otag(h, TAG_CODE, "cT", "Nm");
                 return 1;
         case ROFFT_BODY:
                 print_otag(h, TAG_TD, "");
                 return 1;
         default:

@@ -659,65 +659,28 @@
 static int
 mdoc_it_pre(MDOC_ARGS)
 {
         const struct roff_node  *bl;
         struct tag              *t;
-        const char              *cattr;
         enum mdoc_list           type;
 
         bl = n->parent;
         while (bl->tok != MDOC_Bl)
                 bl = bl->parent;
         type = bl->norm->Bl.type;
 
         switch (type) {
         case LIST_bullet:
-                cattr = "It-bullet";
-                break;
         case LIST_dash:
         case LIST_hyphen:
-                cattr = "It-dash";
-                break;
         case LIST_item:
-                cattr = "It-item";
-                break;
         case LIST_enum:
-                cattr = "It-enum";
-                break;
-        case LIST_diag:
-                cattr = "It-diag";
-                break;
-        case LIST_hang:
-                cattr = "It-hang";
-                break;
-        case LIST_inset:
-                cattr = "It-inset";
-                break;
-        case LIST_ohang:
-                cattr = "It-ohang";
-                break;
-        case LIST_tag:
-                cattr = "It-tag";
-                break;
-        case LIST_column:
-                cattr = "It-column";
-                break;
-        default:
-                break;
-        }
-
-        switch (type) {
-        case LIST_bullet:
-        case LIST_dash:
-        case LIST_hyphen:
-        case LIST_item:
-        case LIST_enum:
                 switch (n->type) {
                 case ROFFT_HEAD:
                         return 0;
                 case ROFFT_BODY:
-                        print_otag(h, TAG_LI, "c", cattr);
+                        print_otag(h, TAG_LI, "");
                         break;
                 default:
                         break;
                 }
                 break;

@@ -725,17 +688,14 @@
         case LIST_hang:
         case LIST_inset:
         case LIST_ohang:
                 switch (n->type) {
                 case ROFFT_HEAD:
-                        print_otag(h, TAG_DT, "c", cattr);
-                        if (type == LIST_diag)
-                                print_otag(h, TAG_B, "c", cattr);
+                        print_otag(h, TAG_DT, "");
                         break;
                 case ROFFT_BODY:
-                        print_otag(h, TAG_DD, "csw*+l", cattr,
-                            bl->norm->Bl.width);
+                        print_otag(h, TAG_DD, "");
                         break;
                 default:
                         break;
                 }
                 break;

@@ -744,28 +704,25 @@
                 case ROFFT_HEAD:
                         if (h->style != NULL && !bl->norm->Bl.comp &&
                             (n->parent->prev == NULL ||
                              n->parent->prev->body == NULL ||
                              n->parent->prev->body->child != NULL)) {
-                                t = print_otag(h, TAG_DT, "csw*+-l",
-                                    cattr, bl->norm->Bl.width);
+                                t = print_otag(h, TAG_DT, "");
                                 print_text(h, "\\ ");
                                 print_tagq(h, t);
-                                t = print_otag(h, TAG_DD, "c", cattr);
+                                t = print_otag(h, TAG_DD, "");
                                 print_text(h, "\\ ");
                                 print_tagq(h, t);
                         }
-                        print_otag(h, TAG_DT, "csw*+-l", cattr,
-                            bl->norm->Bl.width);
+                        print_otag(h, TAG_DT, "");
                         break;
                 case ROFFT_BODY:
                         if (n->child == NULL) {
-                                print_otag(h, TAG_DD, "css?", cattr,
-                                    "width", "auto");
+                                print_otag(h, TAG_DD, "s", "width", "auto");
                                 print_text(h, "\\ ");
                         } else
-                                print_otag(h, TAG_DD, "c", cattr);
+                                print_otag(h, TAG_DD, "");
                         break;
                 default:
                         break;
                 }
                 break;

@@ -772,14 +729,14 @@
         case LIST_column:
                 switch (n->type) {
                 case ROFFT_HEAD:
                         break;
                 case ROFFT_BODY:
-                        print_otag(h, TAG_TD, "c", cattr);
+                        print_otag(h, TAG_TD, "");
                         break;
                 default:
-                        print_otag(h, TAG_TR, "c", cattr);
+                        print_otag(h, TAG_TR, "");
                 }
         default:
                 break;
         }
 

@@ -787,44 +744,24 @@
 }
 
 static int
 mdoc_bl_pre(MDOC_ARGS)
 {
-        char             cattr[21];
-        struct tag      *t;
+        char             cattr[28];
         struct mdoc_bl  *bl;
-        size_t           i;
         enum htmltag     elemtype;
 
-        bl = &n->norm->Bl;
-
         switch (n->type) {
         case ROFFT_BODY:
                 return 1;
-
         case ROFFT_HEAD:
-                if (bl->type != LIST_column || bl->ncols == 0)
                         return 0;
-
-                /*
-                 * For each column, print out the <COL> tag with our
-                 * suggested width.  The last column gets min-width, as
-                 * in terminal mode it auto-sizes to the width of the
-                 * screen and we want to preserve that behaviour.
-                 */
-
-                t = print_otag(h, TAG_COLGROUP, "");
-                for (i = 0; i < bl->ncols - 1; i++)
-                        print_otag(h, TAG_COL, "sw+w", bl->cols[i]);
-                print_otag(h, TAG_COL, "swW", bl->cols[i]);
-                print_tagq(h, t);
-                return 0;
-
         default:
                 break;
         }
 
+        bl = &n->norm->Bl;
         switch (bl->type) {
         case LIST_bullet:
                 elemtype = TAG_UL;
                 (void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
                 break;

@@ -857,24 +794,26 @@
                 elemtype = TAG_DL;
                 (void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
                 break;
         case LIST_tag:
                 if (bl->offs)
-                        print_otag(h, TAG_DIV, "cswl", "Bl-tag", bl->offs);
-                print_otag(h, TAG_DL, "csw*+l", bl->comp ?
-                    "Bl-tag Bl-compact" : "Bl-tag", bl->width);
+                        print_otag(h, TAG_DIV, "c", "Bd-indent");
+                print_otag(h, TAG_DL, "c", bl->comp ?
+                    "Bl-tag Bl-compact" : "Bl-tag");
                 return 1;
         case LIST_column:
                 elemtype = TAG_TABLE;
                 (void)strlcpy(cattr, "Bl-column", sizeof(cattr));
                 break;
         default:
                 abort();
         }
+        if (bl->offs != NULL)
+                (void)strlcat(cattr, " Bd-indent", sizeof(cattr));
         if (bl->comp)
                 (void)strlcat(cattr, " Bl-compact", sizeof(cattr));
-        print_otag(h, elemtype, "cswl", cattr, bl->offs);
+        print_otag(h, elemtype, "c", cattr);
         return 1;
 }
 
 static int
 mdoc_ex_pre(MDOC_ARGS)

@@ -902,11 +841,11 @@
 mdoc_d1_pre(MDOC_ARGS)
 {
         if (n->type != ROFFT_BLOCK)
                 return 1;
 
-        print_otag(h, TAG_DIV, "c", "D1");
+        print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
 
         if (n->tok == MDOC_Dl)
                 print_otag(h, TAG_CODE, "c", "Li");
 
         return 1;

@@ -915,20 +854,20 @@
 static int
 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;
 }
 
 static int
 mdoc_bd_pre(MDOC_ARGS)
 {
-        int                      comp, offs, sv;
+        int                      comp, sv;
         struct roff_node        *nn;
 
         if (n->type == ROFFT_HEAD)
                 return 0;
 

@@ -949,23 +888,14 @@
 
         /* Handle the -offset argument. */
 
         if (n->norm->Bd.offs == NULL ||
             ! strcmp(n->norm->Bd.offs, "left"))
-                offs = 0;
-        else if ( ! strcmp(n->norm->Bd.offs, "indent"))
-                offs = INDENT;
-        else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
-                offs = INDENT * 2;
+                print_otag(h, TAG_DIV, "c", "Bd");
         else
-                offs = -1;
+                print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
 
-        if (offs == -1)
-                print_otag(h, TAG_DIV, "cswl", "Bd", n->norm->Bd.offs);
-        else
-                print_otag(h, TAG_DIV, "cshl", "Bd", offs);
-
         if (n->norm->Bd.type != DISP_unfilled &&
             n->norm->Bd.type != DISP_literal)
                 return 1;
 
         print_otag(h, TAG_PRE, "c", "Li");

@@ -1012,18 +942,18 @@
 }
 
 static int
 mdoc_pa_pre(MDOC_ARGS)
 {
-        print_otag(h, TAG_I, "cT", "Pa");
+        print_otag(h, TAG_SPAN, "cT", "Pa");
         return 1;
 }
 
 static int
 mdoc_ad_pre(MDOC_ARGS)
 {
-        print_otag(h, TAG_I, "c", "Ad");
+        print_otag(h, TAG_SPAN, "c", "Ad");
         return 1;
 }
 
 static int
 mdoc_an_pre(MDOC_ARGS)

@@ -1051,35 +981,33 @@
 
 static int
 mdoc_cd_pre(MDOC_ARGS)
 {
         synopsis_pre(h, n);
-        print_otag(h, TAG_B, "cT", "Cd");
+        print_otag(h, TAG_CODE, "cT", "Cd");
         return 1;
 }
 
 static int
 mdoc_dv_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         print_otag(h, TAG_CODE, "cTi", "Dv", id);
-        free(id);
         return 1;
 }
 
 static int
 mdoc_ev_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         print_otag(h, TAG_CODE, "cTi", "Ev", id);
-        free(id);
         return 1;
 }
 
 static int
 mdoc_er_pre(MDOC_ARGS)

@@ -1088,16 +1016,15 @@
 
         id = n->sec == SEC_ERRORS &&
             (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", "selflink", id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         print_otag(h, TAG_CODE, "cTi", "Er", id);
-        free(id);
         return 1;
 }
 
 static int
 mdoc_fa_pre(MDOC_ARGS)

@@ -1140,15 +1067,15 @@
                 return 0;
 
         assert(n->type == ROFFT_TEXT);
 
         if (strcmp(n->string, "#include")) {
-                print_otag(h, TAG_B, "cT", "Fd");
+                print_otag(h, TAG_CODE, "cT", "Fd");
                 return 1;
         }
 
-        print_otag(h, TAG_B, "cT", "In");
+        print_otag(h, TAG_CODE, "cT", "In");
         print_text(h, n->string);
 
         if (NULL != (n = n->next)) {
                 assert(n->type == ROFFT_TEXT);
 

@@ -1230,11 +1157,11 @@
                         ep = strchr(sp, ' ');
                 }
                 print_tagq(h, t);
         }
 
-        t = print_otag(h, TAG_B, "cT", "Fn");
+        t = print_otag(h, TAG_CODE, "cT", "Fn");
 
         if (sp)
                 print_text(h, sp);
 
         print_tagq(h, t);

@@ -1243,11 +1170,11 @@
         print_text(h, "(");
         h->flags |= HTML_NOSPACE;
 
         for (n = n->child->next; n; n = n->next) {
                 if (NODE_SYNPRETTY & n->flags)
-                        t = print_otag(h, TAG_VAR, "cTss?", "Fa",
+                        t = print_otag(h, TAG_VAR, "cTs", "Fa",
                             "white-space", "nowrap");
                 else
                         t = print_otag(h, TAG_VAR, "cT", "Fa");
                 print_text(h, n->string);
                 print_tagq(h, t);

@@ -1373,11 +1300,11 @@
 
         if (n->child == NULL)
                 return 0;
 
         assert(n->child->string);
-        t = print_otag(h, TAG_B, "cT", "Fn");
+        t = print_otag(h, TAG_CODE, "cT", "Fn");
         print_text(h, n->child->string);
         print_tagq(h, t);
         return 0;
 }
 

@@ -1397,11 +1324,11 @@
 mdoc_in_pre(MDOC_ARGS)
 {
         struct tag      *t;
 
         synopsis_pre(h, n);
-        print_otag(h, TAG_B, "cT", "In");
+        print_otag(h, TAG_CODE, "cT", "In");
 
         /*
          * The first argument of the `In' gets special treatment as
          * being a linked value.  Subsequent values are printed
          * afterward.  groff does similarly.  This also handles the case

@@ -1442,13 +1369,12 @@
 mdoc_ic_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
-        print_otag(h, TAG_B, "cTi", "Ic", id);
-        free(id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
+        print_otag(h, TAG_CODE, "cTi", "Ic", id);
         return 1;
 }
 
 static int
 mdoc_va_pre(MDOC_ARGS)

@@ -1476,36 +1402,31 @@
                 return 0;
         else if (n->type != ROFFT_BODY)
                 return 1;
 
         if (FONT_Em == n->norm->Bf.font)
-                cattr = "Em";
+                cattr = "Bf Em";
         else if (FONT_Sy == n->norm->Bf.font)
-                cattr = "Sy";
+                cattr = "Bf Sy";
         else if (FONT_Li == n->norm->Bf.font)
-                cattr = "Li";
+                cattr = "Bf Li";
         else
-                cattr = "No";
+                cattr = "Bf No";
 
-        /*
-         * We want this to be inline-formatted, but needs to be div to
-         * accept block children.
-         */
-
-        print_otag(h, TAG_DIV, "css?hl", cattr, "display", "inline", 1);
+        /* Cannot use TAG_SPAN because it may contain blocks. */
+        print_otag(h, TAG_DIV, "c", cattr);
         return 1;
 }
 
 static int
 mdoc_ms_pre(MDOC_ARGS)
 {
         char *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
-        print_otag(h, TAG_B, "cTi", "Ms", id);
-        free(id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
+        print_otag(h, TAG_SPAN, "cTi", "Ms", id);
         return 1;
 }
 
 static int
 mdoc_igndelim_pre(MDOC_ARGS)

@@ -1540,25 +1461,23 @@
 mdoc_no_pre(MDOC_ARGS)
 {
         char *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         print_otag(h, TAG_SPAN, "ci", "No", id);
-        free(id);
         return 1;
 }
 
 static int
 mdoc_li_pre(MDOC_ARGS)
 {
         char    *id;
 
         if ((id = cond_id(n)) != NULL)
-                print_otag(h, TAG_A, "chR", "selflink", id);
+                print_otag(h, TAG_A, "chR", "permalink", id);
         print_otag(h, TAG_CODE, "ci", "Li", id);
-        free(id);
         return 1;
 }
 
 static int
 mdoc_sy_pre(MDOC_ARGS)

@@ -1710,11 +1629,12 @@
                 break;
         case MDOC_Oo:
         case MDOC_Op:
                 print_text(h, "\\(lB");
                 h->flags |= HTML_NOSPACE;
-                print_otag(h, TAG_SPAN, "c", "Op");
+                /* Cannot use TAG_SPAN because it may contain blocks. */
+                print_otag(h, TAG_IDIV, "c", "Op");
                 break;
         case MDOC_En:
                 if (NULL == n->norm->Es ||
                     NULL == n->norm->Es->child)
                         return 1;