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