xref: /minix3/external/bsd/mdocml/dist/man_html.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp  */
2d65f6f70SBen Gras /*
3*0a6a1f1dSLionel Sambuc  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
5d65f6f70SBen Gras  *
6d65f6f70SBen Gras  * Permission to use, copy, modify, and distribute this software for any
7d65f6f70SBen Gras  * purpose with or without fee is hereby granted, provided that the above
8d65f6f70SBen Gras  * copyright notice and this permission notice appear in all copies.
9d65f6f70SBen Gras  *
10d65f6f70SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d65f6f70SBen Gras  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d65f6f70SBen Gras  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d65f6f70SBen Gras  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d65f6f70SBen Gras  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d65f6f70SBen Gras  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d65f6f70SBen Gras  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d65f6f70SBen Gras  */
18d65f6f70SBen Gras #ifdef HAVE_CONFIG_H
19d65f6f70SBen Gras #include "config.h"
20d65f6f70SBen Gras #endif
21d65f6f70SBen Gras 
22d65f6f70SBen Gras #include <sys/types.h>
23d65f6f70SBen Gras 
24d65f6f70SBen Gras #include <assert.h>
25d65f6f70SBen Gras #include <ctype.h>
26d65f6f70SBen Gras #include <stdio.h>
27d65f6f70SBen Gras #include <stdlib.h>
28d65f6f70SBen Gras #include <string.h>
29d65f6f70SBen Gras 
30d65f6f70SBen Gras #include "mandoc.h"
31d65f6f70SBen Gras #include "out.h"
32d65f6f70SBen Gras #include "html.h"
33d65f6f70SBen Gras #include "man.h"
34d65f6f70SBen Gras #include "main.h"
35d65f6f70SBen Gras 
36d65f6f70SBen Gras /* TODO: preserve ident widths. */
37d65f6f70SBen Gras /* FIXME: have PD set the default vspace width. */
38d65f6f70SBen Gras 
39d65f6f70SBen Gras #define	INDENT		  5
40d65f6f70SBen Gras 
41*0a6a1f1dSLionel Sambuc #define	MAN_ARGS	  const struct man_meta *man, \
42d65f6f70SBen Gras 			  const struct man_node *n, \
43d65f6f70SBen Gras 			  struct mhtml *mh, \
44d65f6f70SBen Gras 			  struct html *h
45d65f6f70SBen Gras 
46d65f6f70SBen Gras struct	mhtml {
47d65f6f70SBen Gras 	int		  fl;
48d65f6f70SBen Gras #define	MANH_LITERAL	 (1 << 0) /* literal context */
49d65f6f70SBen Gras };
50d65f6f70SBen Gras 
51d65f6f70SBen Gras struct	htmlman {
52d65f6f70SBen Gras 	int		(*pre)(MAN_ARGS);
53d65f6f70SBen Gras 	int		(*post)(MAN_ARGS);
54d65f6f70SBen Gras };
55d65f6f70SBen Gras 
5692395e9cSLionel Sambuc static	void		  print_bvspace(struct html *,
5792395e9cSLionel Sambuc 				const struct man_node *);
58d65f6f70SBen Gras static	void		  print_man(MAN_ARGS);
59d65f6f70SBen Gras static	void		  print_man_head(MAN_ARGS);
60d65f6f70SBen Gras static	void		  print_man_nodelist(MAN_ARGS);
61d65f6f70SBen Gras static	void		  print_man_node(MAN_ARGS);
62d65f6f70SBen Gras static	int		  a2width(const struct man_node *,
63d65f6f70SBen Gras 				struct roffsu *);
6492395e9cSLionel Sambuc static	int		  man_B_pre(MAN_ARGS);
6592395e9cSLionel Sambuc static	int		  man_HP_pre(MAN_ARGS);
6692395e9cSLionel Sambuc static	int		  man_IP_pre(MAN_ARGS);
6792395e9cSLionel Sambuc static	int		  man_I_pre(MAN_ARGS);
6892395e9cSLionel Sambuc static	int		  man_OP_pre(MAN_ARGS);
6992395e9cSLionel Sambuc static	int		  man_PP_pre(MAN_ARGS);
7092395e9cSLionel Sambuc static	int		  man_RS_pre(MAN_ARGS);
7192395e9cSLionel Sambuc static	int		  man_SH_pre(MAN_ARGS);
7292395e9cSLionel Sambuc static	int		  man_SM_pre(MAN_ARGS);
7392395e9cSLionel Sambuc static	int		  man_SS_pre(MAN_ARGS);
74*0a6a1f1dSLionel Sambuc static	int		  man_UR_pre(MAN_ARGS);
75d65f6f70SBen Gras static	int		  man_alt_pre(MAN_ARGS);
76d65f6f70SBen Gras static	int		  man_br_pre(MAN_ARGS);
77d65f6f70SBen Gras static	int		  man_ign_pre(MAN_ARGS);
78d65f6f70SBen Gras static	int		  man_in_pre(MAN_ARGS);
79d65f6f70SBen Gras static	int		  man_literal_pre(MAN_ARGS);
80d65f6f70SBen Gras static	void		  man_root_post(MAN_ARGS);
8192395e9cSLionel Sambuc static	void		  man_root_pre(MAN_ARGS);
82d65f6f70SBen Gras 
83d65f6f70SBen Gras static	const struct htmlman mans[MAN_MAX] = {
84d65f6f70SBen Gras 	{ man_br_pre, NULL }, /* br */
85d65f6f70SBen Gras 	{ NULL, NULL }, /* TH */
86d65f6f70SBen Gras 	{ man_SH_pre, NULL }, /* SH */
87d65f6f70SBen Gras 	{ man_SS_pre, NULL }, /* SS */
88d65f6f70SBen Gras 	{ man_IP_pre, NULL }, /* TP */
89d65f6f70SBen Gras 	{ man_PP_pre, NULL }, /* LP */
90d65f6f70SBen Gras 	{ man_PP_pre, NULL }, /* PP */
91d65f6f70SBen Gras 	{ man_PP_pre, NULL }, /* P */
92d65f6f70SBen Gras 	{ man_IP_pre, NULL }, /* IP */
93d65f6f70SBen Gras 	{ man_HP_pre, NULL }, /* HP */
94d65f6f70SBen Gras 	{ man_SM_pre, NULL }, /* SM */
95d65f6f70SBen Gras 	{ man_SM_pre, NULL }, /* SB */
96d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* BI */
97d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* IB */
98d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* BR */
99d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* RB */
100d65f6f70SBen Gras 	{ NULL, NULL }, /* R */
101d65f6f70SBen Gras 	{ man_B_pre, NULL }, /* B */
102d65f6f70SBen Gras 	{ man_I_pre, NULL }, /* I */
103d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* IR */
104d65f6f70SBen Gras 	{ man_alt_pre, NULL }, /* RI */
10592395e9cSLionel Sambuc 	{ man_ign_pre, NULL }, /* na */
106d65f6f70SBen Gras 	{ man_br_pre, NULL }, /* sp */
107d65f6f70SBen Gras 	{ man_literal_pre, NULL }, /* nf */
108d65f6f70SBen Gras 	{ man_literal_pre, NULL }, /* fi */
109d65f6f70SBen Gras 	{ NULL, NULL }, /* RE */
110d65f6f70SBen Gras 	{ man_RS_pre, NULL }, /* RS */
111d65f6f70SBen Gras 	{ man_ign_pre, NULL }, /* DT */
112d65f6f70SBen Gras 	{ man_ign_pre, NULL }, /* UC */
113d65f6f70SBen Gras 	{ man_ign_pre, NULL }, /* PD */
114d65f6f70SBen Gras 	{ man_ign_pre, NULL }, /* AT */
115d65f6f70SBen Gras 	{ man_in_pre, NULL }, /* in */
116d65f6f70SBen Gras 	{ man_ign_pre, NULL }, /* ft */
11792395e9cSLionel Sambuc 	{ man_OP_pre, NULL }, /* OP */
118*0a6a1f1dSLionel Sambuc 	{ man_literal_pre, NULL }, /* EX */
119*0a6a1f1dSLionel Sambuc 	{ man_literal_pre, NULL }, /* EE */
120*0a6a1f1dSLionel Sambuc 	{ man_UR_pre, NULL }, /* UR */
121*0a6a1f1dSLionel Sambuc 	{ NULL, NULL }, /* UE */
122d65f6f70SBen Gras };
123d65f6f70SBen Gras 
12492395e9cSLionel Sambuc /*
12592395e9cSLionel Sambuc  * Printing leading vertical space before a block.
12692395e9cSLionel Sambuc  * This is used for the paragraph macros.
12792395e9cSLionel Sambuc  * The rules are pretty simple, since there's very little nesting going
12892395e9cSLionel Sambuc  * on here.  Basically, if we're the first within another block (SS/SH),
12992395e9cSLionel Sambuc  * then don't emit vertical space.  If we are (RS), then do.  If not the
13092395e9cSLionel Sambuc  * first, print it.
13192395e9cSLionel Sambuc  */
13292395e9cSLionel Sambuc static void
print_bvspace(struct html * h,const struct man_node * n)13392395e9cSLionel Sambuc print_bvspace(struct html *h, const struct man_node *n)
13492395e9cSLionel Sambuc {
13592395e9cSLionel Sambuc 
13692395e9cSLionel Sambuc 	if (n->body && n->body->child)
13792395e9cSLionel Sambuc 		if (MAN_TBL == n->body->child->type)
13892395e9cSLionel Sambuc 			return;
13992395e9cSLionel Sambuc 
14092395e9cSLionel Sambuc 	if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
14192395e9cSLionel Sambuc 		if (NULL == n->prev)
14292395e9cSLionel Sambuc 			return;
14392395e9cSLionel Sambuc 
14492395e9cSLionel Sambuc 	print_otag(h, TAG_P, 0, NULL);
14592395e9cSLionel Sambuc }
146d65f6f70SBen Gras 
147d65f6f70SBen Gras void
html_man(void * arg,const struct man * man)148*0a6a1f1dSLionel Sambuc html_man(void *arg, const struct man *man)
149d65f6f70SBen Gras {
150d65f6f70SBen Gras 	struct mhtml	 mh;
151d65f6f70SBen Gras 
152d65f6f70SBen Gras 	memset(&mh, 0, sizeof(struct mhtml));
153*0a6a1f1dSLionel Sambuc 	print_man(man_meta(man), man_node(man), &mh, (struct html *)arg);
15492395e9cSLionel Sambuc 	putchar('\n');
155d65f6f70SBen Gras }
156d65f6f70SBen Gras 
157d65f6f70SBen Gras static void
print_man(MAN_ARGS)158d65f6f70SBen Gras print_man(MAN_ARGS)
159d65f6f70SBen Gras {
16092395e9cSLionel Sambuc 	struct tag	*t, *tt;
16192395e9cSLionel Sambuc 	struct htmlpair	 tag;
162d65f6f70SBen Gras 
16392395e9cSLionel Sambuc 	PAIR_CLASS_INIT(&tag, "mandoc");
16492395e9cSLionel Sambuc 
16592395e9cSLionel Sambuc 	if ( ! (HTML_FRAGMENT & h->oflags)) {
16692395e9cSLionel Sambuc 		print_gen_decls(h);
16792395e9cSLionel Sambuc 		t = print_otag(h, TAG_HTML, 0, NULL);
16892395e9cSLionel Sambuc 		tt = print_otag(h, TAG_HEAD, 0, NULL);
169*0a6a1f1dSLionel Sambuc 		print_man_head(man, n, mh, h);
17092395e9cSLionel Sambuc 		print_tagq(h, tt);
17192395e9cSLionel Sambuc 		print_otag(h, TAG_BODY, 0, NULL);
17292395e9cSLionel Sambuc 		print_otag(h, TAG_DIV, 1, &tag);
17392395e9cSLionel Sambuc 	} else
17492395e9cSLionel Sambuc 		t = print_otag(h, TAG_DIV, 1, &tag);
175d65f6f70SBen Gras 
176*0a6a1f1dSLionel Sambuc 	print_man_nodelist(man, n, mh, h);
177d65f6f70SBen Gras 	print_tagq(h, t);
178d65f6f70SBen Gras }
179d65f6f70SBen Gras 
180d65f6f70SBen Gras 
181d65f6f70SBen Gras /* ARGSUSED */
182d65f6f70SBen Gras static void
print_man_head(MAN_ARGS)183d65f6f70SBen Gras print_man_head(MAN_ARGS)
184d65f6f70SBen Gras {
185d65f6f70SBen Gras 
186d65f6f70SBen Gras 	print_gen_head(h);
187*0a6a1f1dSLionel Sambuc 	assert(man->title);
188*0a6a1f1dSLionel Sambuc 	assert(man->msec);
189*0a6a1f1dSLionel Sambuc 	bufcat_fmt(h, "%s(%s)", man->title, man->msec);
190d65f6f70SBen Gras 	print_otag(h, TAG_TITLE, 0, NULL);
191d65f6f70SBen Gras 	print_text(h, h->buf);
192d65f6f70SBen Gras }
193d65f6f70SBen Gras 
194d65f6f70SBen Gras 
195d65f6f70SBen Gras static void
print_man_nodelist(MAN_ARGS)196d65f6f70SBen Gras print_man_nodelist(MAN_ARGS)
197d65f6f70SBen Gras {
198d65f6f70SBen Gras 
199*0a6a1f1dSLionel Sambuc 	print_man_node(man, n, mh, h);
200d65f6f70SBen Gras 	if (n->next)
201*0a6a1f1dSLionel Sambuc 		print_man_nodelist(man, n->next, mh, h);
202d65f6f70SBen Gras }
203d65f6f70SBen Gras 
204d65f6f70SBen Gras 
205d65f6f70SBen Gras static void
print_man_node(MAN_ARGS)206d65f6f70SBen Gras print_man_node(MAN_ARGS)
207d65f6f70SBen Gras {
208d65f6f70SBen Gras 	int		 child;
209d65f6f70SBen Gras 	struct tag	*t;
210d65f6f70SBen Gras 
211d65f6f70SBen Gras 	child = 1;
212d65f6f70SBen Gras 	t = h->tags.head;
213d65f6f70SBen Gras 
214d65f6f70SBen Gras 	switch (n->type) {
215d65f6f70SBen Gras 	case (MAN_ROOT):
216*0a6a1f1dSLionel Sambuc 		man_root_pre(man, n, mh, h);
217d65f6f70SBen Gras 		break;
218d65f6f70SBen Gras 	case (MAN_TEXT):
21992395e9cSLionel Sambuc 		/*
22092395e9cSLionel Sambuc 		 * If we have a blank line, output a vertical space.
22192395e9cSLionel Sambuc 		 * If we have a space as the first character, break
22292395e9cSLionel Sambuc 		 * before printing the line's data.
22392395e9cSLionel Sambuc 		 */
22492395e9cSLionel Sambuc 		if ('\0' == *n->string) {
22592395e9cSLionel Sambuc 			print_otag(h, TAG_P, 0, NULL);
226d65f6f70SBen Gras 			return;
22792395e9cSLionel Sambuc 		}
22892395e9cSLionel Sambuc 
22992395e9cSLionel Sambuc 		if (' ' == *n->string && MAN_LINE & n->flags)
23092395e9cSLionel Sambuc 			print_otag(h, TAG_BR, 0, NULL);
23192395e9cSLionel Sambuc 		else if (MANH_LITERAL & mh->fl && n->prev)
23292395e9cSLionel Sambuc 			print_otag(h, TAG_BR, 0, NULL);
23392395e9cSLionel Sambuc 
23492395e9cSLionel Sambuc 		print_text(h, n->string);
23592395e9cSLionel Sambuc 		return;
23692395e9cSLionel Sambuc 	case (MAN_EQN):
23792395e9cSLionel Sambuc 		print_eqn(h, n->eqn);
238d65f6f70SBen Gras 		break;
23992395e9cSLionel Sambuc 	case (MAN_TBL):
24092395e9cSLionel Sambuc 		/*
24192395e9cSLionel Sambuc 		 * This will take care of initialising all of the table
24292395e9cSLionel Sambuc 		 * state data for the first table, then tearing it down
24392395e9cSLionel Sambuc 		 * for the last one.
24492395e9cSLionel Sambuc 		 */
24592395e9cSLionel Sambuc 		print_tbl(h, n->span);
24692395e9cSLionel Sambuc 		return;
247d65f6f70SBen Gras 	default:
248d65f6f70SBen Gras 		/*
249d65f6f70SBen Gras 		 * Close out scope of font prior to opening a macro
25092395e9cSLionel Sambuc 		 * scope.
251d65f6f70SBen Gras 		 */
252d65f6f70SBen Gras 		if (HTMLFONT_NONE != h->metac) {
253d65f6f70SBen Gras 			h->metal = h->metac;
254d65f6f70SBen Gras 			h->metac = HTMLFONT_NONE;
255d65f6f70SBen Gras 		}
25692395e9cSLionel Sambuc 
25792395e9cSLionel Sambuc 		/*
25892395e9cSLionel Sambuc 		 * Close out the current table, if it's open, and unset
25992395e9cSLionel Sambuc 		 * the "meta" table state.  This will be reopened on the
26092395e9cSLionel Sambuc 		 * next table element.
26192395e9cSLionel Sambuc 		 */
26292395e9cSLionel Sambuc 		if (h->tblt) {
26392395e9cSLionel Sambuc 			print_tblclose(h);
26492395e9cSLionel Sambuc 			t = h->tags.head;
26592395e9cSLionel Sambuc 		}
266d65f6f70SBen Gras 		if (mans[n->tok].pre)
267*0a6a1f1dSLionel Sambuc 			child = (*mans[n->tok].pre)(man, n, mh, h);
268d65f6f70SBen Gras 		break;
269d65f6f70SBen Gras 	}
270d65f6f70SBen Gras 
271d65f6f70SBen Gras 	if (child && n->child)
272*0a6a1f1dSLionel Sambuc 		print_man_nodelist(man, n->child, mh, h);
273d65f6f70SBen Gras 
274d65f6f70SBen Gras 	/* This will automatically close out any font scope. */
275d65f6f70SBen Gras 	print_stagq(h, t);
276d65f6f70SBen Gras 
277d65f6f70SBen Gras 	switch (n->type) {
278d65f6f70SBen Gras 	case (MAN_ROOT):
279*0a6a1f1dSLionel Sambuc 		man_root_post(man, n, mh, h);
280d65f6f70SBen Gras 		break;
28192395e9cSLionel Sambuc 	case (MAN_EQN):
282d65f6f70SBen Gras 		break;
283d65f6f70SBen Gras 	default:
284d65f6f70SBen Gras 		if (mans[n->tok].post)
285*0a6a1f1dSLionel Sambuc 			(*mans[n->tok].post)(man, n, mh, h);
286d65f6f70SBen Gras 		break;
287d65f6f70SBen Gras 	}
288d65f6f70SBen Gras }
289d65f6f70SBen Gras 
290d65f6f70SBen Gras 
291d65f6f70SBen Gras static int
a2width(const struct man_node * n,struct roffsu * su)292d65f6f70SBen Gras a2width(const struct man_node *n, struct roffsu *su)
293d65f6f70SBen Gras {
294d65f6f70SBen Gras 
295d65f6f70SBen Gras 	if (MAN_TEXT != n->type)
296d65f6f70SBen Gras 		return(0);
297d65f6f70SBen Gras 	if (a2roffsu(n->string, su, SCALE_BU))
298d65f6f70SBen Gras 		return(1);
299d65f6f70SBen Gras 
300d65f6f70SBen Gras 	return(0);
301d65f6f70SBen Gras }
302d65f6f70SBen Gras 
303d65f6f70SBen Gras 
304d65f6f70SBen Gras /* ARGSUSED */
30592395e9cSLionel Sambuc static void
man_root_pre(MAN_ARGS)306d65f6f70SBen Gras man_root_pre(MAN_ARGS)
307d65f6f70SBen Gras {
308d65f6f70SBen Gras 	struct htmlpair	 tag[3];
309d65f6f70SBen Gras 	struct tag	*t, *tt;
310d65f6f70SBen Gras 	char		 b[BUFSIZ], title[BUFSIZ];
311d65f6f70SBen Gras 
312d65f6f70SBen Gras 	b[0] = 0;
313*0a6a1f1dSLionel Sambuc 	if (man->vol)
314*0a6a1f1dSLionel Sambuc 		(void)strlcat(b, man->vol, BUFSIZ);
315d65f6f70SBen Gras 
316*0a6a1f1dSLionel Sambuc 	assert(man->title);
317*0a6a1f1dSLionel Sambuc 	assert(man->msec);
318*0a6a1f1dSLionel Sambuc 	snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec);
319d65f6f70SBen Gras 
320d65f6f70SBen Gras 	PAIR_SUMMARY_INIT(&tag[0], "Document Header");
321d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[1], "head");
322d65f6f70SBen Gras 	PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
323d65f6f70SBen Gras 	t = print_otag(h, TAG_TABLE, 3, tag);
324d65f6f70SBen Gras 	PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
325d65f6f70SBen Gras 	print_otag(h, TAG_COL, 1, tag);
326d65f6f70SBen Gras 	print_otag(h, TAG_COL, 1, tag);
327d65f6f70SBen Gras 	print_otag(h, TAG_COL, 1, tag);
328d65f6f70SBen Gras 
329d65f6f70SBen Gras 	print_otag(h, TAG_TBODY, 0, NULL);
330d65f6f70SBen Gras 
331d65f6f70SBen Gras 	tt = print_otag(h, TAG_TR, 0, NULL);
332d65f6f70SBen Gras 
333d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[0], "head-ltitle");
334d65f6f70SBen Gras 	print_otag(h, TAG_TD, 1, tag);
335d65f6f70SBen Gras 	print_text(h, title);
336d65f6f70SBen Gras 	print_stagq(h, tt);
337d65f6f70SBen Gras 
338d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[0], "head-vol");
339d65f6f70SBen Gras 	PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
340d65f6f70SBen Gras 	print_otag(h, TAG_TD, 2, tag);
341d65f6f70SBen Gras 	print_text(h, b);
342d65f6f70SBen Gras 	print_stagq(h, tt);
343d65f6f70SBen Gras 
344d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[0], "head-rtitle");
345d65f6f70SBen Gras 	PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
346d65f6f70SBen Gras 	print_otag(h, TAG_TD, 2, tag);
347d65f6f70SBen Gras 	print_text(h, title);
348d65f6f70SBen Gras 	print_tagq(h, t);
349d65f6f70SBen Gras }
350d65f6f70SBen Gras 
351d65f6f70SBen Gras 
352d65f6f70SBen Gras /* ARGSUSED */
353d65f6f70SBen Gras static void
man_root_post(MAN_ARGS)354d65f6f70SBen Gras man_root_post(MAN_ARGS)
355d65f6f70SBen Gras {
356d65f6f70SBen Gras 	struct htmlpair	 tag[3];
357d65f6f70SBen Gras 	struct tag	*t, *tt;
358d65f6f70SBen Gras 
359d65f6f70SBen Gras 	PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
360d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[1], "foot");
361d65f6f70SBen Gras 	PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
362d65f6f70SBen Gras 	t = print_otag(h, TAG_TABLE, 3, tag);
363d65f6f70SBen Gras 	PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
364d65f6f70SBen Gras 	print_otag(h, TAG_COL, 1, tag);
365d65f6f70SBen Gras 	print_otag(h, TAG_COL, 1, tag);
366d65f6f70SBen Gras 
367d65f6f70SBen Gras 	tt = print_otag(h, TAG_TR, 0, NULL);
368d65f6f70SBen Gras 
369d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[0], "foot-date");
370d65f6f70SBen Gras 	print_otag(h, TAG_TD, 1, tag);
371d65f6f70SBen Gras 
372*0a6a1f1dSLionel Sambuc 	assert(man->date);
373*0a6a1f1dSLionel Sambuc 	print_text(h, man->date);
374d65f6f70SBen Gras 	print_stagq(h, tt);
375d65f6f70SBen Gras 
376d65f6f70SBen Gras 	PAIR_CLASS_INIT(&tag[0], "foot-os");
377d65f6f70SBen Gras 	PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
378d65f6f70SBen Gras 	print_otag(h, TAG_TD, 2, tag);
379d65f6f70SBen Gras 
380*0a6a1f1dSLionel Sambuc 	if (man->source)
381*0a6a1f1dSLionel Sambuc 		print_text(h, man->source);
382d65f6f70SBen Gras 	print_tagq(h, t);
383d65f6f70SBen Gras }
384d65f6f70SBen Gras 
385d65f6f70SBen Gras 
386d65f6f70SBen Gras /* ARGSUSED */
387d65f6f70SBen Gras static int
man_br_pre(MAN_ARGS)388d65f6f70SBen Gras man_br_pre(MAN_ARGS)
389d65f6f70SBen Gras {
390d65f6f70SBen Gras 	struct roffsu	 su;
391d65f6f70SBen Gras 	struct htmlpair	 tag;
392d65f6f70SBen Gras 
393d65f6f70SBen Gras 	SCALE_VS_INIT(&su, 1);
394d65f6f70SBen Gras 
395d65f6f70SBen Gras 	if (MAN_sp == n->tok) {
39692395e9cSLionel Sambuc 		if (NULL != (n = n->child))
39792395e9cSLionel Sambuc 			if ( ! a2roffsu(n->string, &su, SCALE_VS))
39892395e9cSLionel Sambuc 				SCALE_VS_INIT(&su, atoi(n->string));
399d65f6f70SBen Gras 	} else
400d65f6f70SBen Gras 		su.scale = 0;
401d65f6f70SBen Gras 
40292395e9cSLionel Sambuc 	bufinit(h);
403d65f6f70SBen Gras 	bufcat_su(h, "height", &su);
404d65f6f70SBen Gras 	PAIR_STYLE_INIT(&tag, h);
405d65f6f70SBen Gras 	print_otag(h, TAG_DIV, 1, &tag);
406d65f6f70SBen Gras 
407d65f6f70SBen Gras 	/* So the div isn't empty: */
408d65f6f70SBen Gras 	print_text(h, "\\~");
409d65f6f70SBen Gras 
410d65f6f70SBen Gras 	return(0);
411d65f6f70SBen Gras }
412d65f6f70SBen Gras 
413d65f6f70SBen Gras /* ARGSUSED */
414d65f6f70SBen Gras static int
man_SH_pre(MAN_ARGS)415d65f6f70SBen Gras man_SH_pre(MAN_ARGS)
416d65f6f70SBen Gras {
417d65f6f70SBen Gras 	struct htmlpair	 tag;
418d65f6f70SBen Gras 
419d65f6f70SBen Gras 	if (MAN_BLOCK == n->type) {
42092395e9cSLionel Sambuc 		mh->fl &= ~MANH_LITERAL;
421d65f6f70SBen Gras 		PAIR_CLASS_INIT(&tag, "section");
422d65f6f70SBen Gras 		print_otag(h, TAG_DIV, 1, &tag);
423d65f6f70SBen Gras 		return(1);
424d65f6f70SBen Gras 	} else if (MAN_BODY == n->type)
425d65f6f70SBen Gras 		return(1);
426d65f6f70SBen Gras 
427d65f6f70SBen Gras 	print_otag(h, TAG_H1, 0, NULL);
428d65f6f70SBen Gras 	return(1);
429d65f6f70SBen Gras }
430d65f6f70SBen Gras 
431d65f6f70SBen Gras /* ARGSUSED */
432d65f6f70SBen Gras static int
man_alt_pre(MAN_ARGS)433d65f6f70SBen Gras man_alt_pre(MAN_ARGS)
434d65f6f70SBen Gras {
435d65f6f70SBen Gras 	const struct man_node	*nn;
43692395e9cSLionel Sambuc 	int		 i, savelit;
437d65f6f70SBen Gras 	enum htmltag	 fp;
438d65f6f70SBen Gras 	struct tag	*t;
439d65f6f70SBen Gras 
44092395e9cSLionel Sambuc 	if ((savelit = mh->fl & MANH_LITERAL))
44192395e9cSLionel Sambuc 		print_otag(h, TAG_BR, 0, NULL);
44292395e9cSLionel Sambuc 
44392395e9cSLionel Sambuc 	mh->fl &= ~MANH_LITERAL;
44492395e9cSLionel Sambuc 
445d65f6f70SBen Gras 	for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
446d65f6f70SBen Gras 		t = NULL;
447d65f6f70SBen Gras 		switch (n->tok) {
448d65f6f70SBen Gras 		case (MAN_BI):
449d65f6f70SBen Gras 			fp = i % 2 ? TAG_I : TAG_B;
450d65f6f70SBen Gras 			break;
451d65f6f70SBen Gras 		case (MAN_IB):
452d65f6f70SBen Gras 			fp = i % 2 ? TAG_B : TAG_I;
453d65f6f70SBen Gras 			break;
454d65f6f70SBen Gras 		case (MAN_RI):
455d65f6f70SBen Gras 			fp = i % 2 ? TAG_I : TAG_MAX;
456d65f6f70SBen Gras 			break;
457d65f6f70SBen Gras 		case (MAN_IR):
458d65f6f70SBen Gras 			fp = i % 2 ? TAG_MAX : TAG_I;
459d65f6f70SBen Gras 			break;
460d65f6f70SBen Gras 		case (MAN_BR):
461d65f6f70SBen Gras 			fp = i % 2 ? TAG_MAX : TAG_B;
462d65f6f70SBen Gras 			break;
463d65f6f70SBen Gras 		case (MAN_RB):
464d65f6f70SBen Gras 			fp = i % 2 ? TAG_B : TAG_MAX;
465d65f6f70SBen Gras 			break;
466d65f6f70SBen Gras 		default:
467d65f6f70SBen Gras 			abort();
468d65f6f70SBen Gras 			/* NOTREACHED */
469d65f6f70SBen Gras 		}
470d65f6f70SBen Gras 
471d65f6f70SBen Gras 		if (i)
472d65f6f70SBen Gras 			h->flags |= HTML_NOSPACE;
473d65f6f70SBen Gras 
474d65f6f70SBen Gras 		if (TAG_MAX != fp)
475d65f6f70SBen Gras 			t = print_otag(h, fp, 0, NULL);
476d65f6f70SBen Gras 
477*0a6a1f1dSLionel Sambuc 		print_man_node(man, nn, mh, h);
478d65f6f70SBen Gras 
479d65f6f70SBen Gras 		if (t)
480d65f6f70SBen Gras 			print_tagq(h, t);
481d65f6f70SBen Gras 	}
482d65f6f70SBen Gras 
48392395e9cSLionel Sambuc 	if (savelit)
48492395e9cSLionel Sambuc 		mh->fl |= MANH_LITERAL;
48592395e9cSLionel Sambuc 
486d65f6f70SBen Gras 	return(0);
487d65f6f70SBen Gras }
488d65f6f70SBen Gras 
489d65f6f70SBen Gras /* ARGSUSED */
490d65f6f70SBen Gras static int
man_SM_pre(MAN_ARGS)491d65f6f70SBen Gras man_SM_pre(MAN_ARGS)
492d65f6f70SBen Gras {
493d65f6f70SBen Gras 
494d65f6f70SBen Gras 	print_otag(h, TAG_SMALL, 0, NULL);
495d65f6f70SBen Gras 	if (MAN_SB == n->tok)
496d65f6f70SBen Gras 		print_otag(h, TAG_B, 0, NULL);
497d65f6f70SBen Gras 	return(1);
498d65f6f70SBen Gras }
499d65f6f70SBen Gras 
500d65f6f70SBen Gras /* ARGSUSED */
501d65f6f70SBen Gras static int
man_SS_pre(MAN_ARGS)502d65f6f70SBen Gras man_SS_pre(MAN_ARGS)
503d65f6f70SBen Gras {
504d65f6f70SBen Gras 	struct htmlpair	 tag;
505d65f6f70SBen Gras 
506d65f6f70SBen Gras 	if (MAN_BLOCK == n->type) {
50792395e9cSLionel Sambuc 		mh->fl &= ~MANH_LITERAL;
508d65f6f70SBen Gras 		PAIR_CLASS_INIT(&tag, "subsection");
509d65f6f70SBen Gras 		print_otag(h, TAG_DIV, 1, &tag);
510d65f6f70SBen Gras 		return(1);
511d65f6f70SBen Gras 	} else if (MAN_BODY == n->type)
512d65f6f70SBen Gras 		return(1);
513d65f6f70SBen Gras 
514d65f6f70SBen Gras 	print_otag(h, TAG_H2, 0, NULL);
515d65f6f70SBen Gras 	return(1);
516d65f6f70SBen Gras }
517d65f6f70SBen Gras 
518d65f6f70SBen Gras /* ARGSUSED */
519d65f6f70SBen Gras static int
man_PP_pre(MAN_ARGS)520d65f6f70SBen Gras man_PP_pre(MAN_ARGS)
521d65f6f70SBen Gras {
522d65f6f70SBen Gras 
523d65f6f70SBen Gras 	if (MAN_HEAD == n->type)
524d65f6f70SBen Gras 		return(0);
52592395e9cSLionel Sambuc 	else if (MAN_BLOCK == n->type)
52692395e9cSLionel Sambuc 		print_bvspace(h, n);
527d65f6f70SBen Gras 
528d65f6f70SBen Gras 	return(1);
529d65f6f70SBen Gras }
530d65f6f70SBen Gras 
531d65f6f70SBen Gras /* ARGSUSED */
532d65f6f70SBen Gras static int
man_IP_pre(MAN_ARGS)533d65f6f70SBen Gras man_IP_pre(MAN_ARGS)
534d65f6f70SBen Gras {
535d65f6f70SBen Gras 	const struct man_node	*nn;
536d65f6f70SBen Gras 
537d65f6f70SBen Gras 	if (MAN_BODY == n->type) {
53892395e9cSLionel Sambuc 		print_otag(h, TAG_DD, 0, NULL);
53992395e9cSLionel Sambuc 		return(1);
54092395e9cSLionel Sambuc 	} else if (MAN_HEAD != n->type) {
54192395e9cSLionel Sambuc 		print_otag(h, TAG_DL, 0, NULL);
542d65f6f70SBen Gras 		return(1);
543d65f6f70SBen Gras 	}
544d65f6f70SBen Gras 
54592395e9cSLionel Sambuc 	/* FIXME: width specification. */
546d65f6f70SBen Gras 
54792395e9cSLionel Sambuc 	print_otag(h, TAG_DT, 0, NULL);
548d65f6f70SBen Gras 
549d65f6f70SBen Gras 	/* For IP, only print the first header element. */
550d65f6f70SBen Gras 
551d65f6f70SBen Gras 	if (MAN_IP == n->tok && n->child)
552*0a6a1f1dSLionel Sambuc 		print_man_node(man, n->child, mh, h);
553d65f6f70SBen Gras 
554d65f6f70SBen Gras 	/* For TP, only print next-line header elements. */
555d65f6f70SBen Gras 
556d65f6f70SBen Gras 	if (MAN_TP == n->tok)
557d65f6f70SBen Gras 		for (nn = n->child; nn; nn = nn->next)
558d65f6f70SBen Gras 			if (nn->line > n->line)
559*0a6a1f1dSLionel Sambuc 				print_man_node(man, nn, mh, h);
560d65f6f70SBen Gras 
561d65f6f70SBen Gras 	return(0);
562d65f6f70SBen Gras }
563d65f6f70SBen Gras 
564d65f6f70SBen Gras /* ARGSUSED */
565d65f6f70SBen Gras static int
man_HP_pre(MAN_ARGS)566d65f6f70SBen Gras man_HP_pre(MAN_ARGS)
567d65f6f70SBen Gras {
568d65f6f70SBen Gras 	struct htmlpair	 tag;
569d65f6f70SBen Gras 	struct roffsu	 su;
570d65f6f70SBen Gras 	const struct man_node *np;
571d65f6f70SBen Gras 
57292395e9cSLionel Sambuc 	if (MAN_HEAD == n->type)
57392395e9cSLionel Sambuc 		return(0);
57492395e9cSLionel Sambuc 	else if (MAN_BLOCK != n->type)
57592395e9cSLionel Sambuc 		return(1);
57692395e9cSLionel Sambuc 
57792395e9cSLionel Sambuc 	np = n->head->child;
578d65f6f70SBen Gras 
579d65f6f70SBen Gras 	if (NULL == np || ! a2width(np, &su))
580d65f6f70SBen Gras 		SCALE_HS_INIT(&su, INDENT);
581d65f6f70SBen Gras 
58292395e9cSLionel Sambuc 	bufinit(h);
583d65f6f70SBen Gras 
58492395e9cSLionel Sambuc 	print_bvspace(h, n);
58592395e9cSLionel Sambuc 	bufcat_su(h, "margin-left", &su);
586d65f6f70SBen Gras 	su.scale = -su.scale;
587d65f6f70SBen Gras 	bufcat_su(h, "text-indent", &su);
588d65f6f70SBen Gras 	PAIR_STYLE_INIT(&tag, h);
58992395e9cSLionel Sambuc 	print_otag(h, TAG_P, 1, &tag);
590d65f6f70SBen Gras 	return(1);
591d65f6f70SBen Gras }
592d65f6f70SBen Gras 
59392395e9cSLionel Sambuc /* ARGSUSED */
59492395e9cSLionel Sambuc static int
man_OP_pre(MAN_ARGS)59592395e9cSLionel Sambuc man_OP_pre(MAN_ARGS)
59692395e9cSLionel Sambuc {
59792395e9cSLionel Sambuc 	struct tag	*tt;
59892395e9cSLionel Sambuc 	struct htmlpair	 tag;
59992395e9cSLionel Sambuc 
60092395e9cSLionel Sambuc 	print_text(h, "[");
60192395e9cSLionel Sambuc 	h->flags |= HTML_NOSPACE;
60292395e9cSLionel Sambuc 	PAIR_CLASS_INIT(&tag, "opt");
60392395e9cSLionel Sambuc 	tt = print_otag(h, TAG_SPAN, 1, &tag);
60492395e9cSLionel Sambuc 
60592395e9cSLionel Sambuc 	if (NULL != (n = n->child)) {
60692395e9cSLionel Sambuc 		print_otag(h, TAG_B, 0, NULL);
60792395e9cSLionel Sambuc 		print_text(h, n->string);
60892395e9cSLionel Sambuc 	}
60992395e9cSLionel Sambuc 
61092395e9cSLionel Sambuc 	print_stagq(h, tt);
61192395e9cSLionel Sambuc 
61292395e9cSLionel Sambuc 	if (NULL != n && NULL != n->next) {
61392395e9cSLionel Sambuc 		print_otag(h, TAG_I, 0, NULL);
61492395e9cSLionel Sambuc 		print_text(h, n->next->string);
61592395e9cSLionel Sambuc 	}
61692395e9cSLionel Sambuc 
61792395e9cSLionel Sambuc 	print_stagq(h, tt);
61892395e9cSLionel Sambuc 	h->flags |= HTML_NOSPACE;
61992395e9cSLionel Sambuc 	print_text(h, "]");
62092395e9cSLionel Sambuc 	return(0);
62192395e9cSLionel Sambuc }
62292395e9cSLionel Sambuc 
623d65f6f70SBen Gras 
624d65f6f70SBen Gras /* ARGSUSED */
625d65f6f70SBen Gras static int
man_B_pre(MAN_ARGS)626d65f6f70SBen Gras man_B_pre(MAN_ARGS)
627d65f6f70SBen Gras {
628d65f6f70SBen Gras 
629d65f6f70SBen Gras 	print_otag(h, TAG_B, 0, NULL);
630d65f6f70SBen Gras 	return(1);
631d65f6f70SBen Gras }
632d65f6f70SBen Gras 
633d65f6f70SBen Gras /* ARGSUSED */
634d65f6f70SBen Gras static int
man_I_pre(MAN_ARGS)635d65f6f70SBen Gras man_I_pre(MAN_ARGS)
636d65f6f70SBen Gras {
637d65f6f70SBen Gras 
638d65f6f70SBen Gras 	print_otag(h, TAG_I, 0, NULL);
639d65f6f70SBen Gras 	return(1);
640d65f6f70SBen Gras }
641d65f6f70SBen Gras 
642d65f6f70SBen Gras /* ARGSUSED */
643d65f6f70SBen Gras static int
man_literal_pre(MAN_ARGS)644d65f6f70SBen Gras man_literal_pre(MAN_ARGS)
645d65f6f70SBen Gras {
646d65f6f70SBen Gras 
647*0a6a1f1dSLionel Sambuc 	if (MAN_fi == n->tok || MAN_EE == n->tok) {
648d65f6f70SBen Gras 		print_otag(h, TAG_BR, 0, NULL);
649d65f6f70SBen Gras 		mh->fl &= ~MANH_LITERAL;
65092395e9cSLionel Sambuc 	} else
65192395e9cSLionel Sambuc 		mh->fl |= MANH_LITERAL;
652d65f6f70SBen Gras 
65392395e9cSLionel Sambuc 	return(0);
654d65f6f70SBen Gras }
655d65f6f70SBen Gras 
656d65f6f70SBen Gras /* ARGSUSED */
657d65f6f70SBen Gras static int
man_in_pre(MAN_ARGS)658d65f6f70SBen Gras man_in_pre(MAN_ARGS)
659d65f6f70SBen Gras {
660d65f6f70SBen Gras 
661d65f6f70SBen Gras 	print_otag(h, TAG_BR, 0, NULL);
662d65f6f70SBen Gras 	return(0);
663d65f6f70SBen Gras }
664d65f6f70SBen Gras 
665d65f6f70SBen Gras /* ARGSUSED */
666d65f6f70SBen Gras static int
man_ign_pre(MAN_ARGS)667d65f6f70SBen Gras man_ign_pre(MAN_ARGS)
668d65f6f70SBen Gras {
669d65f6f70SBen Gras 
670d65f6f70SBen Gras 	return(0);
671d65f6f70SBen Gras }
672d65f6f70SBen Gras 
673d65f6f70SBen Gras /* ARGSUSED */
674d65f6f70SBen Gras static int
man_RS_pre(MAN_ARGS)675d65f6f70SBen Gras man_RS_pre(MAN_ARGS)
676d65f6f70SBen Gras {
677d65f6f70SBen Gras 	struct htmlpair	 tag;
678d65f6f70SBen Gras 	struct roffsu	 su;
679d65f6f70SBen Gras 
680d65f6f70SBen Gras 	if (MAN_HEAD == n->type)
681d65f6f70SBen Gras 		return(0);
682d65f6f70SBen Gras 	else if (MAN_BODY == n->type)
683d65f6f70SBen Gras 		return(1);
684d65f6f70SBen Gras 
685d65f6f70SBen Gras 	SCALE_HS_INIT(&su, INDENT);
686d65f6f70SBen Gras 	if (n->head->child)
687d65f6f70SBen Gras 		a2width(n->head->child, &su);
688d65f6f70SBen Gras 
68992395e9cSLionel Sambuc 	bufinit(h);
690d65f6f70SBen Gras 	bufcat_su(h, "margin-left", &su);
691d65f6f70SBen Gras 	PAIR_STYLE_INIT(&tag, h);
692d65f6f70SBen Gras 	print_otag(h, TAG_DIV, 1, &tag);
693d65f6f70SBen Gras 	return(1);
694d65f6f70SBen Gras }
695*0a6a1f1dSLionel Sambuc 
696*0a6a1f1dSLionel Sambuc /* ARGSUSED */
697*0a6a1f1dSLionel Sambuc static int
man_UR_pre(MAN_ARGS)698*0a6a1f1dSLionel Sambuc man_UR_pre(MAN_ARGS)
699*0a6a1f1dSLionel Sambuc {
700*0a6a1f1dSLionel Sambuc 	struct htmlpair		 tag[2];
701*0a6a1f1dSLionel Sambuc 
702*0a6a1f1dSLionel Sambuc 	n = n->child;
703*0a6a1f1dSLionel Sambuc 	assert(MAN_HEAD == n->type);
704*0a6a1f1dSLionel Sambuc 	if (n->nchild) {
705*0a6a1f1dSLionel Sambuc 		assert(MAN_TEXT == n->child->type);
706*0a6a1f1dSLionel Sambuc 		PAIR_CLASS_INIT(&tag[0], "link-ext");
707*0a6a1f1dSLionel Sambuc 		PAIR_HREF_INIT(&tag[1], n->child->string);
708*0a6a1f1dSLionel Sambuc 		print_otag(h, TAG_A, 2, tag);
709*0a6a1f1dSLionel Sambuc 	}
710*0a6a1f1dSLionel Sambuc 
711*0a6a1f1dSLionel Sambuc 	assert(MAN_BODY == n->next->type);
712*0a6a1f1dSLionel Sambuc 	if (n->next->nchild)
713*0a6a1f1dSLionel Sambuc 		n = n->next;
714*0a6a1f1dSLionel Sambuc 
715*0a6a1f1dSLionel Sambuc 	print_man_nodelist(man, n->child, mh, h);
716*0a6a1f1dSLionel Sambuc 
717*0a6a1f1dSLionel Sambuc 	return(0);
718*0a6a1f1dSLionel Sambuc }
719