]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_html.c
Lint check (noop).
[mandoc.git] / mdoc_html.c
1 /* $Id: mdoc_html.c,v 1.12 2009/09/25 13:00:13 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 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/queue.h>
20
21 #include <assert.h>
22 #include <ctype.h>
23 #include <err.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "html.h"
30 #include "mdoc.h"
31
32 #define INDENT 5
33 #define HALFINDENT 3
34
35 #define MDOC_ARGS const struct mdoc_meta *m, \
36 const struct mdoc_node *n, \
37 struct html *h
38 #define MAN_ARGS const struct man_meta *m, \
39 const struct man_node *n, \
40 struct html *h
41
42 struct htmlmdoc {
43 int (*pre)(MDOC_ARGS);
44 void (*post)(MDOC_ARGS);
45 };
46
47 static void print_mdoc(MDOC_ARGS);
48 static void print_mdoc_head(MDOC_ARGS);
49 static void print_mdoc_node(MDOC_ARGS);
50 static void print_mdoc_nodelist(MDOC_ARGS);
51
52 static int a2width(const char *);
53 static int a2offs(const char *);
54 static int a2list(const struct mdoc_node *);
55
56 static void mdoc_root_post(MDOC_ARGS);
57 static int mdoc_root_pre(MDOC_ARGS);
58 static int mdoc_tbl_pre(MDOC_ARGS, int);
59 static int mdoc_tbl_block_pre(MDOC_ARGS, int, int, int, int);
60 static int mdoc_tbl_body_pre(MDOC_ARGS, int, int);
61 static int mdoc_tbl_head_pre(MDOC_ARGS, int, int);
62
63 static void mdoc__x_post(MDOC_ARGS);
64 static int mdoc__x_pre(MDOC_ARGS);
65 static int mdoc_ad_pre(MDOC_ARGS);
66 static int mdoc_an_pre(MDOC_ARGS);
67 static int mdoc_ap_pre(MDOC_ARGS);
68 static void mdoc_aq_post(MDOC_ARGS);
69 static int mdoc_aq_pre(MDOC_ARGS);
70 static int mdoc_ar_pre(MDOC_ARGS);
71 static int mdoc_bd_pre(MDOC_ARGS);
72 static int mdoc_bf_pre(MDOC_ARGS);
73 static void mdoc_bl_post(MDOC_ARGS);
74 static int mdoc_bl_pre(MDOC_ARGS);
75 static void mdoc_bq_post(MDOC_ARGS);
76 static int mdoc_bq_pre(MDOC_ARGS);
77 static void mdoc_brq_post(MDOC_ARGS);
78 static int mdoc_brq_pre(MDOC_ARGS);
79 static int mdoc_bt_pre(MDOC_ARGS);
80 static int mdoc_bx_pre(MDOC_ARGS);
81 static int mdoc_cd_pre(MDOC_ARGS);
82 static int mdoc_d1_pre(MDOC_ARGS);
83 static void mdoc_dq_post(MDOC_ARGS);
84 static int mdoc_dq_pre(MDOC_ARGS);
85 static int mdoc_dv_pre(MDOC_ARGS);
86 static int mdoc_fa_pre(MDOC_ARGS);
87 static int mdoc_fd_pre(MDOC_ARGS);
88 static int mdoc_fl_pre(MDOC_ARGS);
89 static int mdoc_fn_pre(MDOC_ARGS);
90 static int mdoc_ft_pre(MDOC_ARGS);
91 static int mdoc_em_pre(MDOC_ARGS);
92 static int mdoc_er_pre(MDOC_ARGS);
93 static int mdoc_ev_pre(MDOC_ARGS);
94 static int mdoc_ex_pre(MDOC_ARGS);
95 static void mdoc_fo_post(MDOC_ARGS);
96 static int mdoc_fo_pre(MDOC_ARGS);
97 static int mdoc_ic_pre(MDOC_ARGS);
98 static int mdoc_in_pre(MDOC_ARGS);
99 static int mdoc_it_pre(MDOC_ARGS);
100 static int mdoc_lb_pre(MDOC_ARGS);
101 static int mdoc_li_pre(MDOC_ARGS);
102 static int mdoc_lk_pre(MDOC_ARGS);
103 static int mdoc_mt_pre(MDOC_ARGS);
104 static int mdoc_ms_pre(MDOC_ARGS);
105 static int mdoc_nd_pre(MDOC_ARGS);
106 static int mdoc_nm_pre(MDOC_ARGS);
107 static int mdoc_ns_pre(MDOC_ARGS);
108 static void mdoc_op_post(MDOC_ARGS);
109 static int mdoc_op_pre(MDOC_ARGS);
110 static int mdoc_pa_pre(MDOC_ARGS);
111 static void mdoc_pf_post(MDOC_ARGS);
112 static int mdoc_pf_pre(MDOC_ARGS);
113 static void mdoc_pq_post(MDOC_ARGS);
114 static int mdoc_pq_pre(MDOC_ARGS);
115 static int mdoc_rs_pre(MDOC_ARGS);
116 static int mdoc_rv_pre(MDOC_ARGS);
117 static int mdoc_sh_pre(MDOC_ARGS);
118 static int mdoc_sp_pre(MDOC_ARGS);
119 static void mdoc_sq_post(MDOC_ARGS);
120 static int mdoc_sq_pre(MDOC_ARGS);
121 static int mdoc_ss_pre(MDOC_ARGS);
122 static int mdoc_sx_pre(MDOC_ARGS);
123 static int mdoc_sy_pre(MDOC_ARGS);
124 static int mdoc_ud_pre(MDOC_ARGS);
125 static int mdoc_va_pre(MDOC_ARGS);
126 static int mdoc_vt_pre(MDOC_ARGS);
127 static int mdoc_xr_pre(MDOC_ARGS);
128 static int mdoc_xx_pre(MDOC_ARGS);
129
130 #ifdef __linux__
131 extern size_t strlcpy(char *, const char *, size_t);
132 extern size_t strlcat(char *, const char *, size_t);
133 #endif
134
135 static const struct htmlmdoc mdocs[MDOC_MAX] = {
136 {mdoc_ap_pre, NULL}, /* Ap */
137 {NULL, NULL}, /* Dd */
138 {NULL, NULL}, /* Dt */
139 {NULL, NULL}, /* Os */
140 {mdoc_sh_pre, NULL }, /* Sh */
141 {mdoc_ss_pre, NULL }, /* Ss */
142 {mdoc_sp_pre, NULL}, /* Pp */
143 {mdoc_d1_pre, NULL}, /* D1 */
144 {mdoc_d1_pre, NULL}, /* Dl */
145 {mdoc_bd_pre, NULL}, /* Bd */
146 {NULL, NULL}, /* Ed */
147 {mdoc_bl_pre, mdoc_bl_post}, /* Bl */
148 {NULL, NULL}, /* El */
149 {mdoc_it_pre, NULL}, /* It */
150 {mdoc_ad_pre, NULL}, /* Ad */
151 {mdoc_an_pre, NULL}, /* An */
152 {mdoc_ar_pre, NULL}, /* Ar */
153 {mdoc_cd_pre, NULL}, /* Cd */
154 {mdoc_fl_pre, NULL}, /* Cm */
155 {mdoc_dv_pre, NULL}, /* Dv */
156 {mdoc_er_pre, NULL}, /* Er */
157 {mdoc_ev_pre, NULL}, /* Ev */
158 {mdoc_ex_pre, NULL}, /* Ex */
159 {mdoc_fa_pre, NULL}, /* Fa */
160 {mdoc_fd_pre, NULL}, /* Fd */
161 {mdoc_fl_pre, NULL}, /* Fl */
162 {mdoc_fn_pre, NULL}, /* Fn */
163 {mdoc_ft_pre, NULL}, /* Ft */
164 {mdoc_ic_pre, NULL}, /* Ic */
165 {mdoc_in_pre, NULL}, /* In */
166 {mdoc_li_pre, NULL}, /* Li */
167 {mdoc_nd_pre, NULL}, /* Nd */
168 {mdoc_nm_pre, NULL}, /* Nm */
169 {mdoc_op_pre, mdoc_op_post}, /* Op */
170 {NULL, NULL}, /* Ot */
171 {mdoc_pa_pre, NULL}, /* Pa */
172 {mdoc_rv_pre, NULL}, /* Rv */
173 {NULL, NULL}, /* St */
174 {mdoc_va_pre, NULL}, /* Va */
175 {mdoc_vt_pre, NULL}, /* Vt */
176 {mdoc_xr_pre, NULL}, /* Xr */
177 {mdoc__x_pre, mdoc__x_post}, /* %A */
178 {mdoc__x_pre, mdoc__x_post}, /* %B */
179 {mdoc__x_pre, mdoc__x_post}, /* %D */
180 {mdoc__x_pre, mdoc__x_post}, /* %I */
181 {mdoc__x_pre, mdoc__x_post}, /* %J */
182 {mdoc__x_pre, mdoc__x_post}, /* %N */
183 {mdoc__x_pre, mdoc__x_post}, /* %O */
184 {mdoc__x_pre, mdoc__x_post}, /* %P */
185 {mdoc__x_pre, mdoc__x_post}, /* %R */
186 {mdoc__x_pre, mdoc__x_post}, /* %T */
187 {mdoc__x_pre, mdoc__x_post}, /* %V */
188 {NULL, NULL}, /* Ac */
189 {mdoc_aq_pre, mdoc_aq_post}, /* Ao */
190 {mdoc_aq_pre, mdoc_aq_post}, /* Aq */
191 {NULL, NULL}, /* At */
192 {NULL, NULL}, /* Bc */
193 {mdoc_bf_pre, NULL}, /* Bf */
194 {mdoc_bq_pre, mdoc_bq_post}, /* Bo */
195 {mdoc_bq_pre, mdoc_bq_post}, /* Bq */
196 {mdoc_xx_pre, NULL}, /* Bsx */
197 {mdoc_bx_pre, NULL}, /* Bx */
198 {NULL, NULL}, /* Db */
199 {NULL, NULL}, /* Dc */
200 {mdoc_dq_pre, mdoc_dq_post}, /* Do */
201 {mdoc_dq_pre, mdoc_dq_post}, /* Dq */
202 {NULL, NULL}, /* Ec */
203 {NULL, NULL}, /* Ef */
204 {mdoc_em_pre, NULL}, /* Em */
205 {NULL, NULL}, /* Eo */
206 {mdoc_xx_pre, NULL}, /* Fx */
207 {mdoc_ms_pre, NULL}, /* Ms */ /* FIXME: convert to symbol? */
208 {NULL, NULL}, /* No */
209 {mdoc_ns_pre, NULL}, /* Ns */
210 {mdoc_xx_pre, NULL}, /* Nx */
211 {mdoc_xx_pre, NULL}, /* Ox */
212 {NULL, NULL}, /* Pc */
213 {mdoc_pf_pre, mdoc_pf_post}, /* Pf */
214 {mdoc_pq_pre, mdoc_pq_post}, /* Po */
215 {mdoc_pq_pre, mdoc_pq_post}, /* Pq */
216 {NULL, NULL}, /* Qc */
217 {mdoc_sq_pre, mdoc_sq_post}, /* Ql */
218 {mdoc_dq_pre, mdoc_dq_post}, /* Qo */
219 {mdoc_dq_pre, mdoc_dq_post}, /* Qq */
220 {NULL, NULL}, /* Re */
221 {mdoc_rs_pre, NULL}, /* Rs */
222 {NULL, NULL}, /* Sc */
223 {mdoc_sq_pre, mdoc_sq_post}, /* So */
224 {mdoc_sq_pre, mdoc_sq_post}, /* Sq */
225 {NULL, NULL}, /* Sm */ /* FIXME - no idea. */
226 {mdoc_sx_pre, NULL}, /* Sx */
227 {mdoc_sy_pre, NULL}, /* Sy */
228 {NULL, NULL}, /* Tn */
229 {mdoc_xx_pre, NULL}, /* Ux */
230 {NULL, NULL}, /* Xc */
231 {NULL, NULL}, /* Xo */
232 {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
233 {NULL, NULL}, /* Fc */
234 {mdoc_op_pre, mdoc_op_post}, /* Oo */
235 {NULL, NULL}, /* Oc */
236 {NULL, NULL}, /* Bk */
237 {NULL, NULL}, /* Ek */
238 {mdoc_bt_pre, NULL}, /* Bt */
239 {NULL, NULL}, /* Hf */
240 {NULL, NULL}, /* Fr */
241 {mdoc_ud_pre, NULL}, /* Ud */
242 {mdoc_lb_pre, NULL}, /* Lb */
243 {mdoc_sp_pre, NULL}, /* Lp */
244 {mdoc_lk_pre, NULL}, /* Lk */
245 {mdoc_mt_pre, NULL}, /* Mt */
246 {mdoc_brq_pre, mdoc_brq_post}, /* Brq */
247 {mdoc_brq_pre, mdoc_brq_post}, /* Bro */
248 {NULL, NULL}, /* Brc */
249 {mdoc__x_pre, mdoc__x_post}, /* %C */
250 {NULL, NULL}, /* Es */ /* TODO */
251 {NULL, NULL}, /* En */ /* TODO */
252 {mdoc_xx_pre, NULL}, /* Dx */
253 {mdoc__x_pre, mdoc__x_post}, /* %Q */
254 {mdoc_sp_pre, NULL}, /* br */
255 {mdoc_sp_pre, NULL}, /* sp */
256 };
257
258 static char buf[BUFSIZ]; /* XXX */
259
260 #define bufcat(x) (void)strlcat(buf, (x), BUFSIZ)
261 #define bufinit() buf[0] = 0
262 #define buffmt(...) (void)snprintf(buf, BUFSIZ - 1, __VA_ARGS__)
263
264 void
265 html_mdoc(void *arg, const struct mdoc *m)
266 {
267 struct html *h;
268 struct tag *t;
269
270 h = (struct html *)arg;
271
272 print_gen_doctype(h);
273 t = print_otag(h, TAG_HTML, 0, NULL);
274 print_mdoc(mdoc_meta(m), mdoc_node(m), h);
275 print_tagq(h, t);
276
277 printf("\n");
278 }
279
280
281 static int
282 a2list(const struct mdoc_node *n)
283 {
284 int i;
285
286 assert(MDOC_BLOCK == n->type && MDOC_Bl == n->tok);
287 assert(n->args);
288
289 for (i = 0; i < (int)n->args->argc; i++)
290 switch (n->args->argv[i].arg) {
291 case (MDOC_Enum):
292 /* FALLTHROUGH */
293 case (MDOC_Dash):
294 /* FALLTHROUGH */
295 case (MDOC_Hyphen):
296 /* FALLTHROUGH */
297 case (MDOC_Bullet):
298 /* FALLTHROUGH */
299 case (MDOC_Tag):
300 /* FALLTHROUGH */
301 case (MDOC_Hang):
302 /* FALLTHROUGH */
303 case (MDOC_Inset):
304 /* FALLTHROUGH */
305 case (MDOC_Diag):
306 /* FALLTHROUGH */
307 case (MDOC_Item):
308 /* FALLTHROUGH */
309 case (MDOC_Column):
310 /* FALLTHROUGH */
311 case (MDOC_Ohang):
312 return(n->args->argv[i].arg);
313 default:
314 break;
315 }
316
317 abort();
318 /* NOTREACHED */
319 }
320
321
322 static int
323 a2width(const char *p)
324 {
325 int i, len;
326
327 if (0 == (len = (int)strlen(p)))
328 return(0);
329 for (i = 0; i < len - 1; i++)
330 if ( ! isdigit((u_char)p[i]))
331 break;
332
333 if (i == len - 1)
334 if ('n' == p[len - 1] || 'm' == p[len - 1])
335 return(atoi(p) + 2);
336
337 return(len + 2);
338 }
339
340
341 static int
342 a2offs(const char *p)
343 {
344 int len, i;
345
346 if (0 == strcmp(p, "left"))
347 return(0);
348 if (0 == strcmp(p, "indent"))
349 return(INDENT + 1);
350 if (0 == strcmp(p, "indent-two"))
351 return((INDENT + 1) * 2);
352
353 if (0 == (len = (int)strlen(p)))
354 return(0);
355
356 for (i = 0; i < len - 1; i++)
357 if ( ! isdigit((u_char)p[i]))
358 break;
359
360 if (i == len - 1)
361 if ('n' == p[len - 1] || 'm' == p[len - 1])
362 return(atoi(p));
363
364 return(len);
365 }
366
367
368 static void
369 print_mdoc(MDOC_ARGS)
370 {
371 struct tag *t;
372 struct htmlpair tag;
373
374 t = print_otag(h, TAG_HEAD, 0, NULL);
375 print_mdoc_head(m, n, h);
376 print_tagq(h, t);
377
378 t = print_otag(h, TAG_BODY, 0, NULL);
379
380 tag.key = ATTR_CLASS;
381 tag.val = "body";
382 print_otag(h, TAG_DIV, 1, &tag);
383
384 print_mdoc_nodelist(m, n, h);
385 print_tagq(h, t);
386 }
387
388
389 /* ARGSUSED */
390 static void
391 print_mdoc_head(MDOC_ARGS)
392 {
393 char b[BUFSIZ];
394
395 print_gen_head(h);
396
397 (void)snprintf(b, BUFSIZ - 1,
398 "%s(%d)", m->title, m->msec);
399
400 if (m->arch) {
401 (void)strlcat(b, " (", BUFSIZ);
402 (void)strlcat(b, m->arch, BUFSIZ);
403 (void)strlcat(b, ")", BUFSIZ);
404 }
405
406 print_otag(h, TAG_TITLE, 0, NULL);
407 print_text(h, b);
408 }
409
410
411 static void
412 print_mdoc_nodelist(MDOC_ARGS)
413 {
414
415 print_mdoc_node(m, n, h);
416 if (n->next)
417 print_mdoc_nodelist(m, n->next, h);
418 }
419
420
421 static void
422 print_mdoc_node(MDOC_ARGS)
423 {
424 int child;
425 struct tag *t;
426
427 child = 1;
428 t = SLIST_FIRST(&h->tags);
429
430 bufinit();
431
432 switch (n->type) {
433 case (MDOC_ROOT):
434 child = mdoc_root_pre(m, n, h);
435 break;
436 case (MDOC_TEXT):
437 print_text(h, n->string);
438 break;
439 default:
440 if (mdocs[n->tok].pre)
441 child = (*mdocs[n->tok].pre)(m, n, h);
442 break;
443 }
444
445 if (child && n->child)
446 print_mdoc_nodelist(m, n->child, h);
447
448 print_stagq(h, t);
449
450 bufinit();
451
452 switch (n->type) {
453 case (MDOC_ROOT):
454 mdoc_root_post(m, n, h);
455 break;
456 case (MDOC_TEXT):
457 break;
458 default:
459 if (mdocs[n->tok].post)
460 (*mdocs[n->tok].post)(m, n, h);
461 break;
462 }
463 }
464
465
466 /* ARGSUSED */
467 static void
468 mdoc_root_post(MDOC_ARGS)
469 {
470 struct tm tm;
471 struct htmlpair tag[2];
472 struct tag *t, *tt;
473 char b[BUFSIZ];
474
475 (void)localtime_r(&m->date, &tm);
476
477 if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", &tm))
478 err(EXIT_FAILURE, "strftime");
479
480 tag[0].key = ATTR_CLASS;
481 tag[0].val = "footer";
482 tag[1].key = ATTR_STYLE;
483 tag[1].val = "width: 100%;";
484 t = print_otag(h, TAG_TABLE, 2, tag);
485 tt = print_otag(h, TAG_TR, 0, NULL);
486
487 tag[0].key = ATTR_STYLE;
488 tag[0].val = "width: 50%;";
489 print_otag(h, TAG_TD, 1, tag);
490 print_text(h, b);
491 print_stagq(h, tt);
492
493 tag[0].key = ATTR_STYLE;
494 tag[0].val = "width: 50%; text-align: right;";
495 print_otag(h, TAG_TD, 1, tag);
496 print_text(h, m->os);
497 print_tagq(h, t);
498 }
499
500
501 /* ARGSUSED */
502 static int
503 mdoc_root_pre(MDOC_ARGS)
504 {
505 struct htmlpair tag[2];
506 struct tag *t, *tt;
507 char b[BUFSIZ], title[BUFSIZ];
508
509 (void)strlcpy(b, m->vol, BUFSIZ);
510
511 if (m->arch) {
512 (void)strlcat(b, " (", BUFSIZ);
513 (void)strlcat(b, m->arch, BUFSIZ);
514 (void)strlcat(b, ")", BUFSIZ);
515 }
516
517 (void)snprintf(title, BUFSIZ - 1,
518 "%s(%d)", m->title, m->msec);
519
520 tag[0].key = ATTR_CLASS;
521 tag[0].val = "header";
522 tag[1].key = ATTR_STYLE;
523 tag[1].val = "width: 100%;";
524 t = print_otag(h, TAG_TABLE, 2, tag);
525 tt = print_otag(h, TAG_TR, 0, NULL);
526
527 tag[0].key = ATTR_STYLE;
528 tag[0].val = "width: 10%;";
529 print_otag(h, TAG_TD, 1, tag);
530 print_text(h, title);
531 print_stagq(h, tt);
532
533 tag[0].key = ATTR_STYLE;
534 tag[0].val = "width: 80%; white-space: nowrap; text-align: center;";
535 print_otag(h, TAG_TD, 1, tag);
536 print_text(h, b);
537 print_stagq(h, tt);
538
539 tag[0].key = ATTR_STYLE;
540 tag[0].val = "width: 10%; text-align: right;";
541 print_otag(h, TAG_TD, 1, tag);
542 print_text(h, title);
543 print_tagq(h, t);
544
545 return(1);
546 }
547
548
549 /* ARGSUSED */
550 static int
551 mdoc_sh_pre(MDOC_ARGS)
552 {
553 struct htmlpair tag[2];
554 const struct mdoc_node *nn;
555
556 if (MDOC_HEAD == n->type) {
557 tag[0].key = ATTR_CLASS;
558 tag[0].val = "sec-head";
559 print_otag(h, TAG_DIV, 1, tag);
560 print_otag(h, TAG_SPAN, 1, tag);
561
562 for (nn = n->child; nn; nn = nn->next) {
563 bufcat(nn->string);
564 if (nn->next)
565 bufcat(" ");
566 }
567 tag[0].key = ATTR_NAME;
568 tag[0].val = buf;
569 print_otag(h, TAG_A, 1, tag);
570 return(1);
571 } else if (MDOC_BLOCK == n->type) {
572 tag[0].key = ATTR_CLASS;
573 tag[0].val = "sec-block";
574
575 if (n->prev && NULL == n->prev->body->child) {
576 print_otag(h, TAG_DIV, 1, tag);
577 return(1);
578 }
579
580 bufcat("margin-top: 1em;");
581 if (NULL == n->next)
582 bufcat("margin-bottom: 1em;");
583
584 tag[1].key = ATTR_STYLE;
585 tag[1].val = buf;
586
587 print_otag(h, TAG_DIV, 2, tag);
588 return(1);
589 }
590
591 buffmt("margin-left: %dem;", INDENT);
592
593 tag[0].key = ATTR_CLASS;
594 tag[0].val = "sec-body";
595 tag[1].key = ATTR_STYLE;
596 tag[1].val = buf;
597
598 print_otag(h, TAG_DIV, 2, tag);
599 return(1);
600 }
601
602
603 /* ARGSUSED */
604 static int
605 mdoc_ss_pre(MDOC_ARGS)
606 {
607 struct htmlpair tag[2];
608 int i;
609 const struct mdoc_node *nn;
610
611 i = 0;
612
613 if (MDOC_BODY == n->type) {
614 tag[i].key = ATTR_CLASS;
615 tag[i++].val = "ssec-body";
616 if (n->parent->next && n->child) {
617 bufcat("margin-bottom: 1em;");
618 tag[i].key = ATTR_STYLE;
619 tag[i++].val = buf;
620 }
621 print_otag(h, TAG_DIV, i, tag);
622 return(1);
623 } else if (MDOC_BLOCK == n->type) {
624 tag[i].key = ATTR_CLASS;
625 tag[i++].val = "ssec-block";
626 if (n->prev) {
627 bufcat("margin-top: 1em;");
628 tag[i].key = ATTR_STYLE;
629 tag[i++].val = buf;
630 }
631 print_otag(h, TAG_DIV, i, tag);
632 return(1);
633 }
634
635 buffmt("margin-left: -%dem;", INDENT - HALFINDENT);
636
637 tag[0].key = ATTR_CLASS;
638 tag[0].val = "ssec-head";
639 tag[1].key = ATTR_STYLE;
640 tag[1].val = buf;
641
642 print_otag(h, TAG_DIV, 2, tag);
643 print_otag(h, TAG_SPAN, 1, tag);
644
645 bufinit();
646 for (nn = n->child; nn; nn = nn->next) {
647 bufcat(nn->string);
648 if (nn->next)
649 bufcat(" ");
650 }
651 tag[0].key = ATTR_NAME;
652 tag[0].val = buf;
653 print_otag(h, TAG_A, 1, tag);
654
655 return(1);
656 }
657
658
659 /* ARGSUSED */
660 static int
661 mdoc_fl_pre(MDOC_ARGS)
662 {
663 struct htmlpair tag;
664
665 tag.key = ATTR_CLASS;
666 tag.val = "flag";
667
668 print_otag(h, TAG_SPAN, 1, &tag);
669 if (MDOC_Fl == n->tok) {
670 print_text(h, "\\-");
671 h->flags |= HTML_NOSPACE;
672 }
673 return(1);
674 }
675
676
677 /* ARGSUSED */
678 static int
679 mdoc_nd_pre(MDOC_ARGS)
680 {
681 struct htmlpair tag;
682
683 if (MDOC_BODY != n->type)
684 return(1);
685
686 /* XXX - this can contain block elements! */
687 print_text(h, "\\(em");
688 tag.key = ATTR_CLASS;
689 tag.val = "desc-body";
690 print_otag(h, TAG_SPAN, 1, &tag);
691 return(1);
692 }
693
694
695 /* ARGSUSED */
696 static int
697 mdoc_op_pre(MDOC_ARGS)
698 {
699 struct htmlpair tag;
700
701 if (MDOC_BODY != n->type)
702 return(1);
703
704 /* XXX - this can contain block elements! */
705 print_text(h, "\\(lB");
706 h->flags |= HTML_NOSPACE;
707 tag.key = ATTR_CLASS;
708 tag.val = "opt";
709 print_otag(h, TAG_SPAN, 1, &tag);
710 return(1);
711 }
712
713
714 /* ARGSUSED */
715 static void
716 mdoc_op_post(MDOC_ARGS)
717 {
718
719 if (MDOC_BODY != n->type)
720 return;
721 h->flags |= HTML_NOSPACE;
722 print_text(h, "\\(rB");
723 }
724
725
726 static int
727 mdoc_nm_pre(MDOC_ARGS)
728 {
729 struct htmlpair tag;
730
731 if ( ! (HTML_NEWLINE & h->flags))
732 if (SEC_SYNOPSIS == n->sec) {
733 tag.key = ATTR_STYLE;
734 tag.val = "clear: both;";
735 print_otag(h, TAG_BR, 1, &tag);
736 }
737
738 tag.key = ATTR_CLASS;
739 tag.val = "name";
740
741 print_otag(h, TAG_SPAN, 1, &tag);
742 if (NULL == n->child)
743 print_text(h, m->name);
744
745 return(1);
746 }
747
748
749 /* ARGSUSED */
750 static int
751 mdoc_xr_pre(MDOC_ARGS)
752 {
753 struct htmlpair tag[2];
754 const char *name, *sec;
755 const struct mdoc_node *nn;
756
757 nn = n->child;
758 name = nn && nn->string ? nn->string : "";
759 nn = nn ? nn->next : NULL;
760 sec = nn && nn->string ? nn->string : "";
761
762 buffmt("%s%s%s.html", name, name && sec ? "." : "", sec);
763
764 tag[0].key = ATTR_CLASS;
765 tag[0].val = "link-man";
766 tag[1].key = ATTR_HREF;
767 tag[1].val = buf;
768 print_otag(h, TAG_A, 2, tag);
769
770 nn = n->child;
771 print_text(h, nn->string);
772 if (NULL == (nn = nn->next))
773 return(0);
774
775 h->flags |= HTML_NOSPACE;
776 print_text(h, "(");
777 h->flags |= HTML_NOSPACE;
778 print_text(h, nn->string);
779 h->flags |= HTML_NOSPACE;
780 print_text(h, ")");
781
782 return(0);
783 }
784
785
786 /* ARGSUSED */
787 static int
788 mdoc_ns_pre(MDOC_ARGS)
789 {
790
791 h->flags |= HTML_NOSPACE;
792 return(1);
793 }
794
795
796 /* ARGSUSED */
797 static int
798 mdoc_ar_pre(MDOC_ARGS)
799 {
800 struct htmlpair tag;
801
802 tag.key = ATTR_CLASS;
803 tag.val = "arg";
804
805 print_otag(h, TAG_SPAN, 1, &tag);
806 return(1);
807 }
808
809
810 /* ARGSUSED */
811 static int
812 mdoc_xx_pre(MDOC_ARGS)
813 {
814 const char *pp;
815 struct htmlpair tag;
816
817 switch (n->tok) {
818 case (MDOC_Bsx):
819 pp = "BSDI BSD/OS";
820 break;
821 case (MDOC_Dx):
822 pp = "DragonFlyBSD";
823 break;
824 case (MDOC_Fx):
825 pp = "FreeBSD";
826 break;
827 case (MDOC_Nx):
828 pp = "NetBSD";
829 break;
830 case (MDOC_Ox):
831 pp = "OpenBSD";
832 break;
833 case (MDOC_Ux):
834 pp = "UNIX";
835 break;
836 default:
837 return(1);
838 }
839
840 tag.key = ATTR_CLASS;
841 tag.val = "unix";
842
843 print_otag(h, TAG_SPAN, 1, &tag);
844 print_text(h, pp);
845 return(1);
846 }
847
848
849 /* ARGSUSED */
850 static int
851 mdoc_bx_pre(MDOC_ARGS)
852 {
853 const struct mdoc_node *nn;
854 struct htmlpair tag;
855
856 tag.key = ATTR_CLASS;
857 tag.val = "unix";
858
859 print_otag(h, TAG_SPAN, 1, &tag);
860
861 for (nn = n->child; nn; nn = nn->next)
862 print_mdoc_node(m, nn, h);
863
864 if (n->child)
865 h->flags |= HTML_NOSPACE;
866
867 print_text(h, "BSD");
868 return(0);
869 }
870
871
872 /* ARGSUSED */
873 static int
874 mdoc_tbl_block_pre(MDOC_ARGS, int t, int w, int o, int c)
875 {
876 struct htmlpair tag;
877
878 switch (t) {
879 case (MDOC_Column):
880 /* FALLTHROUGH */
881 case (MDOC_Item):
882 /* FALLTHROUGH */
883 case (MDOC_Ohang):
884 buffmt("margin-left: %dem; clear: both;", o);
885 break;
886 default:
887 buffmt("margin-left: %dem; clear: both;", w + o);
888 break;
889 }
890
891 if ( ! c && MDOC_Column != t) {
892 if (n->prev && n->prev->body->child)
893 bufcat("padding-top: 1em;");
894 else if (NULL == n->prev)
895 bufcat("padding-top: 1em;");
896 }
897
898 tag.key = ATTR_STYLE;
899 tag.val = buf;
900 print_otag(h, TAG_DIV, 1, &tag);
901 return(1);
902 }
903
904
905 /* ARGSUSED */
906 static int
907 mdoc_tbl_body_pre(MDOC_ARGS, int t, int w)
908 {
909
910 print_otag(h, TAG_DIV, 0, NULL);
911 return(1);
912 }
913
914
915 /* ARGSUSED */
916 static int
917 mdoc_tbl_head_pre(MDOC_ARGS, int t, int w)
918 {
919 struct htmlpair tag;
920 struct ord *ord;
921 char nbuf[BUFSIZ];
922
923 switch (t) {
924 case (MDOC_Item):
925 /* FALLTHROUGH */
926 case (MDOC_Ohang):
927 print_otag(h, TAG_DIV, 0, NULL);
928 break;
929 case (MDOC_Column):
930 buffmt("min-width: %dem;", w);
931 bufcat("clear: none;");
932 if (n->next && MDOC_HEAD == n->next->type)
933 bufcat("float: left;");
934 tag.key = ATTR_STYLE;
935 tag.val = buf;
936 print_otag(h, TAG_DIV, 1, &tag);
937 break;
938 default:
939 buffmt("margin-left: -%dem; min-width: %dem;",
940 w, w ? w - 1 : 0);
941 bufcat("clear: left;");
942 if (n->next && n->next->child)
943 bufcat("float: left;");
944 bufcat("padding-right: 1em;");
945 tag.key = ATTR_STYLE;
946 tag.val = buf;
947 print_otag(h, TAG_DIV, 1, &tag);
948 break;
949 }
950
951 switch (t) {
952 case (MDOC_Diag):
953 tag.key = ATTR_CLASS;
954 tag.val = "diag";
955 print_otag(h, TAG_SPAN, 1, &tag);
956 break;
957 case (MDOC_Enum):
958 ord = SLIST_FIRST(&h->ords);
959 assert(ord);
960 nbuf[BUFSIZ - 1] = 0;
961 (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++);
962 print_text(h, nbuf);
963 return(0);
964 case (MDOC_Dash):
965 print_text(h, "\\(en");
966 return(0);
967 case (MDOC_Hyphen):
968 print_text(h, "\\(hy");
969 return(0);
970 case (MDOC_Bullet):
971 print_text(h, "\\(bu");
972 return(0);
973 default:
974 break;
975 }
976
977 return(1);
978 }
979
980
981 static int
982 mdoc_tbl_pre(MDOC_ARGS, int type)
983 {
984 int i, w, o, c, wp;
985 const struct mdoc_node *bl, *nn;
986
987 bl = n->parent->parent;
988 if (MDOC_BLOCK != n->type)
989 bl = bl->parent;
990
991 /* FIXME: fmt_vspace() equivalent. */
992
993 assert(bl->args);
994
995 w = o = c = 0;
996 wp = -1;
997
998 for (i = 0; i < (int)bl->args->argc; i++)
999 if (MDOC_Width == bl->args->argv[i].arg) {
1000 assert(bl->args->argv[i].sz);
1001 wp = i;
1002 w = a2width(bl->args->argv[i].value[0]);
1003 } else if (MDOC_Offset == bl->args->argv[i].arg) {
1004 assert(bl->args->argv[i].sz);
1005 o = a2offs(bl->args->argv[i].value[0]);
1006 } else if (MDOC_Compact == bl->args->argv[i].arg)
1007 c = 1;
1008
1009 if (MDOC_HEAD == n->type && MDOC_Column == type) {
1010 nn = n->parent->child;
1011 assert(nn && MDOC_HEAD == nn->type);
1012 for (i = 0; nn && nn != n; nn = nn->next, i++)
1013 /* Counter... */ ;
1014 assert(nn);
1015 if (wp >= 0 && i < (int)bl->args[wp].argv->sz)
1016 w = a2width(bl->args->argv[wp].value[i]);
1017 }
1018
1019 switch (type) {
1020 case (MDOC_Enum):
1021 /* FALLTHROUGH */
1022 case (MDOC_Dash):
1023 /* FALLTHROUGH */
1024 case (MDOC_Hyphen):
1025 /* FALLTHROUGH */
1026 case (MDOC_Bullet):
1027 if (w < 4)
1028 w = 4;
1029 break;
1030 case (MDOC_Inset):
1031 /* FALLTHROUGH */
1032 case (MDOC_Diag):
1033 w = 1;
1034 break;
1035 default:
1036 if (0 == w)
1037 w = 10;
1038 break;
1039 }
1040
1041 switch (n->type) {
1042 case (MDOC_BLOCK):
1043 break;
1044 case (MDOC_HEAD):
1045 return(mdoc_tbl_head_pre(m, n, h, type, w));
1046 case (MDOC_BODY):
1047 return(mdoc_tbl_body_pre(m, n, h, type, w));
1048 default:
1049 abort();
1050 /* NOTREACHED */
1051 }
1052
1053 return(mdoc_tbl_block_pre(m, n, h, type, w, o, c));
1054 }
1055
1056
1057 /* ARGSUSED */
1058 static int
1059 mdoc_bl_pre(MDOC_ARGS)
1060 {
1061 struct ord *ord;
1062
1063 if (MDOC_BLOCK != n->type)
1064 return(1);
1065 if (MDOC_Enum != a2list(n))
1066 return(1);
1067
1068 ord = malloc(sizeof(struct ord));
1069 if (NULL == ord)
1070 err(EXIT_FAILURE, "malloc");
1071 ord->cookie = n;
1072 ord->pos = 1;
1073 SLIST_INSERT_HEAD(&h->ords, ord, entry);
1074
1075 return(1);
1076 }
1077
1078
1079 /* ARGSUSED */
1080 static void
1081 mdoc_bl_post(MDOC_ARGS)
1082 {
1083 struct ord *ord;
1084
1085 if (MDOC_BLOCK != n->type)
1086 return;
1087 if (MDOC_Enum != a2list(n))
1088 return;
1089
1090 ord = SLIST_FIRST(&h->ords);
1091 assert(ord);
1092 SLIST_REMOVE_HEAD(&h->ords, entry);
1093 free(ord);
1094 }
1095
1096
1097 static int
1098 mdoc_it_pre(MDOC_ARGS)
1099 {
1100 int type;
1101
1102 if (MDOC_BLOCK == n->type)
1103 type = a2list(n->parent->parent);
1104 else
1105 type = a2list(n->parent->parent->parent);
1106
1107 return(mdoc_tbl_pre(m, n, h, type));
1108 }
1109
1110
1111 /* ARGSUSED */
1112 static int
1113 mdoc_ex_pre(MDOC_ARGS)
1114 {
1115 const struct mdoc_node *nn;
1116 struct tag *t;
1117 struct htmlpair tag;
1118
1119 print_text(h, "The");
1120
1121 tag.key = ATTR_CLASS;
1122 tag.val = "utility";
1123
1124 for (nn = n->child; nn; nn = nn->next) {
1125 t = print_otag(h, TAG_SPAN, 1, &tag);
1126 print_text(h, nn->string);
1127 print_tagq(h, t);
1128
1129 h->flags |= HTML_NOSPACE;
1130
1131 if (nn->next && NULL == nn->next->next)
1132 print_text(h, ", and");
1133 else if (nn->next)
1134 print_text(h, ",");
1135 else
1136 h->flags &= ~HTML_NOSPACE;
1137 }
1138
1139 if (n->child->next)
1140 print_text(h, "utilities exit");
1141 else
1142 print_text(h, "utility exits");
1143
1144 print_text(h, "0 on success, and >0 if an error occurs.");
1145 return(0);
1146 }
1147
1148
1149 /* ARGSUSED */
1150 static int
1151 mdoc_dq_pre(MDOC_ARGS)
1152 {
1153
1154 if (MDOC_BODY != n->type)
1155 return(1);
1156 print_text(h, "\\(lq");
1157 h->flags |= HTML_NOSPACE;
1158 return(1);
1159 }
1160
1161
1162 /* ARGSUSED */
1163 static void
1164 mdoc_dq_post(MDOC_ARGS)
1165 {
1166
1167 if (MDOC_BODY != n->type)
1168 return;
1169 h->flags |= HTML_NOSPACE;
1170 print_text(h, "\\(rq");
1171 }
1172
1173
1174 /* ARGSUSED */
1175 static int
1176 mdoc_pq_pre(MDOC_ARGS)
1177 {
1178
1179 if (MDOC_BODY != n->type)
1180 return(1);
1181 print_text(h, "\\&(");
1182 h->flags |= HTML_NOSPACE;
1183 return(1);
1184 }
1185
1186
1187 /* ARGSUSED */
1188 static void
1189 mdoc_pq_post(MDOC_ARGS)
1190 {
1191
1192 if (MDOC_BODY != n->type)
1193 return;
1194 print_text(h, ")");
1195 }
1196
1197
1198 /* ARGSUSED */
1199 static int
1200 mdoc_sq_pre(MDOC_ARGS)
1201 {
1202
1203 if (MDOC_BODY != n->type)
1204 return(1);
1205 print_text(h, "\\(oq");
1206 h->flags |= HTML_NOSPACE;
1207 return(1);
1208 }
1209
1210
1211 /* ARGSUSED */
1212 static void
1213 mdoc_sq_post(MDOC_ARGS)
1214 {
1215
1216 if (MDOC_BODY != n->type)
1217 return;
1218 h->flags |= HTML_NOSPACE;
1219 print_text(h, "\\(aq");
1220 }
1221
1222
1223 /* ARGSUSED */
1224 static int
1225 mdoc_em_pre(MDOC_ARGS)
1226 {
1227 struct htmlpair tag;
1228
1229 tag.key = ATTR_CLASS;
1230 tag.val = "emph";
1231
1232 print_otag(h, TAG_SPAN, 1, &tag);
1233 return(1);
1234 }
1235
1236
1237 /* ARGSUSED */
1238 static int
1239 mdoc_d1_pre(MDOC_ARGS)
1240 {
1241 struct htmlpair tag[2];
1242
1243 if (MDOC_BLOCK != n->type)
1244 return(1);
1245
1246 buffmt("margin-left: %dem;", INDENT);
1247
1248 tag[0].key = ATTR_CLASS;
1249 tag[0].val = "lit";
1250 tag[1].key = ATTR_STYLE;
1251 tag[1].val = buf;
1252
1253 print_otag(h, TAG_DIV, 2, tag);
1254 return(1);
1255 }
1256
1257
1258 /* ARGSUSED */
1259 static int
1260 mdoc_sx_pre(MDOC_ARGS)
1261 {
1262 struct htmlpair tag[2];
1263 const struct mdoc_node *nn;
1264
1265 bufcat("#");
1266 for (nn = n->child; nn; nn = nn->next) {
1267 bufcat(nn->string);
1268 if (nn->next)
1269 bufcat(" ");
1270 }
1271
1272 tag[0].key = ATTR_HREF;
1273 tag[0].val = buf;
1274 tag[1].key = ATTR_CLASS;
1275 tag[1].val = "link-sec";
1276
1277 print_otag(h, TAG_A, 2, tag);
1278 return(1);
1279 }
1280
1281
1282 /* ARGSUSED */
1283 static int
1284 mdoc_aq_pre(MDOC_ARGS)
1285 {
1286
1287 if (MDOC_BODY != n->type)
1288 return(1);
1289 print_text(h, "\\(la");
1290 h->flags |= HTML_NOSPACE;
1291 return(1);
1292 }
1293
1294
1295 /* ARGSUSED */
1296 static void
1297 mdoc_aq_post(MDOC_ARGS)
1298 {
1299
1300 if (MDOC_BODY != n->type)
1301 return;
1302 h->flags |= HTML_NOSPACE;
1303 print_text(h, "\\(ra");
1304 }
1305
1306
1307 /* ARGSUSED */
1308 static int
1309 mdoc_bd_pre(MDOC_ARGS)
1310 {
1311 struct htmlpair tag[2];
1312 int t, c, o, i;
1313 const struct mdoc_node *bl;
1314
1315 /* FIXME: fmt_vspace() shit. */
1316
1317 if (MDOC_BLOCK == n->type)
1318 bl = n;
1319 else if (MDOC_HEAD == n->type)
1320 return(0);
1321 else
1322 bl = n->parent;
1323
1324 t = o = c = 0;
1325
1326 for (i = 0; i < (int)bl->args->argc; i++)
1327 switch (bl->args->argv[i].arg) {
1328 case (MDOC_Offset):
1329 assert(bl->args->argv[i].sz);
1330 o = a2offs (bl->args->argv[i].value[0]);
1331 break;
1332 case (MDOC_Compact):
1333 c = 1;
1334 break;
1335 case (MDOC_Ragged):
1336 /* FALLTHROUGH */
1337 case (MDOC_Filled):
1338 /* FALLTHROUGH */
1339 case (MDOC_Unfilled):
1340 /* FALLTHROUGH */
1341 case (MDOC_Literal):
1342 t = bl->args->argv[i].arg;
1343 break;
1344 }
1345
1346 if (MDOC_BLOCK == n->type) {
1347 if (o)
1348 buffmt("margin-left: %dem;", o);
1349 bufcat("margin-top: 1em;");
1350 tag[0].key = ATTR_STYLE;
1351 tag[0].val = buf;
1352 print_otag(h, TAG_DIV, 1, tag);
1353 return(1);
1354 }
1355
1356 switch (t) {
1357 case (MDOC_Unfilled):
1358 case (MDOC_Literal):
1359 break;
1360 default:
1361 return(1);
1362 }
1363
1364 bufcat("white-space: pre;");
1365 tag[0].key = ATTR_STYLE;
1366 tag[0].val = buf;
1367 tag[1].key = ATTR_CLASS;
1368 tag[1].val = "lit";
1369
1370 print_otag(h, TAG_DIV, 2, tag);
1371
1372 for (n = n->child; n; n = n->next) {
1373 h->flags |= HTML_NOSPACE;
1374 print_mdoc_node(m, n, h);
1375 if (n->next)
1376 print_text(h, "\n");
1377 }
1378
1379 return(0);
1380 }
1381
1382
1383 /* ARGSUSED */
1384 static int
1385 mdoc_pa_pre(MDOC_ARGS)
1386 {
1387 struct htmlpair tag;
1388
1389 tag.key = ATTR_CLASS;
1390 tag.val = "file";
1391
1392 print_otag(h, TAG_SPAN, 1, &tag);
1393 return(1);
1394 }
1395
1396
1397 /* ARGSUSED */
1398 static int
1399 mdoc_ad_pre(MDOC_ARGS)
1400 {
1401 struct htmlpair tag;
1402
1403 tag.key = ATTR_CLASS;
1404 tag.val = "addr";
1405 print_otag(h, TAG_SPAN, 1, &tag);
1406 return(1);
1407 }
1408
1409
1410 /* ARGSUSED */
1411 static int
1412 mdoc_an_pre(MDOC_ARGS)
1413 {
1414 struct htmlpair tag;
1415
1416 tag.key = ATTR_CLASS;
1417 tag.val = "author";
1418 print_otag(h, TAG_SPAN, 1, &tag);
1419 return(1);
1420 }
1421
1422
1423 /* ARGSUSED */
1424 static int
1425 mdoc_cd_pre(MDOC_ARGS)
1426 {
1427 struct htmlpair tag;
1428
1429 tag.key = ATTR_CLASS;
1430 tag.val = "config";
1431 print_otag(h, TAG_SPAN, 1, &tag);
1432 return(1);
1433 }
1434
1435
1436 /* ARGSUSED */
1437 static int
1438 mdoc_dv_pre(MDOC_ARGS)
1439 {
1440 struct htmlpair tag;
1441
1442 tag.key = ATTR_CLASS;
1443 tag.val = "define";
1444 print_otag(h, TAG_SPAN, 1, &tag);
1445 return(1);
1446 }
1447
1448
1449 /* ARGSUSED */
1450 static int
1451 mdoc_ev_pre(MDOC_ARGS)
1452 {
1453 struct htmlpair tag;
1454
1455 tag.key = ATTR_CLASS;
1456 tag.val = "env";
1457 print_otag(h, TAG_SPAN, 1, &tag);
1458 return(1);
1459 }
1460
1461
1462 /* ARGSUSED */
1463 static int
1464 mdoc_er_pre(MDOC_ARGS)
1465 {
1466 struct htmlpair tag;
1467
1468 tag.key = ATTR_CLASS;
1469 tag.val = "errno";
1470 print_otag(h, TAG_SPAN, 1, &tag);
1471 return(1);
1472 }
1473
1474
1475 /* ARGSUSED */
1476 static int
1477 mdoc_fa_pre(MDOC_ARGS)
1478 {
1479 const struct mdoc_node *nn;
1480 struct htmlpair tag;
1481 struct tag *t;
1482
1483 tag.key = ATTR_CLASS;
1484 tag.val = "farg";
1485
1486 if (n->parent->tok != MDOC_Fo) {
1487 print_otag(h, TAG_SPAN, 1, &tag);
1488 return(1);
1489 }
1490
1491 for (nn = n->child; nn; nn = nn->next) {
1492 t = print_otag(h, TAG_SPAN, 1, &tag);
1493 print_text(h, nn->string);
1494 print_tagq(h, t);
1495 if (nn->next)
1496 print_text(h, ",");
1497 }
1498
1499 if (n->child && n->next && n->next->tok == MDOC_Fa)
1500 print_text(h, ",");
1501
1502 return(0);
1503 }
1504
1505
1506 /* ARGSUSED */
1507 static int
1508 mdoc_fd_pre(MDOC_ARGS)
1509 {
1510 struct htmlpair tag;
1511
1512 if (SEC_SYNOPSIS == n->sec) {
1513 if (n->next && MDOC_Fd != n->next->tok) {
1514 tag.key = ATTR_STYLE;
1515 tag.val = "margin-bottom: 1em;";
1516 print_otag(h, TAG_DIV, 1, &tag);
1517 } else
1518 print_otag(h, TAG_DIV, 0, NULL);
1519 }
1520
1521 tag.key = ATTR_CLASS;
1522 tag.val = "macro";
1523 print_otag(h, TAG_SPAN, 1, &tag);
1524 return(1);
1525 }
1526
1527
1528 /* ARGSUSED */
1529 static int
1530 mdoc_vt_pre(MDOC_ARGS)
1531 {
1532 struct htmlpair tag;
1533
1534 if (SEC_SYNOPSIS == n->sec) {
1535 if (n->next && MDOC_Vt != n->next->tok) {
1536 tag.key = ATTR_STYLE;
1537 tag.val = "margin-bottom: 1em;";
1538 print_otag(h, TAG_DIV, 1, &tag);
1539 } else
1540 print_otag(h, TAG_DIV, 0, NULL);
1541 }
1542
1543 tag.key = ATTR_CLASS;
1544 tag.val = "type";
1545 print_otag(h, TAG_SPAN, 1, &tag);
1546 return(1);
1547 }
1548
1549
1550 /* ARGSUSED */
1551 static int
1552 mdoc_ft_pre(MDOC_ARGS)
1553 {
1554 struct htmlpair tag;
1555
1556 if (SEC_SYNOPSIS == n->sec) {
1557 if (n->prev && MDOC_Fo == n->prev->tok) {
1558 tag.key = ATTR_STYLE;
1559 tag.val = "margin-top: 1em;";
1560 print_otag(h, TAG_DIV, 1, &tag);
1561 } else
1562 print_otag(h, TAG_DIV, 0, NULL);
1563 }
1564
1565 tag.key = ATTR_CLASS;
1566 tag.val = "ftype";
1567 print_otag(h, TAG_SPAN, 1, &tag);
1568 return(1);
1569 }
1570
1571
1572 /* ARGSUSED */
1573 static int
1574 mdoc_fn_pre(MDOC_ARGS)
1575 {
1576 struct tag *t;
1577 struct htmlpair tag;
1578 const struct mdoc_node *nn;
1579 char nbuf[BUFSIZ];
1580 const char *sp, *ep;
1581 int sz;
1582
1583 if (SEC_SYNOPSIS == n->sec) {
1584 if (n->next) {
1585 tag.key = ATTR_STYLE;
1586 tag.val = "margin-bottom: 1em";
1587 print_otag(h, TAG_DIV, 1, &tag);
1588 } else
1589 print_otag(h, TAG_DIV, 0, NULL);
1590 }
1591
1592 /* Split apart into type and name. */
1593
1594 tag.key = ATTR_CLASS;
1595 tag.val = "ftype";
1596 t = print_otag(h, TAG_SPAN, 1, &tag);
1597
1598 assert(n->child->string);
1599 sp = n->child->string;
1600 while (NULL != (ep = strchr(sp, ' '))) {
1601 sz = MIN((int)(ep - sp), BUFSIZ - 1);
1602 (void)memcpy(nbuf, sp, (size_t)sz);
1603 nbuf[sz] = '\0';
1604 print_text(h, nbuf);
1605 sp = ++ep;
1606 }
1607
1608 print_tagq(h, t);
1609
1610 tag.key = ATTR_CLASS;
1611 tag.val = "fname";
1612 t = print_otag(h, TAG_SPAN, 1, &tag);
1613
1614 if (sp) {
1615 (void)strlcpy(nbuf, sp, BUFSIZ);
1616 print_text(h, nbuf);
1617 }
1618
1619 print_tagq(h, t);
1620
1621 h->flags |= HTML_NOSPACE;
1622 print_text(h, "(");
1623
1624 for (nn = n->child->next; nn; nn = nn->next) {
1625 tag.key = ATTR_CLASS;
1626 tag.val = "farg";
1627 t = print_otag(h, TAG_SPAN, 1, &tag);
1628 print_text(h, nn->string);
1629 print_tagq(h, t);
1630 if (nn->next)
1631 print_text(h, ",");
1632 }
1633
1634 print_text(h, ")");
1635
1636 if (SEC_SYNOPSIS == n->sec)
1637 print_text(h, ";");
1638
1639 return(0);
1640 }
1641
1642
1643 /* ARGSUSED */
1644 static int
1645 mdoc_sp_pre(MDOC_ARGS)
1646 {
1647 int len;
1648 struct htmlpair tag;
1649
1650 switch (n->tok) {
1651 case (MDOC_sp):
1652 len = n->child ? atoi(n->child->string) : 1;
1653 break;
1654 case (MDOC_br):
1655 len = 0;
1656 break;
1657 default:
1658 len = 1;
1659 break;
1660 }
1661
1662 buffmt("height: %dem", len);
1663 tag.key = ATTR_STYLE;
1664 tag.val = buf;
1665 print_otag(h, TAG_DIV, 1, &tag);
1666 return(1);
1667
1668 }
1669
1670
1671 /* ARGSUSED */
1672 static int
1673 mdoc_brq_pre(MDOC_ARGS)
1674 {
1675
1676 if (MDOC_BODY != n->type)
1677 return(1);
1678 print_text(h, "\\(lC");
1679 h->flags |= HTML_NOSPACE;
1680 return(1);
1681 }
1682
1683
1684 /* ARGSUSED */
1685 static void
1686 mdoc_brq_post(MDOC_ARGS)
1687 {
1688
1689 if (MDOC_BODY != n->type)
1690 return;
1691 h->flags |= HTML_NOSPACE;
1692 print_text(h, "\\(rC");
1693 }
1694
1695
1696 /* ARGSUSED */
1697 static int
1698 mdoc_lk_pre(MDOC_ARGS)
1699 {
1700 const struct mdoc_node *nn;
1701 struct htmlpair tag[2];
1702
1703 nn = n->child;
1704
1705 tag[0].key = ATTR_CLASS;
1706 tag[0].val = "link-ext";
1707 tag[1].key = ATTR_HREF;
1708 tag[1].val = nn->string;
1709
1710 print_otag(h, TAG_A, 2, tag);
1711
1712 if (NULL == nn->next)
1713 return(1);
1714
1715 for (nn = nn->next; nn; nn = nn->next)
1716 print_text(h, nn->string);
1717
1718 return(0);
1719 }
1720
1721
1722 /* ARGSUSED */
1723 static int
1724 mdoc_mt_pre(MDOC_ARGS)
1725 {
1726 struct htmlpair tag[2];
1727 struct tag *t;
1728 const struct mdoc_node *nn;
1729
1730 tag[0].key = ATTR_CLASS;
1731 tag[0].val = "link-mail";
1732
1733 for (nn = n->child; nn; nn = nn->next) {
1734 bufinit();
1735 bufcat("mailto:");
1736 bufcat(nn->string);
1737
1738 tag[1].key = ATTR_HREF;
1739 tag[1].val = buf;
1740
1741 t = print_otag(h, TAG_A, 2, tag);
1742 print_text(h, nn->string);
1743 print_tagq(h, t);
1744 }
1745
1746 return(0);
1747 }
1748
1749
1750 /* ARGSUSED */
1751 static int
1752 mdoc_fo_pre(MDOC_ARGS)
1753 {
1754 struct htmlpair tag;
1755
1756 if (MDOC_BODY == n->type) {
1757 h->flags |= HTML_NOSPACE;
1758 print_text(h, "(");
1759 h->flags |= HTML_NOSPACE;
1760 return(1);
1761 } else if (MDOC_BLOCK == n->type)
1762 return(1);
1763
1764 tag.key = ATTR_CLASS;
1765 tag.val = "fname";
1766 print_otag(h, TAG_SPAN, 1, &tag);
1767 return(1);
1768 }
1769
1770
1771 /* ARGSUSED */
1772 static void
1773 mdoc_fo_post(MDOC_ARGS)
1774 {
1775 if (MDOC_BODY != n->type)
1776 return;
1777 h->flags |= HTML_NOSPACE;
1778 print_text(h, ")");
1779 h->flags |= HTML_NOSPACE;
1780 print_text(h, ";");
1781 }
1782
1783
1784 /* ARGSUSED */
1785 static int
1786 mdoc_in_pre(MDOC_ARGS)
1787 {
1788 const struct mdoc_node *nn;
1789 struct htmlpair tag;
1790
1791 if (SEC_SYNOPSIS == n->sec) {
1792 if (n->next && MDOC_In != n->next->tok) {
1793 tag.key = ATTR_STYLE;
1794 tag.val = "margin-bottom: 1em;";
1795 print_otag(h, TAG_DIV, 1, &tag);
1796 } else
1797 print_otag(h, TAG_DIV, 0, NULL);
1798 }
1799
1800 tag.key = ATTR_CLASS;
1801 tag.val = "includes";
1802
1803 print_otag(h, TAG_SPAN, 1, &tag);
1804
1805 if (SEC_SYNOPSIS == n->sec)
1806 print_text(h, "#include");
1807
1808 print_text(h, "<");
1809 h->flags |= HTML_NOSPACE;
1810
1811 /* XXX -- see warning in termp_in_post(). */
1812
1813 for (nn = n->child; nn; nn = nn->next)
1814 print_mdoc_node(m, nn, h);
1815
1816 h->flags |= HTML_NOSPACE;
1817 print_text(h, ">");
1818
1819 return(0);
1820 }
1821
1822
1823 /* ARGSUSED */
1824 static int
1825 mdoc_ic_pre(MDOC_ARGS)
1826 {
1827 struct htmlpair tag;
1828
1829 tag.key = ATTR_CLASS;
1830 tag.val = "cmd";
1831
1832 print_otag(h, TAG_SPAN, 1, &tag);
1833 return(1);
1834 }
1835
1836
1837 /* ARGSUSED */
1838 static int
1839 mdoc_rv_pre(MDOC_ARGS)
1840 {
1841 const struct mdoc_node *nn;
1842 struct htmlpair tag;
1843 struct tag *t;
1844
1845 print_otag(h, TAG_DIV, 0, NULL);
1846
1847 print_text(h, "The");
1848
1849 for (nn = n->child; nn; nn = nn->next) {
1850 tag.key = ATTR_CLASS;
1851 tag.val = "fname";
1852 t = print_otag(h, TAG_SPAN, 1, &tag);
1853 print_text(h, nn->string);
1854 print_tagq(h, t);
1855
1856 h->flags |= HTML_NOSPACE;
1857 if (nn->next && NULL == nn->next->next)
1858 print_text(h, "(), and");
1859 else if (nn->next)
1860 print_text(h, "(),");
1861 else
1862 print_text(h, "()");
1863 }
1864
1865 if (n->child->next)
1866 print_text(h, "functions return");
1867 else
1868 print_text(h, "function returns");
1869
1870 print_text(h, "the value 0 if successful; otherwise the value "
1871 "-1 is returned and the global variable");
1872
1873 tag.key = ATTR_CLASS;
1874 tag.val = "var";
1875 t = print_otag(h, TAG_SPAN, 1, &tag);
1876 print_text(h, "errno");
1877 print_tagq(h, t);
1878 print_text(h, "is set to indicate the error.");
1879 return(0);
1880 }
1881
1882
1883 /* ARGSUSED */
1884 static int
1885 mdoc_va_pre(MDOC_ARGS)
1886 {
1887 struct htmlpair tag;
1888
1889 tag.key = ATTR_CLASS;
1890 tag.val = "var";
1891 print_otag(h, TAG_SPAN, 1, &tag);
1892 return(1);
1893 }
1894
1895
1896 /* ARGSUSED */
1897 static int
1898 mdoc_bq_pre(MDOC_ARGS)
1899 {
1900
1901 if (MDOC_BODY != n->type)
1902 return(1);
1903 print_text(h, "\\(lB");
1904 h->flags |= HTML_NOSPACE;
1905 return(1);
1906 }
1907
1908
1909 /* ARGSUSED */
1910 static void
1911 mdoc_bq_post(MDOC_ARGS)
1912 {
1913
1914 if (MDOC_BODY != n->type)
1915 return;
1916 h->flags |= HTML_NOSPACE;
1917 print_text(h, "\\(rB");
1918 }
1919
1920
1921 /* ARGSUSED */
1922 static int
1923 mdoc_ap_pre(MDOC_ARGS)
1924 {
1925
1926 h->flags |= HTML_NOSPACE;
1927 print_text(h, "\\(aq");
1928 h->flags |= HTML_NOSPACE;
1929 return(1);
1930 }
1931
1932
1933 /* ARGSUSED */
1934 static int
1935 mdoc_bf_pre(MDOC_ARGS)
1936 {
1937 int i;
1938 struct htmlpair tag[2];
1939
1940 if (MDOC_HEAD == n->type)
1941 return(0);
1942 else if (MDOC_BLOCK != n->type)
1943 return(1);
1944
1945 tag[0].key = ATTR_CLASS;
1946 tag[0].val = NULL;
1947
1948 if (n->head->child) {
1949 if ( ! strcmp("Em", n->head->child->string))
1950 tag[0].val = "emph";
1951 else if ( ! strcmp("Sy", n->head->child->string))
1952 tag[0].val = "symb";
1953 else if ( ! strcmp("Li", n->head->child->string))
1954 tag[0].val = "lit";
1955 } else {
1956 assert(n->args);
1957 for (i = 0; i < (int)n->args->argc; i++)
1958 switch (n->args->argv[i].arg) {
1959 case (MDOC_Symbolic):
1960 tag[0].val = "symb";
1961 break;
1962 case (MDOC_Literal):
1963 tag[0].val = "lit";
1964 break;
1965 case (MDOC_Emphasis):
1966 tag[0].val = "emph";
1967 break;
1968 default:
1969 break;
1970 }
1971 }
1972
1973 /* FIXME: div's have spaces stripped--we want them. */
1974
1975 assert(tag[0].val);
1976 tag[1].key = ATTR_STYLE;
1977 tag[1].val = "display: inline; margin-right: 1em;";
1978 print_otag(h, TAG_DIV, 2, tag);
1979 return(1);
1980 }
1981
1982
1983 /* ARGSUSED */
1984 static int
1985 mdoc_ms_pre(MDOC_ARGS)
1986 {
1987 struct htmlpair tag;
1988
1989 tag.key = ATTR_CLASS;
1990 tag.val = "symb";
1991 print_otag(h, TAG_SPAN, 1, &tag);
1992 return(1);
1993 }
1994
1995
1996 /* ARGSUSED */
1997 static int
1998 mdoc_pf_pre(MDOC_ARGS)
1999 {
2000
2001 h->flags |= HTML_IGNDELIM;
2002 return(1);
2003 }
2004
2005
2006 /* ARGSUSED */
2007 static void
2008 mdoc_pf_post(MDOC_ARGS)
2009 {
2010
2011 h->flags &= ~HTML_IGNDELIM;
2012 h->flags |= HTML_NOSPACE;
2013 }
2014
2015
2016 /* ARGSUSED */
2017 static int
2018 mdoc_rs_pre(MDOC_ARGS)
2019 {
2020 struct htmlpair tag;
2021
2022 if (MDOC_BLOCK != n->type)
2023 return(1);
2024
2025 if (n->prev && SEC_SEE_ALSO == n->sec) {
2026 tag.key = ATTR_STYLE;
2027 tag.val = "margin-top: 1em;";
2028 print_otag(h, TAG_DIV, 1, &tag);
2029 }
2030
2031 tag.key = ATTR_CLASS;
2032 tag.val = "ref";
2033 print_otag(h, TAG_SPAN, 1, &tag);
2034 return(1);
2035 }
2036
2037
2038
2039 /* ARGSUSED */
2040 static int
2041 mdoc_li_pre(MDOC_ARGS)
2042 {
2043 struct htmlpair tag;
2044
2045 tag.key = ATTR_CLASS;
2046 tag.val = "lit";
2047
2048 print_otag(h, TAG_SPAN, 1, &tag);
2049 return(1);
2050 }
2051
2052
2053 /* ARGSUSED */
2054 static int
2055 mdoc_sy_pre(MDOC_ARGS)
2056 {
2057 struct htmlpair tag;
2058
2059 tag.key = ATTR_CLASS;
2060 tag.val = "symb";
2061
2062 print_otag(h, TAG_SPAN, 1, &tag);
2063 return(1);
2064 }
2065
2066
2067 /* ARGSUSED */
2068 static int
2069 mdoc_bt_pre(MDOC_ARGS)
2070 {
2071
2072 print_text(h, "is currently in beta test.");
2073 return(0);
2074 }
2075
2076
2077 /* ARGSUSED */
2078 static int
2079 mdoc_ud_pre(MDOC_ARGS)
2080 {
2081
2082 print_text(h, "currently under development.");
2083 return(0);
2084 }
2085
2086
2087 /* ARGSUSED */
2088 static int
2089 mdoc_lb_pre(MDOC_ARGS)
2090 {
2091 struct htmlpair tag;
2092
2093 tag.key = ATTR_CLASS;
2094 tag.val = "lib";
2095
2096 if (SEC_SYNOPSIS == n->sec)
2097 print_otag(h, TAG_DIV, 0, NULL);
2098
2099 print_otag(h, TAG_SPAN, 1, &tag);
2100 return(1);
2101 }
2102
2103
2104 /* ARGSUSED */
2105 static int
2106 mdoc__x_pre(MDOC_ARGS)
2107 {
2108 struct htmlpair tag;
2109
2110 tag.key = ATTR_CLASS;
2111
2112 switch (n->tok) {
2113 case(MDOC__A):
2114 tag.val = "ref-auth";
2115 break;
2116 case(MDOC__B):
2117 tag.val = "ref-book";
2118 break;
2119 case(MDOC__C):
2120 tag.val = "ref-city";
2121 break;
2122 case(MDOC__D):
2123 tag.val = "ref-date";
2124 break;
2125 case(MDOC__I):
2126 tag.val = "ref-issue";
2127 break;
2128 case(MDOC__J):
2129 tag.val = "ref-jrnl";
2130 break;
2131 case(MDOC__N):
2132 tag.val = "ref-num";
2133 break;
2134 case(MDOC__O):
2135 tag.val = "ref-opt";
2136 break;
2137 case(MDOC__P):
2138 tag.val = "ref-page";
2139 break;
2140 case(MDOC__Q):
2141 tag.val = "ref-corp";
2142 break;
2143 case(MDOC__R):
2144 tag.val = "ref-rep";
2145 break;
2146 case(MDOC__T):
2147 print_text(h, "\\(lq");
2148 h->flags |= HTML_NOSPACE;
2149 tag.val = "ref-title";
2150 break;
2151 case(MDOC__V):
2152 tag.val = "ref-vol";
2153 break;
2154 default:
2155 abort();
2156 /* NOTREACHED */
2157 }
2158
2159 print_otag(h, TAG_SPAN, 1, &tag);
2160 return(1);
2161 }
2162
2163
2164 /* ARGSUSED */
2165 static void
2166 mdoc__x_post(MDOC_ARGS)
2167 {
2168
2169 h->flags |= HTML_NOSPACE;
2170 switch (n->tok) {
2171 case (MDOC__T):
2172 print_text(h, "\\(rq");
2173 h->flags |= HTML_NOSPACE;
2174 break;
2175 default:
2176 break;
2177 }
2178 print_text(h, n->next ? "," : ".");
2179 }