]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_html.c
Churny commit to quiet lint. No functional changes.
[mandoc.git] / mdoc_html.c
1 /* $Id: mdoc_html.c,v 1.104 2010/09/04 20:18:53 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010 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 "mdoc.h"
34 #include "main.h"
35
36 #define INDENT 5
37 #define HALFINDENT 3
38
39 #define MDOC_ARGS const struct mdoc_meta *m, \
40 const struct mdoc_node *n, \
41 struct html *h
42
43 #ifndef MIN
44 #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
45 #endif
46
47 struct htmlmdoc {
48 int (*pre)(MDOC_ARGS);
49 void (*post)(MDOC_ARGS);
50 };
51
52 static void print_mdoc(MDOC_ARGS);
53 static void print_mdoc_head(MDOC_ARGS);
54 static void print_mdoc_node(MDOC_ARGS);
55 static void print_mdoc_nodelist(MDOC_ARGS);
56 static void synopsis_pre(struct html *,
57 const struct mdoc_node *);
58
59 static void a2width(const char *, struct roffsu *);
60 static void a2offs(const char *, struct roffsu *);
61
62 static void mdoc_root_post(MDOC_ARGS);
63 static int mdoc_root_pre(MDOC_ARGS);
64
65 static void mdoc__x_post(MDOC_ARGS);
66 static int mdoc__x_pre(MDOC_ARGS);
67 static int mdoc_ad_pre(MDOC_ARGS);
68 static int mdoc_an_pre(MDOC_ARGS);
69 static int mdoc_ap_pre(MDOC_ARGS);
70 static void mdoc_aq_post(MDOC_ARGS);
71 static int mdoc_aq_pre(MDOC_ARGS);
72 static int mdoc_ar_pre(MDOC_ARGS);
73 static int mdoc_bd_pre(MDOC_ARGS);
74 static int mdoc_bf_pre(MDOC_ARGS);
75 static void mdoc_bk_post(MDOC_ARGS);
76 static int mdoc_bk_pre(MDOC_ARGS);
77 static void mdoc_bl_post(MDOC_ARGS);
78 static int mdoc_bl_pre(MDOC_ARGS);
79 static void mdoc_bq_post(MDOC_ARGS);
80 static int mdoc_bq_pre(MDOC_ARGS);
81 static void mdoc_brq_post(MDOC_ARGS);
82 static int mdoc_brq_pre(MDOC_ARGS);
83 static int mdoc_bt_pre(MDOC_ARGS);
84 static int mdoc_bx_pre(MDOC_ARGS);
85 static int mdoc_cd_pre(MDOC_ARGS);
86 static int mdoc_d1_pre(MDOC_ARGS);
87 static void mdoc_dq_post(MDOC_ARGS);
88 static int mdoc_dq_pre(MDOC_ARGS);
89 static int mdoc_dv_pre(MDOC_ARGS);
90 static int mdoc_fa_pre(MDOC_ARGS);
91 static int mdoc_fd_pre(MDOC_ARGS);
92 static int mdoc_fl_pre(MDOC_ARGS);
93 static int mdoc_fn_pre(MDOC_ARGS);
94 static int mdoc_ft_pre(MDOC_ARGS);
95 static int mdoc_em_pre(MDOC_ARGS);
96 static int mdoc_er_pre(MDOC_ARGS);
97 static int mdoc_ev_pre(MDOC_ARGS);
98 static int mdoc_ex_pre(MDOC_ARGS);
99 static void mdoc_fo_post(MDOC_ARGS);
100 static int mdoc_fo_pre(MDOC_ARGS);
101 static int mdoc_ic_pre(MDOC_ARGS);
102 static int mdoc_in_pre(MDOC_ARGS);
103 static int mdoc_it_block_pre(MDOC_ARGS, enum mdoc_list,
104 int, struct roffsu *, struct roffsu *);
105 static int mdoc_it_head_pre(MDOC_ARGS, enum mdoc_list,
106 struct roffsu *);
107 static int mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list,
108 struct roffsu *);
109 static int mdoc_it_pre(MDOC_ARGS);
110 static int mdoc_lb_pre(MDOC_ARGS);
111 static int mdoc_li_pre(MDOC_ARGS);
112 static int mdoc_lk_pre(MDOC_ARGS);
113 static int mdoc_mt_pre(MDOC_ARGS);
114 static int mdoc_ms_pre(MDOC_ARGS);
115 static int mdoc_nd_pre(MDOC_ARGS);
116 static int mdoc_nm_pre(MDOC_ARGS);
117 static int mdoc_ns_pre(MDOC_ARGS);
118 static void mdoc_op_post(MDOC_ARGS);
119 static int mdoc_op_pre(MDOC_ARGS);
120 static int mdoc_pa_pre(MDOC_ARGS);
121 static void mdoc_pf_post(MDOC_ARGS);
122 static int mdoc_pf_pre(MDOC_ARGS);
123 static void mdoc_pq_post(MDOC_ARGS);
124 static int mdoc_pq_pre(MDOC_ARGS);
125 static int mdoc_rs_pre(MDOC_ARGS);
126 static int mdoc_rv_pre(MDOC_ARGS);
127 static int mdoc_sh_pre(MDOC_ARGS);
128 static int mdoc_sm_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 */
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 {mdoc_sm_pre, NULL}, /* Sm */
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((int)MANDOCLEVEL_SYSERR);
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 print_mdoc_node(m, nn, h);
1461 if (nn->next && nn->next->line == nn->line)
1462 continue;
1463 print_text(h, "\n");
1464 h->flags |= HTML_NOSPACE;
1465 }
1466
1467 return(0);
1468 }
1469
1470
1471 /* ARGSUSED */
1472 static int
1473 mdoc_pa_pre(MDOC_ARGS)
1474 {
1475 struct htmlpair tag;
1476
1477 PAIR_CLASS_INIT(&tag, "file");
1478 print_otag(h, TAG_SPAN, 1, &tag);
1479 return(1);
1480 }
1481
1482
1483 /* ARGSUSED */
1484 static int
1485 mdoc_ad_pre(MDOC_ARGS)
1486 {
1487 struct htmlpair tag;
1488
1489 PAIR_CLASS_INIT(&tag, "addr");
1490 print_otag(h, TAG_SPAN, 1, &tag);
1491 return(1);
1492 }
1493
1494
1495 /* ARGSUSED */
1496 static int
1497 mdoc_an_pre(MDOC_ARGS)
1498 {
1499 struct htmlpair tag;
1500
1501 /* TODO: -split and -nosplit (see termp_an_pre()). */
1502
1503 PAIR_CLASS_INIT(&tag, "author");
1504 print_otag(h, TAG_SPAN, 1, &tag);
1505 return(1);
1506 }
1507
1508
1509 /* ARGSUSED */
1510 static int
1511 mdoc_cd_pre(MDOC_ARGS)
1512 {
1513 struct htmlpair tag;
1514
1515 synopsis_pre(h, n);
1516 PAIR_CLASS_INIT(&tag, "config");
1517 print_otag(h, TAG_SPAN, 1, &tag);
1518 return(1);
1519 }
1520
1521
1522 /* ARGSUSED */
1523 static int
1524 mdoc_dv_pre(MDOC_ARGS)
1525 {
1526 struct htmlpair tag;
1527
1528 PAIR_CLASS_INIT(&tag, "define");
1529 print_otag(h, TAG_SPAN, 1, &tag);
1530 return(1);
1531 }
1532
1533
1534 /* ARGSUSED */
1535 static int
1536 mdoc_ev_pre(MDOC_ARGS)
1537 {
1538 struct htmlpair tag;
1539
1540 PAIR_CLASS_INIT(&tag, "env");
1541 print_otag(h, TAG_SPAN, 1, &tag);
1542 return(1);
1543 }
1544
1545
1546 /* ARGSUSED */
1547 static int
1548 mdoc_er_pre(MDOC_ARGS)
1549 {
1550 struct htmlpair tag;
1551
1552 PAIR_CLASS_INIT(&tag, "errno");
1553 print_otag(h, TAG_SPAN, 1, &tag);
1554 return(1);
1555 }
1556
1557
1558 /* ARGSUSED */
1559 static int
1560 mdoc_fa_pre(MDOC_ARGS)
1561 {
1562 const struct mdoc_node *nn;
1563 struct htmlpair tag;
1564 struct tag *t;
1565
1566 PAIR_CLASS_INIT(&tag, "farg");
1567 if (n->parent->tok != MDOC_Fo) {
1568 print_otag(h, TAG_SPAN, 1, &tag);
1569 return(1);
1570 }
1571
1572 for (nn = n->child; nn; nn = nn->next) {
1573 t = print_otag(h, TAG_SPAN, 1, &tag);
1574 print_text(h, nn->string);
1575 print_tagq(h, t);
1576 if (nn->next)
1577 print_text(h, ",");
1578 }
1579
1580 if (n->child && n->next && n->next->tok == MDOC_Fa)
1581 print_text(h, ",");
1582
1583 return(0);
1584 }
1585
1586
1587 /* ARGSUSED */
1588 static int
1589 mdoc_fd_pre(MDOC_ARGS)
1590 {
1591 struct htmlpair tag;
1592
1593 synopsis_pre(h, n);
1594
1595 PAIR_CLASS_INIT(&tag, "macro");
1596 print_otag(h, TAG_SPAN, 1, &tag);
1597 return(1);
1598 }
1599
1600
1601 /* ARGSUSED */
1602 static int
1603 mdoc_vt_pre(MDOC_ARGS)
1604 {
1605 struct htmlpair tag;
1606
1607 if (MDOC_BLOCK == n->type) {
1608 synopsis_pre(h, n);
1609 return(1);
1610 } else if (MDOC_ELEM == n->type) {
1611 synopsis_pre(h, n);
1612 } else if (MDOC_HEAD == n->type)
1613 return(0);
1614
1615 PAIR_CLASS_INIT(&tag, "type");
1616 print_otag(h, TAG_SPAN, 1, &tag);
1617 return(1);
1618 }
1619
1620
1621 /* ARGSUSED */
1622 static int
1623 mdoc_ft_pre(MDOC_ARGS)
1624 {
1625 struct htmlpair tag;
1626
1627 synopsis_pre(h, n);
1628 PAIR_CLASS_INIT(&tag, "ftype");
1629 print_otag(h, TAG_SPAN, 1, &tag);
1630 return(1);
1631 }
1632
1633
1634 /* ARGSUSED */
1635 static int
1636 mdoc_fn_pre(MDOC_ARGS)
1637 {
1638 struct tag *t;
1639 struct htmlpair tag[2];
1640 const struct mdoc_node *nn;
1641 char nbuf[BUFSIZ];
1642 const char *sp, *ep;
1643 int sz, i;
1644
1645 synopsis_pre(h, n);
1646
1647 /* Split apart into type and name. */
1648 assert(n->child->string);
1649 sp = n->child->string;
1650
1651 ep = strchr(sp, ' ');
1652 if (NULL != ep) {
1653 PAIR_CLASS_INIT(&tag[0], "ftype");
1654 t = print_otag(h, TAG_SPAN, 1, tag);
1655
1656 while (ep) {
1657 sz = MIN((int)(ep - sp), BUFSIZ - 1);
1658 (void)memcpy(nbuf, sp, (size_t)sz);
1659 nbuf[sz] = '\0';
1660 print_text(h, nbuf);
1661 sp = ++ep;
1662 ep = strchr(sp, ' ');
1663 }
1664 print_tagq(h, t);
1665 }
1666
1667 PAIR_CLASS_INIT(&tag[0], "fname");
1668
1669 /*
1670 * FIXME: only refer to IDs that we know exist.
1671 */
1672
1673 #if 0
1674 if (MDOC_SYNPRETTY & n->flags) {
1675 nbuf[0] = '\0';
1676 html_idcat(nbuf, sp, BUFSIZ);
1677 PAIR_ID_INIT(&tag[1], nbuf);
1678 } else {
1679 strlcpy(nbuf, "#", BUFSIZ);
1680 html_idcat(nbuf, sp, BUFSIZ);
1681 PAIR_HREF_INIT(&tag[1], nbuf);
1682 }
1683 #endif
1684
1685 t = print_otag(h, TAG_SPAN, 1, tag);
1686
1687 if (sp) {
1688 strlcpy(nbuf, sp, BUFSIZ);
1689 print_text(h, nbuf);
1690 }
1691
1692 print_tagq(h, t);
1693
1694 h->flags |= HTML_NOSPACE;
1695 print_text(h, "(");
1696
1697 bufinit(h);
1698 PAIR_CLASS_INIT(&tag[0], "farg");
1699 bufcat_style(h, "white-space", "nowrap");
1700 PAIR_STYLE_INIT(&tag[1], h);
1701
1702 for (nn = n->child->next; nn; nn = nn->next) {
1703 i = 1;
1704 if (MDOC_SYNPRETTY & n->flags)
1705 i = 2;
1706 t = print_otag(h, TAG_SPAN, i, tag);
1707 print_text(h, nn->string);
1708 print_tagq(h, t);
1709 if (nn->next)
1710 print_text(h, ",");
1711 }
1712
1713 print_text(h, ")");
1714 if (MDOC_SYNPRETTY & n->flags)
1715 print_text(h, ";");
1716
1717 return(0);
1718 }
1719
1720
1721 /* ARGSUSED */
1722 static int
1723 mdoc_sm_pre(MDOC_ARGS)
1724 {
1725
1726 assert(n->child && MDOC_TEXT == n->child->type);
1727 if (0 == strcmp("on", n->child->string)) {
1728 /* FIXME: no p->col to check... */
1729 h->flags &= ~HTML_NOSPACE;
1730 h->flags &= ~HTML_NONOSPACE;
1731 } else
1732 h->flags |= HTML_NONOSPACE;
1733
1734 return(0);
1735 }
1736
1737
1738 /* ARGSUSED */
1739 static int
1740 mdoc_sp_pre(MDOC_ARGS)
1741 {
1742 int len;
1743 struct htmlpair tag;
1744 struct roffsu su;
1745
1746 switch (n->tok) {
1747 case (MDOC_sp):
1748 /* FIXME: can this have a scaling indicator? */
1749 len = n->child ? atoi(n->child->string) : 1;
1750 break;
1751 case (MDOC_br):
1752 len = 0;
1753 break;
1754 default:
1755 assert(n->parent);
1756 if ((NULL == n->next || NULL == n->prev) &&
1757 (MDOC_Ss == n->parent->tok ||
1758 MDOC_Sh == n->parent->tok))
1759 return(0);
1760 len = 1;
1761 break;
1762 }
1763
1764 SCALE_VS_INIT(&su, len);
1765 bufcat_su(h, "height", &su);
1766 PAIR_STYLE_INIT(&tag, h);
1767 print_otag(h, TAG_DIV, 1, &tag);
1768 /* So the div isn't empty: */
1769 print_text(h, "\\~");
1770
1771 return(0);
1772
1773 }
1774
1775
1776 /* ARGSUSED */
1777 static int
1778 mdoc_brq_pre(MDOC_ARGS)
1779 {
1780
1781 if (MDOC_BODY != n->type)
1782 return(1);
1783 print_text(h, "\\(lC");
1784 h->flags |= HTML_NOSPACE;
1785 return(1);
1786 }
1787
1788
1789 /* ARGSUSED */
1790 static void
1791 mdoc_brq_post(MDOC_ARGS)
1792 {
1793
1794 if (MDOC_BODY != n->type)
1795 return;
1796 h->flags |= HTML_NOSPACE;
1797 print_text(h, "\\(rC");
1798 }
1799
1800
1801 /* ARGSUSED */
1802 static int
1803 mdoc_lk_pre(MDOC_ARGS)
1804 {
1805 const struct mdoc_node *nn;
1806 struct htmlpair tag[2];
1807
1808 nn = n->child;
1809
1810 PAIR_CLASS_INIT(&tag[0], "link-ext");
1811 PAIR_HREF_INIT(&tag[1], nn->string);
1812 print_otag(h, TAG_A, 2, tag);
1813
1814 if (NULL == nn->next)
1815 return(1);
1816
1817 for (nn = nn->next; nn; nn = nn->next)
1818 print_text(h, nn->string);
1819
1820 return(0);
1821 }
1822
1823
1824 /* ARGSUSED */
1825 static int
1826 mdoc_mt_pre(MDOC_ARGS)
1827 {
1828 struct htmlpair tag[2];
1829 struct tag *t;
1830 const struct mdoc_node *nn;
1831
1832 PAIR_CLASS_INIT(&tag[0], "link-mail");
1833
1834 for (nn = n->child; nn; nn = nn->next) {
1835 bufinit(h);
1836 bufcat(h, "mailto:");
1837 bufcat(h, nn->string);
1838 PAIR_HREF_INIT(&tag[1], h->buf);
1839 t = print_otag(h, TAG_A, 2, tag);
1840 print_text(h, nn->string);
1841 print_tagq(h, t);
1842 }
1843
1844 return(0);
1845 }
1846
1847
1848 /* ARGSUSED */
1849 static int
1850 mdoc_fo_pre(MDOC_ARGS)
1851 {
1852 struct htmlpair tag;
1853 struct tag *t;
1854
1855 if (MDOC_BODY == n->type) {
1856 h->flags |= HTML_NOSPACE;
1857 print_text(h, "(");
1858 h->flags |= HTML_NOSPACE;
1859 return(1);
1860 } else if (MDOC_BLOCK == n->type) {
1861 synopsis_pre(h, n);
1862 return(1);
1863 }
1864
1865 /* XXX: we drop non-initial arguments as per groff. */
1866
1867 assert(n->child);
1868 assert(n->child->string);
1869
1870 PAIR_CLASS_INIT(&tag, "fname");
1871 t = print_otag(h, TAG_SPAN, 1, &tag);
1872 print_text(h, n->child->string);
1873 print_tagq(h, t);
1874 return(0);
1875 }
1876
1877
1878 /* ARGSUSED */
1879 static void
1880 mdoc_fo_post(MDOC_ARGS)
1881 {
1882
1883 if (MDOC_BODY != n->type)
1884 return;
1885 h->flags |= HTML_NOSPACE;
1886 print_text(h, ")");
1887 h->flags |= HTML_NOSPACE;
1888 print_text(h, ";");
1889 }
1890
1891
1892 /* ARGSUSED */
1893 static int
1894 mdoc_in_pre(MDOC_ARGS)
1895 {
1896 const struct mdoc_node *nn;
1897 struct tag *t;
1898 struct htmlpair tag[2];
1899 int i;
1900
1901 synopsis_pre(h, n);
1902
1903 PAIR_CLASS_INIT(&tag[0], "includes");
1904 print_otag(h, TAG_SPAN, 1, tag);
1905
1906 if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags)
1907 print_text(h, "#include");
1908
1909 print_text(h, "<");
1910 h->flags |= HTML_NOSPACE;
1911
1912 for (nn = n->child; nn; nn = nn->next) {
1913 PAIR_CLASS_INIT(&tag[0], "link-includes");
1914 i = 1;
1915 bufinit(h);
1916 if (h->base_includes) {
1917 buffmt_includes(h, nn->string);
1918 PAIR_HREF_INIT(&tag[i], h->buf);
1919 i++;
1920 }
1921 t = print_otag(h, TAG_A, i, tag);
1922 print_mdoc_node(m, nn, h);
1923 print_tagq(h, t);
1924 }
1925
1926 h->flags |= HTML_NOSPACE;
1927 print_text(h, ">");
1928
1929 return(0);
1930 }
1931
1932
1933 /* ARGSUSED */
1934 static int
1935 mdoc_ic_pre(MDOC_ARGS)
1936 {
1937 struct htmlpair tag;
1938
1939 PAIR_CLASS_INIT(&tag, "cmd");
1940 print_otag(h, TAG_SPAN, 1, &tag);
1941 return(1);
1942 }
1943
1944
1945 /* ARGSUSED */
1946 static int
1947 mdoc_rv_pre(MDOC_ARGS)
1948 {
1949 const struct mdoc_node *nn;
1950 struct htmlpair tag;
1951 struct tag *t;
1952
1953 print_otag(h, TAG_DIV, 0, NULL);
1954 print_text(h, "The");
1955
1956 for (nn = n->child; nn; nn = nn->next) {
1957 PAIR_CLASS_INIT(&tag, "fname");
1958 t = print_otag(h, TAG_SPAN, 1, &tag);
1959 print_text(h, nn->string);
1960 print_tagq(h, t);
1961
1962 h->flags |= HTML_NOSPACE;
1963 if (nn->next && NULL == nn->next->next)
1964 print_text(h, "(), and");
1965 else if (nn->next)
1966 print_text(h, "(),");
1967 else
1968 print_text(h, "()");
1969 }
1970
1971 if (n->child && n->child->next)
1972 print_text(h, "functions return");
1973 else
1974 print_text(h, "function returns");
1975
1976 print_text(h, "the value 0 if successful; otherwise the value "
1977 "-1 is returned and the global variable");
1978
1979 PAIR_CLASS_INIT(&tag, "var");
1980 t = print_otag(h, TAG_SPAN, 1, &tag);
1981 print_text(h, "errno");
1982 print_tagq(h, t);
1983 print_text(h, "is set to indicate the error.");
1984 return(0);
1985 }
1986
1987
1988 /* ARGSUSED */
1989 static int
1990 mdoc_va_pre(MDOC_ARGS)
1991 {
1992 struct htmlpair tag;
1993
1994 PAIR_CLASS_INIT(&tag, "var");
1995 print_otag(h, TAG_SPAN, 1, &tag);
1996 return(1);
1997 }
1998
1999
2000 /* ARGSUSED */
2001 static int
2002 mdoc_bq_pre(MDOC_ARGS)
2003 {
2004
2005 if (MDOC_BODY != n->type)
2006 return(1);
2007 print_text(h, "\\(lB");
2008 h->flags |= HTML_NOSPACE;
2009 return(1);
2010 }
2011
2012
2013 /* ARGSUSED */
2014 static void
2015 mdoc_bq_post(MDOC_ARGS)
2016 {
2017
2018 if (MDOC_BODY != n->type)
2019 return;
2020 h->flags |= HTML_NOSPACE;
2021 print_text(h, "\\(rB");
2022 }
2023
2024
2025 /* ARGSUSED */
2026 static int
2027 mdoc_ap_pre(MDOC_ARGS)
2028 {
2029
2030 h->flags |= HTML_NOSPACE;
2031 print_text(h, "\\(aq");
2032 h->flags |= HTML_NOSPACE;
2033 return(1);
2034 }
2035
2036
2037 /* ARGSUSED */
2038 static int
2039 mdoc_bf_pre(MDOC_ARGS)
2040 {
2041 struct htmlpair tag[2];
2042 struct roffsu su;
2043
2044 if (MDOC_HEAD == n->type)
2045 return(0);
2046 else if (MDOC_BODY != n->type)
2047 return(1);
2048
2049 assert(n->data.Bf);
2050
2051 if (FONT_Em == n->data.Bf->font)
2052 PAIR_CLASS_INIT(&tag[0], "emph");
2053 else if (FONT_Sy == n->data.Bf->font)
2054 PAIR_CLASS_INIT(&tag[0], "symb");
2055 else if (FONT_Li == n->data.Bf->font)
2056 PAIR_CLASS_INIT(&tag[0], "lit");
2057 else
2058 PAIR_CLASS_INIT(&tag[0], "none");
2059
2060 /*
2061 * We want this to be inline-formatted, but needs to be div to
2062 * accept block children.
2063 */
2064 bufcat_style(h, "display", "inline");
2065 SCALE_HS_INIT(&su, 1);
2066 /* Needs a left-margin for spacing. */
2067 bufcat_su(h, "margin-left", &su);
2068 PAIR_STYLE_INIT(&tag[1], h);
2069 print_otag(h, TAG_DIV, 2, tag);
2070 return(1);
2071 }
2072
2073
2074 /* ARGSUSED */
2075 static int
2076 mdoc_ms_pre(MDOC_ARGS)
2077 {
2078 struct htmlpair tag;
2079
2080 PAIR_CLASS_INIT(&tag, "symb");
2081 print_otag(h, TAG_SPAN, 1, &tag);
2082 return(1);
2083 }
2084
2085
2086 /* ARGSUSED */
2087 static int
2088 mdoc_pf_pre(MDOC_ARGS)
2089 {
2090
2091 h->flags |= HTML_IGNDELIM;
2092 return(1);
2093 }
2094
2095
2096 /* ARGSUSED */
2097 static void
2098 mdoc_pf_post(MDOC_ARGS)
2099 {
2100
2101 h->flags &= ~HTML_IGNDELIM;
2102 h->flags |= HTML_NOSPACE;
2103 }
2104
2105
2106 /* ARGSUSED */
2107 static int
2108 mdoc_rs_pre(MDOC_ARGS)
2109 {
2110 struct htmlpair tag;
2111 struct roffsu su;
2112
2113 if (MDOC_BLOCK != n->type)
2114 return(1);
2115
2116 if (n->prev && SEC_SEE_ALSO == n->sec) {
2117 SCALE_VS_INIT(&su, 1);
2118 bufcat_su(h, "margin-top", &su);
2119 PAIR_STYLE_INIT(&tag, h);
2120 print_otag(h, TAG_DIV, 1, &tag);
2121 }
2122
2123 PAIR_CLASS_INIT(&tag, "ref");
2124 print_otag(h, TAG_SPAN, 1, &tag);
2125 return(1);
2126 }
2127
2128
2129
2130 /* ARGSUSED */
2131 static int
2132 mdoc_li_pre(MDOC_ARGS)
2133 {
2134 struct htmlpair tag;
2135
2136 PAIR_CLASS_INIT(&tag, "lit");
2137 print_otag(h, TAG_SPAN, 1, &tag);
2138 return(1);
2139 }
2140
2141
2142 /* ARGSUSED */
2143 static int
2144 mdoc_sy_pre(MDOC_ARGS)
2145 {
2146 struct htmlpair tag;
2147
2148 PAIR_CLASS_INIT(&tag, "symb");
2149 print_otag(h, TAG_SPAN, 1, &tag);
2150 return(1);
2151 }
2152
2153
2154 /* ARGSUSED */
2155 static int
2156 mdoc_bt_pre(MDOC_ARGS)
2157 {
2158
2159 print_text(h, "is currently in beta test.");
2160 return(0);
2161 }
2162
2163
2164 /* ARGSUSED */
2165 static int
2166 mdoc_ud_pre(MDOC_ARGS)
2167 {
2168
2169 print_text(h, "currently under development.");
2170 return(0);
2171 }
2172
2173
2174 /* ARGSUSED */
2175 static int
2176 mdoc_lb_pre(MDOC_ARGS)
2177 {
2178 struct htmlpair tag;
2179
2180 if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
2181 print_otag(h, TAG_DIV, 0, NULL);
2182 PAIR_CLASS_INIT(&tag, "lib");
2183 print_otag(h, TAG_SPAN, 1, &tag);
2184 return(1);
2185 }
2186
2187
2188 /* ARGSUSED */
2189 static int
2190 mdoc__x_pre(MDOC_ARGS)
2191 {
2192 struct htmlpair tag[2];
2193
2194 switch (n->tok) {
2195 case(MDOC__A):
2196 PAIR_CLASS_INIT(&tag[0], "ref-auth");
2197 if (n->prev && MDOC__A == n->prev->tok)
2198 if (NULL == n->next || MDOC__A != n->next->tok)
2199 print_text(h, "and");
2200 break;
2201 case(MDOC__B):
2202 PAIR_CLASS_INIT(&tag[0], "ref-book");
2203 break;
2204 case(MDOC__C):
2205 PAIR_CLASS_INIT(&tag[0], "ref-city");
2206 break;
2207 case(MDOC__D):
2208 PAIR_CLASS_INIT(&tag[0], "ref-date");
2209 break;
2210 case(MDOC__I):
2211 PAIR_CLASS_INIT(&tag[0], "ref-issue");
2212 break;
2213 case(MDOC__J):
2214 PAIR_CLASS_INIT(&tag[0], "ref-jrnl");
2215 break;
2216 case(MDOC__N):
2217 PAIR_CLASS_INIT(&tag[0], "ref-num");
2218 break;
2219 case(MDOC__O):
2220 PAIR_CLASS_INIT(&tag[0], "ref-opt");
2221 break;
2222 case(MDOC__P):
2223 PAIR_CLASS_INIT(&tag[0], "ref-page");
2224 break;
2225 case(MDOC__Q):
2226 PAIR_CLASS_INIT(&tag[0], "ref-corp");
2227 break;
2228 case(MDOC__R):
2229 PAIR_CLASS_INIT(&tag[0], "ref-rep");
2230 break;
2231 case(MDOC__T):
2232 PAIR_CLASS_INIT(&tag[0], "ref-title");
2233 break;
2234 case(MDOC__U):
2235 PAIR_CLASS_INIT(&tag[0], "link-ref");
2236 break;
2237 case(MDOC__V):
2238 PAIR_CLASS_INIT(&tag[0], "ref-vol");
2239 break;
2240 default:
2241 abort();
2242 /* NOTREACHED */
2243 }
2244
2245 if (MDOC__U != n->tok) {
2246 print_otag(h, TAG_SPAN, 1, tag);
2247 return(1);
2248 }
2249
2250 PAIR_HREF_INIT(&tag[1], n->child->string);
2251 print_otag(h, TAG_A, 2, tag);
2252
2253 return(1);
2254 }
2255
2256
2257 /* ARGSUSED */
2258 static void
2259 mdoc__x_post(MDOC_ARGS)
2260 {
2261
2262 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
2263 if (NULL == n->next->next || MDOC__A != n->next->next->tok)
2264 if (NULL == n->prev || MDOC__A != n->prev->tok)
2265 return;
2266
2267 /* TODO: %U */
2268
2269 h->flags |= HTML_NOSPACE;
2270 print_text(h, n->next ? "," : ".");
2271 }
2272
2273
2274 /* ARGSUSED */
2275 static int
2276 mdoc_bk_pre(MDOC_ARGS)
2277 {
2278
2279 switch (n->type) {
2280 case (MDOC_BLOCK):
2281 break;
2282 case (MDOC_HEAD):
2283 return(0);
2284 case (MDOC_BODY):
2285 h->flags |= HTML_PREKEEP;
2286 break;
2287 default:
2288 abort();
2289 /* NOTREACHED */
2290 }
2291
2292 return(1);
2293 }
2294
2295
2296 /* ARGSUSED */
2297 static void
2298 mdoc_bk_post(MDOC_ARGS)
2299 {
2300
2301 if (MDOC_BODY == n->type)
2302 h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
2303 }