]>
git.cameronkatri.com Git - mandoc.git/blob - man_html.c
3ff82ae942466929aeb8226cbf19de54ae54f1e7
1 /* $Id: man_html.c,v 1.13 2009/10/24 05:45:04 kristaps Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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.
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.
17 #include <sys/types.h>
18 #include <sys/queue.h>
32 /* TODO: preserve ident widths. */
33 /* FIXME: have PD set the default vspace width. */
38 #define MAN_ARGS const struct man_meta *m, \
39 const struct man_node *n, \
44 int (*post
)(MAN_ARGS
);
47 static void print_man(MAN_ARGS
);
48 static void print_man_head(MAN_ARGS
);
49 static void print_man_nodelist(MAN_ARGS
);
50 static void print_man_node(MAN_ARGS
);
52 static int a2width(const struct man_node
*,
55 static int man_alt_pre(MAN_ARGS
);
56 static int man_br_pre(MAN_ARGS
);
57 static int man_ign_pre(MAN_ARGS
);
58 static void man_root_post(MAN_ARGS
);
59 static int man_root_pre(MAN_ARGS
);
60 static int man_B_pre(MAN_ARGS
);
61 static int man_HP_pre(MAN_ARGS
);
62 static int man_I_pre(MAN_ARGS
);
63 static int man_IP_pre(MAN_ARGS
);
64 static int man_PP_pre(MAN_ARGS
);
65 static int man_RS_pre(MAN_ARGS
);
66 static int man_SB_pre(MAN_ARGS
);
67 static int man_SH_pre(MAN_ARGS
);
68 static int man_SM_pre(MAN_ARGS
);
69 static int man_SS_pre(MAN_ARGS
);
72 extern size_t strlcpy(char *, const char *, size_t);
73 extern size_t strlcat(char *, const char *, size_t);
76 static const struct htmlman mans
[MAN_MAX
] = {
77 { man_br_pre
, NULL
}, /* br */
78 { NULL
, NULL
}, /* TH */
79 { man_SH_pre
, NULL
}, /* SH */
80 { man_SS_pre
, NULL
}, /* SS */
81 { man_IP_pre
, NULL
}, /* TP */
82 { man_PP_pre
, NULL
}, /* LP */
83 { man_PP_pre
, NULL
}, /* PP */
84 { man_PP_pre
, NULL
}, /* P */
85 { man_IP_pre
, NULL
}, /* IP */
86 { man_HP_pre
, NULL
}, /* HP */
87 { man_SM_pre
, NULL
}, /* SM */
88 { man_SB_pre
, NULL
}, /* SB */
89 { man_alt_pre
, NULL
}, /* BI */
90 { man_alt_pre
, NULL
}, /* IB */
91 { man_alt_pre
, NULL
}, /* BR */
92 { man_alt_pre
, NULL
}, /* RB */
93 { NULL
, NULL
}, /* R */
94 { man_B_pre
, NULL
}, /* B */
95 { man_I_pre
, NULL
}, /* I */
96 { man_alt_pre
, NULL
}, /* IR */
97 { man_alt_pre
, NULL
}, /* RI */
98 { NULL
, NULL
}, /* na */
99 { NULL
, NULL
}, /* i */
100 { man_br_pre
, NULL
}, /* sp */
101 { NULL
, NULL
}, /* nf */
102 { NULL
, NULL
}, /* fi */
103 { NULL
, NULL
}, /* r */
104 { NULL
, NULL
}, /* RE */
105 { man_RS_pre
, NULL
}, /* RS */
106 { man_ign_pre
, NULL
}, /* DT */
107 { man_ign_pre
, NULL
}, /* UC */
108 { man_ign_pre
, NULL
}, /* PD */
113 html_man(void *arg
, const struct man
*m
)
118 h
= (struct html
*)arg
;
120 print_gen_doctype(h
);
122 t
= print_otag(h
, TAG_HTML
, 0, NULL
);
123 print_man(man_meta(m
), man_node(m
), h
);
136 t
= print_otag(h
, TAG_HEAD
, 0, NULL
);
138 print_man_head(m
, n
, h
);
140 t
= print_otag(h
, TAG_BODY
, 0, NULL
);
142 tag
.key
= ATTR_CLASS
;
144 print_otag(h
, TAG_DIV
, 1, &tag
);
146 print_man_nodelist(m
, n
, h
);
154 print_man_head(MAN_ARGS
)
159 buffmt(h
, "%s(%d)", m
->title
, m
->msec
);
161 print_otag(h
, TAG_TITLE
, 0, NULL
);
162 print_text(h
, h
->buf
);
167 print_man_nodelist(MAN_ARGS
)
170 print_man_node(m
, n
, h
);
172 print_man_nodelist(m
, n
->next
, h
);
177 print_man_node(MAN_ARGS
)
183 t
= SLIST_FIRST(&h
->tags
);
189 child
= man_root_pre(m
, n
, h
);
192 print_text(h
, n
->string
);
195 if (mans
[n
->tok
].pre
)
196 child
= (*mans
[n
->tok
].pre
)(m
, n
, h
);
200 if (child
&& n
->child
)
201 print_man_nodelist(m
, n
->child
, h
);
209 man_root_post(m
, n
, h
);
214 if (mans
[n
->tok
].post
)
215 (*mans
[n
->tok
].post
)(m
, n
, h
);
222 a2width(const struct man_node
*n
, struct roffsu
*su
)
225 if (MAN_TEXT
!= n
->type
)
227 if (a2roffsu(n
->string
, su
, SCALE_BU
))
236 man_root_pre(MAN_ARGS
)
238 struct htmlpair tag
[2];
240 char b
[BUFSIZ
], title
[BUFSIZ
];
244 (void)strlcat(b
, m
->vol
, BUFSIZ
);
246 (void)snprintf(title
, BUFSIZ
- 1,
247 "%s(%d)", m
->title
, m
->msec
);
249 PAIR_CLASS_INIT(&tag
[0], "header");
250 bufcat_style(h
, "width", "100%");
251 PAIR_STYLE_INIT(&tag
[1], h
);
252 t
= print_otag(h
, TAG_TABLE
, 2, tag
);
253 tt
= print_otag(h
, TAG_TR
, 0, NULL
);
256 bufcat_style(h
, "width", "10%");
257 PAIR_STYLE_INIT(&tag
[0], h
);
258 print_otag(h
, TAG_TD
, 1, tag
);
259 print_text(h
, title
);
263 bufcat_style(h
, "width", "80%");
264 bufcat_style(h
, "white-space", "nowrap");
265 bufcat_style(h
, "text-align", "center");
266 PAIR_STYLE_INIT(&tag
[0], h
);
267 print_otag(h
, TAG_TD
, 1, tag
);
272 bufcat_style(h
, "width", "10%");
273 bufcat_style(h
, "text-align", "right");
274 PAIR_STYLE_INIT(&tag
[0], h
);
275 print_otag(h
, TAG_TD
, 1, tag
);
276 print_text(h
, title
);
284 man_root_post(MAN_ARGS
)
286 struct htmlpair tag
[2];
290 time2a(m
->date
, b
, DATESIZ
);
292 PAIR_CLASS_INIT(&tag
[0], "footer");
293 bufcat_style(h
, "width", "100%");
294 PAIR_STYLE_INIT(&tag
[1], h
);
295 t
= print_otag(h
, TAG_TABLE
, 2, tag
);
296 tt
= print_otag(h
, TAG_TR
, 0, NULL
);
299 bufcat_style(h
, "width", "50%");
300 PAIR_STYLE_INIT(&tag
[0], h
);
301 print_otag(h
, TAG_TD
, 1, tag
);
306 bufcat_style(h
, "width", "50%");
307 bufcat_style(h
, "text-align", "right");
308 PAIR_STYLE_INIT(&tag
[0], h
);
309 print_otag(h
, TAG_TD
, 1, tag
);
311 print_text(h
, m
->source
);
324 SCALE_VS_INIT(&su
, 1);
326 if (MAN_sp
== n
->tok
&& n
->child
)
327 a2roffsu(n
->child
->string
, &su
, SCALE_VS
);
328 else if (MAN_br
== n
->tok
)
331 bufcat_su(h
, "height", &su
);
332 PAIR_STYLE_INIT(&tag
, h
);
333 print_otag(h
, TAG_DIV
, 1, &tag
);
342 struct htmlpair tag
[2];
345 if (MAN_BODY
== n
->type
) {
346 SCALE_HS_INIT(&su
, INDENT
);
347 bufcat_su(h
, "margin-left", &su
);
348 PAIR_CLASS_INIT(&tag
[0], "sec-body");
349 PAIR_STYLE_INIT(&tag
[1], h
);
350 print_otag(h
, TAG_DIV
, 2, tag
);
352 } else if (MAN_BLOCK
== n
->type
) {
353 PAIR_CLASS_INIT(&tag
[0], "sec-block");
354 if (n
->prev
&& MAN_SH
== n
->prev
->tok
)
355 if (NULL
== n
->prev
->body
->child
) {
356 print_otag(h
, TAG_DIV
, 1, tag
);
360 SCALE_VS_INIT(&su
, 1);
361 bufcat_su(h
, "margin-top", &su
);
363 bufcat_su(h
, "margin-bottom", &su
);
364 PAIR_STYLE_INIT(&tag
[1], h
);
365 print_otag(h
, TAG_DIV
, 2, tag
);
369 PAIR_CLASS_INIT(&tag
[0], "sec-head");
370 print_otag(h
, TAG_DIV
, 1, tag
);
377 man_alt_pre(MAN_ARGS
)
379 const struct man_node
*nn
;
382 struct htmlpair tagi
, tagb
, *tagp
;
384 PAIR_CLASS_INIT(&tagi
, "italic");
385 PAIR_CLASS_INIT(&tagb
, "bold");
387 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
390 tagp
= i
% 2 ? &tagi
: &tagb
;
393 tagp
= i
% 2 ? &tagb
: &tagi
;
396 tagp
= i
% 2 ? &tagi
: NULL
;
399 tagp
= i
% 2 ? NULL
: &tagi
;
402 tagp
= i
% 2 ? NULL
: &tagb
;
405 tagp
= i
% 2 ? &tagb
: NULL
;
413 h
->flags
|= HTML_NOSPACE
;
416 t
= print_otag(h
, TAG_SPAN
, 1, tagp
);
417 print_man_node(m
, nn
, h
);
420 print_man_node(m
, nn
, h
);
433 PAIR_CLASS_INIT(&tag
, "small bold");
434 print_otag(h
, TAG_SPAN
, 1, &tag
);
445 PAIR_CLASS_INIT(&tag
, "small");
446 print_otag(h
, TAG_SPAN
, 1, &tag
);
455 struct htmlpair tag
[3];
458 SCALE_VS_INIT(&su
, 1);
460 if (MAN_BODY
== n
->type
) {
461 PAIR_CLASS_INIT(&tag
[0], "ssec-body");
462 if (n
->parent
->next
&& n
->child
) {
463 bufcat_su(h
, "margin-bottom", &su
);
464 PAIR_STYLE_INIT(&tag
[1], h
);
465 print_otag(h
, TAG_DIV
, 2, tag
);
469 print_otag(h
, TAG_DIV
, 1, tag
);
471 } else if (MAN_BLOCK
== n
->type
) {
472 PAIR_CLASS_INIT(&tag
[0], "ssec-block");
473 if (n
->prev
&& MAN_SS
== n
->prev
->tok
)
474 if (n
->prev
->body
->child
) {
475 bufcat_su(h
, "margin-top", &su
);
476 PAIR_STYLE_INIT(&tag
[1], h
);
477 print_otag(h
, TAG_DIV
, 2, tag
);
481 print_otag(h
, TAG_DIV
, 1, tag
);
485 SCALE_HS_INIT(&su
, INDENT
- HALFINDENT
);
486 bufcat_su(h
, "margin-left", &su
);
487 PAIR_CLASS_INIT(&tag
[0], "ssec-head");
488 PAIR_STYLE_INIT(&tag
[1], h
);
489 print_otag(h
, TAG_DIV
, 2, tag
);
502 if (MAN_BLOCK
!= n
->type
)
507 if (MAN_ROOT
== n
->parent
->tok
) {
508 SCALE_HS_INIT(&su
, INDENT
);
509 bufcat_su(h
, "margin-left", &su
);
512 if (n
->next
&& n
->next
->child
) {
513 SCALE_VS_INIT(&su
, 1);
514 bufcat_su(h
, "margin-bottom", &su
);
518 PAIR_STYLE_INIT(&tag
, h
);
519 print_otag(h
, TAG_DIV
, i
? 1 : 0, &tag
);
530 const struct man_node
*nn
;
534 * This scattering of 1-BU margins and pads is to make sure that
535 * when text overruns its box, the subsequent text isn't flush
536 * up against it. However, the rest of the right-hand box must
537 * also be adjusted in consideration of this 1-BU space.
540 if (MAN_BODY
== n
->type
) {
541 SCALE_HS_INIT(&su
, INDENT
);
542 bufcat_su(h
, "margin-left", &su
);
543 PAIR_STYLE_INIT(&tag
, h
);
544 print_otag(h
, TAG_DIV
, 1, &tag
);
548 nn
= MAN_BLOCK
== n
->type
?
549 n
->head
->child
: n
->parent
->head
->child
;
551 SCALE_HS_INIT(&su
, INDENT
);
554 if (MAN_IP
== n
->tok
&& NULL
!= nn
)
555 if (NULL
!= (nn
= nn
->next
)) {
556 for ( ; nn
->next
; nn
= nn
->next
)
558 width
= a2width(nn
, &su
);
561 if (MAN_TP
== n
->tok
&& NULL
!= nn
)
562 width
= a2width(nn
, &su
);
564 if (MAN_BLOCK
== n
->type
) {
565 bufcat_su(h
, "margin-left", &su
);
566 SCALE_VS_INIT(&su
, 1);
567 bufcat_su(h
, "margin-top", &su
);
568 bufcat_style(h
, "clear", "both");
569 PAIR_STYLE_INIT(&tag
, h
);
570 print_otag(h
, TAG_DIV
, 1, &tag
);
574 bufcat_su(h
, "min-width", &su
);
576 bufcat_su(h
, "margin-left", &su
);
577 SCALE_HS_INIT(&su
, 1);
578 bufcat_su(h
, "margin-right", &su
);
579 bufcat_style(h
, "clear", "left");
581 if (n
->next
&& n
->next
->child
)
582 bufcat_style(h
, "float", "left");
584 PAIR_STYLE_INIT(&tag
, h
);
585 print_otag(h
, TAG_DIV
, 1, &tag
);
587 /* With a length string, manually omit the last child. */
592 if (MAN_IP
== n
->tok
)
593 for (nn
= n
->child
; nn
->next
; nn
= nn
->next
)
594 print_man_node(m
, nn
, h
);
595 if (MAN_TP
== n
->tok
)
596 for (nn
= n
->child
->next
; nn
; nn
= nn
->next
)
597 print_man_node(m
, nn
, h
);
607 const struct man_node
*nn
;
611 if (MAN_HEAD
== n
->type
)
614 nn
= MAN_BLOCK
== n
->type
?
615 n
->head
->child
: n
->parent
->head
->child
;
617 SCALE_HS_INIT(&su
, INDENT
);
620 (void)a2width(nn
, &su
);
622 if (MAN_BLOCK
== n
->type
) {
623 bufcat_su(h
, "margin-left", &su
);
624 SCALE_VS_INIT(&su
, 1);
625 bufcat_su(h
, "margin-top", &su
);
626 bufcat_style(h
, "clear", "both");
627 PAIR_STYLE_INIT(&tag
, h
);
628 print_otag(h
, TAG_DIV
, 1, &tag
);
632 bufcat_su(h
, "margin-left", &su
);
634 bufcat_su(h
, "text-indent", &su
);
636 PAIR_STYLE_INIT(&tag
, h
);
637 print_otag(h
, TAG_DIV
, 1, &tag
);
648 PAIR_CLASS_INIT(&tag
, "bold");
649 print_otag(h
, TAG_SPAN
, 1, &tag
);
660 PAIR_CLASS_INIT(&tag
, "italic");
661 print_otag(h
, TAG_SPAN
, 1, &tag
);
668 man_ign_pre(MAN_ARGS
)
682 if (MAN_HEAD
== n
->type
)
684 else if (MAN_BODY
== n
->type
)
687 SCALE_HS_INIT(&su
, INDENT
);
688 bufcat_su(h
, "margin-left", &su
);
690 if (n
->head
->child
) {
691 SCALE_VS_INIT(&su
, 1);
692 a2width(n
->head
->child
, &su
);
693 bufcat_su(h
, "margin-top", &su
);
696 PAIR_STYLE_INIT(&tag
, h
);
697 print_otag(h
, TAG_DIV
, 1, &tag
);