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