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