1322249Sbapt/*	$Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */
2241675Suqs/*
3275432Sbapt * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4316420Sbapt * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
5241675Suqs *
6241675Suqs * Permission to use, copy, modify, and distribute this software for any
7241675Suqs * purpose with or without fee is hereby granted, provided that the above
8241675Suqs * copyright notice and this permission notice appear in all copies.
9241675Suqs *
10294113Sbapt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12294113Sbapt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17241675Suqs */
18241675Suqs#include "config.h"
19241675Suqs
20241675Suqs#include <sys/types.h>
21241675Suqs
22241675Suqs#include <assert.h>
23241675Suqs#include <ctype.h>
24241675Suqs#include <stdio.h>
25241675Suqs#include <stdlib.h>
26241675Suqs#include <string.h>
27241675Suqs
28274880Sbapt#include "mandoc_aux.h"
29322249Sbapt#include "mandoc.h"
30294113Sbapt#include "roff.h"
31276219Sbapt#include "man.h"
32241675Suqs#include "out.h"
33241675Suqs#include "html.h"
34241675Suqs#include "main.h"
35241675Suqs
36241675Suqs/* FIXME: have PD set the default vspace width. */
37241675Suqs
38241675Suqs#define	INDENT		  5
39241675Suqs
40294113Sbapt#define	MAN_ARGS	  const struct roff_meta *man, \
41294113Sbapt			  const struct roff_node *n, \
42241675Suqs			  struct html *h
43241675Suqs
44241675Suqsstruct	htmlman {
45241675Suqs	int		(*pre)(MAN_ARGS);
46241675Suqs	int		(*post)(MAN_ARGS);
47241675Suqs};
48241675Suqs
49274880Sbaptstatic	void		  print_bvspace(struct html *,
50294113Sbapt				const struct roff_node *);
51241675Suqsstatic	void		  print_man_head(MAN_ARGS);
52241675Suqsstatic	void		  print_man_nodelist(MAN_ARGS);
53241675Suqsstatic	void		  print_man_node(MAN_ARGS);
54322249Sbaptstatic	int		  fillmode(struct html *, int);
55294113Sbaptstatic	int		  a2width(const struct roff_node *,
56241675Suqs				struct roffsu *);
57241675Suqsstatic	int		  man_B_pre(MAN_ARGS);
58241675Suqsstatic	int		  man_HP_pre(MAN_ARGS);
59241675Suqsstatic	int		  man_IP_pre(MAN_ARGS);
60241675Suqsstatic	int		  man_I_pre(MAN_ARGS);
61241675Suqsstatic	int		  man_OP_pre(MAN_ARGS);
62241675Suqsstatic	int		  man_PP_pre(MAN_ARGS);
63241675Suqsstatic	int		  man_RS_pre(MAN_ARGS);
64241675Suqsstatic	int		  man_SH_pre(MAN_ARGS);
65241675Suqsstatic	int		  man_SM_pre(MAN_ARGS);
66241675Suqsstatic	int		  man_SS_pre(MAN_ARGS);
67261344Suqsstatic	int		  man_UR_pre(MAN_ARGS);
68241675Suqsstatic	int		  man_alt_pre(MAN_ARGS);
69241675Suqsstatic	int		  man_ign_pre(MAN_ARGS);
70241675Suqsstatic	int		  man_in_pre(MAN_ARGS);
71241675Suqsstatic	void		  man_root_post(MAN_ARGS);
72241675Suqsstatic	void		  man_root_pre(MAN_ARGS);
73241675Suqs
74322249Sbaptstatic	const struct htmlman __mans[MAN_MAX - MAN_TH] = {
75241675Suqs	{ NULL, NULL }, /* TH */
76241675Suqs	{ man_SH_pre, NULL }, /* SH */
77241675Suqs	{ man_SS_pre, NULL }, /* SS */
78241675Suqs	{ man_IP_pre, NULL }, /* TP */
79241675Suqs	{ man_PP_pre, NULL }, /* LP */
80241675Suqs	{ man_PP_pre, NULL }, /* PP */
81241675Suqs	{ man_PP_pre, NULL }, /* P */
82241675Suqs	{ man_IP_pre, NULL }, /* IP */
83274880Sbapt	{ man_HP_pre, NULL }, /* HP */
84241675Suqs	{ man_SM_pre, NULL }, /* SM */
85241675Suqs	{ man_SM_pre, NULL }, /* SB */
86241675Suqs	{ man_alt_pre, NULL }, /* BI */
87241675Suqs	{ man_alt_pre, NULL }, /* IB */
88241675Suqs	{ man_alt_pre, NULL }, /* BR */
89241675Suqs	{ man_alt_pre, NULL }, /* RB */
90241675Suqs	{ NULL, NULL }, /* R */
91241675Suqs	{ man_B_pre, NULL }, /* B */
92241675Suqs	{ man_I_pre, NULL }, /* I */
93241675Suqs	{ man_alt_pre, NULL }, /* IR */
94241675Suqs	{ man_alt_pre, NULL }, /* RI */
95322249Sbapt	{ NULL, NULL }, /* nf */
96322249Sbapt	{ NULL, NULL }, /* fi */
97241675Suqs	{ NULL, NULL }, /* RE */
98241675Suqs	{ man_RS_pre, NULL }, /* RS */
99241675Suqs	{ man_ign_pre, NULL }, /* DT */
100241675Suqs	{ man_ign_pre, NULL }, /* UC */
101241675Suqs	{ man_ign_pre, NULL }, /* PD */
102241675Suqs	{ man_ign_pre, NULL }, /* AT */
103241675Suqs	{ man_in_pre, NULL }, /* in */
104241675Suqs	{ man_OP_pre, NULL }, /* OP */
105322249Sbapt	{ NULL, NULL }, /* EX */
106322249Sbapt	{ NULL, NULL }, /* EE */
107261344Suqs	{ man_UR_pre, NULL }, /* UR */
108261344Suqs	{ NULL, NULL }, /* UE */
109322249Sbapt	{ man_UR_pre, NULL }, /* MT */
110322249Sbapt	{ NULL, NULL }, /* ME */
111241675Suqs};
112322249Sbaptstatic	const struct htmlman *const mans = __mans - MAN_TH;
113241675Suqs
114274880Sbapt
115241675Suqs/*
116241675Suqs * Printing leading vertical space before a block.
117241675Suqs * This is used for the paragraph macros.
118241675Suqs * The rules are pretty simple, since there's very little nesting going
119241675Suqs * on here.  Basically, if we're the first within another block (SS/SH),
120241675Suqs * then don't emit vertical space.  If we are (RS), then do.  If not the
121241675Suqs * first, print it.
122241675Suqs */
123241675Suqsstatic void
124294113Sbaptprint_bvspace(struct html *h, const struct roff_node *n)
125241675Suqs{
126241675Suqs
127241675Suqs	if (n->body && n->body->child)
128294113Sbapt		if (n->body->child->type == ROFFT_TBL)
129241675Suqs			return;
130241675Suqs
131294113Sbapt	if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
132241675Suqs		if (NULL == n->prev)
133241675Suqs			return;
134241675Suqs
135275432Sbapt	print_paragraph(h);
136241675Suqs}
137241675Suqs
138241675Suqsvoid
139294113Sbapthtml_man(void *arg, const struct roff_man *man)
140241675Suqs{
141294113Sbapt	struct html	*h;
142316420Sbapt	struct tag	*t;
143241675Suqs
144294113Sbapt	h = (struct html *)arg;
145241675Suqs
146316420Sbapt	if ((h->oflags & HTML_FRAGMENT) == 0) {
147241675Suqs		print_gen_decls(h);
148316420Sbapt		print_otag(h, TAG_HTML, "");
149316420Sbapt		t = print_otag(h, TAG_HEAD, "");
150322249Sbapt		print_man_head(&man->meta, man->first, h);
151316420Sbapt		print_tagq(h, t);
152316420Sbapt		print_otag(h, TAG_BODY, "");
153316420Sbapt	}
154241675Suqs
155322249Sbapt	man_root_pre(&man->meta, man->first, h);
156316420Sbapt	t = print_otag(h, TAG_DIV, "c", "manual-text");
157322249Sbapt	print_man_nodelist(&man->meta, man->first->child, h);
158241675Suqs	print_tagq(h, t);
159322249Sbapt	man_root_post(&man->meta, man->first, h);
160316420Sbapt	print_tagq(h, NULL);
161241675Suqs}
162241675Suqs
163241675Suqsstatic void
164241675Suqsprint_man_head(MAN_ARGS)
165241675Suqs{
166316420Sbapt	char	*cp;
167241675Suqs
168241675Suqs	print_gen_head(h);
169316420Sbapt	mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
170316420Sbapt	print_otag(h, TAG_TITLE, "");
171316420Sbapt	print_text(h, cp);
172316420Sbapt	free(cp);
173241675Suqs}
174241675Suqs
175241675Suqsstatic void
176241675Suqsprint_man_nodelist(MAN_ARGS)
177241675Suqs{
178241675Suqs
179279527Sbapt	while (n != NULL) {
180322249Sbapt		print_man_node(man, n, h);
181279527Sbapt		n = n->next;
182279527Sbapt	}
183241675Suqs}
184241675Suqs
185241675Suqsstatic void
186241675Suqsprint_man_node(MAN_ARGS)
187241675Suqs{
188322249Sbapt	static int	 want_fillmode = MAN_fi;
189322249Sbapt	static int	 save_fillmode;
190322249Sbapt
191322249Sbapt	struct tag	*t;
192241675Suqs	int		 child;
193241675Suqs
194322249Sbapt	/*
195322249Sbapt	 * Handle fill mode switch requests up front,
196322249Sbapt	 * they would just cause trouble in the subsequent code.
197322249Sbapt	 */
198241675Suqs
199322249Sbapt	switch (n->tok) {
200322249Sbapt	case MAN_nf:
201322249Sbapt	case MAN_EX:
202322249Sbapt		want_fillmode = MAN_nf;
203322249Sbapt		return;
204322249Sbapt	case MAN_fi:
205322249Sbapt	case MAN_EE:
206322249Sbapt		want_fillmode = MAN_fi;
207322249Sbapt		if (fillmode(h, 0) == MAN_fi)
208322249Sbapt			print_otag(h, TAG_BR, "");
209322249Sbapt		return;
210322249Sbapt	default:
211322249Sbapt		break;
212322249Sbapt	}
213322249Sbapt
214322249Sbapt	/* Set up fill mode for the upcoming node. */
215322249Sbapt
216241675Suqs	switch (n->type) {
217322249Sbapt	case ROFFT_BLOCK:
218322249Sbapt		save_fillmode = 0;
219322249Sbapt		/* Some block macros suspend or cancel .nf. */
220322249Sbapt		switch (n->tok) {
221322249Sbapt		case MAN_TP:  /* Tagged paragraphs		*/
222322249Sbapt		case MAN_IP:  /* temporarily disable .nf	*/
223322249Sbapt		case MAN_HP:  /* for the head.			*/
224322249Sbapt			save_fillmode = want_fillmode;
225322249Sbapt			/* FALLTHROUGH */
226322249Sbapt		case MAN_SH:  /* Section headers		*/
227322249Sbapt		case MAN_SS:  /* permanently cancel .nf.	*/
228322249Sbapt			want_fillmode = MAN_fi;
229322249Sbapt			/* FALLTHROUGH */
230322249Sbapt		case MAN_PP:  /* These have no head.		*/
231322249Sbapt		case MAN_LP:  /* They will simply		*/
232322249Sbapt		case MAN_P:   /* reopen .nf in the body.	*/
233322249Sbapt		case MAN_RS:
234322249Sbapt		case MAN_UR:
235322249Sbapt		case MAN_MT:
236322249Sbapt			fillmode(h, MAN_fi);
237322249Sbapt			break;
238322249Sbapt		default:
239322249Sbapt			break;
240322249Sbapt		}
241322249Sbapt		break;
242322249Sbapt	case ROFFT_TBL:
243322249Sbapt		fillmode(h, MAN_fi);
244322249Sbapt		break;
245322249Sbapt	case ROFFT_ELEM:
246322249Sbapt		/*
247322249Sbapt		 * Some in-line macros produce tags and/or text
248322249Sbapt		 * in the handler, so they require fill mode to be
249322249Sbapt		 * configured up front just like for text nodes.
250322249Sbapt		 * For the others, keep the traditional approach
251322249Sbapt		 * of doing the same, for now.
252322249Sbapt		 */
253322249Sbapt		fillmode(h, want_fillmode);
254322249Sbapt		break;
255294113Sbapt	case ROFFT_TEXT:
256322249Sbapt		if (fillmode(h, want_fillmode) == MAN_fi &&
257322249Sbapt		    want_fillmode == MAN_fi &&
258322249Sbapt		    n->flags & NODE_LINE && *n->string == ' ' &&
259322249Sbapt		    (h->flags & HTML_NONEWLINE) == 0)
260316420Sbapt			print_otag(h, TAG_BR, "");
261322249Sbapt		if (*n->string != '\0')
262322249Sbapt			break;
263322249Sbapt		print_paragraph(h);
264322249Sbapt		return;
265322249Sbapt	default:
266322249Sbapt		break;
267322249Sbapt	}
268322249Sbapt
269322249Sbapt	/* Produce output for this node. */
270322249Sbapt
271322249Sbapt	child = 1;
272322249Sbapt	switch (n->type) {
273322249Sbapt	case ROFFT_TEXT:
274322249Sbapt		t = h->tag;
275241675Suqs		print_text(h, n->string);
276322249Sbapt		break;
277294113Sbapt	case ROFFT_EQN:
278322249Sbapt		t = h->tag;
279241675Suqs		print_eqn(h, n->eqn);
280241675Suqs		break;
281294113Sbapt	case ROFFT_TBL:
282241675Suqs		/*
283241675Suqs		 * This will take care of initialising all of the table
284241675Suqs		 * state data for the first table, then tearing it down
285241675Suqs		 * for the last one.
286241675Suqs		 */
287241675Suqs		print_tbl(h, n->span);
288241675Suqs		return;
289241675Suqs	default:
290274880Sbapt		/*
291241675Suqs		 * Close out scope of font prior to opening a macro
292241675Suqs		 * scope.
293241675Suqs		 */
294241675Suqs		if (HTMLFONT_NONE != h->metac) {
295241675Suqs			h->metal = h->metac;
296241675Suqs			h->metac = HTMLFONT_NONE;
297241675Suqs		}
298241675Suqs
299241675Suqs		/*
300241675Suqs		 * Close out the current table, if it's open, and unset
301241675Suqs		 * the "meta" table state.  This will be reopened on the
302241675Suqs		 * next table element.
303241675Suqs		 */
304322249Sbapt		if (h->tblt)
305241675Suqs			print_tblclose(h);
306322249Sbapt
307322249Sbapt		t = h->tag;
308322249Sbapt		if (n->tok < ROFF_MAX) {
309322249Sbapt			roff_html_pre(h, n);
310322249Sbapt			child = 0;
311322249Sbapt			break;
312241675Suqs		}
313322249Sbapt
314322249Sbapt		assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
315241675Suqs		if (mans[n->tok].pre)
316322249Sbapt			child = (*mans[n->tok].pre)(man, n, h);
317322249Sbapt
318322249Sbapt		/* Some block macros resume .nf in the body. */
319322249Sbapt		if (save_fillmode && n->type == ROFFT_BODY)
320322249Sbapt			want_fillmode = save_fillmode;
321322249Sbapt
322241675Suqs		break;
323241675Suqs	}
324241675Suqs
325241675Suqs	if (child && n->child)
326322249Sbapt		print_man_nodelist(man, n->child, h);
327241675Suqs
328241675Suqs	/* This will automatically close out any font scope. */
329241675Suqs	print_stagq(h, t);
330241675Suqs
331322249Sbapt	if (fillmode(h, 0) == MAN_nf &&
332322249Sbapt	    n->next != NULL && n->next->flags & NODE_LINE)
333322249Sbapt		print_endline(h);
334322249Sbapt}
335322249Sbapt
336322249Sbapt/*
337322249Sbapt * MAN_nf switches to no-fill mode, MAN_fi to fill mode.
338322249Sbapt * Other arguments do not switch.
339322249Sbapt * The old mode is returned.
340322249Sbapt */
341322249Sbaptstatic int
342322249Sbaptfillmode(struct html *h, int want)
343322249Sbapt{
344322249Sbapt	struct tag	*pre;
345322249Sbapt	int		 had;
346322249Sbapt
347322249Sbapt	for (pre = h->tag; pre != NULL; pre = pre->next)
348322249Sbapt		if (pre->tag == TAG_PRE)
349322249Sbapt			break;
350322249Sbapt
351322249Sbapt	had = pre == NULL ? MAN_fi : MAN_nf;
352322249Sbapt
353322249Sbapt	if (want && want != had) {
354322249Sbapt		if (want == MAN_nf)
355322249Sbapt			print_otag(h, TAG_PRE, "");
356322249Sbapt		else
357322249Sbapt			print_tagq(h, pre);
358241675Suqs	}
359322249Sbapt	return had;
360241675Suqs}
361241675Suqs
362241675Suqsstatic int
363294113Sbapta2width(const struct roff_node *n, struct roffsu *su)
364241675Suqs{
365294113Sbapt	if (n->type != ROFFT_TEXT)
366294113Sbapt		return 0;
367322249Sbapt	return a2roffsu(n->string, su, SCALE_EN) != NULL;
368241675Suqs}
369241675Suqs
370241675Suqsstatic void
371241675Suqsman_root_pre(MAN_ARGS)
372241675Suqs{
373241675Suqs	struct tag	*t, *tt;
374274880Sbapt	char		*title;
375241675Suqs
376261344Suqs	assert(man->title);
377261344Suqs	assert(man->msec);
378274880Sbapt	mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
379241675Suqs
380316420Sbapt	t = print_otag(h, TAG_TABLE, "c", "head");
381316420Sbapt	tt = print_otag(h, TAG_TR, "");
382241675Suqs
383316420Sbapt	print_otag(h, TAG_TD, "c", "head-ltitle");
384241675Suqs	print_text(h, title);
385241675Suqs	print_stagq(h, tt);
386241675Suqs
387316420Sbapt	print_otag(h, TAG_TD, "c", "head-vol");
388274880Sbapt	if (NULL != man->vol)
389274880Sbapt		print_text(h, man->vol);
390241675Suqs	print_stagq(h, tt);
391241675Suqs
392316420Sbapt	print_otag(h, TAG_TD, "c", "head-rtitle");
393241675Suqs	print_text(h, title);
394241675Suqs	print_tagq(h, t);
395274880Sbapt	free(title);
396241675Suqs}
397241675Suqs
398241675Suqsstatic void
399241675Suqsman_root_post(MAN_ARGS)
400241675Suqs{
401241675Suqs	struct tag	*t, *tt;
402241675Suqs
403316420Sbapt	t = print_otag(h, TAG_TABLE, "c", "foot");
404316420Sbapt	tt = print_otag(h, TAG_TR, "");
405241675Suqs
406316420Sbapt	print_otag(h, TAG_TD, "c", "foot-date");
407261344Suqs	print_text(h, man->date);
408241675Suqs	print_stagq(h, tt);
409241675Suqs
410316420Sbapt	print_otag(h, TAG_TD, "c", "foot-os");
411294113Sbapt	if (man->os)
412294113Sbapt		print_text(h, man->os);
413241675Suqs	print_tagq(h, t);
414241675Suqs}
415241675Suqs
416241675Suqsstatic int
417241675Suqsman_SH_pre(MAN_ARGS)
418241675Suqs{
419322249Sbapt	char	*id;
420241675Suqs
421322249Sbapt	if (n->type == ROFFT_HEAD) {
422322249Sbapt		id = html_make_id(n);
423322249Sbapt		print_otag(h, TAG_H1, "cTi", "Sh", id);
424322249Sbapt		if (id != NULL)
425322249Sbapt			print_otag(h, TAG_A, "chR", "selflink", id);
426322249Sbapt		free(id);
427322249Sbapt	}
428294113Sbapt	return 1;
429241675Suqs}
430241675Suqs
431241675Suqsstatic int
432241675Suqsman_alt_pre(MAN_ARGS)
433241675Suqs{
434294113Sbapt	const struct roff_node	*nn;
435322249Sbapt	int		 i;
436241675Suqs	enum htmltag	 fp;
437241675Suqs	struct tag	*t;
438241675Suqs
439241675Suqs	for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
440241675Suqs		switch (n->tok) {
441274880Sbapt		case MAN_BI:
442241675Suqs			fp = i % 2 ? TAG_I : TAG_B;
443241675Suqs			break;
444274880Sbapt		case MAN_IB:
445241675Suqs			fp = i % 2 ? TAG_B : TAG_I;
446241675Suqs			break;
447274880Sbapt		case MAN_RI:
448241675Suqs			fp = i % 2 ? TAG_I : TAG_MAX;
449241675Suqs			break;
450274880Sbapt		case MAN_IR:
451241675Suqs			fp = i % 2 ? TAG_MAX : TAG_I;
452241675Suqs			break;
453274880Sbapt		case MAN_BR:
454241675Suqs			fp = i % 2 ? TAG_MAX : TAG_B;
455241675Suqs			break;
456274880Sbapt		case MAN_RB:
457241675Suqs			fp = i % 2 ? TAG_B : TAG_MAX;
458241675Suqs			break;
459241675Suqs		default:
460241675Suqs			abort();
461241675Suqs		}
462241675Suqs
463241675Suqs		if (i)
464241675Suqs			h->flags |= HTML_NOSPACE;
465241675Suqs
466322249Sbapt		if (fp != TAG_MAX)
467316420Sbapt			t = print_otag(h, fp, "");
468241675Suqs
469322249Sbapt		print_text(h, nn->string);
470241675Suqs
471322249Sbapt		if (fp != TAG_MAX)
472241675Suqs			print_tagq(h, t);
473241675Suqs	}
474294113Sbapt	return 0;
475241675Suqs}
476241675Suqs
477241675Suqsstatic int
478241675Suqsman_SM_pre(MAN_ARGS)
479241675Suqs{
480316420Sbapt	print_otag(h, TAG_SMALL, "");
481241675Suqs	if (MAN_SB == n->tok)
482316420Sbapt		print_otag(h, TAG_B, "");
483294113Sbapt	return 1;
484241675Suqs}
485241675Suqs
486241675Suqsstatic int
487241675Suqsman_SS_pre(MAN_ARGS)
488241675Suqs{
489322249Sbapt	char	*id;
490241675Suqs
491322249Sbapt	if (n->type == ROFFT_HEAD) {
492322249Sbapt		id = html_make_id(n);
493322249Sbapt		print_otag(h, TAG_H2, "cTi", "Ss", id);
494322249Sbapt		if (id != NULL)
495322249Sbapt			print_otag(h, TAG_A, "chR", "selflink", id);
496322249Sbapt		free(id);
497322249Sbapt	}
498294113Sbapt	return 1;
499241675Suqs}
500241675Suqs
501241675Suqsstatic int
502241675Suqsman_PP_pre(MAN_ARGS)
503241675Suqs{
504241675Suqs
505294113Sbapt	if (n->type == ROFFT_HEAD)
506294113Sbapt		return 0;
507294113Sbapt	else if (n->type == ROFFT_BLOCK)
508241675Suqs		print_bvspace(h, n);
509241675Suqs
510294113Sbapt	return 1;
511241675Suqs}
512241675Suqs
513241675Suqsstatic int
514241675Suqsman_IP_pre(MAN_ARGS)
515241675Suqs{
516294113Sbapt	const struct roff_node	*nn;
517241675Suqs
518294113Sbapt	if (n->type == ROFFT_BODY) {
519316420Sbapt		print_otag(h, TAG_DD, "c", "It-tag");
520294113Sbapt		return 1;
521294113Sbapt	} else if (n->type != ROFFT_HEAD) {
522316420Sbapt		print_otag(h, TAG_DL, "c", "Bl-tag");
523294113Sbapt		return 1;
524241675Suqs	}
525241675Suqs
526241675Suqs	/* FIXME: width specification. */
527241675Suqs
528316420Sbapt	print_otag(h, TAG_DT, "c", "It-tag");
529241675Suqs
530241675Suqs	/* For IP, only print the first header element. */
531241675Suqs
532241675Suqs	if (MAN_IP == n->tok && n->child)
533322249Sbapt		print_man_node(man, n->child, h);
534241675Suqs
535241675Suqs	/* For TP, only print next-line header elements. */
536241675Suqs
537274880Sbapt	if (MAN_TP == n->tok) {
538274880Sbapt		nn = n->child;
539316420Sbapt		while (NULL != nn && 0 == (NODE_LINE & nn->flags))
540274880Sbapt			nn = nn->next;
541274880Sbapt		while (NULL != nn) {
542322249Sbapt			print_man_node(man, nn, h);
543274880Sbapt			nn = nn->next;
544274880Sbapt		}
545274880Sbapt	}
546241675Suqs
547294113Sbapt	return 0;
548241675Suqs}
549241675Suqs
550241675Suqsstatic int
551241675Suqsman_HP_pre(MAN_ARGS)
552241675Suqs{
553316420Sbapt	struct roffsu	 sum, sui;
554294113Sbapt	const struct roff_node *np;
555241675Suqs
556294113Sbapt	if (n->type == ROFFT_HEAD)
557294113Sbapt		return 0;
558294113Sbapt	else if (n->type != ROFFT_BLOCK)
559294113Sbapt		return 1;
560241675Suqs
561241675Suqs	np = n->head->child;
562241675Suqs
563316420Sbapt	if (np == NULL || !a2width(np, &sum))
564316420Sbapt		SCALE_HS_INIT(&sum, INDENT);
565241675Suqs
566316420Sbapt	sui.unit = sum.unit;
567316420Sbapt	sui.scale = -sum.scale;
568241675Suqs
569241675Suqs	print_bvspace(h, n);
570316420Sbapt	print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui);
571294113Sbapt	return 1;
572241675Suqs}
573241675Suqs
574241675Suqsstatic int
575241675Suqsman_OP_pre(MAN_ARGS)
576241675Suqs{
577241675Suqs	struct tag	*tt;
578241675Suqs
579241675Suqs	print_text(h, "[");
580241675Suqs	h->flags |= HTML_NOSPACE;
581316420Sbapt	tt = print_otag(h, TAG_SPAN, "c", "Op");
582241675Suqs
583241675Suqs	if (NULL != (n = n->child)) {
584316420Sbapt		print_otag(h, TAG_B, "");
585241675Suqs		print_text(h, n->string);
586241675Suqs	}
587241675Suqs
588241675Suqs	print_stagq(h, tt);
589241675Suqs
590241675Suqs	if (NULL != n && NULL != n->next) {
591316420Sbapt		print_otag(h, TAG_I, "");
592241675Suqs		print_text(h, n->next->string);
593241675Suqs	}
594241675Suqs
595241675Suqs	print_stagq(h, tt);
596241675Suqs	h->flags |= HTML_NOSPACE;
597241675Suqs	print_text(h, "]");
598294113Sbapt	return 0;
599241675Suqs}
600241675Suqs
601241675Suqsstatic int
602241675Suqsman_B_pre(MAN_ARGS)
603241675Suqs{
604316420Sbapt	print_otag(h, TAG_B, "");
605294113Sbapt	return 1;
606241675Suqs}
607241675Suqs
608241675Suqsstatic int
609241675Suqsman_I_pre(MAN_ARGS)
610241675Suqs{
611316420Sbapt	print_otag(h, TAG_I, "");
612294113Sbapt	return 1;
613241675Suqs}
614241675Suqs
615241675Suqsstatic int
616241675Suqsman_in_pre(MAN_ARGS)
617241675Suqs{
618316420Sbapt	print_otag(h, TAG_BR, "");
619294113Sbapt	return 0;
620241675Suqs}
621241675Suqs
622241675Suqsstatic int
623241675Suqsman_ign_pre(MAN_ARGS)
624241675Suqs{
625241675Suqs
626294113Sbapt	return 0;
627241675Suqs}
628241675Suqs
629241675Suqsstatic int
630241675Suqsman_RS_pre(MAN_ARGS)
631241675Suqs{
632241675Suqs	struct roffsu	 su;
633241675Suqs
634294113Sbapt	if (n->type == ROFFT_HEAD)
635294113Sbapt		return 0;
636294113Sbapt	else if (n->type == ROFFT_BODY)
637294113Sbapt		return 1;
638241675Suqs
639241675Suqs	SCALE_HS_INIT(&su, INDENT);
640241675Suqs	if (n->head->child)
641241675Suqs		a2width(n->head->child, &su);
642241675Suqs
643316420Sbapt	print_otag(h, TAG_DIV, "sul", &su);
644294113Sbapt	return 1;
645241675Suqs}
646261344Suqs
647261344Suqsstatic int
648261344Suqsman_UR_pre(MAN_ARGS)
649261344Suqs{
650322249Sbapt	char *cp;
651261344Suqs	n = n->child;
652294113Sbapt	assert(n->type == ROFFT_HEAD);
653294113Sbapt	if (n->child != NULL) {
654294113Sbapt		assert(n->child->type == ROFFT_TEXT);
655322249Sbapt		if (n->tok == MAN_MT) {
656322249Sbapt			mandoc_asprintf(&cp, "mailto:%s", n->child->string);
657322249Sbapt			print_otag(h, TAG_A, "cTh", "Mt", cp);
658322249Sbapt			free(cp);
659322249Sbapt		} else
660322249Sbapt			print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
661261344Suqs	}
662261344Suqs
663294113Sbapt	assert(n->next->type == ROFFT_BODY);
664294113Sbapt	if (n->next->child != NULL)
665261344Suqs		n = n->next;
666261344Suqs
667322249Sbapt	print_man_nodelist(man, n->child, h);
668261344Suqs
669294113Sbapt	return 0;
670261344Suqs}
671