xref: /netbsd-src/external/bsd/mdocml/dist/man_html.c (revision bbde328be4e75ea9ad02e9715ea13ca54b797ada)
1 /*	$Vendor-Id: man_html.c,v 1.30 2010/03/24 20:10:53 kristaps Exp $ */
2 /*
3  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include <sys/types.h>
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "out.h"
30 #include "html.h"
31 #include "man.h"
32 #include "main.h"
33 
34 /* TODO: preserve ident widths. */
35 /* FIXME: have PD set the default vspace width. */
36 
37 #define	INDENT		  5
38 #define	HALFINDENT	  3
39 
40 #define	MAN_ARGS	  const struct man_meta *m, \
41 			  const struct man_node *n, \
42 			  struct html *h
43 
44 struct	htmlman {
45 	int		(*pre)(MAN_ARGS);
46 	int		(*post)(MAN_ARGS);
47 };
48 
49 static	void		  print_man(MAN_ARGS);
50 static	void		  print_man_head(MAN_ARGS);
51 static	void		  print_man_nodelist(MAN_ARGS);
52 static	void		  print_man_node(MAN_ARGS);
53 
54 static	int		  a2width(const struct man_node *,
55 				struct roffsu *);
56 
57 static	int		  man_alt_pre(MAN_ARGS);
58 static	int		  man_br_pre(MAN_ARGS);
59 static	int		  man_ign_pre(MAN_ARGS);
60 static	void		  man_root_post(MAN_ARGS);
61 static	int		  man_root_pre(MAN_ARGS);
62 static	int		  man_B_pre(MAN_ARGS);
63 static	int		  man_HP_pre(MAN_ARGS);
64 static	int		  man_I_pre(MAN_ARGS);
65 static	int		  man_IP_pre(MAN_ARGS);
66 static	int		  man_PP_pre(MAN_ARGS);
67 static	int		  man_RS_pre(MAN_ARGS);
68 static	int		  man_SB_pre(MAN_ARGS);
69 static	int		  man_SH_pre(MAN_ARGS);
70 static	int		  man_SM_pre(MAN_ARGS);
71 static	int		  man_SS_pre(MAN_ARGS);
72 
73 static	const struct htmlman mans[MAN_MAX] = {
74 	{ man_br_pre, NULL }, /* br */
75 	{ NULL, NULL }, /* TH */
76 	{ man_SH_pre, NULL }, /* SH */
77 	{ man_SS_pre, NULL }, /* SS */
78 	{ man_IP_pre, NULL }, /* TP */
79 	{ man_PP_pre, NULL }, /* LP */
80 	{ man_PP_pre, NULL }, /* PP */
81 	{ man_PP_pre, NULL }, /* P */
82 	{ man_IP_pre, NULL }, /* IP */
83 	{ man_HP_pre, NULL }, /* HP */
84 	{ man_SM_pre, NULL }, /* SM */
85 	{ man_SB_pre, NULL }, /* SB */
86 	{ man_alt_pre, NULL }, /* BI */
87 	{ man_alt_pre, NULL }, /* IB */
88 	{ man_alt_pre, NULL }, /* BR */
89 	{ man_alt_pre, NULL }, /* RB */
90 	{ NULL, NULL }, /* R */
91 	{ man_B_pre, NULL }, /* B */
92 	{ man_I_pre, NULL }, /* I */
93 	{ man_alt_pre, NULL }, /* IR */
94 	{ man_alt_pre, NULL }, /* RI */
95 	{ NULL, NULL }, /* na */
96 	{ NULL, NULL }, /* i */
97 	{ man_br_pre, NULL }, /* sp */
98 	{ NULL, NULL }, /* nf */
99 	{ NULL, NULL }, /* fi */
100 	{ NULL, NULL }, /* r */
101 	{ NULL, NULL }, /* RE */
102 	{ man_RS_pre, NULL }, /* RS */
103 	{ man_ign_pre, NULL }, /* DT */
104 	{ man_ign_pre, NULL }, /* UC */
105 	{ man_ign_pre, NULL }, /* PD */
106 	{ man_br_pre, NULL }, /* Sp */
107 	{ man_ign_pre, NULL }, /* Vb */
108 	{ NULL, NULL }, /* Ve */
109 	{ man_ign_pre, NULL }, /* de */
110 	{ man_ign_pre, NULL }, /* dei */
111 	{ man_ign_pre, NULL }, /* am */
112 	{ man_ign_pre, NULL }, /* ami */
113 	{ man_ign_pre, NULL }, /* ig */
114 	{ NULL, NULL }, /* . */
115 };
116 
117 
118 void
119 html_man(void *arg, const struct man *m)
120 {
121 	struct html	*h;
122 	struct tag	*t;
123 
124 	h = (struct html *)arg;
125 
126 	print_gen_decls(h);
127 
128 	t = print_otag(h, TAG_HTML, 0, NULL);
129 	print_man(man_meta(m), man_node(m), h);
130 	print_tagq(h, t);
131 
132 	printf("\n");
133 }
134 
135 
136 static void
137 print_man(MAN_ARGS)
138 {
139 	struct tag	*t;
140 	struct htmlpair	 tag;
141 
142 	t = print_otag(h, TAG_HEAD, 0, NULL);
143 
144 	print_man_head(m, n, h);
145 	print_tagq(h, t);
146 	t = print_otag(h, TAG_BODY, 0, NULL);
147 
148 	tag.key = ATTR_CLASS;
149 	tag.val = "body";
150 	print_otag(h, TAG_DIV, 1, &tag);
151 
152 	print_man_nodelist(m, n, h);
153 
154 	print_tagq(h, t);
155 }
156 
157 
158 /* ARGSUSED */
159 static void
160 print_man_head(MAN_ARGS)
161 {
162 
163 	print_gen_head(h);
164 	bufinit(h);
165 	buffmt(h, "%s(%d)", m->title, m->msec);
166 
167 	print_otag(h, TAG_TITLE, 0, NULL);
168 	print_text(h, h->buf);
169 }
170 
171 
172 static void
173 print_man_nodelist(MAN_ARGS)
174 {
175 
176 	print_man_node(m, n, h);
177 	if (n->next)
178 		print_man_nodelist(m, n->next, h);
179 }
180 
181 
182 static void
183 print_man_node(MAN_ARGS)
184 {
185 	int		 child;
186 	struct tag	*t;
187 
188 	child = 1;
189 	t = h->tags.head;
190 
191 	bufinit(h);
192 
193 	/*
194 	 * FIXME: embedded elements within next-line scopes (e.g., `br'
195 	 * within an empty `B') will cause formatting to be forgotten
196 	 * due to scope closing out.
197 	 */
198 
199 	switch (n->type) {
200 	case (MAN_ROOT):
201 		child = man_root_pre(m, n, h);
202 		break;
203 	case (MAN_TEXT):
204 		print_text(h, n->string);
205 		return;
206 	default:
207 		/*
208 		 * Close out scope of font prior to opening a macro
209 		 * scope.  Assert that the metafont is on the top of the
210 		 * stack (it's never nested).
211 		 */
212 		if (h->metaf) {
213 			assert(h->metaf == t);
214 			print_tagq(h, h->metaf);
215 			assert(NULL == h->metaf);
216 			t = h->tags.head;
217 		}
218 		if (mans[n->tok].pre)
219 			child = (*mans[n->tok].pre)(m, n, h);
220 		break;
221 	}
222 
223 	if (child && n->child)
224 		print_man_nodelist(m, n->child, h);
225 
226 	/* This will automatically close out any font scope. */
227 	print_stagq(h, t);
228 
229 	bufinit(h);
230 
231 	switch (n->type) {
232 	case (MAN_ROOT):
233 		man_root_post(m, n, h);
234 		break;
235 	case (MAN_TEXT):
236 		break;
237 	default:
238 		if (mans[n->tok].post)
239 			(*mans[n->tok].post)(m, n, h);
240 		break;
241 	}
242 }
243 
244 
245 static int
246 a2width(const struct man_node *n, struct roffsu *su)
247 {
248 
249 	if (MAN_TEXT != n->type)
250 		return(0);
251 	if (a2roffsu(n->string, su, SCALE_BU))
252 		return(1);
253 
254 	return(0);
255 }
256 
257 
258 /* ARGSUSED */
259 static int
260 man_root_pre(MAN_ARGS)
261 {
262 	struct htmlpair	 tag[3];
263 	struct tag	*t, *tt;
264 	char		 b[BUFSIZ], title[BUFSIZ];
265 
266 	b[0] = 0;
267 	if (m->vol)
268 		(void)strlcat(b, m->vol, BUFSIZ);
269 
270 	snprintf(title, BUFSIZ - 1, "%s(%d)", m->title, m->msec);
271 
272 	PAIR_CLASS_INIT(&tag[0], "header");
273 	bufcat_style(h, "width", "100%");
274 	PAIR_STYLE_INIT(&tag[1], h);
275 	PAIR_SUMMARY_INIT(&tag[2], "header");
276 
277 	t = print_otag(h, TAG_TABLE, 3, tag);
278 	tt = print_otag(h, TAG_TR, 0, NULL);
279 
280 	bufinit(h);
281 	bufcat_style(h, "width", "10%");
282 	PAIR_STYLE_INIT(&tag[0], h);
283 	print_otag(h, TAG_TD, 1, tag);
284 	print_text(h, title);
285 	print_stagq(h, tt);
286 
287 	bufinit(h);
288 	bufcat_style(h, "width", "80%");
289 	bufcat_style(h, "white-space", "nowrap");
290 	bufcat_style(h, "text-align", "center");
291 	PAIR_STYLE_INIT(&tag[0], h);
292 	print_otag(h, TAG_TD, 1, tag);
293 	print_text(h, b);
294 	print_stagq(h, tt);
295 
296 	bufinit(h);
297 	bufcat_style(h, "width", "10%");
298 	bufcat_style(h, "text-align", "right");
299 	PAIR_STYLE_INIT(&tag[0], h);
300 	print_otag(h, TAG_TD, 1, tag);
301 	print_text(h, title);
302 	print_tagq(h, t);
303 	return(1);
304 }
305 
306 
307 /* ARGSUSED */
308 static void
309 man_root_post(MAN_ARGS)
310 {
311 	struct htmlpair	 tag[3];
312 	struct tag	*t, *tt;
313 	char		 b[DATESIZ];
314 
315 	time2a(m->date, b, DATESIZ);
316 
317 	PAIR_CLASS_INIT(&tag[0], "footer");
318 	bufcat_style(h, "width", "100%");
319 	PAIR_STYLE_INIT(&tag[1], h);
320 	PAIR_SUMMARY_INIT(&tag[2], "footer");
321 
322 	t = print_otag(h, TAG_TABLE, 3, tag);
323 	tt = print_otag(h, TAG_TR, 0, NULL);
324 
325 	bufinit(h);
326 	bufcat_style(h, "width", "50%");
327 	PAIR_STYLE_INIT(&tag[0], h);
328 	print_otag(h, TAG_TD, 1, tag);
329 	print_text(h, b);
330 	print_stagq(h, tt);
331 
332 	bufinit(h);
333 	bufcat_style(h, "width", "50%");
334 	bufcat_style(h, "text-align", "right");
335 	PAIR_STYLE_INIT(&tag[0], h);
336 	print_otag(h, TAG_TD, 1, tag);
337 	if (m->source)
338 		print_text(h, m->source);
339 	print_tagq(h, t);
340 }
341 
342 
343 
344 /* ARGSUSED */
345 static int
346 man_br_pre(MAN_ARGS)
347 {
348 	struct roffsu	 su;
349 	struct htmlpair	 tag;
350 
351 	SCALE_VS_INIT(&su, 1);
352 
353 	switch (n->tok) {
354 	case (MAN_Sp):
355 		SCALE_VS_INIT(&su, 0.5);
356 		break;
357 	case (MAN_sp):
358 		if (n->child)
359 			a2roffsu(n->child->string, &su, SCALE_VS);
360 		break;
361 	default:
362 		su.scale = 0;
363 		break;
364 	}
365 
366 	bufcat_su(h, "height", &su);
367 	PAIR_STYLE_INIT(&tag, h);
368 	print_otag(h, TAG_DIV, 1, &tag);
369 
370 	/* So the div isn't empty: */
371 	print_text(h, "\\~");
372 
373 	return(0);
374 }
375 
376 
377 /* ARGSUSED */
378 static int
379 man_SH_pre(MAN_ARGS)
380 {
381 	struct htmlpair	 tag[2];
382 	struct roffsu	 su;
383 
384 	if (MAN_BODY == n->type) {
385 		SCALE_HS_INIT(&su, INDENT);
386 		bufcat_su(h, "margin-left", &su);
387 		PAIR_CLASS_INIT(&tag[0], "sec-body");
388 		PAIR_STYLE_INIT(&tag[1], h);
389 		print_otag(h, TAG_DIV, 2, tag);
390 		return(1);
391 	} else if (MAN_BLOCK == n->type) {
392 		PAIR_CLASS_INIT(&tag[0], "sec-block");
393 		if (n->prev && MAN_SH == n->prev->tok)
394 			if (NULL == n->prev->body->child) {
395 				print_otag(h, TAG_DIV, 1, tag);
396 				return(1);
397 			}
398 
399 		SCALE_VS_INIT(&su, 1);
400 		bufcat_su(h, "margin-top", &su);
401 		if (NULL == n->next)
402 			bufcat_su(h, "margin-bottom", &su);
403 		PAIR_STYLE_INIT(&tag[1], h);
404 		print_otag(h, TAG_DIV, 2, tag);
405 		return(1);
406 	}
407 
408 	PAIR_CLASS_INIT(&tag[0], "sec-head");
409 	print_otag(h, TAG_DIV, 1, tag);
410 	return(1);
411 }
412 
413 
414 /* ARGSUSED */
415 static int
416 man_alt_pre(MAN_ARGS)
417 {
418 	const struct man_node	*nn;
419 	struct tag		*t;
420 	int			 i;
421 	enum htmlfont		 fp;
422 
423 	for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
424 		switch (n->tok) {
425 		case (MAN_BI):
426 			fp = i % 2 ? HTMLFONT_ITALIC : HTMLFONT_BOLD;
427 			break;
428 		case (MAN_IB):
429 			fp = i % 2 ? HTMLFONT_BOLD : HTMLFONT_ITALIC;
430 			break;
431 		case (MAN_RI):
432 			fp = i % 2 ? HTMLFONT_ITALIC : HTMLFONT_NONE;
433 			break;
434 		case (MAN_IR):
435 			fp = i % 2 ? HTMLFONT_NONE : HTMLFONT_ITALIC;
436 			break;
437 		case (MAN_BR):
438 			fp = i % 2 ? HTMLFONT_NONE : HTMLFONT_BOLD;
439 			break;
440 		case (MAN_RB):
441 			fp = i % 2 ? HTMLFONT_BOLD : HTMLFONT_NONE;
442 			break;
443 		default:
444 			abort();
445 			/* NOTREACHED */
446 		}
447 
448 		if (i)
449 			h->flags |= HTML_NOSPACE;
450 
451 		/*
452 		 * Open and close the scope with each argument, so that
453 		 * internal \f escapes, which are common, are also
454 		 * closed out with the scope.
455 		 */
456 		t = print_ofont(h, fp);
457 		print_man_node(m, nn, h);
458 		print_tagq(h, t);
459 	}
460 
461 	return(0);
462 }
463 
464 
465 /* ARGSUSED */
466 static int
467 man_SB_pre(MAN_ARGS)
468 {
469 	struct htmlpair	 tag;
470 
471 	/* FIXME: print_ofont(). */
472 	PAIR_CLASS_INIT(&tag, "small bold");
473 	print_otag(h, TAG_SPAN, 1, &tag);
474 	return(1);
475 }
476 
477 
478 /* ARGSUSED */
479 static int
480 man_SM_pre(MAN_ARGS)
481 {
482 	struct htmlpair	 tag;
483 
484 	PAIR_CLASS_INIT(&tag, "small");
485 	print_otag(h, TAG_SPAN, 1, &tag);
486 	return(1);
487 }
488 
489 
490 /* ARGSUSED */
491 static int
492 man_SS_pre(MAN_ARGS)
493 {
494 	struct htmlpair	 tag[3];
495 	struct roffsu	 su;
496 
497 	SCALE_VS_INIT(&su, 1);
498 
499 	if (MAN_BODY == n->type) {
500 		PAIR_CLASS_INIT(&tag[0], "ssec-body");
501 		if (n->parent->next && n->child) {
502 			bufcat_su(h, "margin-bottom", &su);
503 			PAIR_STYLE_INIT(&tag[1], h);
504 			print_otag(h, TAG_DIV, 2, tag);
505 			return(1);
506 		}
507 
508 		print_otag(h, TAG_DIV, 1, tag);
509 		return(1);
510 	} else if (MAN_BLOCK == n->type) {
511 		PAIR_CLASS_INIT(&tag[0], "ssec-block");
512 		if (n->prev && MAN_SS == n->prev->tok)
513 			if (n->prev->body->child) {
514 				bufcat_su(h, "margin-top", &su);
515 				PAIR_STYLE_INIT(&tag[1], h);
516 				print_otag(h, TAG_DIV, 2, tag);
517 				return(1);
518 			}
519 
520 		print_otag(h, TAG_DIV, 1, tag);
521 		return(1);
522 	}
523 
524 	SCALE_HS_INIT(&su, INDENT - HALFINDENT);
525 	bufcat_su(h, "margin-left", &su);
526 	PAIR_CLASS_INIT(&tag[0], "ssec-head");
527 	PAIR_STYLE_INIT(&tag[1], h);
528 	print_otag(h, TAG_DIV, 2, tag);
529 	return(1);
530 }
531 
532 
533 /* ARGSUSED */
534 static int
535 man_PP_pre(MAN_ARGS)
536 {
537 	struct htmlpair	 tag;
538 	struct roffsu	 su;
539 	int		 i;
540 
541 	if (MAN_BLOCK != n->type)
542 		return(1);
543 
544 	i = 0;
545 
546 	if (MAN_ROOT == n->parent->type) {
547 		SCALE_HS_INIT(&su, INDENT);
548 		bufcat_su(h, "margin-left", &su);
549 		i = 1;
550 	}
551 	if (n->prev) {
552 		SCALE_VS_INIT(&su, 1);
553 		bufcat_su(h, "margin-top", &su);
554 		i = 1;
555 	}
556 
557 	PAIR_STYLE_INIT(&tag, h);
558 	print_otag(h, TAG_DIV, i, &tag);
559 	return(1);
560 }
561 
562 
563 /* ARGSUSED */
564 static int
565 man_IP_pre(MAN_ARGS)
566 {
567 	struct roffsu		 su;
568 	struct htmlpair	 	 tag;
569 	const struct man_node	*nn;
570 	int			 width;
571 
572 	/*
573 	 * This scattering of 1-BU margins and pads is to make sure that
574 	 * when text overruns its box, the subsequent text isn't flush
575 	 * up against it.  However, the rest of the right-hand box must
576 	 * also be adjusted in consideration of this 1-BU space.
577 	 */
578 
579 	if (MAN_BODY == n->type) {
580 		SCALE_HS_INIT(&su, INDENT);
581 		bufcat_su(h, "margin-left", &su);
582 		PAIR_STYLE_INIT(&tag, h);
583 		print_otag(h, TAG_DIV, 1, &tag);
584 		return(1);
585 	}
586 
587 	nn = MAN_BLOCK == n->type ?
588 		n->head->child : n->parent->head->child;
589 
590 	SCALE_HS_INIT(&su, INDENT);
591 	width = 0;
592 
593 	/* Width is the last token. */
594 
595 	if (MAN_IP == n->tok && NULL != nn)
596 		if (NULL != (nn = nn->next)) {
597 			for ( ; nn->next; nn = nn->next)
598 				/* Do nothing. */ ;
599 			width = a2width(nn, &su);
600 		}
601 
602 	/* Width is the first token. */
603 
604 	if (MAN_TP == n->tok && NULL != nn) {
605 		/* Skip past non-text children. */
606 		while (nn && MAN_TEXT != nn->type)
607 			nn = nn->next;
608 		if (nn)
609 			width = a2width(nn, &su);
610 	}
611 
612 	if (MAN_BLOCK == n->type) {
613 		bufcat_su(h, "margin-left", &su);
614 		SCALE_VS_INIT(&su, 1);
615 		bufcat_su(h, "margin-top", &su);
616 		bufcat_style(h, "clear", "both");
617 		PAIR_STYLE_INIT(&tag, h);
618 		print_otag(h, TAG_DIV, 1, &tag);
619 		return(1);
620 	}
621 
622 	bufcat_su(h, "min-width", &su);
623 	SCALE_INVERT(&su);
624 	bufcat_su(h, "margin-left", &su);
625 	SCALE_HS_INIT(&su, 1);
626 	bufcat_su(h, "margin-right", &su);
627 	bufcat_style(h, "clear", "left");
628 
629 	if (n->next && n->next->child)
630 		bufcat_style(h, "float", "left");
631 
632 	PAIR_STYLE_INIT(&tag, h);
633 	print_otag(h, TAG_DIV, 1, &tag);
634 
635 	/*
636 	 * Without a length string, we can print all of our children.
637 	 */
638 
639 	if ( ! width)
640 		return(1);
641 
642 	/*
643 	 * When a length has been specified, we need to carefully print
644 	 * our child context:  IP gets all children printed but the last
645 	 * (the width), while TP gets all children printed but the first
646 	 * (the width).
647 	 */
648 
649 	if (MAN_IP == n->tok)
650 		for (nn = n->child; nn->next; nn = nn->next)
651 			print_man_node(m, nn, h);
652 	if (MAN_TP == n->tok)
653 		for (nn = n->child->next; nn; nn = nn->next)
654 			print_man_node(m, nn, h);
655 
656 	return(0);
657 }
658 
659 
660 /* ARGSUSED */
661 static int
662 man_HP_pre(MAN_ARGS)
663 {
664 	const struct man_node	*nn;
665 	struct htmlpair	 	 tag;
666 	struct roffsu		 su;
667 
668 	if (MAN_HEAD == n->type)
669 		return(0);
670 
671 	nn = MAN_BLOCK == n->type ?
672 		n->head->child : n->parent->head->child;
673 
674 	SCALE_HS_INIT(&su, INDENT);
675 
676 	if (NULL != nn)
677 		(void)a2width(nn, &su);
678 
679 	if (MAN_BLOCK == n->type) {
680 		bufcat_su(h, "margin-left", &su);
681 		SCALE_VS_INIT(&su, 1);
682 		bufcat_su(h, "margin-top", &su);
683 		bufcat_style(h, "clear", "both");
684 		PAIR_STYLE_INIT(&tag, h);
685 		print_otag(h, TAG_DIV, 1, &tag);
686 		return(1);
687 	}
688 
689 	bufcat_su(h, "margin-left", &su);
690 	SCALE_INVERT(&su);
691 	bufcat_su(h, "text-indent", &su);
692 
693 	PAIR_STYLE_INIT(&tag, h);
694 	print_otag(h, TAG_DIV, 1, &tag);
695 	return(1);
696 }
697 
698 
699 /* ARGSUSED */
700 static int
701 man_B_pre(MAN_ARGS)
702 {
703 
704 	print_ofont(h, HTMLFONT_BOLD);
705 	return(1);
706 }
707 
708 
709 /* ARGSUSED */
710 static int
711 man_I_pre(MAN_ARGS)
712 {
713 
714 	print_ofont(h, HTMLFONT_ITALIC);
715 	return(1);
716 }
717 
718 
719 /* ARGSUSED */
720 static int
721 man_ign_pre(MAN_ARGS)
722 {
723 
724 	return(0);
725 }
726 
727 
728 /* ARGSUSED */
729 static int
730 man_RS_pre(MAN_ARGS)
731 {
732 	struct htmlpair	 tag;
733 	struct roffsu	 su;
734 
735 	if (MAN_HEAD == n->type)
736 		return(0);
737 	else if (MAN_BODY == n->type)
738 		return(1);
739 
740 	SCALE_HS_INIT(&su, INDENT);
741 	bufcat_su(h, "margin-left", &su);
742 
743 	if (n->head->child) {
744 		SCALE_VS_INIT(&su, 1);
745 		a2width(n->head->child, &su);
746 		bufcat_su(h, "margin-top", &su);
747 	}
748 
749 	PAIR_STYLE_INIT(&tag, h);
750 	print_otag(h, TAG_DIV, 1, &tag);
751 	return(1);
752 }
753