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