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