1*99db7d0eSSascha Wildner /* $Id: man_html.c,v 1.179 2020/10/16 17:22:43 schwarze Exp $ */
280387638SSascha Wildner /*
3*99db7d0eSSascha Wildner * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
454ba9607SSascha Wildner * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
580387638SSascha Wildner *
680387638SSascha Wildner * Permission to use, copy, modify, and distribute this software for any
780387638SSascha Wildner * purpose with or without fee is hereby granted, provided that the above
880387638SSascha Wildner * copyright notice and this permission notice appear in all copies.
980387638SSascha Wildner *
1054ba9607SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1180387638SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1254ba9607SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1380387638SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1480387638SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1580387638SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1680387638SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*99db7d0eSSascha Wildner *
18*99db7d0eSSascha Wildner * HTML formatter for man(7) used by mandoc(1).
1980387638SSascha Wildner */
2080387638SSascha Wildner #include "config.h"
2180387638SSascha Wildner
2280387638SSascha Wildner #include <sys/types.h>
2380387638SSascha Wildner
2480387638SSascha Wildner #include <assert.h>
2580387638SSascha Wildner #include <ctype.h>
2680387638SSascha Wildner #include <stdio.h>
2780387638SSascha Wildner #include <stdlib.h>
2880387638SSascha Wildner #include <string.h>
2980387638SSascha Wildner
30070c62a6SFranco Fichtner #include "mandoc_aux.h"
3154ba9607SSascha Wildner #include "mandoc.h"
3254ba9607SSascha Wildner #include "roff.h"
3354ba9607SSascha Wildner #include "man.h"
3480387638SSascha Wildner #include "out.h"
3580387638SSascha Wildner #include "html.h"
3680387638SSascha Wildner #include "main.h"
3780387638SSascha Wildner
3854ba9607SSascha Wildner #define MAN_ARGS const struct roff_meta *man, \
39*99db7d0eSSascha Wildner struct roff_node *n, \
4080387638SSascha Wildner struct html *h
4180387638SSascha Wildner
4254ba9607SSascha Wildner struct man_html_act {
4380387638SSascha Wildner int (*pre)(MAN_ARGS);
4480387638SSascha Wildner int (*post)(MAN_ARGS);
4580387638SSascha Wildner };
4680387638SSascha Wildner
4754ba9607SSascha Wildner static void print_man_head(const struct roff_meta *,
4854ba9607SSascha Wildner struct html *);
4980387638SSascha Wildner static void print_man_nodelist(MAN_ARGS);
5080387638SSascha Wildner static void print_man_node(MAN_ARGS);
5154ba9607SSascha Wildner static char list_continues(const struct roff_node *,
5254ba9607SSascha Wildner const struct roff_node *);
5336342e81SSascha Wildner static int man_B_pre(MAN_ARGS);
5436342e81SSascha Wildner static int man_IP_pre(MAN_ARGS);
5536342e81SSascha Wildner static int man_I_pre(MAN_ARGS);
5636342e81SSascha Wildner static int man_OP_pre(MAN_ARGS);
5736342e81SSascha Wildner static int man_PP_pre(MAN_ARGS);
5836342e81SSascha Wildner static int man_RS_pre(MAN_ARGS);
5936342e81SSascha Wildner static int man_SH_pre(MAN_ARGS);
6036342e81SSascha Wildner static int man_SM_pre(MAN_ARGS);
6154ba9607SSascha Wildner static int man_SY_pre(MAN_ARGS);
627888c61dSFranco Fichtner static int man_UR_pre(MAN_ARGS);
6354ba9607SSascha Wildner static int man_abort_pre(MAN_ARGS);
6480387638SSascha Wildner static int man_alt_pre(MAN_ARGS);
6580387638SSascha Wildner static int man_ign_pre(MAN_ARGS);
6680387638SSascha Wildner static int man_in_pre(MAN_ARGS);
6754ba9607SSascha Wildner static void man_root_post(const struct roff_meta *,
6854ba9607SSascha Wildner struct html *);
6954ba9607SSascha Wildner static void man_root_pre(const struct roff_meta *,
7054ba9607SSascha Wildner struct html *);
7180387638SSascha Wildner
7254ba9607SSascha Wildner static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
7380387638SSascha Wildner { NULL, NULL }, /* TH */
7480387638SSascha Wildner { man_SH_pre, NULL }, /* SH */
7554ba9607SSascha Wildner { man_SH_pre, NULL }, /* SS */
7680387638SSascha Wildner { man_IP_pre, NULL }, /* TP */
7754ba9607SSascha Wildner { man_IP_pre, NULL }, /* TQ */
7854ba9607SSascha Wildner { man_abort_pre, NULL }, /* LP */
7980387638SSascha Wildner { man_PP_pre, NULL }, /* PP */
8054ba9607SSascha Wildner { man_abort_pre, NULL }, /* P */
8180387638SSascha Wildner { man_IP_pre, NULL }, /* IP */
8254ba9607SSascha Wildner { man_PP_pre, NULL }, /* HP */
8380387638SSascha Wildner { man_SM_pre, NULL }, /* SM */
8480387638SSascha Wildner { man_SM_pre, NULL }, /* SB */
8580387638SSascha Wildner { man_alt_pre, NULL }, /* BI */
8680387638SSascha Wildner { man_alt_pre, NULL }, /* IB */
8780387638SSascha Wildner { man_alt_pre, NULL }, /* BR */
8880387638SSascha Wildner { man_alt_pre, NULL }, /* RB */
8980387638SSascha Wildner { NULL, NULL }, /* R */
9080387638SSascha Wildner { man_B_pre, NULL }, /* B */
9180387638SSascha Wildner { man_I_pre, NULL }, /* I */
9280387638SSascha Wildner { man_alt_pre, NULL }, /* IR */
9380387638SSascha Wildner { man_alt_pre, NULL }, /* RI */
9480387638SSascha Wildner { NULL, NULL }, /* RE */
9580387638SSascha Wildner { man_RS_pre, NULL }, /* RS */
9680387638SSascha Wildner { man_ign_pre, NULL }, /* DT */
9780387638SSascha Wildner { man_ign_pre, NULL }, /* UC */
9880387638SSascha Wildner { man_ign_pre, NULL }, /* PD */
9980387638SSascha Wildner { man_ign_pre, NULL }, /* AT */
10080387638SSascha Wildner { man_in_pre, NULL }, /* in */
10154ba9607SSascha Wildner { man_SY_pre, NULL }, /* SY */
10254ba9607SSascha Wildner { NULL, NULL }, /* YS */
10336342e81SSascha Wildner { man_OP_pre, NULL }, /* OP */
10454ba9607SSascha Wildner { NULL, NULL }, /* EX */
10554ba9607SSascha Wildner { NULL, NULL }, /* EE */
1067888c61dSFranco Fichtner { man_UR_pre, NULL }, /* UR */
1077888c61dSFranco Fichtner { NULL, NULL }, /* UE */
10854ba9607SSascha Wildner { man_UR_pre, NULL }, /* MT */
10954ba9607SSascha Wildner { NULL, NULL }, /* ME */
11080387638SSascha Wildner };
11180387638SSascha Wildner
112070c62a6SFranco Fichtner
11380387638SSascha Wildner void
html_man(void * arg,const struct roff_meta * man)11454ba9607SSascha Wildner html_man(void *arg, const struct roff_meta *man)
11580387638SSascha Wildner {
11654ba9607SSascha Wildner struct html *h;
11754ba9607SSascha Wildner struct roff_node *n;
11854ba9607SSascha Wildner struct tag *t;
11980387638SSascha Wildner
12054ba9607SSascha Wildner h = (struct html *)arg;
12154ba9607SSascha Wildner n = man->first->child;
12280387638SSascha Wildner
12354ba9607SSascha Wildner if ((h->oflags & HTML_FRAGMENT) == 0) {
12436342e81SSascha Wildner print_gen_decls(h);
12554ba9607SSascha Wildner print_otag(h, TAG_HTML, "");
12654ba9607SSascha Wildner if (n != NULL && n->type == ROFFT_COMMENT)
12754ba9607SSascha Wildner print_gen_comment(h, n);
12854ba9607SSascha Wildner t = print_otag(h, TAG_HEAD, "");
12954ba9607SSascha Wildner print_man_head(man, h);
13080387638SSascha Wildner print_tagq(h, t);
13154ba9607SSascha Wildner print_otag(h, TAG_BODY, "");
13254ba9607SSascha Wildner }
13354ba9607SSascha Wildner
13454ba9607SSascha Wildner man_root_pre(man, h);
13554ba9607SSascha Wildner t = print_otag(h, TAG_DIV, "c", "manual-text");
13654ba9607SSascha Wildner print_man_nodelist(man, n, h);
13754ba9607SSascha Wildner print_tagq(h, t);
13854ba9607SSascha Wildner man_root_post(man, h);
13954ba9607SSascha Wildner print_tagq(h, NULL);
14080387638SSascha Wildner }
14180387638SSascha Wildner
14280387638SSascha Wildner static void
print_man_head(const struct roff_meta * man,struct html * h)14354ba9607SSascha Wildner print_man_head(const struct roff_meta *man, struct html *h)
14480387638SSascha Wildner {
14554ba9607SSascha Wildner char *cp;
14680387638SSascha Wildner
14780387638SSascha Wildner print_gen_head(h);
14854ba9607SSascha Wildner mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
14954ba9607SSascha Wildner print_otag(h, TAG_TITLE, "");
15054ba9607SSascha Wildner print_text(h, cp);
15154ba9607SSascha Wildner free(cp);
15280387638SSascha Wildner }
15380387638SSascha Wildner
15480387638SSascha Wildner static void
print_man_nodelist(MAN_ARGS)15580387638SSascha Wildner print_man_nodelist(MAN_ARGS)
15680387638SSascha Wildner {
15754ba9607SSascha Wildner while (n != NULL) {
15854ba9607SSascha Wildner print_man_node(man, n, h);
15954ba9607SSascha Wildner n = n->next;
16054ba9607SSascha Wildner }
16180387638SSascha Wildner }
16280387638SSascha Wildner
16380387638SSascha Wildner static void
print_man_node(MAN_ARGS)16480387638SSascha Wildner print_man_node(MAN_ARGS)
16580387638SSascha Wildner {
16680387638SSascha Wildner struct tag *t;
16754ba9607SSascha Wildner int child;
16854ba9607SSascha Wildner
16954ba9607SSascha Wildner if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
17054ba9607SSascha Wildner return;
17154ba9607SSascha Wildner
172*99db7d0eSSascha Wildner if ((n->flags & NODE_NOFILL) == 0)
173*99db7d0eSSascha Wildner html_fillmode(h, ROFF_fi);
174*99db7d0eSSascha Wildner else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
175*99db7d0eSSascha Wildner n->tok != ROFF_fi && n->flags & NODE_LINE &&
176*99db7d0eSSascha Wildner (n->prev == NULL || n->prev->tok != MAN_YS))
177*99db7d0eSSascha Wildner print_endline(h);
17880387638SSascha Wildner
17980387638SSascha Wildner child = 1;
18080387638SSascha Wildner switch (n->type) {
18154ba9607SSascha Wildner case ROFFT_TEXT:
18254ba9607SSascha Wildner if (*n->string == '\0') {
18354ba9607SSascha Wildner print_endline(h);
18460e1e752SSascha Wildner return;
18536342e81SSascha Wildner }
18654ba9607SSascha Wildner if (*n->string == ' ' && n->flags & NODE_LINE &&
18754ba9607SSascha Wildner (h->flags & HTML_NONEWLINE) == 0)
188*99db7d0eSSascha Wildner print_otag(h, TAG_BR, "");
18954ba9607SSascha Wildner else if (n->flags & NODE_DELIMC)
19054ba9607SSascha Wildner h->flags |= HTML_NOSPACE;
19154ba9607SSascha Wildner t = h->tag;
19254ba9607SSascha Wildner t->refcnt++;
19380387638SSascha Wildner print_text(h, n->string);
19454ba9607SSascha Wildner break;
19554ba9607SSascha Wildner case ROFFT_EQN:
19654ba9607SSascha Wildner t = h->tag;
19754ba9607SSascha Wildner t->refcnt++;
19836342e81SSascha Wildner print_eqn(h, n->eqn);
19980387638SSascha Wildner break;
20054ba9607SSascha Wildner case ROFFT_TBL:
20160e1e752SSascha Wildner /*
20260e1e752SSascha Wildner * This will take care of initialising all of the table
20360e1e752SSascha Wildner * state data for the first table, then tearing it down
20460e1e752SSascha Wildner * for the last one.
20560e1e752SSascha Wildner */
20660e1e752SSascha Wildner print_tbl(h, n->span);
20760e1e752SSascha Wildner return;
20880387638SSascha Wildner default:
20980387638SSascha Wildner /*
21080387638SSascha Wildner * Close out scope of font prior to opening a macro
21160e1e752SSascha Wildner * scope.
21280387638SSascha Wildner */
213*99db7d0eSSascha Wildner if (h->metac != ESCAPE_FONTROMAN) {
21480387638SSascha Wildner h->metal = h->metac;
215*99db7d0eSSascha Wildner h->metac = ESCAPE_FONTROMAN;
21680387638SSascha Wildner }
21760e1e752SSascha Wildner
21860e1e752SSascha Wildner /*
21960e1e752SSascha Wildner * Close out the current table, if it's open, and unset
22060e1e752SSascha Wildner * the "meta" table state. This will be reopened on the
22160e1e752SSascha Wildner * next table element.
22260e1e752SSascha Wildner */
22354ba9607SSascha Wildner if (h->tblt != NULL)
22460e1e752SSascha Wildner print_tblclose(h);
22554ba9607SSascha Wildner t = h->tag;
22654ba9607SSascha Wildner t->refcnt++;
22754ba9607SSascha Wildner if (n->tok < ROFF_MAX) {
22854ba9607SSascha Wildner roff_html_pre(h, n);
22954ba9607SSascha Wildner t->refcnt--;
23054ba9607SSascha Wildner print_stagq(h, t);
23154ba9607SSascha Wildner return;
23260e1e752SSascha Wildner }
23354ba9607SSascha Wildner assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
23454ba9607SSascha Wildner if (man_html_acts[n->tok - MAN_TH].pre != NULL)
23554ba9607SSascha Wildner child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
23654ba9607SSascha Wildner n, h);
23780387638SSascha Wildner break;
23880387638SSascha Wildner }
23980387638SSascha Wildner
24054ba9607SSascha Wildner if (child && n->child != NULL)
24154ba9607SSascha Wildner print_man_nodelist(man, n->child, h);
24280387638SSascha Wildner
24380387638SSascha Wildner /* This will automatically close out any font scope. */
24454ba9607SSascha Wildner t->refcnt--;
24554ba9607SSascha Wildner if (n->type == ROFFT_BLOCK &&
24654ba9607SSascha Wildner (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
24754ba9607SSascha Wildner t = h->tag;
24854ba9607SSascha Wildner while (t->tag != TAG_DL && t->tag != TAG_UL)
24954ba9607SSascha Wildner t = t->next;
25054ba9607SSascha Wildner /*
25154ba9607SSascha Wildner * Close the list if no further item of the same type
25254ba9607SSascha Wildner * follows; otherwise, close the item only.
25354ba9607SSascha Wildner */
254*99db7d0eSSascha Wildner if (list_continues(n, roff_node_next(n)) == '\0') {
25554ba9607SSascha Wildner print_tagq(h, t);
25654ba9607SSascha Wildner t = NULL;
25754ba9607SSascha Wildner }
25854ba9607SSascha Wildner }
25954ba9607SSascha Wildner if (t != NULL)
26080387638SSascha Wildner print_stagq(h, t);
26180387638SSascha Wildner }
26280387638SSascha Wildner
26360e1e752SSascha Wildner static void
man_root_pre(const struct roff_meta * man,struct html * h)26454ba9607SSascha Wildner man_root_pre(const struct roff_meta *man, struct html *h)
26580387638SSascha Wildner {
26680387638SSascha Wildner struct tag *t, *tt;
267070c62a6SFranco Fichtner char *title;
26880387638SSascha Wildner
269f88b6c16SFranco Fichtner assert(man->title);
270f88b6c16SFranco Fichtner assert(man->msec);
271070c62a6SFranco Fichtner mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
27280387638SSascha Wildner
27354ba9607SSascha Wildner t = print_otag(h, TAG_TABLE, "c", "head");
27454ba9607SSascha Wildner tt = print_otag(h, TAG_TR, "");
27580387638SSascha Wildner
27654ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-ltitle");
27780387638SSascha Wildner print_text(h, title);
27880387638SSascha Wildner print_stagq(h, tt);
27980387638SSascha Wildner
28054ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-vol");
28154ba9607SSascha Wildner if (man->vol != NULL)
282070c62a6SFranco Fichtner print_text(h, man->vol);
28380387638SSascha Wildner print_stagq(h, tt);
28480387638SSascha Wildner
28554ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-rtitle");
28680387638SSascha Wildner print_text(h, title);
28780387638SSascha Wildner print_tagq(h, t);
288070c62a6SFranco Fichtner free(title);
28980387638SSascha Wildner }
29080387638SSascha Wildner
29180387638SSascha Wildner static void
man_root_post(const struct roff_meta * man,struct html * h)29254ba9607SSascha Wildner man_root_post(const struct roff_meta *man, struct html *h)
29380387638SSascha Wildner {
29480387638SSascha Wildner struct tag *t, *tt;
29580387638SSascha Wildner
29654ba9607SSascha Wildner t = print_otag(h, TAG_TABLE, "c", "foot");
29754ba9607SSascha Wildner tt = print_otag(h, TAG_TR, "");
29880387638SSascha Wildner
29954ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "foot-date");
300f88b6c16SFranco Fichtner print_text(h, man->date);
30180387638SSascha Wildner print_stagq(h, tt);
30280387638SSascha Wildner
30354ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "foot-os");
30454ba9607SSascha Wildner if (man->os != NULL)
30554ba9607SSascha Wildner print_text(h, man->os);
30680387638SSascha Wildner print_tagq(h, t);
30780387638SSascha Wildner }
30880387638SSascha Wildner
30980387638SSascha Wildner static int
man_SH_pre(MAN_ARGS)31080387638SSascha Wildner man_SH_pre(MAN_ARGS)
31180387638SSascha Wildner {
31254ba9607SSascha Wildner const char *class;
31354ba9607SSascha Wildner enum htmltag tag;
31480387638SSascha Wildner
31554ba9607SSascha Wildner if (n->tok == MAN_SH) {
31654ba9607SSascha Wildner tag = TAG_H1;
31754ba9607SSascha Wildner class = "Sh";
31854ba9607SSascha Wildner } else {
31954ba9607SSascha Wildner tag = TAG_H2;
32054ba9607SSascha Wildner class = "Ss";
32154ba9607SSascha Wildner }
32254ba9607SSascha Wildner switch (n->type) {
32354ba9607SSascha Wildner case ROFFT_BLOCK:
32454ba9607SSascha Wildner html_close_paragraph(h);
32554ba9607SSascha Wildner print_otag(h, TAG_SECTION, "c", class);
32654ba9607SSascha Wildner break;
32754ba9607SSascha Wildner case ROFFT_HEAD:
328*99db7d0eSSascha Wildner print_otag_id(h, tag, class, n);
32954ba9607SSascha Wildner break;
33054ba9607SSascha Wildner case ROFFT_BODY:
33154ba9607SSascha Wildner break;
33254ba9607SSascha Wildner default:
33354ba9607SSascha Wildner abort();
33454ba9607SSascha Wildner }
33554ba9607SSascha Wildner return 1;
33680387638SSascha Wildner }
33780387638SSascha Wildner
33880387638SSascha Wildner static int
man_alt_pre(MAN_ARGS)33980387638SSascha Wildner man_alt_pre(MAN_ARGS)
34080387638SSascha Wildner {
34154ba9607SSascha Wildner const struct roff_node *nn;
34280387638SSascha Wildner struct tag *t;
34354ba9607SSascha Wildner int i;
34454ba9607SSascha Wildner enum htmltag fp;
34580387638SSascha Wildner
34654ba9607SSascha Wildner for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
34780387638SSascha Wildner switch (n->tok) {
348070c62a6SFranco Fichtner case MAN_BI:
34980387638SSascha Wildner fp = i % 2 ? TAG_I : TAG_B;
35080387638SSascha Wildner break;
351070c62a6SFranco Fichtner case MAN_IB:
35280387638SSascha Wildner fp = i % 2 ? TAG_B : TAG_I;
35380387638SSascha Wildner break;
354070c62a6SFranco Fichtner case MAN_RI:
35580387638SSascha Wildner fp = i % 2 ? TAG_I : TAG_MAX;
35680387638SSascha Wildner break;
357070c62a6SFranco Fichtner case MAN_IR:
35880387638SSascha Wildner fp = i % 2 ? TAG_MAX : TAG_I;
35980387638SSascha Wildner break;
360070c62a6SFranco Fichtner case MAN_BR:
36180387638SSascha Wildner fp = i % 2 ? TAG_MAX : TAG_B;
36280387638SSascha Wildner break;
363070c62a6SFranco Fichtner case MAN_RB:
36480387638SSascha Wildner fp = i % 2 ? TAG_B : TAG_MAX;
36580387638SSascha Wildner break;
36680387638SSascha Wildner default:
36780387638SSascha Wildner abort();
36880387638SSascha Wildner }
36980387638SSascha Wildner
37080387638SSascha Wildner if (i)
37180387638SSascha Wildner h->flags |= HTML_NOSPACE;
37280387638SSascha Wildner
37354ba9607SSascha Wildner if (fp != TAG_MAX)
37454ba9607SSascha Wildner t = print_otag(h, fp, "");
37580387638SSascha Wildner
37654ba9607SSascha Wildner print_text(h, nn->string);
37780387638SSascha Wildner
37854ba9607SSascha Wildner if (fp != TAG_MAX)
37980387638SSascha Wildner print_tagq(h, t);
38080387638SSascha Wildner }
38154ba9607SSascha Wildner return 0;
38280387638SSascha Wildner }
38380387638SSascha Wildner
38480387638SSascha Wildner static int
man_SM_pre(MAN_ARGS)38580387638SSascha Wildner man_SM_pre(MAN_ARGS)
38680387638SSascha Wildner {
38754ba9607SSascha Wildner print_otag(h, TAG_SMALL, "");
38854ba9607SSascha Wildner if (n->tok == MAN_SB)
38954ba9607SSascha Wildner print_otag(h, TAG_B, "");
39054ba9607SSascha Wildner return 1;
39180387638SSascha Wildner }
39280387638SSascha Wildner
39380387638SSascha Wildner static int
man_PP_pre(MAN_ARGS)39480387638SSascha Wildner man_PP_pre(MAN_ARGS)
39580387638SSascha Wildner {
39654ba9607SSascha Wildner switch (n->type) {
39754ba9607SSascha Wildner case ROFFT_BLOCK:
39854ba9607SSascha Wildner html_close_paragraph(h);
39954ba9607SSascha Wildner break;
40054ba9607SSascha Wildner case ROFFT_HEAD:
40154ba9607SSascha Wildner return 0;
40254ba9607SSascha Wildner case ROFFT_BODY:
40354ba9607SSascha Wildner if (n->child != NULL &&
40454ba9607SSascha Wildner (n->child->flags & NODE_NOFILL) == 0)
40554ba9607SSascha Wildner print_otag(h, TAG_P, "c",
40654ba9607SSascha Wildner n->tok == MAN_PP ? "Pp" : "Pp HP");
40754ba9607SSascha Wildner break;
40854ba9607SSascha Wildner default:
40954ba9607SSascha Wildner abort();
41054ba9607SSascha Wildner }
41154ba9607SSascha Wildner return 1;
41254ba9607SSascha Wildner }
41380387638SSascha Wildner
41454ba9607SSascha Wildner static char
list_continues(const struct roff_node * n1,const struct roff_node * n2)41554ba9607SSascha Wildner list_continues(const struct roff_node *n1, const struct roff_node *n2)
41654ba9607SSascha Wildner {
41754ba9607SSascha Wildner const char *s1, *s2;
41854ba9607SSascha Wildner char c1, c2;
41980387638SSascha Wildner
42054ba9607SSascha Wildner if (n1 == NULL || n1->type != ROFFT_BLOCK ||
42154ba9607SSascha Wildner n2 == NULL || n2->type != ROFFT_BLOCK)
42254ba9607SSascha Wildner return '\0';
42354ba9607SSascha Wildner if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
42454ba9607SSascha Wildner (n2->tok == MAN_TP || n2->tok == MAN_TQ))
42554ba9607SSascha Wildner return ' ';
42654ba9607SSascha Wildner if (n1->tok != MAN_IP || n2->tok != MAN_IP)
42754ba9607SSascha Wildner return '\0';
42854ba9607SSascha Wildner n1 = n1->head->child;
42954ba9607SSascha Wildner n2 = n2->head->child;
43054ba9607SSascha Wildner s1 = n1 == NULL ? "" : n1->string;
43154ba9607SSascha Wildner s2 = n2 == NULL ? "" : n2->string;
43254ba9607SSascha Wildner c1 = strcmp(s1, "*") == 0 ? '*' :
43354ba9607SSascha Wildner strcmp(s1, "\\-") == 0 ? '-' :
43454ba9607SSascha Wildner strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
43554ba9607SSascha Wildner c2 = strcmp(s2, "*") == 0 ? '*' :
43654ba9607SSascha Wildner strcmp(s2, "\\-") == 0 ? '-' :
43754ba9607SSascha Wildner strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
43854ba9607SSascha Wildner return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
43980387638SSascha Wildner }
44080387638SSascha Wildner
44180387638SSascha Wildner static int
man_IP_pre(MAN_ARGS)44280387638SSascha Wildner man_IP_pre(MAN_ARGS)
44380387638SSascha Wildner {
444*99db7d0eSSascha Wildner struct roff_node *nn;
44554ba9607SSascha Wildner const char *list_class;
44654ba9607SSascha Wildner enum htmltag list_elem, body_elem;
44754ba9607SSascha Wildner char list_type;
44880387638SSascha Wildner
44954ba9607SSascha Wildner nn = n->type == ROFFT_BLOCK ? n : n->parent;
450*99db7d0eSSascha Wildner list_type = list_continues(roff_node_prev(nn), nn);
451*99db7d0eSSascha Wildner if (list_type == '\0') {
45254ba9607SSascha Wildner /* Start a new list. */
453*99db7d0eSSascha Wildner list_type = list_continues(nn, roff_node_next(nn));
454*99db7d0eSSascha Wildner if (list_type == '\0')
45554ba9607SSascha Wildner list_type = ' ';
45654ba9607SSascha Wildner switch (list_type) {
45754ba9607SSascha Wildner case ' ':
45854ba9607SSascha Wildner list_class = "Bl-tag";
45954ba9607SSascha Wildner list_elem = TAG_DL;
46054ba9607SSascha Wildner break;
46154ba9607SSascha Wildner case '*':
46254ba9607SSascha Wildner list_class = "Bl-bullet";
46354ba9607SSascha Wildner list_elem = TAG_UL;
46454ba9607SSascha Wildner break;
46554ba9607SSascha Wildner case '-':
46654ba9607SSascha Wildner list_class = "Bl-dash";
46754ba9607SSascha Wildner list_elem = TAG_UL;
46854ba9607SSascha Wildner break;
46954ba9607SSascha Wildner default:
47054ba9607SSascha Wildner abort();
47154ba9607SSascha Wildner }
47254ba9607SSascha Wildner } else {
47354ba9607SSascha Wildner /* Continue a list that was started earlier. */
47454ba9607SSascha Wildner list_class = NULL;
47554ba9607SSascha Wildner list_elem = TAG_MAX;
47654ba9607SSascha Wildner }
47754ba9607SSascha Wildner body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
47854ba9607SSascha Wildner
47954ba9607SSascha Wildner switch (n->type) {
48054ba9607SSascha Wildner case ROFFT_BLOCK:
48154ba9607SSascha Wildner html_close_paragraph(h);
48254ba9607SSascha Wildner if (list_elem != TAG_MAX)
48354ba9607SSascha Wildner print_otag(h, list_elem, "c", list_class);
48454ba9607SSascha Wildner return 1;
48554ba9607SSascha Wildner case ROFFT_HEAD:
48654ba9607SSascha Wildner if (body_elem == TAG_LI)
48754ba9607SSascha Wildner return 0;
488*99db7d0eSSascha Wildner print_otag_id(h, TAG_DT, NULL, n);
48954ba9607SSascha Wildner break;
49054ba9607SSascha Wildner case ROFFT_BODY:
49154ba9607SSascha Wildner print_otag(h, body_elem, "");
49254ba9607SSascha Wildner return 1;
49354ba9607SSascha Wildner default:
49454ba9607SSascha Wildner abort();
49580387638SSascha Wildner }
49654ba9607SSascha Wildner switch(n->tok) {
49754ba9607SSascha Wildner case MAN_IP: /* Only print the first header element. */
49854ba9607SSascha Wildner if (n->child != NULL)
49954ba9607SSascha Wildner print_man_node(man, n->child, h);
50054ba9607SSascha Wildner break;
50154ba9607SSascha Wildner case MAN_TP: /* Only print next-line header elements. */
50254ba9607SSascha Wildner case MAN_TQ:
503070c62a6SFranco Fichtner nn = n->child;
50454ba9607SSascha Wildner while (nn != NULL && (NODE_LINE & nn->flags) == 0)
505070c62a6SFranco Fichtner nn = nn->next;
50654ba9607SSascha Wildner while (nn != NULL) {
50754ba9607SSascha Wildner print_man_node(man, nn, h);
508070c62a6SFranco Fichtner nn = nn->next;
509070c62a6SFranco Fichtner }
51054ba9607SSascha Wildner break;
51154ba9607SSascha Wildner default:
51254ba9607SSascha Wildner abort();
513070c62a6SFranco Fichtner }
51454ba9607SSascha Wildner return 0;
51580387638SSascha Wildner }
51680387638SSascha Wildner
51736342e81SSascha Wildner static int
man_OP_pre(MAN_ARGS)51836342e81SSascha Wildner man_OP_pre(MAN_ARGS)
51936342e81SSascha Wildner {
52036342e81SSascha Wildner struct tag *tt;
52136342e81SSascha Wildner
52236342e81SSascha Wildner print_text(h, "[");
52336342e81SSascha Wildner h->flags |= HTML_NOSPACE;
52454ba9607SSascha Wildner tt = print_otag(h, TAG_SPAN, "c", "Op");
52536342e81SSascha Wildner
52654ba9607SSascha Wildner if ((n = n->child) != NULL) {
52754ba9607SSascha Wildner print_otag(h, TAG_B, "");
52836342e81SSascha Wildner print_text(h, n->string);
52936342e81SSascha Wildner }
53036342e81SSascha Wildner
53136342e81SSascha Wildner print_stagq(h, tt);
53236342e81SSascha Wildner
53354ba9607SSascha Wildner if (n != NULL && n->next != NULL) {
53454ba9607SSascha Wildner print_otag(h, TAG_I, "");
53536342e81SSascha Wildner print_text(h, n->next->string);
53636342e81SSascha Wildner }
53736342e81SSascha Wildner
53836342e81SSascha Wildner print_stagq(h, tt);
53936342e81SSascha Wildner h->flags |= HTML_NOSPACE;
54036342e81SSascha Wildner print_text(h, "]");
54154ba9607SSascha Wildner return 0;
54236342e81SSascha Wildner }
54336342e81SSascha Wildner
54480387638SSascha Wildner static int
man_B_pre(MAN_ARGS)54580387638SSascha Wildner man_B_pre(MAN_ARGS)
54680387638SSascha Wildner {
54754ba9607SSascha Wildner print_otag(h, TAG_B, "");
54854ba9607SSascha Wildner return 1;
54980387638SSascha Wildner }
55080387638SSascha Wildner
55180387638SSascha Wildner static int
man_I_pre(MAN_ARGS)55280387638SSascha Wildner man_I_pre(MAN_ARGS)
55380387638SSascha Wildner {
55454ba9607SSascha Wildner print_otag(h, TAG_I, "");
55554ba9607SSascha Wildner return 1;
55680387638SSascha Wildner }
55780387638SSascha Wildner
55880387638SSascha Wildner static int
man_in_pre(MAN_ARGS)55980387638SSascha Wildner man_in_pre(MAN_ARGS)
56080387638SSascha Wildner {
56154ba9607SSascha Wildner print_otag(h, TAG_BR, "");
56254ba9607SSascha Wildner return 0;
56380387638SSascha Wildner }
56480387638SSascha Wildner
56580387638SSascha Wildner static int
man_ign_pre(MAN_ARGS)56680387638SSascha Wildner man_ign_pre(MAN_ARGS)
56780387638SSascha Wildner {
56854ba9607SSascha Wildner return 0;
56980387638SSascha Wildner }
57080387638SSascha Wildner
57180387638SSascha Wildner static int
man_RS_pre(MAN_ARGS)57280387638SSascha Wildner man_RS_pre(MAN_ARGS)
57380387638SSascha Wildner {
57454ba9607SSascha Wildner switch (n->type) {
57554ba9607SSascha Wildner case ROFFT_BLOCK:
57654ba9607SSascha Wildner html_close_paragraph(h);
57754ba9607SSascha Wildner break;
57854ba9607SSascha Wildner case ROFFT_HEAD:
57954ba9607SSascha Wildner return 0;
58054ba9607SSascha Wildner case ROFFT_BODY:
58154ba9607SSascha Wildner print_otag(h, TAG_DIV, "c", "Bd-indent");
58254ba9607SSascha Wildner break;
58354ba9607SSascha Wildner default:
58454ba9607SSascha Wildner abort();
58554ba9607SSascha Wildner }
58654ba9607SSascha Wildner return 1;
58754ba9607SSascha Wildner }
58880387638SSascha Wildner
58954ba9607SSascha Wildner static int
man_SY_pre(MAN_ARGS)59054ba9607SSascha Wildner man_SY_pre(MAN_ARGS)
59154ba9607SSascha Wildner {
59254ba9607SSascha Wildner switch (n->type) {
59354ba9607SSascha Wildner case ROFFT_BLOCK:
59454ba9607SSascha Wildner html_close_paragraph(h);
59554ba9607SSascha Wildner print_otag(h, TAG_TABLE, "c", "Nm");
59654ba9607SSascha Wildner print_otag(h, TAG_TR, "");
59754ba9607SSascha Wildner break;
59854ba9607SSascha Wildner case ROFFT_HEAD:
59954ba9607SSascha Wildner print_otag(h, TAG_TD, "");
60054ba9607SSascha Wildner print_otag(h, TAG_CODE, "c", "Nm");
60154ba9607SSascha Wildner break;
60254ba9607SSascha Wildner case ROFFT_BODY:
60354ba9607SSascha Wildner print_otag(h, TAG_TD, "");
60454ba9607SSascha Wildner break;
60554ba9607SSascha Wildner default:
60654ba9607SSascha Wildner abort();
60754ba9607SSascha Wildner }
60854ba9607SSascha Wildner return 1;
60980387638SSascha Wildner }
6107888c61dSFranco Fichtner
6117888c61dSFranco Fichtner static int
man_UR_pre(MAN_ARGS)6127888c61dSFranco Fichtner man_UR_pre(MAN_ARGS)
6137888c61dSFranco Fichtner {
61454ba9607SSascha Wildner char *cp;
6157888c61dSFranco Fichtner
6167888c61dSFranco Fichtner n = n->child;
61754ba9607SSascha Wildner assert(n->type == ROFFT_HEAD);
61854ba9607SSascha Wildner if (n->child != NULL) {
61954ba9607SSascha Wildner assert(n->child->type == ROFFT_TEXT);
62054ba9607SSascha Wildner if (n->tok == MAN_MT) {
62154ba9607SSascha Wildner mandoc_asprintf(&cp, "mailto:%s", n->child->string);
62254ba9607SSascha Wildner print_otag(h, TAG_A, "ch", "Mt", cp);
62354ba9607SSascha Wildner free(cp);
62454ba9607SSascha Wildner } else
62554ba9607SSascha Wildner print_otag(h, TAG_A, "ch", "Lk", n->child->string);
6267888c61dSFranco Fichtner }
6277888c61dSFranco Fichtner
62854ba9607SSascha Wildner assert(n->next->type == ROFFT_BODY);
62954ba9607SSascha Wildner if (n->next->child != NULL)
6307888c61dSFranco Fichtner n = n->next;
6317888c61dSFranco Fichtner
63254ba9607SSascha Wildner print_man_nodelist(man, n->child, h);
63354ba9607SSascha Wildner return 0;
63454ba9607SSascha Wildner }
6357888c61dSFranco Fichtner
63654ba9607SSascha Wildner static int
man_abort_pre(MAN_ARGS)63754ba9607SSascha Wildner man_abort_pre(MAN_ARGS)
63854ba9607SSascha Wildner {
63954ba9607SSascha Wildner abort();
6407888c61dSFranco Fichtner }
641