]>
git.cameronkatri.com Git - mandoc.git/blob - html.c
1 /* $Id: html.c,v 1.46 2009/09/21 13:44:56 kristaps Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/types.h>
18 #include <sys/queue.h>
32 #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
33 #define DTD "http://www.w3.org/TR/html4/strict.dtd"
81 #define HTML_CLRLINE (1 << 0)
82 #define HTML_NOSTACK (1 << 1)
85 static const struct htmldata htmltags
[TAG_MAX
] = {
86 {"html", HTML_CLRLINE
}, /* TAG_HTML */
87 {"head", HTML_CLRLINE
}, /* TAG_HEAD */
88 {"body", HTML_CLRLINE
}, /* TAG_BODY */
89 {"meta", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_META */
90 {"title", HTML_CLRLINE
}, /* TAG_TITLE */
91 {"div", HTML_CLRLINE
}, /* TAG_DIV */
92 {"h1", 0}, /* TAG_H1 */
93 {"h2", 0}, /* TAG_H2 */
94 {"p", HTML_CLRLINE
}, /* TAG_P */
95 {"span", 0}, /* TAG_SPAN */
96 {"link", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_LINK */
97 {"br", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_LINK */
99 {"table", HTML_CLRLINE
}, /* TAG_TABLE */
100 {"col", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_COL */
101 {"tr", HTML_CLRLINE
}, /* TAG_TR */
102 {"td", HTML_CLRLINE
}, /* TAG_TD */
103 {"li", HTML_CLRLINE
}, /* TAG_LI */
104 {"ul", HTML_CLRLINE
}, /* TAG_UL */
105 {"ol", HTML_CLRLINE
}, /* TAG_OL */
106 {"base", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_BASE */
109 static const char *const htmlattrs
[ATTR_MAX
] = {
130 SLIST_ENTRY(tag
) entry
;
136 SLIST_ENTRY(ord
) entry
;
139 SLIST_HEAD(tagq
, tag
);
140 SLIST_HEAD(ordq
, ord
);
144 #define HTML_NOSPACE (1 << 0)
145 #define HTML_NEWLINE (1 << 1)
153 #define MDOC_ARGS const struct mdoc_meta *m, \
154 const struct mdoc_node *n, \
156 #define MAN_ARGS const struct man_meta *m, \
157 const struct man_node *n, \
160 int (*pre
)(MDOC_ARGS
);
161 void (*post
)(MDOC_ARGS
);
164 static void print_gen_doctype(struct html
*);
165 static void print_gen_head(struct html
*);
166 static void print_mdoc(MDOC_ARGS
);
167 static void print_mdoc_head(MDOC_ARGS
);
168 static void print_mdoc_node(MDOC_ARGS
);
169 static void print_mdoc_nodelist(MDOC_ARGS
);
170 static void print_man(MAN_ARGS
);
171 static void print_man_head(MAN_ARGS
);
172 static struct tag
*print_otag(struct html
*, enum htmltag
,
173 int, const struct htmlpair
*);
174 static void print_tagq(struct html
*, const struct tag
*);
175 static void print_stagq(struct html
*, const struct tag
*);
176 static void print_ctag(struct html
*, enum htmltag
);
177 static void print_encode(struct html
*, const char *);
178 static void print_escape(struct html
*, const char **);
179 static void print_text(struct html
*, const char *);
180 static void print_res(struct html
*, const char *, int);
181 static void print_spec(struct html
*, const char *, int);
183 static int a2width(const char *);
184 static int a2offs(const char *);
185 static int a2list(const struct mdoc_node
*);
187 static void mdoc_root_post(MDOC_ARGS
);
188 static int mdoc_root_pre(MDOC_ARGS
);
189 static int mdoc_tbl_pre(MDOC_ARGS
, int);
190 static int mdoc_tbl_block_pre(MDOC_ARGS
, int, int, int, int);
191 static int mdoc_tbl_body_pre(MDOC_ARGS
, int, int);
192 static int mdoc_tbl_head_pre(MDOC_ARGS
, int, int);
194 static int mdoc_ad_pre(MDOC_ARGS
);
195 static int mdoc_an_pre(MDOC_ARGS
);
196 static void mdoc_aq_post(MDOC_ARGS
);
197 static int mdoc_aq_pre(MDOC_ARGS
);
198 static int mdoc_ar_pre(MDOC_ARGS
);
199 static int mdoc_bd_pre(MDOC_ARGS
);
200 static void mdoc_bl_post(MDOC_ARGS
);
201 static int mdoc_bl_pre(MDOC_ARGS
);
202 static int mdoc_cd_pre(MDOC_ARGS
);
203 static int mdoc_d1_pre(MDOC_ARGS
);
204 static void mdoc_dq_post(MDOC_ARGS
);
205 static int mdoc_dq_pre(MDOC_ARGS
);
206 static int mdoc_dv_pre(MDOC_ARGS
);
207 static int mdoc_fa_pre(MDOC_ARGS
);
208 static int mdoc_fd_pre(MDOC_ARGS
);
209 static int mdoc_fl_pre(MDOC_ARGS
);
210 static int mdoc_fn_pre(MDOC_ARGS
);
211 static int mdoc_ft_pre(MDOC_ARGS
);
212 static int mdoc_em_pre(MDOC_ARGS
);
213 static int mdoc_er_pre(MDOC_ARGS
);
214 static int mdoc_ev_pre(MDOC_ARGS
);
215 static int mdoc_ex_pre(MDOC_ARGS
);
216 static int mdoc_it_pre(MDOC_ARGS
);
217 static int mdoc_nd_pre(MDOC_ARGS
);
218 static int mdoc_nm_pre(MDOC_ARGS
);
219 static int mdoc_ns_pre(MDOC_ARGS
);
220 static void mdoc_op_post(MDOC_ARGS
);
221 static int mdoc_op_pre(MDOC_ARGS
);
222 static int mdoc_pa_pre(MDOC_ARGS
);
223 static int mdoc_pp_pre(MDOC_ARGS
);
224 static void mdoc_pq_post(MDOC_ARGS
);
225 static int mdoc_pq_pre(MDOC_ARGS
);
226 static void mdoc_qq_post(MDOC_ARGS
);
227 static int mdoc_qq_pre(MDOC_ARGS
);
228 static int mdoc_sh_pre(MDOC_ARGS
);
229 static void mdoc_sq_post(MDOC_ARGS
);
230 static int mdoc_sq_pre(MDOC_ARGS
);
231 static int mdoc_ss_pre(MDOC_ARGS
);
232 static int mdoc_sx_pre(MDOC_ARGS
);
233 static int mdoc_vt_pre(MDOC_ARGS
);
234 static int mdoc_xr_pre(MDOC_ARGS
);
235 static int mdoc_xx_pre(MDOC_ARGS
);
238 extern int getsubopt(char **, char * const *, char **);
239 extern size_t strlcpy(char *, const char *, size_t);
240 extern size_t strlcat(char *, const char *, size_t);
243 static const struct htmlmdoc mdocs
[MDOC_MAX
] = {
244 {mdoc_pp_pre
, NULL
}, /* Ap */
245 {NULL
, NULL
}, /* Dd */
246 {NULL
, NULL
}, /* Dt */
247 {NULL
, NULL
}, /* Os */
248 {mdoc_sh_pre
, NULL
}, /* Sh */
249 {mdoc_ss_pre
, NULL
}, /* Ss */
250 {mdoc_pp_pre
, NULL
}, /* Pp */
251 {mdoc_d1_pre
, NULL
}, /* D1 */
252 {mdoc_d1_pre
, NULL
}, /* Dl */
253 {mdoc_bd_pre
, NULL
}, /* Bd */
254 {NULL
, NULL
}, /* Ed */
255 {mdoc_bl_pre
, mdoc_bl_post
}, /* Bl */
256 {NULL
, NULL
}, /* El */
257 {mdoc_it_pre
, NULL
}, /* It */
258 {mdoc_ad_pre
, NULL
}, /* Ad */
259 {mdoc_an_pre
, NULL
}, /* An */
260 {mdoc_ar_pre
, NULL
}, /* Ar */
261 {mdoc_cd_pre
, NULL
}, /* Cd */
262 {mdoc_fl_pre
, NULL
}, /* Cm */
263 {mdoc_dv_pre
, NULL
}, /* Dv */
264 {mdoc_er_pre
, NULL
}, /* Er */
265 {mdoc_ev_pre
, NULL
}, /* Ev */
266 {mdoc_ex_pre
, NULL
}, /* Ex */
267 {mdoc_fa_pre
, NULL
}, /* Fa */
268 {mdoc_fd_pre
, NULL
}, /* Fd */
269 {mdoc_fl_pre
, NULL
}, /* Fl */
270 {mdoc_fn_pre
, NULL
}, /* Fn */
271 {mdoc_ft_pre
, NULL
}, /* Ft */
272 {NULL
, NULL
}, /* Ic */
273 {NULL
, NULL
}, /* In */
274 {NULL
, NULL
}, /* Li */
275 {mdoc_nd_pre
, NULL
}, /* Nd */
276 {mdoc_nm_pre
, NULL
}, /* Nm */
277 {mdoc_op_pre
, mdoc_op_post
}, /* Op */
278 {NULL
, NULL
}, /* Ot */
279 {mdoc_pa_pre
, NULL
}, /* Pa */
280 {NULL
, NULL
}, /* Rv */
281 {NULL
, NULL
}, /* St */
282 {NULL
, NULL
}, /* Va */
283 {mdoc_vt_pre
, NULL
}, /* Vt */
284 {mdoc_xr_pre
, NULL
}, /* Xr */
285 {NULL
, NULL
}, /* %A */
286 {NULL
, NULL
}, /* %B */
287 {NULL
, NULL
}, /* %D */
288 {NULL
, NULL
}, /* %I */
289 {NULL
, NULL
}, /* %J */
290 {NULL
, NULL
}, /* %N */
291 {NULL
, NULL
}, /* %O */
292 {NULL
, NULL
}, /* %P */
293 {NULL
, NULL
}, /* %R */
294 {NULL
, NULL
}, /* %T */
295 {NULL
, NULL
}, /* %V */
296 {NULL
, NULL
}, /* Ac */
297 {mdoc_aq_pre
, mdoc_aq_post
}, /* Ao */
298 {mdoc_aq_pre
, mdoc_aq_post
}, /* Aq */
299 {NULL
, NULL
}, /* At */
300 {NULL
, NULL
}, /* Bc */
301 {NULL
, NULL
}, /* Bf */
302 {NULL
, NULL
}, /* Bo */
303 {NULL
, NULL
}, /* Bq */
304 {mdoc_xx_pre
, NULL
}, /* Bsx */
305 {NULL
, NULL
}, /* Bx */
306 {NULL
, NULL
}, /* Db */
307 {NULL
, NULL
}, /* Dc */
308 {NULL
, NULL
}, /* Do */
309 {mdoc_dq_pre
, mdoc_dq_post
}, /* Dq */
310 {NULL
, NULL
}, /* Ec */
311 {NULL
, NULL
}, /* Ef */
312 {mdoc_em_pre
, NULL
}, /* Em */
313 {NULL
, NULL
}, /* Eo */
314 {mdoc_xx_pre
, NULL
}, /* Fx */
315 {NULL
, NULL
}, /* Ms */
316 {NULL
, NULL
}, /* No */
317 {mdoc_ns_pre
, NULL
}, /* Ns */
318 {mdoc_xx_pre
, NULL
}, /* Nx */
319 {mdoc_xx_pre
, NULL
}, /* Ox */
320 {NULL
, NULL
}, /* Pc */
321 {NULL
, NULL
}, /* Pf */
322 {mdoc_pq_pre
, mdoc_pq_post
}, /* Po */
323 {mdoc_pq_pre
, mdoc_pq_post
}, /* Pq */
324 {NULL
, NULL
}, /* Qc */
325 {NULL
, NULL
}, /* Ql */
326 {mdoc_qq_pre
, mdoc_qq_post
}, /* Qo */
327 {mdoc_qq_pre
, mdoc_qq_post
}, /* Qq */
328 {NULL
, NULL
}, /* Re */
329 {NULL
, NULL
}, /* Rs */
330 {NULL
, NULL
}, /* Sc */
331 {mdoc_sq_pre
, mdoc_sq_post
}, /* So */
332 {mdoc_sq_pre
, mdoc_sq_post
}, /* Sq */
333 {NULL
, NULL
}, /* Sm */
334 {mdoc_sx_pre
, NULL
}, /* Sx */
335 {NULL
, NULL
}, /* Sy */
336 {NULL
, NULL
}, /* Tn */
337 {mdoc_xx_pre
, NULL
}, /* Ux */
338 {NULL
, NULL
}, /* Xc */
339 {NULL
, NULL
}, /* Xo */
340 {NULL
, NULL
}, /* Fo */
341 {NULL
, NULL
}, /* Fc */
342 {NULL
, NULL
}, /* Oo */
343 {NULL
, NULL
}, /* Oc */
344 {NULL
, NULL
}, /* Bk */
345 {NULL
, NULL
}, /* Ek */
346 {NULL
, NULL
}, /* Bt */
347 {NULL
, NULL
}, /* Hf */
348 {NULL
, NULL
}, /* Fr */
349 {NULL
, NULL
}, /* Ud */
350 {NULL
, NULL
}, /* Lb */
351 {NULL
, NULL
}, /* Lp */
352 {NULL
, NULL
}, /* Lk */
353 {NULL
, NULL
}, /* Mt */
354 {NULL
, NULL
}, /* Brq */
355 {NULL
, NULL
}, /* Bro */
356 {NULL
, NULL
}, /* Brc */
357 {NULL
, NULL
}, /* %C */
358 {NULL
, NULL
}, /* Es */
359 {NULL
, NULL
}, /* En */
360 {mdoc_xx_pre
, NULL
}, /* Dx */
361 {NULL
, NULL
}, /* %Q */
362 {NULL
, NULL
}, /* br */
363 {NULL
, NULL
}, /* sp */
366 static char buf
[BUFSIZ
]; /* XXX */
368 #define bufcat(x) (void)strlcat(buf, (x), BUFSIZ)
369 #define bufinit() buf[0] = 0
370 #define buffmt(...) (void)snprintf(buf, BUFSIZ - 1, __VA_ARGS__)
373 html_mdoc(void *arg
, const struct mdoc
*m
)
378 h
= (struct html
*)arg
;
380 print_gen_doctype(h
);
381 t
= print_otag(h
, TAG_HTML
, 0, NULL
);
382 print_mdoc(mdoc_meta(m
), mdoc_node(m
), h
);
390 html_man(void *arg
, const struct man
*m
)
395 h
= (struct html
*)arg
;
397 print_gen_doctype(h
);
398 t
= print_otag(h
, TAG_HTML
, 0, NULL
);
399 print_man(man_meta(m
), man_node(m
), h
);
407 html_alloc(char *outopts
)
416 if (NULL
== (h
= calloc(1, sizeof(struct html
))))
419 SLIST_INIT(&h
->tags
);
420 SLIST_INIT(&h
->ords
);
422 if (NULL
== (h
->symtab
= chars_init(CHARS_HTML
))) {
428 switch (getsubopt(&outopts
, toks
, &v
)) {
450 h
= (struct html
*)p
;
452 while ( ! SLIST_EMPTY(&h
->ords
)) {
453 ord
= SLIST_FIRST(&h
->ords
);
454 SLIST_REMOVE_HEAD(&h
->ords
, entry
);
458 while ( ! SLIST_EMPTY(&h
->tags
)) {
459 tag
= SLIST_FIRST(&h
->tags
);
460 SLIST_REMOVE_HEAD(&h
->tags
, entry
);
465 chars_free(h
->symtab
);
471 a2list(const struct mdoc_node
*n
)
475 assert(MDOC_BLOCK
== n
->type
&& MDOC_Bl
== n
->tok
);
478 for (i
= 0; i
< (int)n
->args
->argc
; i
++)
479 switch (n
->args
->argv
[i
].arg
) {
501 return(n
->args
->argv
[i
].arg
);
512 a2width(const char *p
)
516 if (0 == (len
= (int)strlen(p
)))
518 for (i
= 0; i
< len
- 1; i
++)
519 if ( ! isdigit((u_char
)p
[i
]))
523 if ('n' == p
[len
- 1] || 'm' == p
[len
- 1])
531 a2offs(const char *p
)
535 if (0 == strcmp(p
, "left"))
537 if (0 == strcmp(p
, "indent"))
539 if (0 == strcmp(p
, "indent-two"))
540 return((INDENT
+ 1) * 2);
542 if (0 == (len
= (int)strlen(p
)))
545 for (i
= 0; i
< len
- 1; i
++)
546 if ( ! isdigit((u_char
)p
[i
]))
550 if ('n' == p
[len
- 1] || 'm' == p
[len
- 1])
558 print_mdoc(MDOC_ARGS
)
563 t
= print_otag(h
, TAG_HEAD
, 0, NULL
);
564 print_mdoc_head(m
, n
, h
);
567 t
= print_otag(h
, TAG_BODY
, 0, NULL
);
569 tag
.key
= ATTR_CLASS
;
571 print_otag(h
, TAG_DIV
, 1, &tag
);
573 print_mdoc_nodelist(m
, n
, h
);
579 print_gen_head(struct html
*h
)
581 struct htmlpair tag
[4];
583 tag
[0].key
= ATTR_HTTPEQUIV
;
584 tag
[0].val
= "Content-Type";
585 tag
[1].key
= ATTR_CONTENT
;
586 tag
[1].val
= "text/html; charset=utf-8";
587 print_otag(h
, TAG_META
, 2, tag
);
589 tag
[0].key
= ATTR_NAME
;
590 tag
[0].val
= "resource-type";
591 tag
[1].key
= ATTR_CONTENT
;
592 tag
[1].val
= "document";
593 print_otag(h
, TAG_META
, 2, tag
);
596 tag
[0].key
= ATTR_REL
;
597 tag
[0].val
= "stylesheet";
598 tag
[1].key
= ATTR_HREF
;
599 tag
[1].val
= h
->style
;
600 tag
[2].key
= ATTR_TYPE
;
601 tag
[2].val
= "text/css";
602 tag
[3].key
= ATTR_MEDIA
;
604 print_otag(h
, TAG_LINK
, 4, tag
);
608 tag
[0].key
= ATTR_HREF
;
609 tag
[1].val
= h
->base
;
610 print_otag(h
, TAG_BASE
, 1, tag
);
617 print_mdoc_head(MDOC_ARGS
)
621 print_otag(h
, TAG_TITLE
, 0, NULL
);
622 print_text(h
, m
->title
);
627 print_mdoc_nodelist(MDOC_ARGS
)
630 print_mdoc_node(m
, n
, h
);
632 print_mdoc_nodelist(m
, n
->next
, h
);
637 print_mdoc_node(MDOC_ARGS
)
643 t
= SLIST_FIRST(&h
->tags
);
649 child
= mdoc_root_pre(m
, n
, h
);
652 print_text(h
, n
->string
);
655 if (mdocs
[n
->tok
].pre
)
656 child
= (*mdocs
[n
->tok
].pre
)(m
, n
, h
);
660 if (child
&& n
->child
)
661 print_mdoc_nodelist(m
, n
->child
, h
);
669 mdoc_root_post(m
, n
, h
);
674 if (mdocs
[n
->tok
].post
)
675 (*mdocs
[n
->tok
].post
)(m
, n
, h
);
686 t
= print_otag(h
, TAG_HEAD
, 0, NULL
);
687 print_man_head(m
, n
, h
);
690 t
= print_otag(h
, TAG_BODY
, 0, NULL
);
691 /*print_man_body(m, n, h);*/
698 print_man_head(MAN_ARGS
)
702 print_otag(h
, TAG_TITLE
, 0, NULL
);
703 print_text(h
, m
->title
);
708 print_spec(struct html
*h
, const char *p
, int len
)
714 rhs
= chars_a2ascii(h
->symtab
, p
, (size_t)len
, &sz
);
718 for (i
= 0; i
< (int)sz
; i
++)
724 print_res(struct html
*h
, const char *p
, int len
)
730 rhs
= chars_a2res(h
->symtab
, p
, (size_t)len
, &sz
);
734 for (i
= 0; i
< (int)sz
; i
++)
740 print_escape(struct html
*h
, const char **p
)
755 if (0 == *wp
|| 0 == *(wp
+ 1)) {
756 *p
= 0 == *wp
? wp
: wp
+ 1;
760 print_spec(h
, wp
, 2);
764 } else if ('*' == *wp
) {
773 if (0 == *wp
|| 0 == *(wp
+ 1)) {
774 *p
= 0 == *wp
? wp
: wp
+ 1;
790 } else if ('f' == *wp
) {
815 } else if ('[' != *wp
) {
816 print_spec(h
, wp
, 1);
822 for (j
= 0; *wp
&& ']' != *wp
; wp
++, j
++)
831 print_spec(h
, wp
- j
, j
);
833 print_res(h
, wp
- j
, j
);
840 print_encode(struct html
*h
, const char *p
)
867 print_otag(struct html
*h
, enum htmltag tag
,
868 int sz
, const struct htmlpair
*p
)
873 if ( ! (HTML_NOSTACK
& htmltags
[tag
].flags
)) {
874 if (NULL
== (t
= malloc(sizeof(struct tag
))))
875 err(EXIT_FAILURE
, "malloc");
877 SLIST_INSERT_HEAD(&h
->tags
, t
, entry
);
881 if ( ! (HTML_NOSPACE
& h
->flags
))
882 if ( ! (HTML_CLRLINE
& htmltags
[tag
].flags
))
885 printf("<%s", htmltags
[tag
].name
);
886 for (i
= 0; i
< sz
; i
++) {
887 printf(" %s=\"", htmlattrs
[p
[i
].key
]);
889 print_encode(h
, p
[i
].val
);
894 h
->flags
|= HTML_NOSPACE
;
895 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
896 h
->flags
|= HTML_NEWLINE
;
898 h
->flags
&= ~HTML_NEWLINE
;
906 print_ctag(struct html
*h
, enum htmltag tag
)
909 printf("</%s>", htmltags
[tag
].name
);
910 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
911 h
->flags
|= HTML_NOSPACE
;
912 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
913 h
->flags
|= HTML_NEWLINE
;
915 h
->flags
&= ~HTML_NEWLINE
;
921 print_gen_doctype(struct html
*h
)
924 printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">", DOCTYPE
, DTD
);
929 print_text(struct html
*h
, const char *p
)
932 if (*p
&& 0 == *(p
+ 1))
951 h
->flags
|= HTML_NOSPACE
;
957 if ( ! (h
->flags
& HTML_NOSPACE
))
960 h
->flags
&= ~HTML_NOSPACE
;
961 h
->flags
&= ~HTML_NEWLINE
;
966 if (*p
&& 0 == *(p
+ 1))
973 h
->flags
|= HTML_NOSPACE
;
982 print_tagq(struct html
*h
, const struct tag
*until
)
986 while ( ! SLIST_EMPTY(&h
->tags
)) {
987 tag
= SLIST_FIRST(&h
->tags
);
988 print_ctag(h
, tag
->tag
);
989 SLIST_REMOVE_HEAD(&h
->tags
, entry
);
991 if (until
&& tag
== until
)
998 print_stagq(struct html
*h
, const struct tag
*suntil
)
1002 while ( ! SLIST_EMPTY(&h
->tags
)) {
1003 tag
= SLIST_FIRST(&h
->tags
);
1004 if (suntil
&& tag
== suntil
)
1006 print_ctag(h
, tag
->tag
);
1007 SLIST_REMOVE_HEAD(&h
->tags
, entry
);
1015 mdoc_root_post(MDOC_ARGS
)
1018 struct htmlpair tag
[2];
1022 (void)localtime_r(&m
->date
, &tm
);
1024 if (0 == strftime(b
, BUFSIZ
- 1, "%B %e, %Y", &tm
))
1025 err(EXIT_FAILURE
, "strftime");
1027 tag
[0].key
= ATTR_CLASS
;
1028 tag
[0].val
= "footer";
1029 tag
[1].key
= ATTR_STYLE
;
1030 tag
[1].val
= "width: 100%;";
1031 t
= print_otag(h
, TAG_TABLE
, 2, tag
);
1032 tt
= print_otag(h
, TAG_TR
, 0, NULL
);
1034 tag
[0].key
= ATTR_STYLE
;
1035 tag
[0].val
= "width: 50%;";
1036 print_otag(h
, TAG_TD
, 1, tag
);
1040 tag
[0].key
= ATTR_STYLE
;
1041 tag
[0].val
= "width: 50%; text-align: right;";
1042 print_otag(h
, TAG_TD
, 1, tag
);
1043 print_text(h
, m
->os
);
1050 mdoc_root_pre(MDOC_ARGS
)
1052 struct htmlpair tag
[2];
1054 char b
[BUFSIZ
], title
[BUFSIZ
];
1056 (void)strlcpy(b
, m
->vol
, BUFSIZ
);
1059 (void)strlcat(b
, " (", BUFSIZ
);
1060 (void)strlcat(b
, m
->arch
, BUFSIZ
);
1061 (void)strlcat(b
, ")", BUFSIZ
);
1064 (void)snprintf(title
, BUFSIZ
- 1,
1065 "%s(%d)", m
->title
, m
->msec
);
1067 tag
[0].key
= ATTR_CLASS
;
1068 tag
[0].val
= "header";
1069 tag
[1].key
= ATTR_STYLE
;
1070 tag
[1].val
= "width: 100%;";
1071 t
= print_otag(h
, TAG_TABLE
, 2, tag
);
1072 tt
= print_otag(h
, TAG_TR
, 0, NULL
);
1074 tag
[0].key
= ATTR_STYLE
;
1075 tag
[0].val
= "width: 33%;";
1076 print_otag(h
, TAG_TD
, 1, tag
);
1080 tag
[0].key
= ATTR_STYLE
;
1081 tag
[0].val
= "width: 33%; text-align: center;";
1082 print_otag(h
, TAG_TD
, 1, tag
);
1083 print_text(h
, title
);
1086 tag
[0].key
= ATTR_STYLE
;
1087 tag
[0].val
= "width: 33%; text-align: right;";
1088 print_otag(h
, TAG_TD
, 1, tag
);
1098 mdoc_sh_pre(MDOC_ARGS
)
1100 struct htmlpair tag
[2];
1101 const struct mdoc_node
*nn
;
1103 if (MDOC_HEAD
== n
->type
) {
1104 tag
[0].key
= ATTR_CLASS
;
1105 tag
[0].val
= "sec-head";
1106 print_otag(h
, TAG_DIV
, 1, tag
);
1107 print_otag(h
, TAG_SPAN
, 1, tag
);
1109 for (nn
= n
->child
; nn
; nn
= nn
->next
) {
1114 tag
[0].key
= ATTR_NAME
;
1116 print_otag(h
, TAG_A
, 1, tag
);
1118 } else if (MDOC_BLOCK
== n
->type
) {
1119 tag
[0].key
= ATTR_CLASS
;
1120 tag
[0].val
= "sec-block";
1122 if (n
->prev
&& NULL
== n
->prev
->body
->child
) {
1123 print_otag(h
, TAG_DIV
, 1, tag
);
1127 bufcat("margin-top: 1em;");
1128 if (NULL
== n
->next
)
1129 bufcat("margin-bottom: 1em;");
1131 tag
[1].key
= ATTR_STYLE
;
1134 print_otag(h
, TAG_DIV
, 2, tag
);
1138 buffmt("margin-left: %dem;", INDENT
);
1140 tag
[0].key
= ATTR_CLASS
;
1141 tag
[0].val
= "sec-body";
1142 tag
[1].key
= ATTR_STYLE
;
1145 print_otag(h
, TAG_DIV
, 2, tag
);
1152 mdoc_ss_pre(MDOC_ARGS
)
1154 struct htmlpair tag
[2];
1156 const struct mdoc_node
*nn
;
1160 if (MDOC_BODY
== n
->type
) {
1161 tag
[i
].key
= ATTR_CLASS
;
1162 tag
[i
++].val
= "ssec-body";
1163 if (n
->parent
->next
&& n
->child
) {
1164 bufcat("margin-bottom: 1em;");
1165 tag
[i
].key
= ATTR_STYLE
;
1168 print_otag(h
, TAG_DIV
, i
, tag
);
1170 } else if (MDOC_BLOCK
== n
->type
) {
1171 tag
[i
].key
= ATTR_CLASS
;
1172 tag
[i
++].val
= "ssec-block";
1174 bufcat("margin-top: 1em;");
1175 tag
[i
].key
= ATTR_STYLE
;
1178 print_otag(h
, TAG_DIV
, i
, tag
);
1182 buffmt("margin-left: -%dem;", INDENT
- HALFINDENT
);
1184 tag
[0].key
= ATTR_CLASS
;
1185 tag
[0].val
= "ssec-head";
1186 tag
[1].key
= ATTR_STYLE
;
1189 print_otag(h
, TAG_DIV
, 2, tag
);
1190 print_otag(h
, TAG_SPAN
, 1, tag
);
1193 for (nn
= n
->child
; nn
; nn
= nn
->next
) {
1198 tag
[0].key
= ATTR_NAME
;
1200 print_otag(h
, TAG_A
, 1, tag
);
1208 mdoc_fl_pre(MDOC_ARGS
)
1210 struct htmlpair tag
;
1212 tag
.key
= ATTR_CLASS
;
1215 print_otag(h
, TAG_SPAN
, 1, &tag
);
1216 if (MDOC_Fl
== n
->tok
) {
1217 print_text(h
, "\\-");
1218 h
->flags
|= HTML_NOSPACE
;
1226 mdoc_pp_pre(MDOC_ARGS
)
1228 struct htmlpair tag
;
1230 tag
.key
= ATTR_STYLE
;
1231 tag
.val
= "clear: both; height: 1em;";
1232 print_otag(h
, TAG_DIV
, 1, &tag
);
1239 mdoc_nd_pre(MDOC_ARGS
)
1241 struct htmlpair tag
;
1243 if (MDOC_BODY
!= n
->type
)
1246 /* XXX - this can contain block elements! */
1247 print_text(h
, "\\(em");
1248 tag
.key
= ATTR_CLASS
;
1249 tag
.val
= "desc-body";
1250 print_otag(h
, TAG_SPAN
, 1, &tag
);
1257 mdoc_op_pre(MDOC_ARGS
)
1259 struct htmlpair tag
;
1261 if (MDOC_BODY
!= n
->type
)
1264 /* XXX - this can contain block elements! */
1265 print_text(h
, "\\(lB");
1266 h
->flags
|= HTML_NOSPACE
;
1267 tag
.key
= ATTR_CLASS
;
1269 print_otag(h
, TAG_SPAN
, 1, &tag
);
1276 mdoc_op_post(MDOC_ARGS
)
1279 if (MDOC_BODY
!= n
->type
)
1281 h
->flags
|= HTML_NOSPACE
;
1282 print_text(h
, "\\(rB");
1287 mdoc_nm_pre(MDOC_ARGS
)
1289 struct htmlpair tag
;
1291 if ( ! (HTML_NEWLINE
& h
->flags
))
1292 if (SEC_SYNOPSIS
== n
->sec
) {
1293 tag
.key
= ATTR_STYLE
;
1294 tag
.val
= "clear: both;";
1295 print_otag(h
, TAG_BR
, 1, &tag
);
1298 tag
.key
= ATTR_CLASS
;
1301 print_otag(h
, TAG_SPAN
, 1, &tag
);
1302 if (NULL
== n
->child
)
1303 print_text(h
, m
->name
);
1311 mdoc_xr_pre(MDOC_ARGS
)
1313 struct htmlpair tag
[2];
1314 const char *name
, *sec
;
1315 const struct mdoc_node
*nn
;
1318 name
= nn
&& nn
->string
? nn
->string
: "";
1319 nn
= nn
? nn
->next
: NULL
;
1320 sec
= nn
&& nn
->string
? nn
->string
: "";
1322 buffmt("%s%s%s.html", name
, name
&& sec
? "." : "", sec
);
1324 tag
[0].key
= ATTR_CLASS
;
1325 tag
[0].val
= "link-man";
1326 tag
[1].key
= ATTR_HREF
;
1328 print_otag(h
, TAG_A
, 2, tag
);
1331 print_text(h
, nn
->string
);
1332 if (NULL
== (nn
= nn
->next
))
1335 h
->flags
|= HTML_NOSPACE
;
1337 h
->flags
|= HTML_NOSPACE
;
1338 print_text(h
, nn
->string
);
1339 h
->flags
|= HTML_NOSPACE
;
1348 mdoc_ns_pre(MDOC_ARGS
)
1351 h
->flags
|= HTML_NOSPACE
;
1358 mdoc_ar_pre(MDOC_ARGS
)
1360 struct htmlpair tag
;
1362 tag
.key
= ATTR_CLASS
;
1365 print_otag(h
, TAG_SPAN
, 1, &tag
);
1372 mdoc_xx_pre(MDOC_ARGS
)
1375 struct htmlpair tag
;
1382 pp
= "DragonFlyBSD";
1400 tag
.key
= ATTR_CLASS
;
1403 print_otag(h
, TAG_SPAN
, 1, &tag
);
1411 mdoc_tbl_block_pre(MDOC_ARGS
, int t
, int w
, int o
, int c
)
1413 struct htmlpair tag
;
1421 buffmt("margin-left: %dem; clear: both;", o
);
1424 buffmt("margin-left: %dem; clear: both;", w
+ o
);
1428 if ( ! c
&& MDOC_Column
!= t
) {
1429 if (n
->prev
&& n
->prev
->body
->child
)
1430 bufcat("padding-top: 1em;");
1431 else if (NULL
== n
->prev
)
1432 bufcat("padding-top: 1em;");
1435 tag
.key
= ATTR_STYLE
;
1437 print_otag(h
, TAG_DIV
, 1, &tag
);
1444 mdoc_tbl_body_pre(MDOC_ARGS
, int t
, int w
)
1447 print_otag(h
, TAG_DIV
, 0, NULL
);
1454 mdoc_tbl_head_pre(MDOC_ARGS
, int t
, int w
)
1456 struct htmlpair tag
;
1464 print_otag(h
, TAG_DIV
, 0, NULL
);
1467 buffmt("min-width: %dem;", w
);
1468 bufcat("clear: none;");
1469 if (n
->next
&& MDOC_HEAD
== n
->next
->type
)
1470 bufcat("float: left;");
1471 tag
.key
= ATTR_STYLE
;
1473 print_otag(h
, TAG_DIV
, 1, &tag
);
1476 buffmt("margin-left: -%dem;", w
);
1477 bufcat("clear: left;");
1478 bufcat("float: left;");
1479 bufcat("padding-right: 1em;");
1480 tag
.key
= ATTR_STYLE
;
1482 print_otag(h
, TAG_DIV
, 1, &tag
);
1488 tag
.key
= ATTR_CLASS
;
1490 print_otag(h
, TAG_SPAN
, 1, &tag
);
1493 ord
= SLIST_FIRST(&h
->ords
);
1495 nbuf
[BUFSIZ
- 1] = 0;
1496 (void)snprintf(nbuf
, BUFSIZ
- 1, "%d.", ord
->pos
++);
1497 print_text(h
, nbuf
);
1500 print_text(h
, "\\(en");
1503 print_text(h
, "\\-");
1506 print_text(h
, "\\(bu");
1517 mdoc_tbl_pre(MDOC_ARGS
, int type
)
1520 const struct mdoc_node
*bl
, *nn
;
1522 bl
= n
->parent
->parent
;
1523 if (MDOC_BLOCK
!= n
->type
)
1526 /* FIXME: fmt_vspace() equivalent. */
1533 for (i
= 0; i
< (int)bl
->args
->argc
; i
++)
1534 if (MDOC_Width
== bl
->args
->argv
[i
].arg
) {
1535 assert(bl
->args
->argv
[i
].sz
);
1537 w
= a2width(bl
->args
->argv
[i
].value
[0]);
1538 } else if (MDOC_Offset
== bl
->args
->argv
[i
].arg
) {
1539 assert(bl
->args
->argv
[i
].sz
);
1540 o
= a2offs(bl
->args
->argv
[i
].value
[0]);
1541 } else if (MDOC_Compact
== bl
->args
->argv
[i
].arg
)
1544 if (MDOC_HEAD
== n
->type
&& MDOC_Column
== type
) {
1545 nn
= n
->parent
->child
;
1546 assert(nn
&& MDOC_HEAD
== nn
->type
);
1547 for (i
= 0; nn
&& nn
!= n
; nn
= nn
->next
, i
++)
1550 if (wp
>= 0 && i
< (int)bl
->args
[wp
].argv
->sz
)
1551 w
= a2width(bl
->args
->argv
[wp
].value
[i
]);
1580 return(mdoc_tbl_head_pre(m
, n
, h
, type
, w
));
1582 return(mdoc_tbl_body_pre(m
, n
, h
, type
, w
));
1588 return(mdoc_tbl_block_pre(m
, n
, h
, type
, w
, o
, c
));
1594 mdoc_bl_pre(MDOC_ARGS
)
1598 if (MDOC_BLOCK
!= n
->type
)
1600 if (MDOC_Enum
!= a2list(n
))
1603 ord
= malloc(sizeof(struct ord
));
1605 err(EXIT_FAILURE
, "malloc");
1608 SLIST_INSERT_HEAD(&h
->ords
, ord
, entry
);
1616 mdoc_bl_post(MDOC_ARGS
)
1620 if (MDOC_BLOCK
!= n
->type
)
1622 if (MDOC_Enum
!= a2list(n
))
1625 ord
= SLIST_FIRST(&h
->ords
);
1627 SLIST_REMOVE_HEAD(&h
->ords
, entry
);
1633 mdoc_it_pre(MDOC_ARGS
)
1637 if (MDOC_BLOCK
== n
->type
)
1638 type
= a2list(n
->parent
->parent
);
1640 type
= a2list(n
->parent
->parent
->parent
);
1642 return(mdoc_tbl_pre(m
, n
, h
, type
));
1648 mdoc_ex_pre(MDOC_ARGS
)
1650 const struct mdoc_node
*nn
;
1652 struct htmlpair tag
;
1654 print_text(h
, "The");
1656 tag
.key
= ATTR_CLASS
;
1657 tag
.val
= "utility";
1659 for (nn
= n
->child
; nn
; nn
= nn
->next
) {
1660 t
= print_otag(h
, TAG_SPAN
, 1, &tag
);
1661 print_text(h
, nn
->string
);
1664 h
->flags
|= HTML_NOSPACE
;
1666 if (nn
->next
&& NULL
== nn
->next
->next
)
1667 print_text(h
, ", and");
1671 h
->flags
&= ~HTML_NOSPACE
;
1675 print_text(h
, "utilities exit");
1677 print_text(h
, "utility exits");
1679 print_text(h
, "0 on success, and >0 if an error occurs.");
1686 mdoc_dq_pre(MDOC_ARGS
)
1689 if (MDOC_BODY
!= n
->type
)
1691 print_text(h
, "\\(lq");
1692 h
->flags
|= HTML_NOSPACE
;
1699 mdoc_dq_post(MDOC_ARGS
)
1702 if (MDOC_BODY
!= n
->type
)
1704 h
->flags
|= HTML_NOSPACE
;
1705 print_text(h
, "\\(rq");
1711 mdoc_pq_pre(MDOC_ARGS
)
1714 if (MDOC_BODY
!= n
->type
)
1716 print_text(h
, "\\&(");
1717 h
->flags
|= HTML_NOSPACE
;
1724 mdoc_pq_post(MDOC_ARGS
)
1727 if (MDOC_BODY
!= n
->type
)
1735 mdoc_sq_pre(MDOC_ARGS
)
1738 if (MDOC_BODY
!= n
->type
)
1740 print_text(h
, "\\(oq");
1741 h
->flags
|= HTML_NOSPACE
;
1748 mdoc_sq_post(MDOC_ARGS
)
1751 if (MDOC_BODY
!= n
->type
)
1753 h
->flags
|= HTML_NOSPACE
;
1754 print_text(h
, "\\(aq");
1760 mdoc_em_pre(MDOC_ARGS
)
1762 struct htmlpair tag
;
1764 tag
.key
= ATTR_CLASS
;
1767 print_otag(h
, TAG_SPAN
, 1, &tag
);
1774 mdoc_d1_pre(MDOC_ARGS
)
1776 struct htmlpair tag
[2];
1778 if (MDOC_BLOCK
!= n
->type
)
1781 buffmt("margin-left: %dem;", INDENT
);
1783 tag
[0].key
= ATTR_CLASS
;
1784 tag
[0].val
= "lit-block";
1785 tag
[1].key
= ATTR_STYLE
;
1788 print_otag(h
, TAG_DIV
, 2, tag
);
1795 mdoc_sx_pre(MDOC_ARGS
)
1797 struct htmlpair tag
[2];
1798 const struct mdoc_node
*nn
;
1801 for (nn
= n
->child
; nn
; nn
= nn
->next
) {
1807 tag
[0].key
= ATTR_HREF
;
1809 tag
[1].key
= ATTR_CLASS
;
1810 tag
[1].val
= "link-sec";
1812 print_otag(h
, TAG_A
, 2, tag
);
1819 mdoc_aq_pre(MDOC_ARGS
)
1822 if (MDOC_BODY
!= n
->type
)
1824 print_text(h
, "\\(la");
1825 h
->flags
|= HTML_NOSPACE
;
1832 mdoc_aq_post(MDOC_ARGS
)
1835 if (MDOC_BODY
!= n
->type
)
1837 h
->flags
|= HTML_NOSPACE
;
1838 print_text(h
, "\\(ra");
1844 mdoc_bd_pre(MDOC_ARGS
)
1846 struct htmlpair tag
[2];
1848 const struct mdoc_node
*bl
;
1850 /* FIXME: fmt_vspace() shit. */
1852 if (MDOC_BLOCK
== n
->type
)
1854 else if (MDOC_HEAD
== n
->type
)
1861 for (i
= 0; i
< (int)bl
->args
->argc
; i
++)
1862 switch (bl
->args
->argv
[i
].arg
) {
1864 assert(bl
->args
->argv
[i
].sz
);
1865 o
= a2offs (bl
->args
->argv
[i
].value
[0]);
1867 case (MDOC_Compact
):
1874 case (MDOC_Unfilled
):
1876 case (MDOC_Literal
):
1877 t
= bl
->args
->argv
[i
].arg
;
1881 if (MDOC_BLOCK
== n
->type
) {
1883 buffmt("margin-left: %dem;", o
);
1884 bufcat("margin-top: 1em;");
1885 tag
[0].key
= ATTR_STYLE
;
1887 print_otag(h
, TAG_DIV
, 1, tag
);
1892 case (MDOC_Unfilled
):
1893 case (MDOC_Literal
):
1899 bufcat("white-space: pre;");
1900 tag
[0].key
= ATTR_STYLE
;
1902 tag
[1].key
= ATTR_CLASS
;
1903 tag
[1].val
= "lit-block";
1905 print_otag(h
, TAG_DIV
, 2, tag
);
1907 for (n
= n
->child
; n
; n
= n
->next
) {
1908 h
->flags
|= HTML_NOSPACE
;
1909 print_mdoc_node(m
, n
, h
);
1911 print_text(h
, "\n");
1920 mdoc_pa_pre(MDOC_ARGS
)
1922 struct htmlpair tag
;
1924 tag
.key
= ATTR_CLASS
;
1927 print_otag(h
, TAG_SPAN
, 1, &tag
);
1934 mdoc_qq_pre(MDOC_ARGS
)
1937 if (MDOC_BODY
!= n
->type
)
1939 print_text(h
, "\\*q");
1940 h
->flags
|= HTML_NOSPACE
;
1947 mdoc_qq_post(MDOC_ARGS
)
1950 if (MDOC_BODY
!= n
->type
)
1952 h
->flags
|= HTML_NOSPACE
;
1953 print_text(h
, "\\*q");
1959 mdoc_ad_pre(MDOC_ARGS
)
1961 struct htmlpair tag
;
1963 tag
.key
= ATTR_CLASS
;
1965 print_otag(h
, TAG_SPAN
, 1, &tag
);
1972 mdoc_an_pre(MDOC_ARGS
)
1974 struct htmlpair tag
;
1976 tag
.key
= ATTR_CLASS
;
1978 print_otag(h
, TAG_SPAN
, 1, &tag
);
1985 mdoc_cd_pre(MDOC_ARGS
)
1987 struct htmlpair tag
;
1989 tag
.key
= ATTR_CLASS
;
1991 print_otag(h
, TAG_SPAN
, 1, &tag
);
1998 mdoc_dv_pre(MDOC_ARGS
)
2000 struct htmlpair tag
;
2002 tag
.key
= ATTR_CLASS
;
2004 print_otag(h
, TAG_SPAN
, 1, &tag
);
2011 mdoc_ev_pre(MDOC_ARGS
)
2013 struct htmlpair tag
;
2015 tag
.key
= ATTR_CLASS
;
2017 print_otag(h
, TAG_SPAN
, 1, &tag
);
2024 mdoc_er_pre(MDOC_ARGS
)
2026 struct htmlpair tag
;
2028 tag
.key
= ATTR_CLASS
;
2030 print_otag(h
, TAG_SPAN
, 1, &tag
);
2037 mdoc_fa_pre(MDOC_ARGS
)
2039 const struct mdoc_node
*nn
;
2040 struct htmlpair tag
;
2043 tag
.key
= ATTR_CLASS
;
2046 if (n
->parent
->tok
!= MDOC_Fo
) {
2047 print_otag(h
, TAG_SPAN
, 1, &tag
);
2051 for (nn
= n
->child
; nn
; nn
= nn
->next
) {
2052 t
= print_otag(h
, TAG_SPAN
, 1, &tag
);
2053 print_text(h
, nn
->string
);
2059 if (n
->child
&& n
->next
&& n
->next
->tok
== MDOC_Fa
)
2068 mdoc_fd_pre(MDOC_ARGS
)
2070 struct htmlpair tag
;
2072 if (SEC_SYNOPSIS
== n
->sec
) {
2073 if (n
->next
&& MDOC_Fd
!= n
->next
->tok
) {
2074 tag
.key
= ATTR_STYLE
;
2075 tag
.val
= "margin-bottom: 1em;";
2076 print_otag(h
, TAG_DIV
, 1, &tag
);
2078 print_otag(h
, TAG_DIV
, 0, NULL
);
2081 tag
.key
= ATTR_CLASS
;
2083 print_otag(h
, TAG_SPAN
, 1, &tag
);
2090 mdoc_vt_pre(MDOC_ARGS
)
2092 struct htmlpair tag
;
2094 if (SEC_SYNOPSIS
== n
->sec
) {
2095 if (n
->next
&& MDOC_Vt
!= n
->next
->tok
) {
2096 tag
.key
= ATTR_STYLE
;
2097 tag
.val
= "margin-bottom: 1em;";
2098 print_otag(h
, TAG_DIV
, 1, &tag
);
2100 print_otag(h
, TAG_DIV
, 0, NULL
);
2103 tag
.key
= ATTR_CLASS
;
2105 print_otag(h
, TAG_SPAN
, 1, &tag
);
2111 mdoc_ft_pre(MDOC_ARGS
)
2113 struct htmlpair tag
;
2115 if (SEC_SYNOPSIS
== n
->sec
) {
2116 if (n
->prev
&& MDOC_Fo
== n
->prev
->tok
) {
2117 tag
.key
= ATTR_STYLE
;
2118 tag
.val
= "magin-bottom: 1em;";
2119 print_otag(h
, TAG_DIV
, 1, &tag
);
2121 print_otag(h
, TAG_DIV
, 0, NULL
);
2124 tag
.key
= ATTR_CLASS
;
2126 print_otag(h
, TAG_SPAN
, 1, &tag
);
2133 mdoc_fn_pre(MDOC_ARGS
)
2136 struct htmlpair tag
;
2137 const struct mdoc_node
*nn
;
2139 if (SEC_SYNOPSIS
== n
->sec
) {
2141 tag
.key
= ATTR_STYLE
;
2142 tag
.val
= "margin-bottom: 1em";
2143 print_otag(h
, TAG_DIV
, 1, &tag
);
2145 print_otag(h
, TAG_DIV
, 0, NULL
);
2148 tag
.key
= ATTR_CLASS
;
2151 t
= print_otag(h
, TAG_SPAN
, 1, &tag
);
2152 print_text(h
, n
->child
->string
);
2155 h
->flags
|= HTML_NOSPACE
;
2158 for (nn
= n
->child
->next
; nn
; nn
= nn
->next
) {
2159 tag
.key
= ATTR_CLASS
;
2161 t
= print_otag(h
, TAG_SPAN
, 1, &tag
);
2162 print_text(h
, nn
->string
);
2170 if (SEC_SYNOPSIS
== n
->sec
)