]>
git.cameronkatri.com Git - mandoc.git/blob - html.c
1 /* $Id: html.c,v 1.32 2009/09/17 08:21:42 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/queue.h>
28 #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
29 #define DTD "http://www.w3.org/TR/html4/strict.dtd"
63 #define HTML_CLRLINE (1 << 0)
64 #define HTML_NOSTACK (1 << 1)
67 static const struct htmldata htmltags
[TAG_MAX
] = {
68 {"html", HTML_CLRLINE
}, /* TAG_HTML */
69 {"head", HTML_CLRLINE
}, /* TAG_HEAD */
70 {"body", HTML_CLRLINE
}, /* TAG_BODY */
71 {"meta", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_META */
72 {"title", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_TITLE */
73 {"div", HTML_CLRLINE
}, /* TAG_DIV */
74 {"h1", 0}, /* TAG_H1 */
75 {"h2", 0}, /* TAG_H2 */
76 {"p", HTML_CLRLINE
}, /* TAG_P */
77 {"span", 0}, /* TAG_SPAN */
78 {"link", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_LINK */
79 {"br", HTML_CLRLINE
| HTML_NOSTACK
}, /* TAG_LINK */
83 static const char *const htmlattrs
[ATTR_MAX
] = {
101 SLIST_ENTRY(tag
) entry
;
104 SLIST_HEAD(tagq
, tag
);
108 #define HTML_NOSPACE (1 << 0)
109 #define HTML_NEWLINE (1 << 1)
114 #define MDOC_ARGS const struct mdoc_meta *m, \
115 const struct mdoc_node *n, \
117 #define MAN_ARGS const struct man_meta *m, \
118 const struct man_node *n, \
121 int (*pre
)(MDOC_ARGS
);
122 void (*post
)(MDOC_ARGS
);
125 static void print_gen_doctype(struct html
*);
126 static void print_gen_head(struct html
*);
127 static void print_mdoc(MDOC_ARGS
);
128 static void print_mdoc_head(MDOC_ARGS
);
129 static void print_mdoc_title(MDOC_ARGS
);
130 static void print_mdoc_node(MDOC_ARGS
);
131 static void print_man(MAN_ARGS
);
132 static void print_man_head(MAN_ARGS
);
133 static void print_man_body(MAN_ARGS
);
134 static struct tag
*print_otag(struct html
*, enum htmltag
,
135 int, const struct htmlpair
*);
136 static void print_tagq(struct html
*, const struct tag
*);
137 static void print_stagq(struct html
*, const struct tag
*);
138 static void print_ctag(struct html
*, enum htmltag
);
139 static void print_encode(struct html
*, const char *);
140 static void print_escape(struct html
*, const char **);
141 static void print_text(struct html
*, const char *);
142 static void print_res(struct html
*, const char *, int);
143 static void print_spec(struct html
*, const char *, int);
144 static int mdoc_root_pre(MDOC_ARGS
);
146 static int mdoc_ar_pre(MDOC_ARGS
);
147 static int mdoc_fl_pre(MDOC_ARGS
);
148 static int mdoc_nd_pre(MDOC_ARGS
);
149 static int mdoc_nm_pre(MDOC_ARGS
);
150 static int mdoc_ns_pre(MDOC_ARGS
);
151 static int mdoc_op_pre(MDOC_ARGS
);
152 static void mdoc_op_post(MDOC_ARGS
);
153 static int mdoc_pp_pre(MDOC_ARGS
);
154 static int mdoc_sh_pre(MDOC_ARGS
);
155 static int mdoc_ss_pre(MDOC_ARGS
);
156 static int mdoc_xr_pre(MDOC_ARGS
);
158 static const struct htmlmdoc mdocs
[MDOC_MAX
] = {
159 {NULL
, NULL
}, /* Ap */
160 {NULL
, NULL
}, /* Dd */
161 {NULL
, NULL
}, /* Dt */
162 {NULL
, NULL
}, /* Os */
163 {mdoc_sh_pre
, NULL
}, /* Sh */
164 {mdoc_ss_pre
, NULL
}, /* Ss */
165 {mdoc_pp_pre
, NULL
}, /* Pp */
166 {NULL
, NULL
}, /* D1 */
167 {NULL
, NULL
}, /* Dl */
168 {NULL
, NULL
}, /* Bd */
169 {NULL
, NULL
}, /* Ed */
170 {NULL
, NULL
}, /* Bl */
171 {NULL
, NULL
}, /* El */
172 {NULL
, NULL
}, /* It */
173 {NULL
, NULL
}, /* Ad */
174 {NULL
, NULL
}, /* An */
175 {mdoc_ar_pre
, NULL
}, /* Ar */
176 {NULL
, NULL
}, /* Cd */
177 {NULL
, NULL
}, /* Cm */
178 {NULL
, NULL
}, /* Dv */
179 {NULL
, NULL
}, /* Er */
180 {NULL
, NULL
}, /* Ev */
181 {NULL
, NULL
}, /* Ex */
182 {NULL
, NULL
}, /* Fa */
183 {NULL
, NULL
}, /* Fd */
184 {mdoc_fl_pre
, NULL
}, /* Fl */
185 {NULL
, NULL
}, /* Fn */
186 {NULL
, NULL
}, /* Ft */
187 {NULL
, NULL
}, /* Ic */
188 {NULL
, NULL
}, /* In */
189 {NULL
, NULL
}, /* Li */
190 {mdoc_nd_pre
, NULL
}, /* Nd */
191 {mdoc_nm_pre
, NULL
}, /* Nm */
192 {mdoc_op_pre
, mdoc_op_post
}, /* Op */
193 {NULL
, NULL
}, /* Ot */
194 {NULL
, NULL
}, /* Pa */
195 {NULL
, NULL
}, /* Rv */
196 {NULL
, NULL
}, /* St */
197 {NULL
, NULL
}, /* Va */
198 {NULL
, NULL
}, /* Vt */
199 {mdoc_xr_pre
, NULL
}, /* Xr */
200 {NULL
, NULL
}, /* %A */
201 {NULL
, NULL
}, /* %B */
202 {NULL
, NULL
}, /* %D */
203 {NULL
, NULL
}, /* %I */
204 {NULL
, NULL
}, /* %J */
205 {NULL
, NULL
}, /* %N */
206 {NULL
, NULL
}, /* %O */
207 {NULL
, NULL
}, /* %P */
208 {NULL
, NULL
}, /* %R */
209 {NULL
, NULL
}, /* %T */
210 {NULL
, NULL
}, /* %V */
211 {NULL
, NULL
}, /* Ac */
212 {NULL
, NULL
}, /* Ao */
213 {NULL
, NULL
}, /* Aq */
214 {NULL
, NULL
}, /* At */
215 {NULL
, NULL
}, /* Bc */
216 {NULL
, NULL
}, /* Bf */
217 {NULL
, NULL
}, /* Bo */
218 {NULL
, NULL
}, /* Bq */
219 {NULL
, NULL
}, /* Bsx */
220 {NULL
, NULL
}, /* Bx */
221 {NULL
, NULL
}, /* Db */
222 {NULL
, NULL
}, /* Dc */
223 {NULL
, NULL
}, /* Do */
224 {NULL
, NULL
}, /* Dq */
225 {NULL
, NULL
}, /* Ec */
226 {NULL
, NULL
}, /* Ef */
227 {NULL
, NULL
}, /* Em */
228 {NULL
, NULL
}, /* Eo */
229 {NULL
, NULL
}, /* Fx */
230 {NULL
, NULL
}, /* Ms */
231 {NULL
, NULL
}, /* No */
232 {mdoc_ns_pre
, NULL
}, /* Ns */
233 {NULL
, NULL
}, /* Nx */
234 {NULL
, NULL
}, /* Ox */
235 {NULL
, NULL
}, /* Pc */
236 {NULL
, NULL
}, /* Pf */
237 {NULL
, NULL
}, /* Po */
238 {NULL
, NULL
}, /* Pq */
239 {NULL
, NULL
}, /* Qc */
240 {NULL
, NULL
}, /* Ql */
241 {NULL
, NULL
}, /* Qo */
242 {NULL
, NULL
}, /* Qq */
243 {NULL
, NULL
}, /* Re */
244 {NULL
, NULL
}, /* Rs */
245 {NULL
, NULL
}, /* Sc */
246 {NULL
, NULL
}, /* So */
247 {NULL
, NULL
}, /* Sq */
248 {NULL
, NULL
}, /* Sm */
249 {NULL
, NULL
}, /* Sx */
250 {NULL
, NULL
}, /* Sy */
251 {NULL
, NULL
}, /* Tn */
252 {NULL
, NULL
}, /* Ux */
253 {NULL
, NULL
}, /* Xc */
254 {NULL
, NULL
}, /* Xo */
255 {NULL
, NULL
}, /* Fo */
256 {NULL
, NULL
}, /* Fc */
257 {NULL
, NULL
}, /* Oo */
258 {NULL
, NULL
}, /* Oc */
259 {NULL
, NULL
}, /* Bk */
260 {NULL
, NULL
}, /* Ek */
261 {NULL
, NULL
}, /* Bt */
262 {NULL
, NULL
}, /* Hf */
263 {NULL
, NULL
}, /* Fr */
264 {NULL
, NULL
}, /* Ud */
265 {NULL
, NULL
}, /* Lb */
266 {NULL
, NULL
}, /* Lp */
267 {NULL
, NULL
}, /* Lk */
268 {NULL
, NULL
}, /* Mt */
269 {NULL
, NULL
}, /* Brq */
270 {NULL
, NULL
}, /* Bro */
271 {NULL
, NULL
}, /* Brc */
272 {NULL
, NULL
}, /* %C */
273 {NULL
, NULL
}, /* Es */
274 {NULL
, NULL
}, /* En */
275 {NULL
, NULL
}, /* Dx */
276 {NULL
, NULL
}, /* %Q */
277 {NULL
, NULL
}, /* br */
278 {NULL
, NULL
}, /* sp */
282 html_mdoc(void *arg
, const struct mdoc
*m
)
287 h
= (struct html
*)arg
;
289 print_gen_doctype(h
);
290 t
= print_otag(h
, TAG_HTML
, 0, NULL
);
291 print_mdoc(mdoc_meta(m
), mdoc_node(m
), h
);
298 html_man(void *arg
, const struct man
*m
)
303 h
= (struct html
*)arg
;
305 print_gen_doctype(h
);
306 t
= print_otag(h
, TAG_HTML
, 0, NULL
);
307 print_man(man_meta(m
), man_node(m
), h
);
318 if (NULL
== (h
= calloc(1, sizeof(struct html
))))
321 SLIST_INIT(&h
->stack
);
322 if (NULL
== (h
->symtab
= chars_init(CHARS_HTML
))) {
335 h
= (struct html
*)p
;
337 while ( ! SLIST_EMPTY(&h
->stack
)) {
338 tag
= SLIST_FIRST(&h
->stack
);
339 SLIST_REMOVE_HEAD(&h
->stack
, entry
);
346 print_mdoc(MDOC_ARGS
)
350 t
= print_otag(h
, TAG_HEAD
, 0, NULL
);
351 print_mdoc_head(m
, n
, h
);
354 t
= print_otag(h
, TAG_BODY
, 0, NULL
);
355 print_mdoc_title(m
, n
, h
);
356 print_mdoc_node(m
, n
, h
);
361 print_gen_head(struct html
*h
)
363 struct htmlpair meta0
[2];
364 struct htmlpair meta1
[2];
365 struct htmlpair link
[4];
367 meta0
[0].key
= ATTR_HTTPEQUIV
;
368 meta0
[0].val
= "Content-Type";
369 meta0
[1].key
= ATTR_CONTENT
;
370 meta0
[1].val
= "text/html; charest-utf-8";
372 meta1
[0].key
= ATTR_NAME
;
373 meta1
[0].val
= "resource-type";
374 meta1
[1].key
= ATTR_CONTENT
;
375 meta1
[1].val
= "document";
377 link
[0].key
= ATTR_REL
;
378 link
[0].val
= "stylesheet";
379 link
[1].key
= ATTR_HREF
;
380 link
[1].val
= "style.css"; /* XXX */
381 link
[2].key
= ATTR_TYPE
;
382 link
[2].val
= "text/css";
383 link
[3].key
= ATTR_MEDIA
;
386 print_otag(h
, TAG_META
, 2, meta0
);
387 print_otag(h
, TAG_META
, 2, meta1
);
388 print_otag(h
, TAG_LINK
, 4, link
);
393 print_mdoc_head(MDOC_ARGS
)
397 print_otag(h
, TAG_TITLE
, 0, NULL
);
398 print_encode(h
, m
->title
);
403 print_mdoc_title(MDOC_ARGS
)
410 print_mdoc_node(MDOC_ARGS
)
416 t
= SLIST_FIRST(&h
->stack
);
420 child
= mdoc_root_pre(m
, n
, h
);
423 print_text(h
, n
->string
);
426 if (mdocs
[n
->tok
].pre
)
427 child
= (*mdocs
[n
->tok
].pre
)(m
, n
, h
);
431 if (child
&& n
->child
)
432 print_mdoc_node(m
, n
->child
, h
);
442 if (mdocs
[n
->tok
].post
)
443 (*mdocs
[n
->tok
].post
)(m
, n
, h
);
448 print_mdoc_node(m
, n
->next
, h
);
456 t
= print_otag(h
, TAG_HEAD
, 0, NULL
);
457 print_man_head(m
, n
, h
);
460 t
= print_otag(h
, TAG_BODY
, 0, NULL
);
461 print_man_body(m
, n
, h
);
467 print_man_head(MAN_ARGS
)
471 print_otag(h
, TAG_TITLE
, 0, NULL
);
472 print_encode(h
, m
->title
);
477 print_man_body(MAN_ARGS
)
484 print_spec(struct html
*h
, const char *p
, int len
)
490 rhs
= chars_a2ascii(h
->symtab
, p
, (size_t)len
, &sz
);
494 for (i
= 0; i
< (int)sz
; i
++)
499 print_res(struct html
*h
, const char *p
, int len
)
505 rhs
= chars_a2res(h
->symtab
, p
, (size_t)len
, &sz
);
509 for (i
= 0; i
< (int)sz
; i
++)
514 print_escape(struct html
*h
, const char **p
)
529 if (0 == *wp
|| 0 == *(wp
+ 1)) {
530 *p
= 0 == *wp
? wp
: wp
+ 1;
534 print_spec(h
, wp
, 2);
538 } else if ('*' == *wp
) {
547 if (0 == *wp
|| 0 == *(wp
+ 1)) {
548 *p
= 0 == *wp
? wp
: wp
+ 1;
564 } else if ('f' == *wp
) {
589 } else if ('[' != *wp
) {
590 print_spec(h
, wp
, 1);
596 for (j
= 0; *wp
&& ']' != *wp
; wp
++, j
++)
605 print_spec(h
, wp
- j
, j
);
607 print_res(h
, wp
- j
, j
);
614 print_encode(struct html
*h
, const char *p
)
628 print_otag(struct html
*h
, enum htmltag tag
,
629 int sz
, const struct htmlpair
*p
)
634 if ( ! (HTML_NOSTACK
& htmltags
[tag
].flags
)) {
635 if (NULL
== (t
= malloc(sizeof(struct tag
))))
636 err(EXIT_FAILURE
, "malloc");
638 SLIST_INSERT_HEAD(&h
->stack
, t
, entry
);
642 if ( ! (HTML_NOSPACE
& h
->flags
))
643 if ( ! (HTML_CLRLINE
& htmltags
[tag
].flags
))
646 printf("<%s", htmltags
[tag
].name
);
647 for (i
= 0; i
< sz
; i
++) {
648 printf(" %s=\"", htmlattrs
[p
[i
].key
]);
650 print_encode(h
, p
[i
].val
);
655 h
->flags
|= HTML_NOSPACE
;
656 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
657 h
->flags
|= HTML_NEWLINE
;
659 h
->flags
&= ~HTML_NEWLINE
;
667 print_ctag(struct html
*h
, enum htmltag tag
)
670 printf("</%s>", htmltags
[tag
].name
);
671 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
672 h
->flags
|= HTML_NOSPACE
;
673 if (HTML_CLRLINE
& htmltags
[tag
].flags
)
674 h
->flags
|= HTML_NEWLINE
;
676 h
->flags
&= ~HTML_NEWLINE
;
682 print_gen_doctype(struct html
*h
)
685 printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE
, DTD
);
690 print_text(struct html
*h
, const char *p
)
693 if (*p
&& 0 == *(p
+ 1))
712 h
->flags
|= HTML_NOSPACE
;
718 if ( ! (h
->flags
& HTML_NOSPACE
))
721 h
->flags
&= ~HTML_NOSPACE
;
722 h
->flags
&= ~HTML_NEWLINE
;
727 if (*p
&& 0 == *(p
+ 1))
734 h
->flags
|= HTML_NOSPACE
;
743 print_tagq(struct html
*h
, const struct tag
*until
)
747 while ( ! SLIST_EMPTY(&h
->stack
)) {
748 tag
= SLIST_FIRST(&h
->stack
);
749 print_ctag(h
, tag
->tag
);
750 SLIST_REMOVE_HEAD(&h
->stack
, entry
);
752 if (until
&& tag
== until
)
759 print_stagq(struct html
*h
, const struct tag
*suntil
)
763 while ( ! SLIST_EMPTY(&h
->stack
)) {
764 tag
= SLIST_FIRST(&h
->stack
);
765 if (suntil
&& tag
== suntil
)
767 print_ctag(h
, tag
->tag
);
768 SLIST_REMOVE_HEAD(&h
->stack
, entry
);
776 mdoc_root_pre(MDOC_ARGS
)
780 tag
.key
= ATTR_CLASS
;
783 print_otag(h
, TAG_DIV
, 1, &tag
);
790 mdoc_ss_pre(MDOC_ARGS
)
793 if (MDOC_BODY
== n
->type
)
794 print_otag(h
, TAG_P
, 0, NULL
);
795 if (MDOC_HEAD
== n
->type
)
796 print_otag(h
, TAG_H2
, 0, NULL
);
803 mdoc_fl_pre(MDOC_ARGS
)
807 tag
.key
= ATTR_CLASS
;
810 print_otag(h
, TAG_SPAN
, 1, &tag
);
811 print_text(h
, "\\-");
812 h
->flags
|= HTML_NOSPACE
;
819 mdoc_pp_pre(MDOC_ARGS
)
822 print_otag(h
, TAG_BR
, 0, NULL
);
823 print_otag(h
, TAG_BR
, 0, NULL
);
830 mdoc_nd_pre(MDOC_ARGS
)
833 if (MDOC_BODY
== n
->type
)
834 print_text(h
, "\\(en");
841 mdoc_op_pre(MDOC_ARGS
)
844 if (MDOC_BODY
== n
->type
) {
845 print_text(h
, "\\(lB");
846 h
->flags
|= HTML_NOSPACE
;
854 mdoc_op_post(MDOC_ARGS
)
857 if (MDOC_BODY
!= n
->type
)
859 h
->flags
|= HTML_NOSPACE
;
860 print_text(h
, "\\(rB");
865 mdoc_nm_pre(MDOC_ARGS
)
867 struct htmlpair
class;
869 if ( ! (HTML_NEWLINE
& h
->flags
))
870 if (SEC_SYNOPSIS
== n
->sec
)
871 print_otag(h
, TAG_BR
, 0, NULL
);
873 class.key
= ATTR_CLASS
;
876 print_otag(h
, TAG_SPAN
, 1, &class);
877 if (NULL
== n
->child
)
878 print_text(h
, m
->name
);
886 mdoc_sh_pre(MDOC_ARGS
)
889 if (MDOC_BODY
== n
->type
)
890 print_otag(h
, TAG_P
, 0, NULL
);
891 if (MDOC_HEAD
== n
->type
)
892 print_otag(h
, TAG_H1
, 0, NULL
);
899 mdoc_xr_pre(MDOC_ARGS
)
904 tag
.val
= "#"; /* TODO */
906 print_otag(h
, TAG_A
, 1, &tag
);
909 print_text(h
, n
->string
);
910 if (NULL
== (n
= n
->next
))
913 h
->flags
|= HTML_NOSPACE
;
915 h
->flags
|= HTML_NOSPACE
;
916 print_text(h
, n
->string
);
917 h
->flags
|= HTML_NOSPACE
;
926 mdoc_ns_pre(MDOC_ARGS
)
929 h
->flags
|= HTML_NOSPACE
;
936 mdoc_ar_pre(MDOC_ARGS
)
940 tag
.key
= ATTR_CLASS
;
943 print_otag(h
, TAG_SPAN
, 1, &tag
);