]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_html.c
Suppress whitespace following Pp, Lp, sp, and the other newline-emitting
[mandoc.git] / mdoc_html.c
1 /* $Id: mdoc_html.c,v 1.108 2010/09/27 11:21:39 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <sys/types.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "mandoc.h"
31 #include "out.h"
32 #include "html.h"
33 #include "mdoc.h"
34 #include "main.h"
35
36 #define INDENT 5
37 #define HALFINDENT 3
38
39 #define MDOC_ARGS const struct mdoc_meta *m, \
40 const struct mdoc_node *n, \
41 struct html *h
42
43 #ifndef MIN
44 #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
45 #endif
46
47 struct htmlmdoc {
48 int (*pre)(MDOC_ARGS);
49 void (*post)(MDOC_ARGS);
50 };
51
52 static void print_mdoc(MDOC_ARGS);
53 static void print_mdoc_head(MDOC_ARGS);
54 static void print_mdoc_node(MDOC_ARGS);
55 static void print_mdoc_nodelist(MDOC_ARGS);
56 static void synopsis_pre(struct html *,
57 const struct mdoc_node *);
58
59 static void a2width(const char *, struct roffsu *);
60 static void a2offs(const char *, struct roffsu *);
61
62 static void mdoc_root_post(MDOC_ARGS);
63 static int mdoc_root_pre(MDOC_ARGS);
64
65 static void mdoc__x_post(MDOC_ARGS);
66 static int mdoc__x_pre(MDOC_ARGS);
67 static int mdoc_ad_pre(MDOC_ARGS);
68 static int mdoc_an_pre(MDOC_ARGS);
69 static int mdoc_ap_pre(MDOC_ARGS);
70 static 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_in_pre(MDOC_ARGS);
95 static int mdoc_it_block_pre(MDOC_ARGS, enum mdoc_list,
96 int, struct roffsu *, struct roffsu *);
97 static int mdoc_it_head_pre(MDOC_ARGS, enum mdoc_list,
98 struct roffsu *);
99 static int mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list,
100 struct roffsu *);
101 static int mdoc_it_pre(MDOC_ARGS);
102 static int mdoc_lb_pre(MDOC_ARGS);
103 static int mdoc_li_pre(MDOC_ARGS);
104 static int mdoc_lk_pre(MDOC_ARGS);
105 static int mdoc_mt_pre(MDOC_ARGS);
106 static int mdoc_ms_pre(MDOC_ARGS);
107 static int mdoc_nd_pre(MDOC_ARGS);
108 static int mdoc_nm_pre(MDOC_ARGS);
109 static int mdoc_ns_pre(MDOC_ARGS);
110 static int mdoc_pa_pre(MDOC_ARGS);
111 static void mdoc_pf_post(MDOC_ARGS);
112 static int mdoc_pf_pre(MDOC_ARGS);
113 static void mdoc_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 {NULL, 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_pf_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 = "BSDI 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_br):
1327 /* FALLTHROUGH */
1328 case (MDOC_sp):
1329 /* FALLTHROUGH */
1330 case (MDOC_Bl):
1331 /* FALLTHROUGH */
1332 case (MDOC_Lp):
1333 /* FALLTHROUGH */
1334 case (MDOC_Pp):
1335 continue;
1336 default:
1337 break;
1338 }
1339 if (nn->next && nn->next->line == nn->line)
1340 continue;
1341 print_text(h, "\n");
1342 h->flags |= HTML_NOSPACE;
1343 }
1344
1345 return(0);
1346 }
1347
1348
1349 /* ARGSUSED */
1350 static int
1351 mdoc_pa_pre(MDOC_ARGS)
1352 {
1353 struct htmlpair tag;
1354
1355 PAIR_CLASS_INIT(&tag, "file");
1356 print_otag(h, TAG_SPAN, 1, &tag);
1357 return(1);
1358 }
1359
1360
1361 /* ARGSUSED */
1362 static int
1363 mdoc_ad_pre(MDOC_ARGS)
1364 {
1365 struct htmlpair tag;
1366
1367 PAIR_CLASS_INIT(&tag, "addr");
1368 print_otag(h, TAG_SPAN, 1, &tag);
1369 return(1);
1370 }
1371
1372
1373 /* ARGSUSED */
1374 static int
1375 mdoc_an_pre(MDOC_ARGS)
1376 {
1377 struct htmlpair tag;
1378
1379 /* TODO: -split and -nosplit (see termp_an_pre()). */
1380
1381 PAIR_CLASS_INIT(&tag, "author");
1382 print_otag(h, TAG_SPAN, 1, &tag);
1383 return(1);
1384 }
1385
1386
1387 /* ARGSUSED */
1388 static int
1389 mdoc_cd_pre(MDOC_ARGS)
1390 {
1391 struct htmlpair tag;
1392
1393 synopsis_pre(h, n);
1394 PAIR_CLASS_INIT(&tag, "config");
1395 print_otag(h, TAG_SPAN, 1, &tag);
1396 return(1);
1397 }
1398
1399
1400 /* ARGSUSED */
1401 static int
1402 mdoc_dv_pre(MDOC_ARGS)
1403 {
1404 struct htmlpair tag;
1405
1406 PAIR_CLASS_INIT(&tag, "define");
1407 print_otag(h, TAG_SPAN, 1, &tag);
1408 return(1);
1409 }
1410
1411
1412 /* ARGSUSED */
1413 static int
1414 mdoc_ev_pre(MDOC_ARGS)
1415 {
1416 struct htmlpair tag;
1417
1418 PAIR_CLASS_INIT(&tag, "env");
1419 print_otag(h, TAG_SPAN, 1, &tag);
1420 return(1);
1421 }
1422
1423
1424 /* ARGSUSED */
1425 static int
1426 mdoc_er_pre(MDOC_ARGS)
1427 {
1428 struct htmlpair tag;
1429
1430 PAIR_CLASS_INIT(&tag, "errno");
1431 print_otag(h, TAG_SPAN, 1, &tag);
1432 return(1);
1433 }
1434
1435
1436 /* ARGSUSED */
1437 static int
1438 mdoc_fa_pre(MDOC_ARGS)
1439 {
1440 const struct mdoc_node *nn;
1441 struct htmlpair tag;
1442 struct tag *t;
1443
1444 PAIR_CLASS_INIT(&tag, "farg");
1445 if (n->parent->tok != MDOC_Fo) {
1446 print_otag(h, TAG_SPAN, 1, &tag);
1447 return(1);
1448 }
1449
1450 for (nn = n->child; nn; nn = nn->next) {
1451 t = print_otag(h, TAG_SPAN, 1, &tag);
1452 print_text(h, nn->string);
1453 print_tagq(h, t);
1454 if (nn->next)
1455 print_text(h, ",");
1456 }
1457
1458 if (n->child && n->next && n->next->tok == MDOC_Fa)
1459 print_text(h, ",");
1460
1461 return(0);
1462 }
1463
1464
1465 /* ARGSUSED */
1466 static int
1467 mdoc_fd_pre(MDOC_ARGS)
1468 {
1469 struct htmlpair tag;
1470
1471 synopsis_pre(h, n);
1472
1473 PAIR_CLASS_INIT(&tag, "macro");
1474 print_otag(h, TAG_SPAN, 1, &tag);
1475 return(1);
1476 }
1477
1478
1479 /* ARGSUSED */
1480 static int
1481 mdoc_vt_pre(MDOC_ARGS)
1482 {
1483 struct htmlpair tag;
1484
1485 if (MDOC_BLOCK == n->type) {
1486 synopsis_pre(h, n);
1487 return(1);
1488 } else if (MDOC_ELEM == n->type) {
1489 synopsis_pre(h, n);
1490 } else if (MDOC_HEAD == n->type)
1491 return(0);
1492
1493 PAIR_CLASS_INIT(&tag, "type");
1494 print_otag(h, TAG_SPAN, 1, &tag);
1495 return(1);
1496 }
1497
1498
1499 /* ARGSUSED */
1500 static int
1501 mdoc_ft_pre(MDOC_ARGS)
1502 {
1503 struct htmlpair tag;
1504
1505 synopsis_pre(h, n);
1506 PAIR_CLASS_INIT(&tag, "ftype");
1507 print_otag(h, TAG_SPAN, 1, &tag);
1508 return(1);
1509 }
1510
1511
1512 /* ARGSUSED */
1513 static int
1514 mdoc_fn_pre(MDOC_ARGS)
1515 {
1516 struct tag *t;
1517 struct htmlpair tag[2];
1518 const struct mdoc_node *nn;
1519 char nbuf[BUFSIZ];
1520 const char *sp, *ep;
1521 int sz, i;
1522
1523 synopsis_pre(h, n);
1524
1525 /* Split apart into type and name. */
1526 assert(n->child->string);
1527 sp = n->child->string;
1528
1529 ep = strchr(sp, ' ');
1530 if (NULL != ep) {
1531 PAIR_CLASS_INIT(&tag[0], "ftype");
1532 t = print_otag(h, TAG_SPAN, 1, tag);
1533
1534 while (ep) {
1535 sz = MIN((int)(ep - sp), BUFSIZ - 1);
1536 (void)memcpy(nbuf, sp, (size_t)sz);
1537 nbuf[sz] = '\0';
1538 print_text(h, nbuf);
1539 sp = ++ep;
1540 ep = strchr(sp, ' ');
1541 }
1542 print_tagq(h, t);
1543 }
1544
1545 PAIR_CLASS_INIT(&tag[0], "fname");
1546
1547 /*
1548 * FIXME: only refer to IDs that we know exist.
1549 */
1550
1551 #if 0
1552 if (MDOC_SYNPRETTY & n->flags) {
1553 nbuf[0] = '\0';
1554 html_idcat(nbuf, sp, BUFSIZ);
1555 PAIR_ID_INIT(&tag[1], nbuf);
1556 } else {
1557 strlcpy(nbuf, "#", BUFSIZ);
1558 html_idcat(nbuf, sp, BUFSIZ);
1559 PAIR_HREF_INIT(&tag[1], nbuf);
1560 }
1561 #endif
1562
1563 t = print_otag(h, TAG_SPAN, 1, tag);
1564
1565 if (sp) {
1566 strlcpy(nbuf, sp, BUFSIZ);
1567 print_text(h, nbuf);
1568 }
1569
1570 print_tagq(h, t);
1571
1572 h->flags |= HTML_NOSPACE;
1573 print_text(h, "(");
1574
1575 bufinit(h);
1576 PAIR_CLASS_INIT(&tag[0], "farg");
1577 bufcat_style(h, "white-space", "nowrap");
1578 PAIR_STYLE_INIT(&tag[1], h);
1579
1580 for (nn = n->child->next; nn; nn = nn->next) {
1581 i = 1;
1582 if (MDOC_SYNPRETTY & n->flags)
1583 i = 2;
1584 t = print_otag(h, TAG_SPAN, i, tag);
1585 print_text(h, nn->string);
1586 print_tagq(h, t);
1587 if (nn->next)
1588 print_text(h, ",");
1589 }
1590
1591 print_text(h, ")");
1592 if (MDOC_SYNPRETTY & n->flags)
1593 print_text(h, ";");
1594
1595 return(0);
1596 }
1597
1598
1599 /* ARGSUSED */
1600 static int
1601 mdoc_sm_pre(MDOC_ARGS)
1602 {
1603
1604 assert(n->child && MDOC_TEXT == n->child->type);
1605 if (0 == strcmp("on", n->child->string)) {
1606 /* FIXME: no p->col to check... */
1607 h->flags &= ~HTML_NOSPACE;
1608 h->flags &= ~HTML_NONOSPACE;
1609 } else
1610 h->flags |= HTML_NONOSPACE;
1611
1612 return(0);
1613 }
1614
1615
1616 /* ARGSUSED */
1617 static int
1618 mdoc_sp_pre(MDOC_ARGS)
1619 {
1620 int len;
1621 struct htmlpair tag;
1622 struct roffsu su;
1623
1624 switch (n->tok) {
1625 case (MDOC_sp):
1626 /* FIXME: can this have a scaling indicator? */
1627 len = n->child ? atoi(n->child->string) : 1;
1628 break;
1629 case (MDOC_br):
1630 len = 0;
1631 break;
1632 default:
1633 assert(n->parent);
1634 if ((NULL == n->next || NULL == n->prev) &&
1635 (MDOC_Ss == n->parent->tok ||
1636 MDOC_Sh == n->parent->tok))
1637 return(0);
1638 len = 1;
1639 break;
1640 }
1641
1642 SCALE_VS_INIT(&su, len);
1643 bufcat_su(h, "height", &su);
1644 PAIR_STYLE_INIT(&tag, h);
1645 print_otag(h, TAG_DIV, 1, &tag);
1646 /* So the div isn't empty: */
1647 print_text(h, "\\~");
1648
1649 return(0);
1650
1651 }
1652
1653
1654 /* ARGSUSED */
1655 static int
1656 mdoc_lk_pre(MDOC_ARGS)
1657 {
1658 const struct mdoc_node *nn;
1659 struct htmlpair tag[2];
1660
1661 nn = n->child;
1662
1663 PAIR_CLASS_INIT(&tag[0], "link-ext");
1664 PAIR_HREF_INIT(&tag[1], nn->string);
1665 print_otag(h, TAG_A, 2, tag);
1666
1667 if (NULL == nn->next)
1668 return(1);
1669
1670 for (nn = nn->next; nn; nn = nn->next)
1671 print_text(h, nn->string);
1672
1673 return(0);
1674 }
1675
1676
1677 /* ARGSUSED */
1678 static int
1679 mdoc_mt_pre(MDOC_ARGS)
1680 {
1681 struct htmlpair tag[2];
1682 struct tag *t;
1683 const struct mdoc_node *nn;
1684
1685 PAIR_CLASS_INIT(&tag[0], "link-mail");
1686
1687 for (nn = n->child; nn; nn = nn->next) {
1688 bufinit(h);
1689 bufcat(h, "mailto:");
1690 bufcat(h, nn->string);
1691 PAIR_HREF_INIT(&tag[1], h->buf);
1692 t = print_otag(h, TAG_A, 2, tag);
1693 print_text(h, nn->string);
1694 print_tagq(h, t);
1695 }
1696
1697 return(0);
1698 }
1699
1700
1701 /* ARGSUSED */
1702 static int
1703 mdoc_fo_pre(MDOC_ARGS)
1704 {
1705 struct htmlpair tag;
1706 struct tag *t;
1707
1708 if (MDOC_BODY == n->type) {
1709 h->flags |= HTML_NOSPACE;
1710 print_text(h, "(");
1711 h->flags |= HTML_NOSPACE;
1712 return(1);
1713 } else if (MDOC_BLOCK == n->type) {
1714 synopsis_pre(h, n);
1715 return(1);
1716 }
1717
1718 /* XXX: we drop non-initial arguments as per groff. */
1719
1720 assert(n->child);
1721 assert(n->child->string);
1722
1723 PAIR_CLASS_INIT(&tag, "fname");
1724 t = print_otag(h, TAG_SPAN, 1, &tag);
1725 print_text(h, n->child->string);
1726 print_tagq(h, t);
1727 return(0);
1728 }
1729
1730
1731 /* ARGSUSED */
1732 static void
1733 mdoc_fo_post(MDOC_ARGS)
1734 {
1735
1736 if (MDOC_BODY != n->type)
1737 return;
1738 print_text(h, ")");
1739 print_text(h, ";");
1740 }
1741
1742
1743 /* ARGSUSED */
1744 static int
1745 mdoc_in_pre(MDOC_ARGS)
1746 {
1747 const struct mdoc_node *nn;
1748 struct tag *t;
1749 struct htmlpair tag[2];
1750 int i;
1751
1752 synopsis_pre(h, n);
1753
1754 PAIR_CLASS_INIT(&tag[0], "includes");
1755 print_otag(h, TAG_SPAN, 1, tag);
1756
1757 if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags)
1758 print_text(h, "#include");
1759
1760 print_text(h, "<");
1761 h->flags |= HTML_NOSPACE;
1762
1763 for (nn = n->child; nn; nn = nn->next) {
1764 PAIR_CLASS_INIT(&tag[0], "link-includes");
1765 i = 1;
1766 bufinit(h);
1767 if (h->base_includes) {
1768 buffmt_includes(h, nn->string);
1769 PAIR_HREF_INIT(&tag[i], h->buf);
1770 i++;
1771 }
1772 t = print_otag(h, TAG_A, i, tag);
1773 print_mdoc_node(m, nn, h);
1774 print_tagq(h, t);
1775 }
1776
1777 h->flags |= HTML_NOSPACE;
1778 print_text(h, ">");
1779
1780 return(0);
1781 }
1782
1783
1784 /* ARGSUSED */
1785 static int
1786 mdoc_ic_pre(MDOC_ARGS)
1787 {
1788 struct htmlpair tag;
1789
1790 PAIR_CLASS_INIT(&tag, "cmd");
1791 print_otag(h, TAG_SPAN, 1, &tag);
1792 return(1);
1793 }
1794
1795
1796 /* ARGSUSED */
1797 static int
1798 mdoc_rv_pre(MDOC_ARGS)
1799 {
1800 const struct mdoc_node *nn;
1801 struct htmlpair tag;
1802 struct tag *t;
1803
1804 print_otag(h, TAG_DIV, 0, NULL);
1805 print_text(h, "The");
1806
1807 for (nn = n->child; nn; nn = nn->next) {
1808 PAIR_CLASS_INIT(&tag, "fname");
1809 t = print_otag(h, TAG_SPAN, 1, &tag);
1810 print_text(h, nn->string);
1811 print_tagq(h, t);
1812
1813 h->flags |= HTML_NOSPACE;
1814 if (nn->next && NULL == nn->next->next)
1815 print_text(h, "(), and");
1816 else if (nn->next)
1817 print_text(h, "(),");
1818 else
1819 print_text(h, "()");
1820 }
1821
1822 if (n->child && n->child->next)
1823 print_text(h, "functions return");
1824 else
1825 print_text(h, "function returns");
1826
1827 print_text(h, "the value 0 if successful; otherwise the value "
1828 "-1 is returned and the global variable");
1829
1830 PAIR_CLASS_INIT(&tag, "var");
1831 t = print_otag(h, TAG_SPAN, 1, &tag);
1832 print_text(h, "errno");
1833 print_tagq(h, t);
1834 print_text(h, "is set to indicate the error.");
1835 return(0);
1836 }
1837
1838
1839 /* ARGSUSED */
1840 static int
1841 mdoc_va_pre(MDOC_ARGS)
1842 {
1843 struct htmlpair tag;
1844
1845 PAIR_CLASS_INIT(&tag, "var");
1846 print_otag(h, TAG_SPAN, 1, &tag);
1847 return(1);
1848 }
1849
1850
1851 /* ARGSUSED */
1852 static int
1853 mdoc_ap_pre(MDOC_ARGS)
1854 {
1855
1856 h->flags |= HTML_NOSPACE;
1857 print_text(h, "\\(aq");
1858 h->flags |= HTML_NOSPACE;
1859 return(1);
1860 }
1861
1862
1863 /* ARGSUSED */
1864 static int
1865 mdoc_bf_pre(MDOC_ARGS)
1866 {
1867 struct htmlpair tag[2];
1868 struct roffsu su;
1869
1870 if (MDOC_HEAD == n->type)
1871 return(0);
1872 else if (MDOC_BODY != n->type)
1873 return(1);
1874
1875 assert(n->data.Bf);
1876
1877 if (FONT_Em == n->data.Bf->font)
1878 PAIR_CLASS_INIT(&tag[0], "emph");
1879 else if (FONT_Sy == n->data.Bf->font)
1880 PAIR_CLASS_INIT(&tag[0], "symb");
1881 else if (FONT_Li == n->data.Bf->font)
1882 PAIR_CLASS_INIT(&tag[0], "lit");
1883 else
1884 PAIR_CLASS_INIT(&tag[0], "none");
1885
1886 /*
1887 * We want this to be inline-formatted, but needs to be div to
1888 * accept block children.
1889 */
1890 bufcat_style(h, "display", "inline");
1891 SCALE_HS_INIT(&su, 1);
1892 /* Needs a left-margin for spacing. */
1893 bufcat_su(h, "margin-left", &su);
1894 PAIR_STYLE_INIT(&tag[1], h);
1895 print_otag(h, TAG_DIV, 2, tag);
1896 return(1);
1897 }
1898
1899
1900 /* ARGSUSED */
1901 static int
1902 mdoc_ms_pre(MDOC_ARGS)
1903 {
1904 struct htmlpair tag;
1905
1906 PAIR_CLASS_INIT(&tag, "symb");
1907 print_otag(h, TAG_SPAN, 1, &tag);
1908 return(1);
1909 }
1910
1911
1912 /* ARGSUSED */
1913 static int
1914 mdoc_pf_pre(MDOC_ARGS)
1915 {
1916
1917 h->flags |= HTML_IGNDELIM;
1918 return(1);
1919 }
1920
1921
1922 /* ARGSUSED */
1923 static void
1924 mdoc_pf_post(MDOC_ARGS)
1925 {
1926
1927 h->flags &= ~HTML_IGNDELIM;
1928 h->flags |= HTML_NOSPACE;
1929 }
1930
1931
1932 /* ARGSUSED */
1933 static int
1934 mdoc_rs_pre(MDOC_ARGS)
1935 {
1936 struct htmlpair tag;
1937
1938 if (MDOC_BLOCK != n->type)
1939 return(1);
1940
1941 if (n->prev && SEC_SEE_ALSO == n->sec) {
1942 print_otag(h, TAG_BR, 0, NULL);
1943 print_otag(h, TAG_BR, 0, NULL);
1944 }
1945
1946 PAIR_CLASS_INIT(&tag, "ref");
1947 print_otag(h, TAG_SPAN, 1, &tag);
1948 return(1);
1949 }
1950
1951
1952
1953 /* ARGSUSED */
1954 static int
1955 mdoc_li_pre(MDOC_ARGS)
1956 {
1957 struct htmlpair tag;
1958
1959 PAIR_CLASS_INIT(&tag, "lit");
1960 print_otag(h, TAG_SPAN, 1, &tag);
1961 return(1);
1962 }
1963
1964
1965 /* ARGSUSED */
1966 static int
1967 mdoc_sy_pre(MDOC_ARGS)
1968 {
1969 struct htmlpair tag;
1970
1971 PAIR_CLASS_INIT(&tag, "symb");
1972 print_otag(h, TAG_SPAN, 1, &tag);
1973 return(1);
1974 }
1975
1976
1977 /* ARGSUSED */
1978 static int
1979 mdoc_bt_pre(MDOC_ARGS)
1980 {
1981
1982 print_text(h, "is currently in beta test.");
1983 return(0);
1984 }
1985
1986
1987 /* ARGSUSED */
1988 static int
1989 mdoc_ud_pre(MDOC_ARGS)
1990 {
1991
1992 print_text(h, "currently under development.");
1993 return(0);
1994 }
1995
1996
1997 /* ARGSUSED */
1998 static int
1999 mdoc_lb_pre(MDOC_ARGS)
2000 {
2001 struct htmlpair tag;
2002
2003 if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
2004 print_otag(h, TAG_DIV, 0, NULL);
2005 PAIR_CLASS_INIT(&tag, "lib");
2006 print_otag(h, TAG_SPAN, 1, &tag);
2007 return(1);
2008 }
2009
2010
2011 /* ARGSUSED */
2012 static int
2013 mdoc__x_pre(MDOC_ARGS)
2014 {
2015 struct htmlpair tag[2];
2016
2017 switch (n->tok) {
2018 case(MDOC__A):
2019 PAIR_CLASS_INIT(&tag[0], "ref-auth");
2020 if (n->prev && MDOC__A == n->prev->tok)
2021 if (NULL == n->next || MDOC__A != n->next->tok)
2022 print_text(h, "and");
2023 break;
2024 case(MDOC__B):
2025 PAIR_CLASS_INIT(&tag[0], "ref-book");
2026 break;
2027 case(MDOC__C):
2028 PAIR_CLASS_INIT(&tag[0], "ref-city");
2029 break;
2030 case(MDOC__D):
2031 PAIR_CLASS_INIT(&tag[0], "ref-date");
2032 break;
2033 case(MDOC__I):
2034 PAIR_CLASS_INIT(&tag[0], "ref-issue");
2035 break;
2036 case(MDOC__J):
2037 PAIR_CLASS_INIT(&tag[0], "ref-jrnl");
2038 break;
2039 case(MDOC__N):
2040 PAIR_CLASS_INIT(&tag[0], "ref-num");
2041 break;
2042 case(MDOC__O):
2043 PAIR_CLASS_INIT(&tag[0], "ref-opt");
2044 break;
2045 case(MDOC__P):
2046 PAIR_CLASS_INIT(&tag[0], "ref-page");
2047 break;
2048 case(MDOC__Q):
2049 PAIR_CLASS_INIT(&tag[0], "ref-corp");
2050 break;
2051 case(MDOC__R):
2052 PAIR_CLASS_INIT(&tag[0], "ref-rep");
2053 break;
2054 case(MDOC__T):
2055 PAIR_CLASS_INIT(&tag[0], "ref-title");
2056 break;
2057 case(MDOC__U):
2058 PAIR_CLASS_INIT(&tag[0], "link-ref");
2059 break;
2060 case(MDOC__V):
2061 PAIR_CLASS_INIT(&tag[0], "ref-vol");
2062 break;
2063 default:
2064 abort();
2065 /* NOTREACHED */
2066 }
2067
2068 if (MDOC__U != n->tok) {
2069 print_otag(h, TAG_SPAN, 1, tag);
2070 return(1);
2071 }
2072
2073 PAIR_HREF_INIT(&tag[1], n->child->string);
2074 print_otag(h, TAG_A, 2, tag);
2075
2076 return(1);
2077 }
2078
2079
2080 /* ARGSUSED */
2081 static void
2082 mdoc__x_post(MDOC_ARGS)
2083 {
2084
2085 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
2086 if (NULL == n->next->next || MDOC__A != n->next->next->tok)
2087 if (NULL == n->prev || MDOC__A != n->prev->tok)
2088 return;
2089
2090 /* TODO: %U */
2091
2092 if (NULL == n->parent || MDOC_Rs != n->parent->tok)
2093 return;
2094
2095 print_text(h, n->next ? "," : ".");
2096 }
2097
2098
2099 /* ARGSUSED */
2100 static int
2101 mdoc_bk_pre(MDOC_ARGS)
2102 {
2103
2104 switch (n->type) {
2105 case (MDOC_BLOCK):
2106 break;
2107 case (MDOC_HEAD):
2108 return(0);
2109 case (MDOC_BODY):
2110 h->flags |= HTML_PREKEEP;
2111 break;
2112 default:
2113 abort();
2114 /* NOTREACHED */
2115 }
2116
2117 return(1);
2118 }
2119
2120
2121 /* ARGSUSED */
2122 static void
2123 mdoc_bk_post(MDOC_ARGS)
2124 {
2125
2126 if (MDOC_BODY == n->type)
2127 h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
2128 }
2129
2130
2131 /* ARGSUSED */
2132 static int
2133 mdoc_quote_pre(MDOC_ARGS)
2134 {
2135 struct htmlpair tag;
2136
2137 if (MDOC_BODY != n->type)
2138 return(1);
2139
2140 switch (n->tok) {
2141 case (MDOC_Ao):
2142 /* FALLTHROUGH */
2143 case (MDOC_Aq):
2144 print_text(h, "\\(la");
2145 break;
2146 case (MDOC_Bro):
2147 /* FALLTHROUGH */
2148 case (MDOC_Brq):
2149 print_text(h, "\\(lC");
2150 break;
2151 case (MDOC_Bo):
2152 /* FALLTHROUGH */
2153 case (MDOC_Bq):
2154 print_text(h, "\\(lB");
2155 break;
2156 case (MDOC_Oo):
2157 /* FALLTHROUGH */
2158 case (MDOC_Op):
2159 print_text(h, "\\(lB");
2160 PAIR_CLASS_INIT(&tag, "opt");
2161 print_otag(h, TAG_SPAN, 1, &tag);
2162 break;
2163 case (MDOC_Do):
2164 /* FALLTHROUGH */
2165 case (MDOC_Dq):
2166 /* FALLTHROUGH */
2167 case (MDOC_Qo):
2168 /* FALLTHROUGH */
2169 case (MDOC_Qq):
2170 print_text(h, "\\(lq");
2171 break;
2172 case (MDOC_Po):
2173 /* FALLTHROUGH */
2174 case (MDOC_Pq):
2175 print_text(h, "(");
2176 break;
2177 case (MDOC_Ql):
2178 /* FALLTHROUGH */
2179 case (MDOC_So):
2180 /* FALLTHROUGH */
2181 case (MDOC_Sq):
2182 print_text(h, "\\(oq");
2183 break;
2184 default:
2185 abort();
2186 /* NOTREACHED */
2187 }
2188
2189 h->flags |= HTML_NOSPACE;
2190 return(1);
2191 }
2192
2193
2194 /* ARGSUSED */
2195 static void
2196 mdoc_quote_post(MDOC_ARGS)
2197 {
2198
2199 if (MDOC_BODY != n->type)
2200 return;
2201
2202 h->flags |= HTML_NOSPACE;
2203
2204 switch (n->tok) {
2205 case (MDOC_Ao):
2206 /* FALLTHROUGH */
2207 case (MDOC_Aq):
2208 print_text(h, "\\(ra");
2209 break;
2210 case (MDOC_Bro):
2211 /* FALLTHROUGH */
2212 case (MDOC_Brq):
2213 print_text(h, "\\(rC");
2214 break;
2215 case (MDOC_Oo):
2216 /* FALLTHROUGH */
2217 case (MDOC_Op):
2218 /* FALLTHROUGH */
2219 case (MDOC_Bo):
2220 /* FALLTHROUGH */
2221 case (MDOC_Bq):
2222 print_text(h, "\\(rB");
2223 break;
2224 case (MDOC_Qo):
2225 /* FALLTHROUGH */
2226 case (MDOC_Qq):
2227 /* FALLTHROUGH */
2228 case (MDOC_Do):
2229 /* FALLTHROUGH */
2230 case (MDOC_Dq):
2231 print_text(h, "\\(rq");
2232 break;
2233 case (MDOC_Po):
2234 /* FALLTHROUGH */
2235 case (MDOC_Pq):
2236 print_text(h, ")");
2237 break;
2238 case (MDOC_Ql):
2239 /* FALLTHROUGH */
2240 case (MDOC_So):
2241 /* FALLTHROUGH */
2242 case (MDOC_Sq):
2243 print_text(h, "\\(aq");
2244 break;
2245 default:
2246 abort();
2247 /* NOTREACHED */
2248 }
2249 }
2250
2251