1*4d131170SRobert Mustacchi /* $Id: man_html.c,v 1.179 2020/10/16 17:22:43 schwarze Exp $ */
295c635efSGarrett D'Amore /*
3*4d131170SRobert Mustacchi * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
4260e9a87SYuri Pankov * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
10371584c2SYuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12371584c2SYuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*4d131170SRobert Mustacchi *
18*4d131170SRobert Mustacchi * HTML formatter for man(7) used by mandoc(1).
1995c635efSGarrett D'Amore */
2095c635efSGarrett D'Amore #include "config.h"
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #include <sys/types.h>
2395c635efSGarrett D'Amore
2495c635efSGarrett D'Amore #include <assert.h>
2595c635efSGarrett D'Amore #include <ctype.h>
2695c635efSGarrett D'Amore #include <stdio.h>
2795c635efSGarrett D'Amore #include <stdlib.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore
30260e9a87SYuri Pankov #include "mandoc_aux.h"
31c66b8046SYuri Pankov #include "mandoc.h"
32371584c2SYuri Pankov #include "roff.h"
33260e9a87SYuri Pankov #include "man.h"
3495c635efSGarrett D'Amore #include "out.h"
3595c635efSGarrett D'Amore #include "html.h"
3695c635efSGarrett D'Amore #include "main.h"
3795c635efSGarrett D'Amore
38371584c2SYuri Pankov #define MAN_ARGS const struct roff_meta *man, \
39*4d131170SRobert Mustacchi struct roff_node *n, \
4095c635efSGarrett D'Amore struct html *h
4195c635efSGarrett D'Amore
42cec8643bSMichal Nowak struct man_html_act {
4395c635efSGarrett D'Amore int (*pre)(MAN_ARGS);
4495c635efSGarrett D'Amore int (*post)(MAN_ARGS);
4595c635efSGarrett D'Amore };
4695c635efSGarrett D'Amore
476640c13bSYuri Pankov static void print_man_head(const struct roff_meta *,
486640c13bSYuri Pankov struct html *);
4995c635efSGarrett D'Amore static void print_man_nodelist(MAN_ARGS);
5095c635efSGarrett D'Amore static void print_man_node(MAN_ARGS);
51cec8643bSMichal Nowak static char list_continues(const struct roff_node *,
52cec8643bSMichal Nowak const struct roff_node *);
5395c635efSGarrett D'Amore static int man_B_pre(MAN_ARGS);
5495c635efSGarrett D'Amore static int man_IP_pre(MAN_ARGS);
5595c635efSGarrett D'Amore static int man_I_pre(MAN_ARGS);
5695c635efSGarrett D'Amore static int man_OP_pre(MAN_ARGS);
5795c635efSGarrett D'Amore static int man_PP_pre(MAN_ARGS);
5895c635efSGarrett D'Amore static int man_RS_pre(MAN_ARGS);
5995c635efSGarrett D'Amore static int man_SH_pre(MAN_ARGS);
6095c635efSGarrett D'Amore static int man_SM_pre(MAN_ARGS);
61cec8643bSMichal Nowak static int man_SY_pre(MAN_ARGS);
62698f87a4SGarrett D'Amore static int man_UR_pre(MAN_ARGS);
63cec8643bSMichal Nowak static int man_abort_pre(MAN_ARGS);
6495c635efSGarrett D'Amore static int man_alt_pre(MAN_ARGS);
6595c635efSGarrett D'Amore static int man_ign_pre(MAN_ARGS);
6695c635efSGarrett D'Amore static int man_in_pre(MAN_ARGS);
676640c13bSYuri Pankov static void man_root_post(const struct roff_meta *,
686640c13bSYuri Pankov struct html *);
696640c13bSYuri Pankov static void man_root_pre(const struct roff_meta *,
706640c13bSYuri Pankov struct html *);
7195c635efSGarrett D'Amore
72cec8643bSMichal Nowak static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
7395c635efSGarrett D'Amore { NULL, NULL }, /* TH */
7495c635efSGarrett D'Amore { man_SH_pre, NULL }, /* SH */
75cec8643bSMichal Nowak { man_SH_pre, NULL }, /* SS */
7695c635efSGarrett D'Amore { man_IP_pre, NULL }, /* TP */
77cec8643bSMichal Nowak { man_IP_pre, NULL }, /* TQ */
78cec8643bSMichal Nowak { man_abort_pre, NULL }, /* LP */
7995c635efSGarrett D'Amore { man_PP_pre, NULL }, /* PP */
80cec8643bSMichal Nowak { man_abort_pre, NULL }, /* P */
8195c635efSGarrett D'Amore { man_IP_pre, NULL }, /* IP */
82cec8643bSMichal Nowak { man_PP_pre, NULL }, /* HP */
8395c635efSGarrett D'Amore { man_SM_pre, NULL }, /* SM */
8495c635efSGarrett D'Amore { man_SM_pre, NULL }, /* SB */
8595c635efSGarrett D'Amore { man_alt_pre, NULL }, /* BI */
8695c635efSGarrett D'Amore { man_alt_pre, NULL }, /* IB */
8795c635efSGarrett D'Amore { man_alt_pre, NULL }, /* BR */
8895c635efSGarrett D'Amore { man_alt_pre, NULL }, /* RB */
8995c635efSGarrett D'Amore { NULL, NULL }, /* R */
9095c635efSGarrett D'Amore { man_B_pre, NULL }, /* B */
9195c635efSGarrett D'Amore { man_I_pre, NULL }, /* I */
9295c635efSGarrett D'Amore { man_alt_pre, NULL }, /* IR */
9395c635efSGarrett D'Amore { man_alt_pre, NULL }, /* RI */
9495c635efSGarrett D'Amore { NULL, NULL }, /* RE */
9595c635efSGarrett D'Amore { man_RS_pre, NULL }, /* RS */
9695c635efSGarrett D'Amore { man_ign_pre, NULL }, /* DT */
9795c635efSGarrett D'Amore { man_ign_pre, NULL }, /* UC */
9895c635efSGarrett D'Amore { man_ign_pre, NULL }, /* PD */
9995c635efSGarrett D'Amore { man_ign_pre, NULL }, /* AT */
10095c635efSGarrett D'Amore { man_in_pre, NULL }, /* in */
101cec8643bSMichal Nowak { man_SY_pre, NULL }, /* SY */
102cec8643bSMichal Nowak { NULL, NULL }, /* YS */
10395c635efSGarrett D'Amore { man_OP_pre, NULL }, /* OP */
104a40ea1a7SYuri Pankov { NULL, NULL }, /* EX */
105a40ea1a7SYuri Pankov { NULL, NULL }, /* EE */
106698f87a4SGarrett D'Amore { man_UR_pre, NULL }, /* UR */
107698f87a4SGarrett D'Amore { NULL, NULL }, /* UE */
108c66b8046SYuri Pankov { man_UR_pre, NULL }, /* MT */
109c66b8046SYuri Pankov { NULL, NULL }, /* ME */
11095c635efSGarrett D'Amore };
11195c635efSGarrett D'Amore
11295c635efSGarrett D'Amore
11395c635efSGarrett D'Amore void
html_man(void * arg,const struct roff_meta * man)114cec8643bSMichal Nowak html_man(void *arg, const struct roff_meta *man)
11595c635efSGarrett D'Amore {
1166640c13bSYuri Pankov struct html *h;
1176640c13bSYuri Pankov struct roff_node *n;
1186640c13bSYuri Pankov struct tag *t;
11995c635efSGarrett D'Amore
120371584c2SYuri Pankov h = (struct html *)arg;
1216640c13bSYuri Pankov n = man->first->child;
12295c635efSGarrett D'Amore
123a40ea1a7SYuri Pankov if ((h->oflags & HTML_FRAGMENT) == 0) {
12495c635efSGarrett D'Amore print_gen_decls(h);
125a40ea1a7SYuri Pankov print_otag(h, TAG_HTML, "");
126cec8643bSMichal Nowak if (n != NULL && n->type == ROFFT_COMMENT)
1276640c13bSYuri Pankov print_gen_comment(h, n);
128a40ea1a7SYuri Pankov t = print_otag(h, TAG_HEAD, "");
129cec8643bSMichal Nowak print_man_head(man, h);
130a40ea1a7SYuri Pankov print_tagq(h, t);
131a40ea1a7SYuri Pankov print_otag(h, TAG_BODY, "");
132a40ea1a7SYuri Pankov }
13395c635efSGarrett D'Amore
134cec8643bSMichal Nowak man_root_pre(man, h);
135a40ea1a7SYuri Pankov t = print_otag(h, TAG_DIV, "c", "manual-text");
136cec8643bSMichal Nowak print_man_nodelist(man, n, h);
13795c635efSGarrett D'Amore print_tagq(h, t);
138cec8643bSMichal Nowak man_root_post(man, h);
139a40ea1a7SYuri Pankov print_tagq(h, NULL);
14095c635efSGarrett D'Amore }
14195c635efSGarrett D'Amore
14295c635efSGarrett D'Amore static void
print_man_head(const struct roff_meta * man,struct html * h)1436640c13bSYuri Pankov print_man_head(const struct roff_meta *man, struct html *h)
14495c635efSGarrett D'Amore {
145a40ea1a7SYuri Pankov char *cp;
14695c635efSGarrett D'Amore
14795c635efSGarrett D'Amore print_gen_head(h);
148a40ea1a7SYuri Pankov mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
149a40ea1a7SYuri Pankov print_otag(h, TAG_TITLE, "");
150a40ea1a7SYuri Pankov print_text(h, cp);
151a40ea1a7SYuri Pankov free(cp);
15295c635efSGarrett D'Amore }
15395c635efSGarrett D'Amore
15495c635efSGarrett D'Amore static void
print_man_nodelist(MAN_ARGS)15595c635efSGarrett D'Amore print_man_nodelist(MAN_ARGS)
15695c635efSGarrett D'Amore {
157260e9a87SYuri Pankov while (n != NULL) {
158a40ea1a7SYuri Pankov print_man_node(man, n, h);
159260e9a87SYuri Pankov n = n->next;
160260e9a87SYuri Pankov }
16195c635efSGarrett D'Amore }
16295c635efSGarrett D'Amore
16395c635efSGarrett D'Amore static void
print_man_node(MAN_ARGS)16495c635efSGarrett D'Amore print_man_node(MAN_ARGS)
16595c635efSGarrett D'Amore {
16695c635efSGarrett D'Amore struct tag *t;
167a40ea1a7SYuri Pankov int child;
16895c635efSGarrett D'Amore
169cec8643bSMichal Nowak if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
170a40ea1a7SYuri Pankov return;
171a40ea1a7SYuri Pankov
172*4d131170SRobert Mustacchi if ((n->flags & NODE_NOFILL) == 0)
173*4d131170SRobert Mustacchi html_fillmode(h, ROFF_fi);
174*4d131170SRobert Mustacchi else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
175*4d131170SRobert Mustacchi n->tok != ROFF_fi && n->flags & NODE_LINE &&
176*4d131170SRobert Mustacchi (n->prev == NULL || n->prev->tok != MAN_YS))
177*4d131170SRobert Mustacchi print_endline(h);
178a40ea1a7SYuri Pankov
179a40ea1a7SYuri Pankov child = 1;
180a40ea1a7SYuri Pankov switch (n->type) {
181a40ea1a7SYuri Pankov case ROFFT_TEXT:
182cec8643bSMichal Nowak if (*n->string == '\0') {
183cec8643bSMichal Nowak print_endline(h);
184cec8643bSMichal Nowak return;
185cec8643bSMichal Nowak }
186cec8643bSMichal Nowak if (*n->string == ' ' && n->flags & NODE_LINE &&
187cec8643bSMichal Nowak (h->flags & HTML_NONEWLINE) == 0)
188*4d131170SRobert Mustacchi print_otag(h, TAG_BR, "");
189cec8643bSMichal Nowak else if (n->flags & NODE_DELIMC)
190cec8643bSMichal Nowak h->flags |= HTML_NOSPACE;
191a40ea1a7SYuri Pankov t = h->tag;
192cec8643bSMichal Nowak t->refcnt++;
193a40ea1a7SYuri Pankov print_text(h, n->string);
194a40ea1a7SYuri Pankov break;
195371584c2SYuri Pankov case ROFFT_EQN:
196a40ea1a7SYuri Pankov t = h->tag;
197cec8643bSMichal Nowak t->refcnt++;
19895c635efSGarrett D'Amore print_eqn(h, n->eqn);
19995c635efSGarrett D'Amore break;
200371584c2SYuri Pankov case ROFFT_TBL:
20195c635efSGarrett D'Amore /*
20295c635efSGarrett D'Amore * This will take care of initialising all of the table
20395c635efSGarrett D'Amore * state data for the first table, then tearing it down
20495c635efSGarrett D'Amore * for the last one.
20595c635efSGarrett D'Amore */
20695c635efSGarrett D'Amore print_tbl(h, n->span);
20795c635efSGarrett D'Amore return;
20895c635efSGarrett D'Amore default:
209260e9a87SYuri Pankov /*
21095c635efSGarrett D'Amore * Close out scope of font prior to opening a macro
21195c635efSGarrett D'Amore * scope.
21295c635efSGarrett D'Amore */
213*4d131170SRobert Mustacchi if (h->metac != ESCAPE_FONTROMAN) {
21495c635efSGarrett D'Amore h->metal = h->metac;
215*4d131170SRobert Mustacchi h->metac = ESCAPE_FONTROMAN;
21695c635efSGarrett D'Amore }
21795c635efSGarrett D'Amore
21895c635efSGarrett D'Amore /*
21995c635efSGarrett D'Amore * Close out the current table, if it's open, and unset
22095c635efSGarrett D'Amore * the "meta" table state. This will be reopened on the
22195c635efSGarrett D'Amore * next table element.
22295c635efSGarrett D'Amore */
223cec8643bSMichal Nowak if (h->tblt != NULL)
22495c635efSGarrett D'Amore print_tblclose(h);
225a40ea1a7SYuri Pankov t = h->tag;
226cec8643bSMichal Nowak t->refcnt++;
227c66b8046SYuri Pankov if (n->tok < ROFF_MAX) {
228c66b8046SYuri Pankov roff_html_pre(h, n);
229cec8643bSMichal Nowak t->refcnt--;
230cec8643bSMichal Nowak print_stagq(h, t);
231cec8643bSMichal Nowak return;
232c66b8046SYuri Pankov }
233c66b8046SYuri Pankov assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
234cec8643bSMichal Nowak if (man_html_acts[n->tok - MAN_TH].pre != NULL)
235cec8643bSMichal Nowak child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
236cec8643bSMichal Nowak n, h);
23795c635efSGarrett D'Amore break;
23895c635efSGarrett D'Amore }
23995c635efSGarrett D'Amore
240cec8643bSMichal Nowak if (child && n->child != NULL)
241a40ea1a7SYuri Pankov print_man_nodelist(man, n->child, h);
24295c635efSGarrett D'Amore
24395c635efSGarrett D'Amore /* This will automatically close out any font scope. */
244cec8643bSMichal Nowak t->refcnt--;
245cec8643bSMichal Nowak if (n->type == ROFFT_BLOCK &&
246cec8643bSMichal Nowak (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
247cec8643bSMichal Nowak t = h->tag;
248cec8643bSMichal Nowak while (t->tag != TAG_DL && t->tag != TAG_UL)
249cec8643bSMichal Nowak t = t->next;
250cec8643bSMichal Nowak /*
251cec8643bSMichal Nowak * Close the list if no further item of the same type
252cec8643bSMichal Nowak * follows; otherwise, close the item only.
253cec8643bSMichal Nowak */
254*4d131170SRobert Mustacchi if (list_continues(n, roff_node_next(n)) == '\0') {
255cec8643bSMichal Nowak print_tagq(h, t);
256cec8643bSMichal Nowak t = NULL;
257cec8643bSMichal Nowak }
258cec8643bSMichal Nowak }
259cec8643bSMichal Nowak if (t != NULL)
260cec8643bSMichal Nowak print_stagq(h, t);
26195c635efSGarrett D'Amore }
26295c635efSGarrett D'Amore
26395c635efSGarrett D'Amore static void
man_root_pre(const struct roff_meta * man,struct html * h)2646640c13bSYuri Pankov man_root_pre(const struct roff_meta *man, struct html *h)
26595c635efSGarrett D'Amore {
26695c635efSGarrett D'Amore struct tag *t, *tt;
267260e9a87SYuri Pankov char *title;
26895c635efSGarrett D'Amore
269698f87a4SGarrett D'Amore assert(man->title);
270698f87a4SGarrett D'Amore assert(man->msec);
271260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
27295c635efSGarrett D'Amore
273a40ea1a7SYuri Pankov t = print_otag(h, TAG_TABLE, "c", "head");
274a40ea1a7SYuri Pankov tt = print_otag(h, TAG_TR, "");
27595c635efSGarrett D'Amore
276a40ea1a7SYuri Pankov print_otag(h, TAG_TD, "c", "head-ltitle");
27795c635efSGarrett D'Amore print_text(h, title);
27895c635efSGarrett D'Amore print_stagq(h, tt);
27995c635efSGarrett D'Amore
280a40ea1a7SYuri Pankov print_otag(h, TAG_TD, "c", "head-vol");
281cec8643bSMichal Nowak if (man->vol != NULL)
282260e9a87SYuri Pankov print_text(h, man->vol);
28395c635efSGarrett D'Amore print_stagq(h, tt);
28495c635efSGarrett D'Amore
285a40ea1a7SYuri Pankov print_otag(h, TAG_TD, "c", "head-rtitle");
28695c635efSGarrett D'Amore print_text(h, title);
28795c635efSGarrett D'Amore print_tagq(h, t);
288260e9a87SYuri Pankov free(title);
28995c635efSGarrett D'Amore }
29095c635efSGarrett D'Amore
29195c635efSGarrett D'Amore static void
man_root_post(const struct roff_meta * man,struct html * h)2926640c13bSYuri Pankov man_root_post(const struct roff_meta *man, struct html *h)
29395c635efSGarrett D'Amore {
29495c635efSGarrett D'Amore struct tag *t, *tt;
29595c635efSGarrett D'Amore
296a40ea1a7SYuri Pankov t = print_otag(h, TAG_TABLE, "c", "foot");
297a40ea1a7SYuri Pankov tt = print_otag(h, TAG_TR, "");
29895c635efSGarrett D'Amore
299a40ea1a7SYuri Pankov print_otag(h, TAG_TD, "c", "foot-date");
300698f87a4SGarrett D'Amore print_text(h, man->date);
30195c635efSGarrett D'Amore print_stagq(h, tt);
30295c635efSGarrett D'Amore
303a40ea1a7SYuri Pankov print_otag(h, TAG_TD, "c", "foot-os");
304cec8643bSMichal Nowak if (man->os != NULL)
305371584c2SYuri Pankov print_text(h, man->os);
30695c635efSGarrett D'Amore print_tagq(h, t);
30795c635efSGarrett D'Amore }
30895c635efSGarrett D'Amore
30995c635efSGarrett D'Amore static int
man_SH_pre(MAN_ARGS)31095c635efSGarrett D'Amore man_SH_pre(MAN_ARGS)
31195c635efSGarrett D'Amore {
312cec8643bSMichal Nowak const char *class;
313cec8643bSMichal Nowak enum htmltag tag;
314cec8643bSMichal Nowak
315cec8643bSMichal Nowak if (n->tok == MAN_SH) {
316cec8643bSMichal Nowak tag = TAG_H1;
317cec8643bSMichal Nowak class = "Sh";
318cec8643bSMichal Nowak } else {
319cec8643bSMichal Nowak tag = TAG_H2;
320cec8643bSMichal Nowak class = "Ss";
321cec8643bSMichal Nowak }
322cec8643bSMichal Nowak switch (n->type) {
323cec8643bSMichal Nowak case ROFFT_BLOCK:
324cec8643bSMichal Nowak html_close_paragraph(h);
325cec8643bSMichal Nowak print_otag(h, TAG_SECTION, "c", class);
326cec8643bSMichal Nowak break;
327cec8643bSMichal Nowak case ROFFT_HEAD:
328*4d131170SRobert Mustacchi print_otag_id(h, tag, class, n);
329cec8643bSMichal Nowak break;
330cec8643bSMichal Nowak case ROFFT_BODY:
331cec8643bSMichal Nowak break;
332cec8643bSMichal Nowak default:
333cec8643bSMichal Nowak abort();
334c66b8046SYuri Pankov }
335371584c2SYuri Pankov return 1;
33695c635efSGarrett D'Amore }
33795c635efSGarrett D'Amore
33895c635efSGarrett D'Amore static int
man_alt_pre(MAN_ARGS)33995c635efSGarrett D'Amore man_alt_pre(MAN_ARGS)
34095c635efSGarrett D'Amore {
341371584c2SYuri Pankov const struct roff_node *nn;
342cec8643bSMichal Nowak struct tag *t;
343a40ea1a7SYuri Pankov int i;
34495c635efSGarrett D'Amore enum htmltag fp;
34595c635efSGarrett D'Amore
346cec8643bSMichal Nowak for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
34795c635efSGarrett D'Amore switch (n->tok) {
348260e9a87SYuri Pankov case MAN_BI:
34995c635efSGarrett D'Amore fp = i % 2 ? TAG_I : TAG_B;
35095c635efSGarrett D'Amore break;
351260e9a87SYuri Pankov case MAN_IB:
35295c635efSGarrett D'Amore fp = i % 2 ? TAG_B : TAG_I;
35395c635efSGarrett D'Amore break;
354260e9a87SYuri Pankov case MAN_RI:
35595c635efSGarrett D'Amore fp = i % 2 ? TAG_I : TAG_MAX;
35695c635efSGarrett D'Amore break;
357260e9a87SYuri Pankov case MAN_IR:
35895c635efSGarrett D'Amore fp = i % 2 ? TAG_MAX : TAG_I;
35995c635efSGarrett D'Amore break;
360260e9a87SYuri Pankov case MAN_BR:
36195c635efSGarrett D'Amore fp = i % 2 ? TAG_MAX : TAG_B;
36295c635efSGarrett D'Amore break;
363260e9a87SYuri Pankov case MAN_RB:
36495c635efSGarrett D'Amore fp = i % 2 ? TAG_B : TAG_MAX;
36595c635efSGarrett D'Amore break;
36695c635efSGarrett D'Amore default:
36795c635efSGarrett D'Amore abort();
36895c635efSGarrett D'Amore }
36995c635efSGarrett D'Amore
37095c635efSGarrett D'Amore if (i)
37195c635efSGarrett D'Amore h->flags |= HTML_NOSPACE;
37295c635efSGarrett D'Amore
373a40ea1a7SYuri Pankov if (fp != TAG_MAX)
374a40ea1a7SYuri Pankov t = print_otag(h, fp, "");
37595c635efSGarrett D'Amore
376a40ea1a7SYuri Pankov print_text(h, nn->string);
37795c635efSGarrett D'Amore
378a40ea1a7SYuri Pankov if (fp != TAG_MAX)
37995c635efSGarrett D'Amore print_tagq(h, t);
38095c635efSGarrett D'Amore }
381371584c2SYuri Pankov return 0;
38295c635efSGarrett D'Amore }
38395c635efSGarrett D'Amore
38495c635efSGarrett D'Amore static int
man_SM_pre(MAN_ARGS)38595c635efSGarrett D'Amore man_SM_pre(MAN_ARGS)
38695c635efSGarrett D'Amore {
387a40ea1a7SYuri Pankov print_otag(h, TAG_SMALL, "");
388cec8643bSMichal Nowak if (n->tok == MAN_SB)
389a40ea1a7SYuri Pankov print_otag(h, TAG_B, "");
390371584c2SYuri Pankov return 1;
39195c635efSGarrett D'Amore }
39295c635efSGarrett D'Amore
39395c635efSGarrett D'Amore static int
man_PP_pre(MAN_ARGS)394cec8643bSMichal Nowak man_PP_pre(MAN_ARGS)
39595c635efSGarrett D'Amore {
396cec8643bSMichal Nowak switch (n->type) {
397cec8643bSMichal Nowak case ROFFT_BLOCK:
398cec8643bSMichal Nowak html_close_paragraph(h);
399cec8643bSMichal Nowak break;
400cec8643bSMichal Nowak case ROFFT_HEAD:
401cec8643bSMichal Nowak return 0;
402cec8643bSMichal Nowak case ROFFT_BODY:
403cec8643bSMichal Nowak if (n->child != NULL &&
404cec8643bSMichal Nowak (n->child->flags & NODE_NOFILL) == 0)
405cec8643bSMichal Nowak print_otag(h, TAG_P, "c",
406cec8643bSMichal Nowak n->tok == MAN_PP ? "Pp" : "Pp HP");
407cec8643bSMichal Nowak break;
408cec8643bSMichal Nowak default:
409cec8643bSMichal Nowak abort();
410c66b8046SYuri Pankov }
411371584c2SYuri Pankov return 1;
41295c635efSGarrett D'Amore }
41395c635efSGarrett D'Amore
414cec8643bSMichal Nowak static char
list_continues(const struct roff_node * n1,const struct roff_node * n2)415cec8643bSMichal Nowak list_continues(const struct roff_node *n1, const struct roff_node *n2)
41695c635efSGarrett D'Amore {
417cec8643bSMichal Nowak const char *s1, *s2;
418cec8643bSMichal Nowak char c1, c2;
419cec8643bSMichal Nowak
420cec8643bSMichal Nowak if (n1 == NULL || n1->type != ROFFT_BLOCK ||
421cec8643bSMichal Nowak n2 == NULL || n2->type != ROFFT_BLOCK)
422cec8643bSMichal Nowak return '\0';
423cec8643bSMichal Nowak if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
424cec8643bSMichal Nowak (n2->tok == MAN_TP || n2->tok == MAN_TQ))
425cec8643bSMichal Nowak return ' ';
426cec8643bSMichal Nowak if (n1->tok != MAN_IP || n2->tok != MAN_IP)
427cec8643bSMichal Nowak return '\0';
428cec8643bSMichal Nowak n1 = n1->head->child;
429cec8643bSMichal Nowak n2 = n2->head->child;
430cec8643bSMichal Nowak s1 = n1 == NULL ? "" : n1->string;
431cec8643bSMichal Nowak s2 = n2 == NULL ? "" : n2->string;
432cec8643bSMichal Nowak c1 = strcmp(s1, "*") == 0 ? '*' :
433cec8643bSMichal Nowak strcmp(s1, "\\-") == 0 ? '-' :
434cec8643bSMichal Nowak strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
435cec8643bSMichal Nowak c2 = strcmp(s2, "*") == 0 ? '*' :
436cec8643bSMichal Nowak strcmp(s2, "\\-") == 0 ? '-' :
437cec8643bSMichal Nowak strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
438cec8643bSMichal Nowak return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
43995c635efSGarrett D'Amore }
44095c635efSGarrett D'Amore
44195c635efSGarrett D'Amore static int
man_IP_pre(MAN_ARGS)44295c635efSGarrett D'Amore man_IP_pre(MAN_ARGS)
44395c635efSGarrett D'Amore {
444*4d131170SRobert Mustacchi struct roff_node *nn;
445cec8643bSMichal Nowak const char *list_class;
446cec8643bSMichal Nowak enum htmltag list_elem, body_elem;
447cec8643bSMichal Nowak char list_type;
448cec8643bSMichal Nowak
449cec8643bSMichal Nowak nn = n->type == ROFFT_BLOCK ? n : n->parent;
450*4d131170SRobert Mustacchi list_type = list_continues(roff_node_prev(nn), nn);
451*4d131170SRobert Mustacchi if (list_type == '\0') {
452cec8643bSMichal Nowak /* Start a new list. */
453*4d131170SRobert Mustacchi list_type = list_continues(nn, roff_node_next(nn));
454*4d131170SRobert Mustacchi if (list_type == '\0')
455cec8643bSMichal Nowak list_type = ' ';
456cec8643bSMichal Nowak switch (list_type) {
457cec8643bSMichal Nowak case ' ':
458cec8643bSMichal Nowak list_class = "Bl-tag";
459cec8643bSMichal Nowak list_elem = TAG_DL;
460cec8643bSMichal Nowak break;
461cec8643bSMichal Nowak case '*':
462cec8643bSMichal Nowak list_class = "Bl-bullet";
463cec8643bSMichal Nowak list_elem = TAG_UL;
464cec8643bSMichal Nowak break;
465cec8643bSMichal Nowak case '-':
466cec8643bSMichal Nowak list_class = "Bl-dash";
467cec8643bSMichal Nowak list_elem = TAG_UL;
468cec8643bSMichal Nowak break;
469cec8643bSMichal Nowak default:
470cec8643bSMichal Nowak abort();
471cec8643bSMichal Nowak }
472cec8643bSMichal Nowak } else {
473cec8643bSMichal Nowak /* Continue a list that was started earlier. */
474cec8643bSMichal Nowak list_class = NULL;
475cec8643bSMichal Nowak list_elem = TAG_MAX;
476cec8643bSMichal Nowak }
477cec8643bSMichal Nowak body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
47895c635efSGarrett D'Amore
479cec8643bSMichal Nowak switch (n->type) {
480cec8643bSMichal Nowak case ROFFT_BLOCK:
481cec8643bSMichal Nowak html_close_paragraph(h);
482cec8643bSMichal Nowak if (list_elem != TAG_MAX)
483cec8643bSMichal Nowak print_otag(h, list_elem, "c", list_class);
484371584c2SYuri Pankov return 1;
485cec8643bSMichal Nowak case ROFFT_HEAD:
486cec8643bSMichal Nowak if (body_elem == TAG_LI)
487cec8643bSMichal Nowak return 0;
488*4d131170SRobert Mustacchi print_otag_id(h, TAG_DT, NULL, n);
489cec8643bSMichal Nowak break;
490cec8643bSMichal Nowak case ROFFT_BODY:
491cec8643bSMichal Nowak print_otag(h, body_elem, "");
492371584c2SYuri Pankov return 1;
493cec8643bSMichal Nowak default:
494cec8643bSMichal Nowak abort();
49595c635efSGarrett D'Amore }
496cec8643bSMichal Nowak switch(n->tok) {
497cec8643bSMichal Nowak case MAN_IP: /* Only print the first header element. */
498cec8643bSMichal Nowak if (n->child != NULL)
499cec8643bSMichal Nowak print_man_node(man, n->child, h);
500cec8643bSMichal Nowak break;
501cec8643bSMichal Nowak case MAN_TP: /* Only print next-line header elements. */
502cec8643bSMichal Nowak case MAN_TQ:
503260e9a87SYuri Pankov nn = n->child;
504cec8643bSMichal Nowak while (nn != NULL && (NODE_LINE & nn->flags) == 0)
505260e9a87SYuri Pankov nn = nn->next;
506cec8643bSMichal Nowak while (nn != NULL) {
507a40ea1a7SYuri Pankov print_man_node(man, nn, h);
508260e9a87SYuri Pankov nn = nn->next;
509260e9a87SYuri Pankov }
510cec8643bSMichal Nowak break;
511cec8643bSMichal Nowak default:
512cec8643bSMichal Nowak abort();
513260e9a87SYuri Pankov }
514371584c2SYuri Pankov return 0;
51595c635efSGarrett D'Amore }
51695c635efSGarrett D'Amore
51795c635efSGarrett D'Amore static int
man_OP_pre(MAN_ARGS)51895c635efSGarrett D'Amore man_OP_pre(MAN_ARGS)
51995c635efSGarrett D'Amore {
52095c635efSGarrett D'Amore struct tag *tt;
52195c635efSGarrett D'Amore
52295c635efSGarrett D'Amore print_text(h, "[");
52395c635efSGarrett D'Amore h->flags |= HTML_NOSPACE;
524a40ea1a7SYuri Pankov tt = print_otag(h, TAG_SPAN, "c", "Op");
52595c635efSGarrett D'Amore
526cec8643bSMichal Nowak if ((n = n->child) != NULL) {
527a40ea1a7SYuri Pankov print_otag(h, TAG_B, "");
52895c635efSGarrett D'Amore print_text(h, n->string);
52995c635efSGarrett D'Amore }
53095c635efSGarrett D'Amore
53195c635efSGarrett D'Amore print_stagq(h, tt);
53295c635efSGarrett D'Amore
533cec8643bSMichal Nowak if (n != NULL && n->next != NULL) {
534a40ea1a7SYuri Pankov print_otag(h, TAG_I, "");
53595c635efSGarrett D'Amore print_text(h, n->next->string);
53695c635efSGarrett D'Amore }
53795c635efSGarrett D'Amore
53895c635efSGarrett D'Amore print_stagq(h, tt);
53995c635efSGarrett D'Amore h->flags |= HTML_NOSPACE;
54095c635efSGarrett D'Amore print_text(h, "]");
541371584c2SYuri Pankov return 0;
54295c635efSGarrett D'Amore }
54395c635efSGarrett D'Amore
54495c635efSGarrett D'Amore static int
man_B_pre(MAN_ARGS)54595c635efSGarrett D'Amore man_B_pre(MAN_ARGS)
54695c635efSGarrett D'Amore {
547a40ea1a7SYuri Pankov print_otag(h, TAG_B, "");
548371584c2SYuri Pankov return 1;
54995c635efSGarrett D'Amore }
55095c635efSGarrett D'Amore
55195c635efSGarrett D'Amore static int
man_I_pre(MAN_ARGS)55295c635efSGarrett D'Amore man_I_pre(MAN_ARGS)
55395c635efSGarrett D'Amore {
554a40ea1a7SYuri Pankov print_otag(h, TAG_I, "");
555371584c2SYuri Pankov return 1;
55695c635efSGarrett D'Amore }
55795c635efSGarrett D'Amore
55895c635efSGarrett D'Amore static int
man_in_pre(MAN_ARGS)55995c635efSGarrett D'Amore man_in_pre(MAN_ARGS)
56095c635efSGarrett D'Amore {
561a40ea1a7SYuri Pankov print_otag(h, TAG_BR, "");
562371584c2SYuri Pankov return 0;
56395c635efSGarrett D'Amore }
56495c635efSGarrett D'Amore
56595c635efSGarrett D'Amore static int
man_ign_pre(MAN_ARGS)56695c635efSGarrett D'Amore man_ign_pre(MAN_ARGS)
56795c635efSGarrett D'Amore {
568371584c2SYuri Pankov return 0;
56995c635efSGarrett D'Amore }
57095c635efSGarrett D'Amore
57195c635efSGarrett D'Amore static int
man_RS_pre(MAN_ARGS)57295c635efSGarrett D'Amore man_RS_pre(MAN_ARGS)
57395c635efSGarrett D'Amore {
574cec8643bSMichal Nowak switch (n->type) {
575cec8643bSMichal Nowak case ROFFT_BLOCK:
576cec8643bSMichal Nowak html_close_paragraph(h);
577cec8643bSMichal Nowak break;
578cec8643bSMichal Nowak case ROFFT_HEAD:
579371584c2SYuri Pankov return 0;
580cec8643bSMichal Nowak case ROFFT_BODY:
5816640c13bSYuri Pankov print_otag(h, TAG_DIV, "c", "Bd-indent");
582cec8643bSMichal Nowak break;
583cec8643bSMichal Nowak default:
584cec8643bSMichal Nowak abort();
585cec8643bSMichal Nowak }
586cec8643bSMichal Nowak return 1;
587cec8643bSMichal Nowak }
588cec8643bSMichal Nowak
589cec8643bSMichal Nowak static int
man_SY_pre(MAN_ARGS)590cec8643bSMichal Nowak man_SY_pre(MAN_ARGS)
591cec8643bSMichal Nowak {
592cec8643bSMichal Nowak switch (n->type) {
593cec8643bSMichal Nowak case ROFFT_BLOCK:
594cec8643bSMichal Nowak html_close_paragraph(h);
595cec8643bSMichal Nowak print_otag(h, TAG_TABLE, "c", "Nm");
596cec8643bSMichal Nowak print_otag(h, TAG_TR, "");
597cec8643bSMichal Nowak break;
598cec8643bSMichal Nowak case ROFFT_HEAD:
599cec8643bSMichal Nowak print_otag(h, TAG_TD, "");
600cec8643bSMichal Nowak print_otag(h, TAG_CODE, "c", "Nm");
601cec8643bSMichal Nowak break;
602cec8643bSMichal Nowak case ROFFT_BODY:
603cec8643bSMichal Nowak print_otag(h, TAG_TD, "");
604cec8643bSMichal Nowak break;
605cec8643bSMichal Nowak default:
606cec8643bSMichal Nowak abort();
607cec8643bSMichal Nowak }
608371584c2SYuri Pankov return 1;
60995c635efSGarrett D'Amore }
610698f87a4SGarrett D'Amore
611698f87a4SGarrett D'Amore static int
man_UR_pre(MAN_ARGS)612698f87a4SGarrett D'Amore man_UR_pre(MAN_ARGS)
613698f87a4SGarrett D'Amore {
614c66b8046SYuri Pankov char *cp;
615cec8643bSMichal Nowak
616698f87a4SGarrett D'Amore n = n->child;
617371584c2SYuri Pankov assert(n->type == ROFFT_HEAD);
618371584c2SYuri Pankov if (n->child != NULL) {
619371584c2SYuri Pankov assert(n->child->type == ROFFT_TEXT);
620c66b8046SYuri Pankov if (n->tok == MAN_MT) {
621c66b8046SYuri Pankov mandoc_asprintf(&cp, "mailto:%s", n->child->string);
622cec8643bSMichal Nowak print_otag(h, TAG_A, "ch", "Mt", cp);
623c66b8046SYuri Pankov free(cp);
624c66b8046SYuri Pankov } else
625cec8643bSMichal Nowak print_otag(h, TAG_A, "ch", "Lk", n->child->string);
626698f87a4SGarrett D'Amore }
627698f87a4SGarrett D'Amore
628371584c2SYuri Pankov assert(n->next->type == ROFFT_BODY);
629371584c2SYuri Pankov if (n->next->child != NULL)
630698f87a4SGarrett D'Amore n = n->next;
631698f87a4SGarrett D'Amore
632a40ea1a7SYuri Pankov print_man_nodelist(man, n->child, h);
633371584c2SYuri Pankov return 0;
634698f87a4SGarrett D'Amore }
635cec8643bSMichal Nowak
636cec8643bSMichal Nowak static int
man_abort_pre(MAN_ARGS)637cec8643bSMichal Nowak man_abort_pre(MAN_ARGS)
638cec8643bSMichal Nowak {
639cec8643bSMichal Nowak abort();
640cec8643bSMichal Nowak }
641