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