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